blob: 5ec0e39593b532af62f75ad52a4a50200fed2b9b [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 Wangbb3c6bf2009-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 Iwaibc9b5622008-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 Iwaibc9b5622008-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 Iwaibc9b5622008-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{
2046 unsigned int hp_present, present = 0;
2047 struct via_spec *spec = codec->spec;
2048 int i;
2049
2050 if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
2051 return;
2052
2053 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
2054 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2055
2056 present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0,
2057 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2058
2059 if (!spec->hp_independent_mode) {
2060 /* Mute Line-Outs */
2061 for (i = 0; i < spec->autocfg.line_outs; i++)
2062 snd_hda_codec_amp_stereo(
2063 codec, spec->autocfg.line_out_pins[i],
2064 HDA_OUTPUT, 0,
2065 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
2066 if (hp_present)
2067 present = hp_present;
2068 }
2069 /* Speakers */
2070 for (i = 0; i < spec->autocfg.speaker_outs; i++)
2071 snd_hda_codec_amp_stereo(
2072 codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
2073 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
2074}
2075
2076
Harald Welte69e52a82008-09-09 15:57:32 +08002077/* unsolicited event for jack sensing */
2078static void via_unsol_event(struct hda_codec *codec,
2079 unsigned int res)
2080{
2081 res >>= 26;
Lydia Wanga34df192009-10-10 19:08:01 +08002082 if (res & VIA_HP_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08002083 via_hp_automute(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08002084 if (res & VIA_GPIO_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08002085 via_gpio_control(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08002086 if (res & VIA_JACK_EVENT)
2087 set_jack_power_state(codec);
Lydia Wangf3db4232009-10-10 19:08:41 +08002088 if (res & VIA_MONO_EVENT)
2089 via_mono_automute(codec);
Lydia Wang25eaba22009-10-10 19:08:43 +08002090 if (res & VIA_SPEAKER_EVENT)
2091 via_speaker_automute(codec);
2092 if (res & VIA_BIND_HP_EVENT)
2093 via_hp_bind_automute(codec);
Harald Welte69e52a82008-09-09 15:57:32 +08002094}
2095
Joseph Chanc577b8a2006-11-29 15:29:40 +01002096static int via_init(struct hda_codec *codec)
2097{
2098 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +08002099 int i;
2100 for (i = 0; i < spec->num_iverbs; i++)
2101 snd_hda_sequence_write(codec, spec->init_verbs[i]);
2102
Lydia Wang518bf3b2009-10-10 19:07:29 +08002103 spec->codec_type = get_codec_type(codec);
2104 if (spec->codec_type == VT1708BCE)
2105 spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
2106 same */
Josepch Chanf7278fd2007-12-13 16:40:40 +01002107 /* Lydia Add for EAPD enable */
2108 if (!spec->dig_in_nid) { /* No Digital In connection */
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002109 if (spec->dig_in_pin) {
2110 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002111 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +01002112 PIN_OUT);
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002113 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002114 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
2115 }
Takashi Iwai12b74c82008-01-15 12:39:38 +01002116 } else /* enable SPDIF-input pin */
2117 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
2118 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002119
Takashi Iwai9da29272009-05-07 16:31:14 +02002120 /* assign slave outs */
2121 if (spec->slave_dig_outs[0])
2122 codec->slave_dig_outs = spec->slave_dig_outs;
Harald Welte5691ec72008-09-15 22:42:26 +08002123
Lydia Wang377ff312009-10-10 19:08:55 +08002124 return 0;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002125}
2126
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002127#ifdef SND_HDA_NEEDS_RESUME
2128static int via_suspend(struct hda_codec *codec, pm_message_t state)
2129{
2130 struct via_spec *spec = codec->spec;
2131 vt1708_stop_hp_work(spec);
2132 return 0;
2133}
2134#endif
2135
Takashi Iwaicb53c622007-08-10 17:21:45 +02002136#ifdef CONFIG_SND_HDA_POWER_SAVE
2137static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2138{
2139 struct via_spec *spec = codec->spec;
2140 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2141}
2142#endif
2143
Joseph Chanc577b8a2006-11-29 15:29:40 +01002144/*
2145 */
2146static struct hda_codec_ops via_patch_ops = {
2147 .build_controls = via_build_controls,
2148 .build_pcms = via_build_pcms,
2149 .init = via_init,
2150 .free = via_free,
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002151#ifdef SND_HDA_NEEDS_RESUME
2152 .suspend = via_suspend,
2153#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002154#ifdef CONFIG_SND_HDA_POWER_SAVE
2155 .check_power_status = via_check_power_status,
2156#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002157};
2158
2159/* fill in the dac_nids table from the parsed pin configuration */
2160static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
2161 const struct auto_pin_cfg *cfg)
2162{
2163 int i;
2164 hda_nid_t nid;
2165
2166 spec->multiout.num_dacs = cfg->line_outs;
2167
2168 spec->multiout.dac_nids = spec->private_dac_nids;
Lydia Wang377ff312009-10-10 19:08:55 +08002169
2170 for (i = 0; i < 4; i++) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002171 nid = cfg->line_out_pins[i];
2172 if (nid) {
2173 /* config dac list */
2174 switch (i) {
2175 case AUTO_SEQ_FRONT:
2176 spec->multiout.dac_nids[i] = 0x10;
2177 break;
2178 case AUTO_SEQ_CENLFE:
2179 spec->multiout.dac_nids[i] = 0x12;
2180 break;
2181 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002182 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002183 break;
2184 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002185 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002186 break;
2187 }
2188 }
2189 }
2190
2191 return 0;
2192}
2193
2194/* add playback controls from the parsed DAC table */
2195static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
2196 const struct auto_pin_cfg *cfg)
2197{
2198 char name[32];
2199 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang9645c202009-10-10 19:08:27 +08002200 hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002201 int i, err;
2202
2203 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2204 nid = cfg->line_out_pins[i];
2205
2206 if (!nid)
2207 continue;
Lydia Wang377ff312009-10-10 19:08:55 +08002208
Lydia Wang9645c202009-10-10 19:08:27 +08002209 nid_vol = nid_vols[i];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002210
2211 if (i == AUTO_SEQ_CENLFE) {
2212 /* Center/LFE */
2213 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002214 "Center Playback Volume",
2215 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2216 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002217 if (err < 0)
2218 return err;
2219 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2220 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002221 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2222 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002223 if (err < 0)
2224 return err;
2225 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2226 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002227 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2228 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002229 if (err < 0)
2230 return err;
2231 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2232 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002233 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2234 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002235 if (err < 0)
2236 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002237 } else if (i == AUTO_SEQ_FRONT) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002238 /* add control to mixer index 0 */
2239 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2240 "Master Front Playback Volume",
Lydia Wang9645c202009-10-10 19:08:27 +08002241 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002242 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002243 if (err < 0)
2244 return err;
2245 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2246 "Master Front Playback Switch",
Lydia Wang9645c202009-10-10 19:08:27 +08002247 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002248 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002249 if (err < 0)
2250 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002251
Joseph Chanc577b8a2006-11-29 15:29:40 +01002252 /* add control to PW3 */
2253 sprintf(name, "%s Playback Volume", chname[i]);
2254 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002255 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2256 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002257 if (err < 0)
2258 return err;
2259 sprintf(name, "%s Playback Switch", chname[i]);
2260 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002261 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2262 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002263 if (err < 0)
2264 return err;
2265 } else {
2266 sprintf(name, "%s Playback Volume", chname[i]);
2267 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002268 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2269 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002270 if (err < 0)
2271 return err;
2272 sprintf(name, "%s Playback Switch", chname[i]);
2273 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002274 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2275 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002276 if (err < 0)
2277 return err;
2278 }
2279 }
2280
2281 return 0;
2282}
2283
Harald Welte0aa62ae2008-09-09 15:58:27 +08002284static void create_hp_imux(struct via_spec *spec)
2285{
2286 int i;
2287 struct hda_input_mux *imux = &spec->private_imux[1];
2288 static const char *texts[] = { "OFF", "ON", NULL};
2289
2290 /* for hp mode select */
2291 i = 0;
2292 while (texts[i] != NULL) {
2293 imux->items[imux->num_items].label = texts[i];
2294 imux->items[imux->num_items].index = i;
2295 imux->num_items++;
2296 i++;
2297 }
2298
2299 spec->hp_mux = &spec->private_imux[1];
2300}
2301
Joseph Chanc577b8a2006-11-29 15:29:40 +01002302static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2303{
2304 int err;
2305
2306 if (!pin)
2307 return 0;
2308
2309 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08002310 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002311
2312 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2313 "Headphone Playback Volume",
2314 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2315 if (err < 0)
2316 return err;
2317 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2318 "Headphone Playback Switch",
2319 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2320 if (err < 0)
2321 return err;
2322
Harald Welte0aa62ae2008-09-09 15:58:27 +08002323 create_hp_imux(spec);
2324
Joseph Chanc577b8a2006-11-29 15:29:40 +01002325 return 0;
2326}
2327
2328/* create playback/capture controls for input pins */
2329static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
2330 const struct auto_pin_cfg *cfg)
2331{
2332 static char *labels[] = {
2333 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2334 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002335 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002336 int i, err, idx = 0;
2337
2338 /* for internal loopback recording select */
2339 imux->items[imux->num_items].label = "Stereo Mixer";
2340 imux->items[imux->num_items].index = idx;
2341 imux->num_items++;
2342
2343 for (i = 0; i < AUTO_PIN_LAST; i++) {
2344 if (!cfg->input_pins[i])
2345 continue;
2346
2347 switch (cfg->input_pins[i]) {
2348 case 0x1d: /* Mic */
2349 idx = 2;
2350 break;
Lydia Wang377ff312009-10-10 19:08:55 +08002351
Joseph Chanc577b8a2006-11-29 15:29:40 +01002352 case 0x1e: /* Line In */
2353 idx = 3;
2354 break;
2355
2356 case 0x21: /* Front Mic */
2357 idx = 4;
2358 break;
2359
2360 case 0x24: /* CD */
2361 idx = 1;
2362 break;
2363 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002364 err = via_new_analog_input(spec, labels[i], idx, 0x17);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002365 if (err < 0)
2366 return err;
2367 imux->items[imux->num_items].label = labels[i];
2368 imux->items[imux->num_items].index = idx;
2369 imux->num_items++;
2370 }
2371 return 0;
2372}
2373
Takashi Iwaicb53c622007-08-10 17:21:45 +02002374#ifdef CONFIG_SND_HDA_POWER_SAVE
2375static struct hda_amp_list vt1708_loopbacks[] = {
2376 { 0x17, HDA_INPUT, 1 },
2377 { 0x17, HDA_INPUT, 2 },
2378 { 0x17, HDA_INPUT, 3 },
2379 { 0x17, HDA_INPUT, 4 },
2380 { } /* end */
2381};
2382#endif
2383
Harald Welte76d9b0d2008-09-09 15:50:37 +08002384static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
2385{
2386 unsigned int def_conf;
2387 unsigned char seqassoc;
2388
Takashi Iwai2f334f92009-02-20 14:37:42 +01002389 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Harald Welte76d9b0d2008-09-09 15:50:37 +08002390 seqassoc = (unsigned char) get_defcfg_association(def_conf);
2391 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
Lydia Wang82ef9e42009-10-10 19:08:19 +08002392 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
2393 && (seqassoc == 0xf0 || seqassoc == 0xff)) {
2394 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
2395 snd_hda_codec_set_pincfg(codec, nid, def_conf);
Harald Welte76d9b0d2008-09-09 15:50:37 +08002396 }
2397
2398 return;
2399}
2400
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002401static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
2402 struct snd_ctl_elem_value *ucontrol)
2403{
2404 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2405 struct via_spec *spec = codec->spec;
2406
2407 if (spec->codec_type != VT1708)
2408 return 0;
2409 spec->vt1708_jack_detectect =
2410 !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
2411 ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
2412 return 0;
2413}
2414
2415static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
2416 struct snd_ctl_elem_value *ucontrol)
2417{
2418 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2419 struct via_spec *spec = codec->spec;
2420 int change;
2421
2422 if (spec->codec_type != VT1708)
2423 return 0;
2424 spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
2425 change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
2426 == !spec->vt1708_jack_detectect;
2427 if (spec->vt1708_jack_detectect) {
2428 mute_aa_path(codec, 1);
2429 notify_aa_path_ctls(codec);
2430 }
2431 return change;
2432}
2433
2434static struct snd_kcontrol_new vt1708_jack_detectect[] = {
2435 {
2436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2437 .name = "Jack Detect",
2438 .count = 1,
2439 .info = snd_ctl_boolean_mono_info,
2440 .get = vt1708_jack_detectect_get,
2441 .put = vt1708_jack_detectect_put,
2442 },
2443 {} /* end */
2444};
2445
Joseph Chanc577b8a2006-11-29 15:29:40 +01002446static int vt1708_parse_auto_config(struct hda_codec *codec)
2447{
2448 struct via_spec *spec = codec->spec;
2449 int err;
2450
Harald Welte76d9b0d2008-09-09 15:50:37 +08002451 /* Add HP and CD pin config connect bit re-config action */
2452 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
2453 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
2454
Joseph Chanc577b8a2006-11-29 15:29:40 +01002455 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2456 if (err < 0)
2457 return err;
2458 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
2459 if (err < 0)
2460 return err;
2461 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2462 return 0; /* can't find valid BIOS pin config */
2463
2464 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
2465 if (err < 0)
2466 return err;
2467 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2468 if (err < 0)
2469 return err;
2470 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
2471 if (err < 0)
2472 return err;
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002473 /* add jack detect on/off control */
2474 err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
2475 if (err < 0)
2476 return err;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002477
2478 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2479
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002480 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002481 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002482 spec->dig_in_pin = VT1708_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002483 if (spec->autocfg.dig_in_pin)
2484 spec->dig_in_nid = VT1708_DIGIN_NID;
2485
Takashi Iwai603c4012008-07-30 15:01:44 +02002486 if (spec->kctls.list)
2487 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002488
Harald Welte69e52a82008-09-09 15:57:32 +08002489 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002490
Harald Welte0aa62ae2008-09-09 15:58:27 +08002491 spec->input_mux = &spec->private_imux[0];
2492
Harald Weltef8fdd492008-09-15 22:41:31 +08002493 if (spec->hp_mux)
2494 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002495
Lydia Wang1564b282009-10-10 19:07:52 +08002496 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002497 return 1;
2498}
2499
2500/* init callback for auto-configuration model -- overriding the default init */
2501static int via_auto_init(struct hda_codec *codec)
2502{
Lydia Wang25eaba22009-10-10 19:08:43 +08002503 struct via_spec *spec = codec->spec;
2504
Joseph Chanc577b8a2006-11-29 15:29:40 +01002505 via_init(codec);
2506 via_auto_init_multi_out(codec);
2507 via_auto_init_hp_out(codec);
2508 via_auto_init_analog_input(codec);
Lydia Wangab6734e2009-10-10 19:08:46 +08002509 if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
Lydia Wang25eaba22009-10-10 19:08:43 +08002510 via_hp_bind_automute(codec);
2511 } else {
2512 via_hp_automute(codec);
2513 via_speaker_automute(codec);
2514 }
2515
Joseph Chanc577b8a2006-11-29 15:29:40 +01002516 return 0;
2517}
2518
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002519static void vt1708_update_hp_jack_state(struct work_struct *work)
2520{
2521 struct via_spec *spec = container_of(work, struct via_spec,
2522 vt1708_hp_work.work);
2523 if (spec->codec_type != VT1708)
2524 return;
2525 /* if jack state toggled */
2526 if (spec->vt1708_hp_present
2527 != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0,
2528 AC_VERB_GET_PIN_SENSE, 0) >> 31)) {
2529 spec->vt1708_hp_present ^= 1;
2530 via_hp_automute(spec->codec);
2531 }
2532 vt1708_start_hp_work(spec);
2533}
2534
Takashi Iwai337b9d02009-07-07 18:18:59 +02002535static int get_mux_nids(struct hda_codec *codec)
2536{
2537 struct via_spec *spec = codec->spec;
2538 hda_nid_t nid, conn[8];
2539 unsigned int type;
2540 int i, n;
2541
2542 for (i = 0; i < spec->num_adc_nids; i++) {
2543 nid = spec->adc_nids[i];
2544 while (nid) {
Takashi Iwaia22d5432009-07-27 12:54:26 +02002545 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai1c55d522009-07-08 07:45:46 +02002546 if (type == AC_WID_PIN)
2547 break;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002548 n = snd_hda_get_connections(codec, nid, conn,
2549 ARRAY_SIZE(conn));
2550 if (n <= 0)
2551 break;
2552 if (n > 1) {
2553 spec->mux_nids[i] = nid;
2554 break;
2555 }
2556 nid = conn[0];
2557 }
2558 }
Takashi Iwai1c55d522009-07-08 07:45:46 +02002559 return 0;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002560}
2561
Joseph Chanc577b8a2006-11-29 15:29:40 +01002562static int patch_vt1708(struct hda_codec *codec)
2563{
2564 struct via_spec *spec;
2565 int err;
2566
2567 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002568 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002569 if (spec == NULL)
2570 return -ENOMEM;
2571
2572 codec->spec = spec;
2573
2574 /* automatic parse from the BIOS config */
2575 err = vt1708_parse_auto_config(codec);
2576 if (err < 0) {
2577 via_free(codec);
2578 return err;
2579 } else if (!err) {
2580 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2581 "from BIOS. Using genenic mode...\n");
2582 }
2583
Lydia Wang377ff312009-10-10 19:08:55 +08002584
Joseph Chanc577b8a2006-11-29 15:29:40 +01002585 spec->stream_name_analog = "VT1708 Analog";
2586 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +02002587 /* disable 32bit format on VT1708 */
2588 if (codec->vendor_id == 0x11061708)
2589 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002590 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
2591
2592 spec->stream_name_digital = "VT1708 Digital";
2593 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
2594 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
2595
Lydia Wang377ff312009-10-10 19:08:55 +08002596
Joseph Chanc577b8a2006-11-29 15:29:40 +01002597 if (!spec->adc_nids && spec->input_mux) {
2598 spec->adc_nids = vt1708_adc_nids;
2599 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
Takashi Iwai0f67a612009-08-31 08:12:29 +02002600 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002601 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
2602 spec->num_mixers++;
2603 }
2604
2605 codec->patch_ops = via_patch_ops;
2606
2607 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002608#ifdef CONFIG_SND_HDA_POWER_SAVE
2609 spec->loopback.amplist = vt1708_loopbacks;
2610#endif
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002611 spec->codec = codec;
2612 INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002613 return 0;
2614}
2615
2616/* capture mixer elements */
2617static struct snd_kcontrol_new vt1709_capture_mixer[] = {
2618 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
2619 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
2620 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
2621 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
2622 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
2623 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
2624 {
2625 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2626 /* The multiple "Capture Source" controls confuse alsamixer
2627 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01002628 */
2629 /* .name = "Capture Source", */
2630 .name = "Input Source",
2631 .count = 1,
2632 .info = via_mux_enum_info,
2633 .get = via_mux_enum_get,
2634 .put = via_mux_enum_put,
2635 },
2636 { } /* end */
2637};
2638
Harald Welte69e52a82008-09-09 15:57:32 +08002639static struct hda_verb vt1709_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08002640 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
2641 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08002642 { }
2643};
2644
Joseph Chanc577b8a2006-11-29 15:29:40 +01002645/*
2646 * generic initialization of ADC, input mixers and output mixers
2647 */
2648static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
2649 /*
2650 * Unmute ADC0-2 and set the default input to mic-in
2651 */
2652 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2653 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2654 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2655
2656
Josepch Chanf7278fd2007-12-13 16:40:40 +01002657 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01002658 * mixer widget
2659 */
2660 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01002661 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2662 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2663 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2664 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002666
2667 /*
2668 * Set up output selector (0x1a, 0x1b, 0x29)
2669 */
2670 /* set vol=0 to output mixers */
2671 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2672 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2673 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2674
2675 /*
2676 * Unmute PW3 and PW4
2677 */
2678 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2679 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2680
Lydia Wangbfdc6752009-10-10 19:08:50 +08002681 /* Set input of PW4 as MW0 */
2682 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002683 /* PW9 Output enable */
2684 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2685 { }
2686};
2687
2688static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
2689 .substreams = 1,
2690 .channels_min = 2,
2691 .channels_max = 10,
2692 .nid = 0x10, /* NID to query formats and rates */
2693 .ops = {
2694 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002695 .prepare = via_playback_multi_pcm_prepare,
2696 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002697 },
2698};
2699
2700static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
2701 .substreams = 1,
2702 .channels_min = 2,
2703 .channels_max = 6,
2704 .nid = 0x10, /* NID to query formats and rates */
2705 .ops = {
2706 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002707 .prepare = via_playback_multi_pcm_prepare,
2708 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002709 },
2710};
2711
2712static struct hda_pcm_stream vt1709_pcm_analog_capture = {
2713 .substreams = 2,
2714 .channels_min = 2,
2715 .channels_max = 2,
2716 .nid = 0x14, /* NID to query formats and rates */
2717 .ops = {
2718 .prepare = via_capture_pcm_prepare,
2719 .cleanup = via_capture_pcm_cleanup
2720 },
2721};
2722
2723static struct hda_pcm_stream vt1709_pcm_digital_playback = {
2724 .substreams = 1,
2725 .channels_min = 2,
2726 .channels_max = 2,
2727 /* NID is set in via_build_pcms */
2728 .ops = {
2729 .open = via_dig_playback_pcm_open,
2730 .close = via_dig_playback_pcm_close
2731 },
2732};
2733
2734static struct hda_pcm_stream vt1709_pcm_digital_capture = {
2735 .substreams = 1,
2736 .channels_min = 2,
2737 .channels_max = 2,
2738};
2739
2740static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
2741 const struct auto_pin_cfg *cfg)
2742{
2743 int i;
2744 hda_nid_t nid;
2745
2746 if (cfg->line_outs == 4) /* 10 channels */
2747 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
2748 else if (cfg->line_outs == 3) /* 6 channels */
2749 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
2750
2751 spec->multiout.dac_nids = spec->private_dac_nids;
2752
2753 if (cfg->line_outs == 4) { /* 10 channels */
2754 for (i = 0; i < cfg->line_outs; i++) {
2755 nid = cfg->line_out_pins[i];
2756 if (nid) {
2757 /* config dac list */
2758 switch (i) {
2759 case AUTO_SEQ_FRONT:
2760 /* AOW0 */
2761 spec->multiout.dac_nids[i] = 0x10;
2762 break;
2763 case AUTO_SEQ_CENLFE:
2764 /* AOW2 */
2765 spec->multiout.dac_nids[i] = 0x12;
2766 break;
2767 case AUTO_SEQ_SURROUND:
2768 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002769 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002770 break;
2771 case AUTO_SEQ_SIDE:
2772 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002773 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002774 break;
2775 default:
2776 break;
2777 }
2778 }
2779 }
2780 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
2781
2782 } else if (cfg->line_outs == 3) { /* 6 channels */
Lydia Wang377ff312009-10-10 19:08:55 +08002783 for (i = 0; i < cfg->line_outs; i++) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002784 nid = cfg->line_out_pins[i];
2785 if (nid) {
2786 /* config dac list */
Lydia Wang377ff312009-10-10 19:08:55 +08002787 switch (i) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002788 case AUTO_SEQ_FRONT:
2789 /* AOW0 */
2790 spec->multiout.dac_nids[i] = 0x10;
2791 break;
2792 case AUTO_SEQ_CENLFE:
2793 /* AOW2 */
2794 spec->multiout.dac_nids[i] = 0x12;
2795 break;
2796 case AUTO_SEQ_SURROUND:
2797 /* AOW1 */
2798 spec->multiout.dac_nids[i] = 0x11;
2799 break;
2800 default:
2801 break;
2802 }
2803 }
2804 }
2805 }
2806
2807 return 0;
2808}
2809
2810/* add playback controls from the parsed DAC table */
2811static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
2812 const struct auto_pin_cfg *cfg)
2813{
2814 char name[32];
2815 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang4483a2f2009-10-10 19:08:29 +08002816 hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002817 int i, err;
2818
2819 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2820 nid = cfg->line_out_pins[i];
2821
Lydia Wang377ff312009-10-10 19:08:55 +08002822 if (!nid)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002823 continue;
2824
Lydia Wang4483a2f2009-10-10 19:08:29 +08002825 nid_vol = nid_vols[i];
2826
Joseph Chanc577b8a2006-11-29 15:29:40 +01002827 if (i == AUTO_SEQ_CENLFE) {
2828 /* Center/LFE */
2829 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2830 "Center Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002831 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002832 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002833 if (err < 0)
2834 return err;
2835 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2836 "LFE Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002837 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002838 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002839 if (err < 0)
2840 return err;
2841 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2842 "Center Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002843 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002844 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002845 if (err < 0)
2846 return err;
2847 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2848 "LFE Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002849 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002850 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002851 if (err < 0)
2852 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002853 } else if (i == AUTO_SEQ_FRONT) {
Lydia Wang4483a2f2009-10-10 19:08:29 +08002854 /* ADD control to mixer index 0 */
Joseph Chanc577b8a2006-11-29 15:29:40 +01002855 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2856 "Master Front Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002857 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002858 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002859 if (err < 0)
2860 return err;
2861 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2862 "Master Front Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002863 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002864 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002865 if (err < 0)
2866 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002867
Joseph Chanc577b8a2006-11-29 15:29:40 +01002868 /* add control to PW3 */
2869 sprintf(name, "%s Playback Volume", chname[i]);
2870 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002871 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2872 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002873 if (err < 0)
2874 return err;
2875 sprintf(name, "%s Playback Switch", chname[i]);
2876 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002877 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2878 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002879 if (err < 0)
2880 return err;
2881 } else if (i == AUTO_SEQ_SURROUND) {
2882 sprintf(name, "%s Playback Volume", chname[i]);
2883 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002884 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002885 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002886 if (err < 0)
2887 return err;
2888 sprintf(name, "%s Playback Switch", chname[i]);
2889 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002890 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002891 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002892 if (err < 0)
2893 return err;
2894 } else if (i == AUTO_SEQ_SIDE) {
2895 sprintf(name, "%s Playback Volume", chname[i]);
2896 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002897 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002898 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002899 if (err < 0)
2900 return err;
2901 sprintf(name, "%s Playback Switch", chname[i]);
2902 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002903 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002904 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002905 if (err < 0)
2906 return err;
2907 }
2908 }
2909
2910 return 0;
2911}
2912
2913static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2914{
2915 int err;
2916
2917 if (!pin)
2918 return 0;
2919
2920 if (spec->multiout.num_dacs == 5) /* 10 channels */
2921 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
2922 else if (spec->multiout.num_dacs == 3) /* 6 channels */
2923 spec->multiout.hp_nid = 0;
Lydia Wangcdc17842009-10-10 19:07:47 +08002924 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002925
2926 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2927 "Headphone Playback Volume",
2928 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2929 if (err < 0)
2930 return err;
2931 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2932 "Headphone Playback Switch",
2933 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2934 if (err < 0)
2935 return err;
2936
2937 return 0;
2938}
2939
2940/* create playback/capture controls for input pins */
2941static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
2942 const struct auto_pin_cfg *cfg)
2943{
2944 static char *labels[] = {
2945 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2946 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002947 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002948 int i, err, idx = 0;
2949
2950 /* for internal loopback recording select */
2951 imux->items[imux->num_items].label = "Stereo Mixer";
2952 imux->items[imux->num_items].index = idx;
2953 imux->num_items++;
2954
2955 for (i = 0; i < AUTO_PIN_LAST; i++) {
2956 if (!cfg->input_pins[i])
2957 continue;
2958
2959 switch (cfg->input_pins[i]) {
2960 case 0x1d: /* Mic */
2961 idx = 2;
2962 break;
Lydia Wang377ff312009-10-10 19:08:55 +08002963
Joseph Chanc577b8a2006-11-29 15:29:40 +01002964 case 0x1e: /* Line In */
2965 idx = 3;
2966 break;
2967
2968 case 0x21: /* Front Mic */
2969 idx = 4;
2970 break;
2971
2972 case 0x23: /* CD */
2973 idx = 1;
2974 break;
2975 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002976 err = via_new_analog_input(spec, labels[i], idx, 0x18);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002977 if (err < 0)
2978 return err;
2979 imux->items[imux->num_items].label = labels[i];
2980 imux->items[imux->num_items].index = idx;
2981 imux->num_items++;
2982 }
2983 return 0;
2984}
2985
2986static int vt1709_parse_auto_config(struct hda_codec *codec)
2987{
2988 struct via_spec *spec = codec->spec;
2989 int err;
2990
2991 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2992 if (err < 0)
2993 return err;
2994 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
2995 if (err < 0)
2996 return err;
2997 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2998 return 0; /* can't find valid BIOS pin config */
2999
3000 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
3001 if (err < 0)
3002 return err;
3003 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3004 if (err < 0)
3005 return err;
3006 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
3007 if (err < 0)
3008 return err;
3009
3010 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3011
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003012 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01003013 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02003014 spec->dig_in_pin = VT1709_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003015 if (spec->autocfg.dig_in_pin)
3016 spec->dig_in_nid = VT1709_DIGIN_NID;
3017
Takashi Iwai603c4012008-07-30 15:01:44 +02003018 if (spec->kctls.list)
3019 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003020
Harald Welte0aa62ae2008-09-09 15:58:27 +08003021 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01003022
Harald Weltef8fdd492008-09-15 22:41:31 +08003023 if (spec->hp_mux)
3024 spec->mixers[spec->num_mixers++] = via_hp_mixer;
3025
Lydia Wang1564b282009-10-10 19:07:52 +08003026 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003027 return 1;
3028}
3029
Takashi Iwaicb53c622007-08-10 17:21:45 +02003030#ifdef CONFIG_SND_HDA_POWER_SAVE
3031static struct hda_amp_list vt1709_loopbacks[] = {
3032 { 0x18, HDA_INPUT, 1 },
3033 { 0x18, HDA_INPUT, 2 },
3034 { 0x18, HDA_INPUT, 3 },
3035 { 0x18, HDA_INPUT, 4 },
3036 { } /* end */
3037};
3038#endif
3039
Joseph Chanc577b8a2006-11-29 15:29:40 +01003040static int patch_vt1709_10ch(struct hda_codec *codec)
3041{
3042 struct via_spec *spec;
3043 int err;
3044
3045 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003046 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003047 if (spec == NULL)
3048 return -ENOMEM;
3049
3050 codec->spec = spec;
3051
3052 err = vt1709_parse_auto_config(codec);
3053 if (err < 0) {
3054 via_free(codec);
3055 return err;
3056 } else if (!err) {
3057 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
3058 "Using genenic mode...\n");
3059 }
3060
Harald Welte69e52a82008-09-09 15:57:32 +08003061 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
3062 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003063
3064 spec->stream_name_analog = "VT1709 Analog";
3065 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
3066 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
3067
3068 spec->stream_name_digital = "VT1709 Digital";
3069 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
3070 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
3071
Lydia Wang377ff312009-10-10 19:08:55 +08003072
Joseph Chanc577b8a2006-11-29 15:29:40 +01003073 if (!spec->adc_nids && spec->input_mux) {
3074 spec->adc_nids = vt1709_adc_nids;
3075 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003076 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003077 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
3078 spec->num_mixers++;
3079 }
3080
3081 codec->patch_ops = via_patch_ops;
3082
3083 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003084 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003085#ifdef CONFIG_SND_HDA_POWER_SAVE
3086 spec->loopback.amplist = vt1709_loopbacks;
3087#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01003088
3089 return 0;
3090}
3091/*
3092 * generic initialization of ADC, input mixers and output mixers
3093 */
3094static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
3095 /*
3096 * Unmute ADC0-2 and set the default input to mic-in
3097 */
3098 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3099 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3100 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3101
3102
3103 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3104 * mixer widget
3105 */
3106 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3107 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3108 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3109 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3110 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3111 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3112
3113 /*
3114 * Set up output selector (0x1a, 0x1b, 0x29)
3115 */
3116 /* set vol=0 to output mixers */
3117 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3118 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3119 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3120
3121 /*
3122 * Unmute PW3 and PW4
3123 */
3124 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3125 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3126
3127 /* Set input of PW4 as MW0 */
3128 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01003129 /* PW9 Output enable */
3130 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3131 { }
3132};
3133
3134static int patch_vt1709_6ch(struct hda_codec *codec)
3135{
3136 struct via_spec *spec;
3137 int err;
3138
3139 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003140 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003141 if (spec == NULL)
3142 return -ENOMEM;
3143
3144 codec->spec = spec;
3145
3146 err = vt1709_parse_auto_config(codec);
3147 if (err < 0) {
3148 via_free(codec);
3149 return err;
3150 } else if (!err) {
3151 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
3152 "Using genenic mode...\n");
3153 }
3154
Harald Welte69e52a82008-09-09 15:57:32 +08003155 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
3156 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003157
3158 spec->stream_name_analog = "VT1709 Analog";
3159 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
3160 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
3161
3162 spec->stream_name_digital = "VT1709 Digital";
3163 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
3164 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
3165
Lydia Wang377ff312009-10-10 19:08:55 +08003166
Joseph Chanc577b8a2006-11-29 15:29:40 +01003167 if (!spec->adc_nids && spec->input_mux) {
3168 spec->adc_nids = vt1709_adc_nids;
3169 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003170 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003171 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
3172 spec->num_mixers++;
3173 }
3174
3175 codec->patch_ops = via_patch_ops;
3176
3177 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003178 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003179#ifdef CONFIG_SND_HDA_POWER_SAVE
3180 spec->loopback.amplist = vt1709_loopbacks;
3181#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01003182 return 0;
3183}
3184
3185/* capture mixer elements */
3186static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
3187 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3188 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3189 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3190 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
3191 {
3192 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3193 /* The multiple "Capture Source" controls confuse alsamixer
3194 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01003195 */
3196 /* .name = "Capture Source", */
3197 .name = "Input Source",
3198 .count = 1,
3199 .info = via_mux_enum_info,
3200 .get = via_mux_enum_get,
3201 .put = via_mux_enum_put,
3202 },
3203 { } /* end */
3204};
3205/*
3206 * generic initialization of ADC, input mixers and output mixers
3207 */
3208static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
3209 /*
3210 * Unmute ADC0-1 and set the default input to mic-in
3211 */
3212 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3213 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3214
3215
3216 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3217 * mixer widget
3218 */
3219 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3220 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3221 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3222 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3223 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3224 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3225
3226 /*
3227 * Set up output mixers
3228 */
3229 /* set vol=0 to output mixers */
3230 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3231 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3232 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3233
3234 /* Setup default input to PW4 */
Lydia Wangbfdc6752009-10-10 19:08:50 +08003235 {0x1d, AC_VERB_SET_CONNECT_SEL, 0},
Josepch Chanf7278fd2007-12-13 16:40:40 +01003236 /* PW9 Output enable */
3237 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3238 /* PW10 Input enable */
3239 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3240 { }
3241};
3242
3243static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
3244 /*
3245 * Unmute ADC0-1 and set the default input to mic-in
3246 */
3247 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3248 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3249
3250
3251 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3252 * mixer widget
3253 */
3254 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3255 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3256 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3257 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3258 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3259 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3260
3261 /*
3262 * Set up output mixers
3263 */
3264 /* set vol=0 to output mixers */
3265 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3266 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3267 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3268
3269 /* Setup default input of PW4 to MW0 */
3270 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
3271 /* PW9 Output enable */
3272 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3273 /* PW10 Input enable */
3274 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3275 { }
3276};
3277
Harald Welte69e52a82008-09-09 15:57:32 +08003278static struct hda_verb vt1708B_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003279 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3280 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3281 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3282 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3283 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3284 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3285 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3286 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3287 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003288 { }
3289};
3290
Lydia Wang17314372009-10-10 19:07:37 +08003291static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
3292 struct hda_codec *codec,
3293 struct snd_pcm_substream *substream)
3294{
3295 int idle = substream->pstr->substream_opened == 1
3296 && substream->ref_count == 0;
3297
3298 analog_low_current_mode(codec, idle);
3299 return 0;
3300}
3301
Josepch Chanf7278fd2007-12-13 16:40:40 +01003302static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003303 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003304 .channels_min = 2,
3305 .channels_max = 8,
3306 .nid = 0x10, /* NID to query formats and rates */
3307 .ops = {
3308 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003309 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003310 .cleanup = via_playback_multi_pcm_cleanup,
3311 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01003312 },
3313};
3314
3315static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003316 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003317 .channels_min = 2,
3318 .channels_max = 4,
3319 .nid = 0x10, /* NID to query formats and rates */
3320 .ops = {
3321 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003322 .prepare = via_playback_multi_pcm_prepare,
3323 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01003324 },
3325};
3326
3327static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
3328 .substreams = 2,
3329 .channels_min = 2,
3330 .channels_max = 2,
3331 .nid = 0x13, /* NID to query formats and rates */
3332 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003333 .open = via_pcm_open_close,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003334 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003335 .cleanup = via_capture_pcm_cleanup,
3336 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01003337 },
3338};
3339
3340static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
3341 .substreams = 1,
3342 .channels_min = 2,
3343 .channels_max = 2,
3344 /* NID is set in via_build_pcms */
3345 .ops = {
3346 .open = via_dig_playback_pcm_open,
3347 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003348 .prepare = via_dig_playback_pcm_prepare,
3349 .cleanup = via_dig_playback_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01003350 },
3351};
3352
3353static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
3354 .substreams = 1,
3355 .channels_min = 2,
3356 .channels_max = 2,
3357};
3358
3359/* fill in the dac_nids table from the parsed pin configuration */
3360static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
3361 const struct auto_pin_cfg *cfg)
3362{
3363 int i;
3364 hda_nid_t nid;
3365
3366 spec->multiout.num_dacs = cfg->line_outs;
3367
3368 spec->multiout.dac_nids = spec->private_dac_nids;
3369
3370 for (i = 0; i < 4; i++) {
3371 nid = cfg->line_out_pins[i];
3372 if (nid) {
3373 /* config dac list */
3374 switch (i) {
3375 case AUTO_SEQ_FRONT:
3376 spec->multiout.dac_nids[i] = 0x10;
3377 break;
3378 case AUTO_SEQ_CENLFE:
3379 spec->multiout.dac_nids[i] = 0x24;
3380 break;
3381 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08003382 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003383 break;
3384 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08003385 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003386 break;
3387 }
3388 }
3389 }
3390
3391 return 0;
3392}
3393
3394/* add playback controls from the parsed DAC table */
3395static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
3396 const struct auto_pin_cfg *cfg)
3397{
3398 char name[32];
3399 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08003400 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01003401 hda_nid_t nid, nid_vol = 0;
3402 int i, err;
3403
3404 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3405 nid = cfg->line_out_pins[i];
3406
3407 if (!nid)
3408 continue;
3409
3410 nid_vol = nid_vols[i];
3411
3412 if (i == AUTO_SEQ_CENLFE) {
3413 /* Center/LFE */
3414 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3415 "Center Playback Volume",
3416 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3417 HDA_OUTPUT));
3418 if (err < 0)
3419 return err;
3420 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3421 "LFE Playback Volume",
3422 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3423 HDA_OUTPUT));
3424 if (err < 0)
3425 return err;
3426 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3427 "Center Playback Switch",
3428 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3429 HDA_OUTPUT));
3430 if (err < 0)
3431 return err;
3432 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3433 "LFE Playback Switch",
3434 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3435 HDA_OUTPUT));
3436 if (err < 0)
3437 return err;
3438 } else if (i == AUTO_SEQ_FRONT) {
3439 /* add control to mixer index 0 */
3440 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3441 "Master Front Playback Volume",
3442 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3443 HDA_INPUT));
3444 if (err < 0)
3445 return err;
3446 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3447 "Master Front Playback Switch",
3448 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3449 HDA_INPUT));
3450 if (err < 0)
3451 return err;
3452
3453 /* add control to PW3 */
3454 sprintf(name, "%s Playback Volume", chname[i]);
3455 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3456 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3457 HDA_OUTPUT));
3458 if (err < 0)
3459 return err;
3460 sprintf(name, "%s Playback Switch", chname[i]);
3461 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3462 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3463 HDA_OUTPUT));
3464 if (err < 0)
3465 return err;
3466 } else {
3467 sprintf(name, "%s Playback Volume", chname[i]);
3468 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3469 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3470 HDA_OUTPUT));
3471 if (err < 0)
3472 return err;
3473 sprintf(name, "%s Playback Switch", chname[i]);
3474 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3475 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3476 HDA_OUTPUT));
3477 if (err < 0)
3478 return err;
3479 }
3480 }
3481
3482 return 0;
3483}
3484
3485static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3486{
3487 int err;
3488
3489 if (!pin)
3490 return 0;
3491
3492 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003493 spec->hp_independent_mode_index = 1;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003494
3495 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3496 "Headphone Playback Volume",
3497 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3498 if (err < 0)
3499 return err;
3500 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3501 "Headphone Playback Switch",
3502 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3503 if (err < 0)
3504 return err;
3505
Harald Welte0aa62ae2008-09-09 15:58:27 +08003506 create_hp_imux(spec);
3507
Josepch Chanf7278fd2007-12-13 16:40:40 +01003508 return 0;
3509}
3510
3511/* create playback/capture controls for input pins */
3512static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
3513 const struct auto_pin_cfg *cfg)
3514{
3515 static char *labels[] = {
3516 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3517 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003518 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01003519 int i, err, idx = 0;
3520
3521 /* for internal loopback recording select */
3522 imux->items[imux->num_items].label = "Stereo Mixer";
3523 imux->items[imux->num_items].index = idx;
3524 imux->num_items++;
3525
3526 for (i = 0; i < AUTO_PIN_LAST; i++) {
3527 if (!cfg->input_pins[i])
3528 continue;
3529
3530 switch (cfg->input_pins[i]) {
3531 case 0x1a: /* Mic */
3532 idx = 2;
3533 break;
3534
3535 case 0x1b: /* Line In */
3536 idx = 3;
3537 break;
3538
3539 case 0x1e: /* Front Mic */
3540 idx = 4;
3541 break;
3542
3543 case 0x1f: /* CD */
3544 idx = 1;
3545 break;
3546 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003547 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003548 if (err < 0)
3549 return err;
3550 imux->items[imux->num_items].label = labels[i];
3551 imux->items[imux->num_items].index = idx;
3552 imux->num_items++;
3553 }
3554 return 0;
3555}
3556
3557static int vt1708B_parse_auto_config(struct hda_codec *codec)
3558{
3559 struct via_spec *spec = codec->spec;
3560 int err;
3561
3562 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3563 if (err < 0)
3564 return err;
3565 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
3566 if (err < 0)
3567 return err;
3568 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3569 return 0; /* can't find valid BIOS pin config */
3570
3571 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
3572 if (err < 0)
3573 return err;
3574 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3575 if (err < 0)
3576 return err;
3577 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
3578 if (err < 0)
3579 return err;
3580
3581 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3582
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003583 if (spec->autocfg.dig_outs)
Josepch Chanf7278fd2007-12-13 16:40:40 +01003584 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02003585 spec->dig_in_pin = VT1708B_DIGIN_PIN;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003586 if (spec->autocfg.dig_in_pin)
3587 spec->dig_in_nid = VT1708B_DIGIN_NID;
3588
Takashi Iwai603c4012008-07-30 15:01:44 +02003589 if (spec->kctls.list)
3590 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003591
Harald Welte0aa62ae2008-09-09 15:58:27 +08003592 spec->input_mux = &spec->private_imux[0];
3593
Harald Weltef8fdd492008-09-15 22:41:31 +08003594 if (spec->hp_mux)
3595 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003596
Lydia Wang1564b282009-10-10 19:07:52 +08003597 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003598 return 1;
3599}
3600
3601#ifdef CONFIG_SND_HDA_POWER_SAVE
3602static struct hda_amp_list vt1708B_loopbacks[] = {
3603 { 0x16, HDA_INPUT, 1 },
3604 { 0x16, HDA_INPUT, 2 },
3605 { 0x16, HDA_INPUT, 3 },
3606 { 0x16, HDA_INPUT, 4 },
3607 { } /* end */
3608};
3609#endif
Lydia Wang518bf3b2009-10-10 19:07:29 +08003610static int patch_vt1708S(struct hda_codec *codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003611static int patch_vt1708B_8ch(struct hda_codec *codec)
3612{
3613 struct via_spec *spec;
3614 int err;
3615
Lydia Wang518bf3b2009-10-10 19:07:29 +08003616 if (get_codec_type(codec) == VT1708BCE)
3617 return patch_vt1708S(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003618 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003619 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003620 if (spec == NULL)
3621 return -ENOMEM;
3622
3623 codec->spec = spec;
3624
3625 /* automatic parse from the BIOS config */
3626 err = vt1708B_parse_auto_config(codec);
3627 if (err < 0) {
3628 via_free(codec);
3629 return err;
3630 } else if (!err) {
3631 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3632 "from BIOS. Using genenic mode...\n");
3633 }
3634
Harald Welte69e52a82008-09-09 15:57:32 +08003635 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
3636 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003637
3638 spec->stream_name_analog = "VT1708B Analog";
3639 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
3640 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3641
3642 spec->stream_name_digital = "VT1708B Digital";
3643 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3644 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3645
3646 if (!spec->adc_nids && spec->input_mux) {
3647 spec->adc_nids = vt1708B_adc_nids;
3648 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003649 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003650 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3651 spec->num_mixers++;
3652 }
3653
3654 codec->patch_ops = via_patch_ops;
3655
3656 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003657 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003658#ifdef CONFIG_SND_HDA_POWER_SAVE
3659 spec->loopback.amplist = vt1708B_loopbacks;
3660#endif
3661
3662 return 0;
3663}
3664
3665static int patch_vt1708B_4ch(struct hda_codec *codec)
3666{
3667 struct via_spec *spec;
3668 int err;
3669
3670 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003671 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003672 if (spec == NULL)
3673 return -ENOMEM;
3674
3675 codec->spec = spec;
3676
3677 /* automatic parse from the BIOS config */
3678 err = vt1708B_parse_auto_config(codec);
3679 if (err < 0) {
3680 via_free(codec);
3681 return err;
3682 } else if (!err) {
3683 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3684 "from BIOS. Using genenic mode...\n");
3685 }
3686
Harald Welte69e52a82008-09-09 15:57:32 +08003687 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
3688 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003689
3690 spec->stream_name_analog = "VT1708B Analog";
3691 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
3692 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3693
3694 spec->stream_name_digital = "VT1708B Digital";
3695 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3696 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3697
3698 if (!spec->adc_nids && spec->input_mux) {
3699 spec->adc_nids = vt1708B_adc_nids;
3700 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003701 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003702 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3703 spec->num_mixers++;
3704 }
3705
3706 codec->patch_ops = via_patch_ops;
3707
3708 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003709 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003710#ifdef CONFIG_SND_HDA_POWER_SAVE
3711 spec->loopback.amplist = vt1708B_loopbacks;
3712#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01003713
3714 return 0;
3715}
3716
Harald Welted949cac2008-09-09 15:56:01 +08003717/* Patch for VT1708S */
3718
3719/* capture mixer elements */
3720static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
3721 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3722 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3723 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3724 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
Lydia Wang6369bcf2009-10-10 19:08:31 +08003725 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
3726 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
3727 HDA_INPUT),
Harald Welted949cac2008-09-09 15:56:01 +08003728 {
3729 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3730 /* The multiple "Capture Source" controls confuse alsamixer
3731 * So call somewhat different..
3732 */
3733 /* .name = "Capture Source", */
3734 .name = "Input Source",
3735 .count = 1,
3736 .info = via_mux_enum_info,
3737 .get = via_mux_enum_get,
3738 .put = via_mux_enum_put,
3739 },
3740 { } /* end */
3741};
3742
3743static struct hda_verb vt1708S_volume_init_verbs[] = {
3744 /* Unmute ADC0-1 and set the default input to mic-in */
3745 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3746 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3747
3748 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
3749 * analog-loopback mixer widget */
3750 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3751 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3752 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3753 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3754 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3755 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3756
3757 /* Setup default input of PW4 to MW0 */
3758 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08003759 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08003760 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08003761 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted7426322008-09-15 22:43:23 +08003762 /* Enable Mic Boost Volume backdoor */
3763 {0x1, 0xf98, 0x1},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08003764 /* don't bybass mixer */
3765 {0x1, 0xf88, 0xc0},
Harald Welted949cac2008-09-09 15:56:01 +08003766 { }
3767};
3768
Harald Welte69e52a82008-09-09 15:57:32 +08003769static struct hda_verb vt1708S_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003770 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3771 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3772 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3773 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3774 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3775 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3776 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3777 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3778 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003779 { }
3780};
3781
Harald Welted949cac2008-09-09 15:56:01 +08003782static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
3783 .substreams = 2,
3784 .channels_min = 2,
3785 .channels_max = 8,
3786 .nid = 0x10, /* NID to query formats and rates */
3787 .ops = {
3788 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08003789 .prepare = via_playback_multi_pcm_prepare,
3790 .cleanup = via_playback_multi_pcm_cleanup,
Lydia Wang17314372009-10-10 19:07:37 +08003791 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003792 },
3793};
3794
3795static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
3796 .substreams = 2,
3797 .channels_min = 2,
3798 .channels_max = 2,
3799 .nid = 0x13, /* NID to query formats and rates */
3800 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003801 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08003802 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003803 .cleanup = via_capture_pcm_cleanup,
3804 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003805 },
3806};
3807
3808static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Takashi Iwai9da29272009-05-07 16:31:14 +02003809 .substreams = 1,
Harald Welted949cac2008-09-09 15:56:01 +08003810 .channels_min = 2,
3811 .channels_max = 2,
3812 /* NID is set in via_build_pcms */
3813 .ops = {
3814 .open = via_dig_playback_pcm_open,
3815 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003816 .prepare = via_dig_playback_pcm_prepare,
3817 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003818 },
3819};
3820
3821/* fill in the dac_nids table from the parsed pin configuration */
3822static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
3823 const struct auto_pin_cfg *cfg)
3824{
3825 int i;
3826 hda_nid_t nid;
3827
3828 spec->multiout.num_dacs = cfg->line_outs;
3829
3830 spec->multiout.dac_nids = spec->private_dac_nids;
3831
3832 for (i = 0; i < 4; i++) {
3833 nid = cfg->line_out_pins[i];
3834 if (nid) {
3835 /* config dac list */
3836 switch (i) {
3837 case AUTO_SEQ_FRONT:
3838 spec->multiout.dac_nids[i] = 0x10;
3839 break;
3840 case AUTO_SEQ_CENLFE:
3841 spec->multiout.dac_nids[i] = 0x24;
3842 break;
3843 case AUTO_SEQ_SURROUND:
3844 spec->multiout.dac_nids[i] = 0x11;
3845 break;
3846 case AUTO_SEQ_SIDE:
3847 spec->multiout.dac_nids[i] = 0x25;
3848 break;
3849 }
3850 }
3851 }
3852
3853 return 0;
3854}
3855
3856/* add playback controls from the parsed DAC table */
3857static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
3858 const struct auto_pin_cfg *cfg)
3859{
3860 char name[32];
3861 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
3862 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
3863 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
3864 hda_nid_t nid, nid_vol, nid_mute;
3865 int i, err;
3866
3867 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3868 nid = cfg->line_out_pins[i];
3869
3870 if (!nid)
3871 continue;
3872
3873 nid_vol = nid_vols[i];
3874 nid_mute = nid_mutes[i];
3875
3876 if (i == AUTO_SEQ_CENLFE) {
3877 /* Center/LFE */
3878 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3879 "Center Playback Volume",
3880 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3881 HDA_OUTPUT));
3882 if (err < 0)
3883 return err;
3884 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3885 "LFE Playback Volume",
3886 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3887 HDA_OUTPUT));
3888 if (err < 0)
3889 return err;
3890 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3891 "Center Playback Switch",
3892 HDA_COMPOSE_AMP_VAL(nid_mute,
3893 1, 0,
3894 HDA_OUTPUT));
3895 if (err < 0)
3896 return err;
3897 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3898 "LFE Playback Switch",
3899 HDA_COMPOSE_AMP_VAL(nid_mute,
3900 2, 0,
3901 HDA_OUTPUT));
3902 if (err < 0)
3903 return err;
3904 } else if (i == AUTO_SEQ_FRONT) {
3905 /* add control to mixer index 0 */
3906 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3907 "Master Front Playback Volume",
3908 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3909 HDA_INPUT));
3910 if (err < 0)
3911 return err;
3912 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3913 "Master Front Playback Switch",
3914 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3915 HDA_INPUT));
3916 if (err < 0)
3917 return err;
3918
3919 /* Front */
3920 sprintf(name, "%s Playback Volume", chname[i]);
3921 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3922 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3923 HDA_OUTPUT));
3924 if (err < 0)
3925 return err;
3926 sprintf(name, "%s Playback Switch", chname[i]);
3927 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3928 HDA_COMPOSE_AMP_VAL(nid_mute,
3929 3, 0,
3930 HDA_OUTPUT));
3931 if (err < 0)
3932 return err;
3933 } else {
3934 sprintf(name, "%s Playback Volume", chname[i]);
3935 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3936 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3937 HDA_OUTPUT));
3938 if (err < 0)
3939 return err;
3940 sprintf(name, "%s Playback Switch", chname[i]);
3941 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3942 HDA_COMPOSE_AMP_VAL(nid_mute,
3943 3, 0,
3944 HDA_OUTPUT));
3945 if (err < 0)
3946 return err;
3947 }
3948 }
3949
3950 return 0;
3951}
3952
3953static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3954{
3955 int err;
3956
3957 if (!pin)
3958 return 0;
3959
3960 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003961 spec->hp_independent_mode_index = 1;
Harald Welted949cac2008-09-09 15:56:01 +08003962
3963 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3964 "Headphone Playback Volume",
3965 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
3966 if (err < 0)
3967 return err;
3968
3969 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3970 "Headphone Playback Switch",
3971 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3972 if (err < 0)
3973 return err;
3974
Harald Welte0aa62ae2008-09-09 15:58:27 +08003975 create_hp_imux(spec);
3976
Harald Welted949cac2008-09-09 15:56:01 +08003977 return 0;
3978}
3979
3980/* create playback/capture controls for input pins */
3981static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
3982 const struct auto_pin_cfg *cfg)
3983{
3984 static char *labels[] = {
3985 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3986 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003987 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003988 int i, err, idx = 0;
3989
3990 /* for internal loopback recording select */
3991 imux->items[imux->num_items].label = "Stereo Mixer";
3992 imux->items[imux->num_items].index = 5;
3993 imux->num_items++;
3994
3995 for (i = 0; i < AUTO_PIN_LAST; i++) {
3996 if (!cfg->input_pins[i])
3997 continue;
3998
3999 switch (cfg->input_pins[i]) {
4000 case 0x1a: /* Mic */
4001 idx = 2;
4002 break;
4003
4004 case 0x1b: /* Line In */
4005 idx = 3;
4006 break;
4007
4008 case 0x1e: /* Front Mic */
4009 idx = 4;
4010 break;
4011
4012 case 0x1f: /* CD */
4013 idx = 1;
4014 break;
4015 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08004016 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Harald Welted949cac2008-09-09 15:56:01 +08004017 if (err < 0)
4018 return err;
4019 imux->items[imux->num_items].label = labels[i];
4020 imux->items[imux->num_items].index = idx-1;
4021 imux->num_items++;
4022 }
4023 return 0;
4024}
4025
Takashi Iwai9da29272009-05-07 16:31:14 +02004026/* fill out digital output widgets; one for master and one for slave outputs */
4027static void fill_dig_outs(struct hda_codec *codec)
4028{
4029 struct via_spec *spec = codec->spec;
4030 int i;
4031
4032 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4033 hda_nid_t nid;
4034 int conn;
4035
4036 nid = spec->autocfg.dig_out_pins[i];
4037 if (!nid)
4038 continue;
4039 conn = snd_hda_get_connections(codec, nid, &nid, 1);
4040 if (conn < 1)
4041 continue;
4042 if (!spec->multiout.dig_out_nid)
4043 spec->multiout.dig_out_nid = nid;
4044 else {
4045 spec->slave_dig_outs[0] = nid;
4046 break; /* at most two dig outs */
4047 }
4048 }
4049}
4050
Harald Welted949cac2008-09-09 15:56:01 +08004051static int vt1708S_parse_auto_config(struct hda_codec *codec)
4052{
4053 struct via_spec *spec = codec->spec;
4054 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004055
Takashi Iwai9da29272009-05-07 16:31:14 +02004056 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08004057 if (err < 0)
4058 return err;
4059 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
4060 if (err < 0)
4061 return err;
4062 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4063 return 0; /* can't find valid BIOS pin config */
4064
4065 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4066 if (err < 0)
4067 return err;
4068 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4069 if (err < 0)
4070 return err;
4071 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4072 if (err < 0)
4073 return err;
4074
4075 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4076
Takashi Iwai9da29272009-05-07 16:31:14 +02004077 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08004078
Takashi Iwai603c4012008-07-30 15:01:44 +02004079 if (spec->kctls.list)
4080 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08004081
Harald Welte0aa62ae2008-09-09 15:58:27 +08004082 spec->input_mux = &spec->private_imux[0];
4083
Harald Weltef8fdd492008-09-15 22:41:31 +08004084 if (spec->hp_mux)
4085 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004086
Lydia Wang1564b282009-10-10 19:07:52 +08004087 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004088 return 1;
4089}
4090
4091#ifdef CONFIG_SND_HDA_POWER_SAVE
4092static struct hda_amp_list vt1708S_loopbacks[] = {
4093 { 0x16, HDA_INPUT, 1 },
4094 { 0x16, HDA_INPUT, 2 },
4095 { 0x16, HDA_INPUT, 3 },
4096 { 0x16, HDA_INPUT, 4 },
4097 { } /* end */
4098};
4099#endif
4100
Lydia Wang6369bcf2009-10-10 19:08:31 +08004101static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
4102 int offset, int num_steps, int step_size)
4103{
4104 snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
4105 (offset << AC_AMPCAP_OFFSET_SHIFT) |
4106 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
4107 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
4108 (0 << AC_AMPCAP_MUTE_SHIFT));
4109}
4110
Harald Welted949cac2008-09-09 15:56:01 +08004111static int patch_vt1708S(struct hda_codec *codec)
4112{
4113 struct via_spec *spec;
4114 int err;
4115
4116 /* create a codec specific record */
4117 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4118 if (spec == NULL)
4119 return -ENOMEM;
4120
4121 codec->spec = spec;
4122
4123 /* automatic parse from the BIOS config */
4124 err = vt1708S_parse_auto_config(codec);
4125 if (err < 0) {
4126 via_free(codec);
4127 return err;
4128 } else if (!err) {
4129 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4130 "from BIOS. Using genenic mode...\n");
4131 }
4132
Harald Welte69e52a82008-09-09 15:57:32 +08004133 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
4134 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08004135
Lydia Wang36dd5c42009-10-20 13:18:04 +08004136 if (codec->vendor_id == 0x11060440)
4137 spec->stream_name_analog = "VT1818S Analog";
4138 else
4139 spec->stream_name_analog = "VT1708S Analog";
Harald Welted949cac2008-09-09 15:56:01 +08004140 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
4141 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
4142
Lydia Wang36dd5c42009-10-20 13:18:04 +08004143 if (codec->vendor_id == 0x11060440)
4144 spec->stream_name_digital = "VT1818S Digital";
4145 else
4146 spec->stream_name_digital = "VT1708S Digital";
Harald Welted949cac2008-09-09 15:56:01 +08004147 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
4148
4149 if (!spec->adc_nids && spec->input_mux) {
4150 spec->adc_nids = vt1708S_adc_nids;
4151 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004152 get_mux_nids(codec);
Lydia Wang6369bcf2009-10-10 19:08:31 +08004153 override_mic_boost(codec, 0x1a, 0, 3, 40);
4154 override_mic_boost(codec, 0x1e, 0, 3, 40);
Harald Welted949cac2008-09-09 15:56:01 +08004155 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
4156 spec->num_mixers++;
4157 }
4158
4159 codec->patch_ops = via_patch_ops;
4160
4161 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004162 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004163#ifdef CONFIG_SND_HDA_POWER_SAVE
4164 spec->loopback.amplist = vt1708S_loopbacks;
4165#endif
4166
Lydia Wang518bf3b2009-10-10 19:07:29 +08004167 /* correct names for VT1708BCE */
4168 if (get_codec_type(codec) == VT1708BCE) {
4169 kfree(codec->chip_name);
4170 codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
4171 snprintf(codec->bus->card->mixername,
4172 sizeof(codec->bus->card->mixername),
4173 "%s %s", codec->vendor_name, codec->chip_name);
4174 spec->stream_name_analog = "VT1708BCE Analog";
4175 spec->stream_name_digital = "VT1708BCE Digital";
4176 }
Harald Welted949cac2008-09-09 15:56:01 +08004177 return 0;
4178}
4179
4180/* Patch for VT1702 */
4181
4182/* capture mixer elements */
4183static struct snd_kcontrol_new vt1702_capture_mixer[] = {
4184 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
4185 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
4186 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
4187 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
4188 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
4189 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
4190 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
4191 HDA_INPUT),
4192 {
4193 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4194 /* The multiple "Capture Source" controls confuse alsamixer
4195 * So call somewhat different..
4196 */
4197 /* .name = "Capture Source", */
4198 .name = "Input Source",
4199 .count = 1,
4200 .info = via_mux_enum_info,
4201 .get = via_mux_enum_get,
4202 .put = via_mux_enum_put,
4203 },
4204 { } /* end */
4205};
4206
4207static struct hda_verb vt1702_volume_init_verbs[] = {
4208 /*
4209 * Unmute ADC0-1 and set the default input to mic-in
4210 */
4211 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4212 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4213 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4214
4215
4216 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4217 * mixer widget
4218 */
4219 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
4220 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4221 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4222 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4223 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4224 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4225
4226 /* Setup default input of PW4 to MW0 */
4227 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
4228 /* PW6 PW7 Output enable */
4229 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4230 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08004231 /* mixer enable */
4232 {0x1, 0xF88, 0x3},
4233 /* GPIO 0~2 */
4234 {0x1, 0xF82, 0x3F},
Harald Welted949cac2008-09-09 15:56:01 +08004235 { }
4236};
4237
Harald Welte69e52a82008-09-09 15:57:32 +08004238static struct hda_verb vt1702_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08004239 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
4240 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4241 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4242 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4243 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4244 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08004245 { }
4246};
4247
Harald Welted949cac2008-09-09 15:56:01 +08004248static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08004249 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08004250 .channels_min = 2,
4251 .channels_max = 2,
4252 .nid = 0x10, /* NID to query formats and rates */
4253 .ops = {
4254 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08004255 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08004256 .cleanup = via_playback_multi_pcm_cleanup,
4257 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08004258 },
4259};
4260
4261static struct hda_pcm_stream vt1702_pcm_analog_capture = {
4262 .substreams = 3,
4263 .channels_min = 2,
4264 .channels_max = 2,
4265 .nid = 0x12, /* NID to query formats and rates */
4266 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08004267 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08004268 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08004269 .cleanup = via_capture_pcm_cleanup,
4270 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08004271 },
4272};
4273
4274static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08004275 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08004276 .channels_min = 2,
4277 .channels_max = 2,
4278 /* NID is set in via_build_pcms */
4279 .ops = {
4280 .open = via_dig_playback_pcm_open,
4281 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02004282 .prepare = via_dig_playback_pcm_prepare,
4283 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08004284 },
4285};
4286
4287/* fill in the dac_nids table from the parsed pin configuration */
4288static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
4289 const struct auto_pin_cfg *cfg)
4290{
4291 spec->multiout.num_dacs = 1;
4292 spec->multiout.dac_nids = spec->private_dac_nids;
4293
4294 if (cfg->line_out_pins[0]) {
4295 /* config dac list */
4296 spec->multiout.dac_nids[0] = 0x10;
4297 }
4298
4299 return 0;
4300}
4301
4302/* add playback controls from the parsed DAC table */
4303static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
4304 const struct auto_pin_cfg *cfg)
4305{
4306 int err;
4307
4308 if (!cfg->line_out_pins[0])
4309 return -1;
4310
4311 /* add control to mixer index 0 */
4312 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4313 "Master Front Playback Volume",
4314 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4315 if (err < 0)
4316 return err;
4317 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4318 "Master Front Playback Switch",
4319 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4320 if (err < 0)
4321 return err;
4322
4323 /* Front */
4324 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4325 "Front Playback Volume",
4326 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
4327 if (err < 0)
4328 return err;
4329 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4330 "Front Playback Switch",
4331 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
4332 if (err < 0)
4333 return err;
4334
4335 return 0;
4336}
4337
4338static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4339{
Lydia Wang0713efe2009-10-10 19:07:43 +08004340 int err, i;
4341 struct hda_input_mux *imux;
4342 static const char *texts[] = { "ON", "OFF", NULL};
Harald Welted949cac2008-09-09 15:56:01 +08004343 if (!pin)
4344 return 0;
Harald Welted949cac2008-09-09 15:56:01 +08004345 spec->multiout.hp_nid = 0x1D;
Lydia Wangcdc17842009-10-10 19:07:47 +08004346 spec->hp_independent_mode_index = 0;
Harald Welted949cac2008-09-09 15:56:01 +08004347
4348 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4349 "Headphone Playback Volume",
4350 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
4351 if (err < 0)
4352 return err;
4353
4354 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4355 "Headphone Playback Switch",
4356 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4357 if (err < 0)
4358 return err;
4359
Lydia Wang0713efe2009-10-10 19:07:43 +08004360 imux = &spec->private_imux[1];
Harald Welte0aa62ae2008-09-09 15:58:27 +08004361
Lydia Wang0713efe2009-10-10 19:07:43 +08004362 /* for hp mode select */
4363 i = 0;
4364 while (texts[i] != NULL) {
4365 imux->items[imux->num_items].label = texts[i];
4366 imux->items[imux->num_items].index = i;
4367 imux->num_items++;
4368 i++;
4369 }
4370
4371 spec->hp_mux = &spec->private_imux[1];
Harald Welted949cac2008-09-09 15:56:01 +08004372 return 0;
4373}
4374
4375/* create playback/capture controls for input pins */
4376static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
4377 const struct auto_pin_cfg *cfg)
4378{
4379 static char *labels[] = {
4380 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4381 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08004382 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08004383 int i, err, idx = 0;
4384
4385 /* for internal loopback recording select */
4386 imux->items[imux->num_items].label = "Stereo Mixer";
4387 imux->items[imux->num_items].index = 3;
4388 imux->num_items++;
4389
4390 for (i = 0; i < AUTO_PIN_LAST; i++) {
4391 if (!cfg->input_pins[i])
4392 continue;
4393
4394 switch (cfg->input_pins[i]) {
4395 case 0x14: /* Mic */
4396 idx = 1;
4397 break;
4398
4399 case 0x15: /* Line In */
4400 idx = 2;
4401 break;
4402
4403 case 0x18: /* Front Mic */
4404 idx = 3;
4405 break;
4406 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08004407 err = via_new_analog_input(spec, labels[i], idx, 0x1A);
Harald Welted949cac2008-09-09 15:56:01 +08004408 if (err < 0)
4409 return err;
4410 imux->items[imux->num_items].label = labels[i];
4411 imux->items[imux->num_items].index = idx-1;
4412 imux->num_items++;
4413 }
4414 return 0;
4415}
4416
4417static int vt1702_parse_auto_config(struct hda_codec *codec)
4418{
4419 struct via_spec *spec = codec->spec;
4420 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004421
Takashi Iwai9da29272009-05-07 16:31:14 +02004422 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08004423 if (err < 0)
4424 return err;
4425 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
4426 if (err < 0)
4427 return err;
4428 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4429 return 0; /* can't find valid BIOS pin config */
4430
4431 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
4432 if (err < 0)
4433 return err;
4434 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4435 if (err < 0)
4436 return err;
Lydia Wangc2c02ea2009-10-10 19:07:32 +08004437 /* limit AA path volume to 0 dB */
4438 snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
4439 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4440 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4441 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4442 (1 << AC_AMPCAP_MUTE_SHIFT));
Harald Welted949cac2008-09-09 15:56:01 +08004443 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
4444 if (err < 0)
4445 return err;
4446
4447 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4448
Takashi Iwai9da29272009-05-07 16:31:14 +02004449 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08004450
Takashi Iwai603c4012008-07-30 15:01:44 +02004451 if (spec->kctls.list)
4452 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08004453
Harald Welte0aa62ae2008-09-09 15:58:27 +08004454 spec->input_mux = &spec->private_imux[0];
4455
Harald Weltef8fdd492008-09-15 22:41:31 +08004456 if (spec->hp_mux)
4457 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004458
4459 return 1;
4460}
4461
4462#ifdef CONFIG_SND_HDA_POWER_SAVE
4463static struct hda_amp_list vt1702_loopbacks[] = {
4464 { 0x1A, HDA_INPUT, 1 },
4465 { 0x1A, HDA_INPUT, 2 },
4466 { 0x1A, HDA_INPUT, 3 },
4467 { 0x1A, HDA_INPUT, 4 },
4468 { } /* end */
4469};
4470#endif
4471
4472static int patch_vt1702(struct hda_codec *codec)
4473{
4474 struct via_spec *spec;
4475 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004476
4477 /* create a codec specific record */
4478 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4479 if (spec == NULL)
4480 return -ENOMEM;
4481
4482 codec->spec = spec;
4483
4484 /* automatic parse from the BIOS config */
4485 err = vt1702_parse_auto_config(codec);
4486 if (err < 0) {
4487 via_free(codec);
4488 return err;
4489 } else if (!err) {
4490 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4491 "from BIOS. Using genenic mode...\n");
4492 }
4493
Harald Welte69e52a82008-09-09 15:57:32 +08004494 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
4495 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08004496
4497 spec->stream_name_analog = "VT1702 Analog";
4498 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
4499 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
4500
4501 spec->stream_name_digital = "VT1702 Digital";
4502 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
4503
4504 if (!spec->adc_nids && spec->input_mux) {
4505 spec->adc_nids = vt1702_adc_nids;
4506 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004507 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08004508 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
4509 spec->num_mixers++;
4510 }
4511
4512 codec->patch_ops = via_patch_ops;
4513
4514 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004515 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004516#ifdef CONFIG_SND_HDA_POWER_SAVE
4517 spec->loopback.amplist = vt1702_loopbacks;
4518#endif
4519
Harald Welted949cac2008-09-09 15:56:01 +08004520 return 0;
4521}
4522
Lydia Wangeb7188c2009-10-10 19:08:34 +08004523/* Patch for VT1718S */
4524
4525/* capture mixer elements */
4526static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
4527 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
4528 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
4529 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
4530 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
4531 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
4532 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
4533 HDA_INPUT),
4534 {
4535 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4536 /* The multiple "Capture Source" controls confuse alsamixer
4537 * So call somewhat different..
4538 */
4539 .name = "Input Source",
4540 .count = 2,
4541 .info = via_mux_enum_info,
4542 .get = via_mux_enum_get,
4543 .put = via_mux_enum_put,
4544 },
4545 { } /* end */
4546};
4547
4548static struct hda_verb vt1718S_volume_init_verbs[] = {
4549 /*
4550 * Unmute ADC0-1 and set the default input to mic-in
4551 */
4552 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4553 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4554
4555
4556 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4557 * mixer widget
4558 */
4559 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4560 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4561 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4562 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4563 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4564 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4565
4566 /* Setup default input of Front HP to MW9 */
4567 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4568 /* PW9 PW10 Output enable */
4569 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4570 {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4571 /* PW11 Input enable */
4572 {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
4573 /* Enable Boost Volume backdoor */
4574 {0x1, 0xf88, 0x8},
4575 /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
4576 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4577 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4578 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4579 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4580 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4581 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4582 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4583 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4584 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4585 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4586 /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
4587 {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
4588 {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
4589 /* Unmute MW4's index 0 */
4590 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4591 { }
4592};
4593
4594
4595static struct hda_verb vt1718S_uniwill_init_verbs[] = {
4596 {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
4597 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4598 {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4599 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4600 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4601 {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4602 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4603 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4604 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4605 { }
4606};
4607
4608static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
4609 .substreams = 2,
4610 .channels_min = 2,
4611 .channels_max = 10,
4612 .nid = 0x8, /* NID to query formats and rates */
4613 .ops = {
4614 .open = via_playback_pcm_open,
4615 .prepare = via_playback_multi_pcm_prepare,
4616 .cleanup = via_playback_multi_pcm_cleanup,
4617 .close = via_pcm_open_close,
4618 },
4619};
4620
4621static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
4622 .substreams = 2,
4623 .channels_min = 2,
4624 .channels_max = 2,
4625 .nid = 0x10, /* NID to query formats and rates */
4626 .ops = {
4627 .open = via_pcm_open_close,
4628 .prepare = via_capture_pcm_prepare,
4629 .cleanup = via_capture_pcm_cleanup,
4630 .close = via_pcm_open_close,
4631 },
4632};
4633
4634static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
4635 .substreams = 2,
4636 .channels_min = 2,
4637 .channels_max = 2,
Lydia Wangeb7188c2009-10-10 19:08:34 +08004638 /* NID is set in via_build_pcms */
4639 .ops = {
4640 .open = via_dig_playback_pcm_open,
4641 .close = via_dig_playback_pcm_close,
4642 .prepare = via_dig_playback_pcm_prepare,
4643 .cleanup = via_dig_playback_pcm_cleanup
4644 },
4645};
4646
4647static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
4648 .substreams = 1,
4649 .channels_min = 2,
4650 .channels_max = 2,
4651};
4652
4653/* fill in the dac_nids table from the parsed pin configuration */
4654static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
4655 const struct auto_pin_cfg *cfg)
4656{
4657 int i;
4658 hda_nid_t nid;
4659
4660 spec->multiout.num_dacs = cfg->line_outs;
4661
4662 spec->multiout.dac_nids = spec->private_dac_nids;
4663
4664 for (i = 0; i < 4; i++) {
4665 nid = cfg->line_out_pins[i];
4666 if (nid) {
4667 /* config dac list */
4668 switch (i) {
4669 case AUTO_SEQ_FRONT:
4670 spec->multiout.dac_nids[i] = 0x8;
4671 break;
4672 case AUTO_SEQ_CENLFE:
4673 spec->multiout.dac_nids[i] = 0xa;
4674 break;
4675 case AUTO_SEQ_SURROUND:
4676 spec->multiout.dac_nids[i] = 0x9;
4677 break;
4678 case AUTO_SEQ_SIDE:
4679 spec->multiout.dac_nids[i] = 0xb;
4680 break;
4681 }
4682 }
4683 }
4684
4685 return 0;
4686}
4687
4688/* add playback controls from the parsed DAC table */
4689static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
4690 const struct auto_pin_cfg *cfg)
4691{
4692 char name[32];
4693 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
4694 hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
4695 hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
4696 hda_nid_t nid, nid_vol, nid_mute = 0;
4697 int i, err;
4698
4699 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
4700 nid = cfg->line_out_pins[i];
4701
4702 if (!nid)
4703 continue;
4704 nid_vol = nid_vols[i];
4705 nid_mute = nid_mutes[i];
4706
4707 if (i == AUTO_SEQ_CENLFE) {
4708 /* Center/LFE */
4709 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4710 "Center Playback Volume",
4711 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
4712 HDA_OUTPUT));
4713 if (err < 0)
4714 return err;
4715 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4716 "LFE Playback Volume",
4717 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
4718 HDA_OUTPUT));
4719 if (err < 0)
4720 return err;
4721 err = via_add_control(
4722 spec, VIA_CTL_WIDGET_MUTE,
4723 "Center Playback Switch",
4724 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
4725 HDA_OUTPUT));
4726 if (err < 0)
4727 return err;
4728 err = via_add_control(
4729 spec, VIA_CTL_WIDGET_MUTE,
4730 "LFE Playback Switch",
4731 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
4732 HDA_OUTPUT));
4733 if (err < 0)
4734 return err;
4735 } else if (i == AUTO_SEQ_FRONT) {
4736 /* Front */
4737 sprintf(name, "%s Playback Volume", chname[i]);
4738 err = via_add_control(
4739 spec, VIA_CTL_WIDGET_VOL, name,
4740 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4741 if (err < 0)
4742 return err;
4743 sprintf(name, "%s Playback Switch", chname[i]);
4744 err = via_add_control(
4745 spec, VIA_CTL_WIDGET_MUTE, name,
4746 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4747 HDA_OUTPUT));
4748 if (err < 0)
4749 return err;
4750 } else {
4751 sprintf(name, "%s Playback Volume", chname[i]);
4752 err = via_add_control(
4753 spec, VIA_CTL_WIDGET_VOL, name,
4754 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4755 if (err < 0)
4756 return err;
4757 sprintf(name, "%s Playback Switch", chname[i]);
4758 err = via_add_control(
4759 spec, VIA_CTL_WIDGET_MUTE, name,
4760 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4761 HDA_OUTPUT));
4762 if (err < 0)
4763 return err;
4764 }
4765 }
4766 return 0;
4767}
4768
4769static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4770{
4771 int err;
4772
4773 if (!pin)
4774 return 0;
4775
4776 spec->multiout.hp_nid = 0xc; /* AOW4 */
4777 spec->hp_independent_mode_index = 1;
4778
4779 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4780 "Headphone Playback Volume",
4781 HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
4782 if (err < 0)
4783 return err;
4784
4785 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4786 "Headphone Playback Switch",
4787 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4788 if (err < 0)
4789 return err;
4790
4791 create_hp_imux(spec);
4792 return 0;
4793}
4794
4795/* create playback/capture controls for input pins */
4796static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
4797 const struct auto_pin_cfg *cfg)
4798{
4799 static char *labels[] = {
4800 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4801 };
4802 struct hda_input_mux *imux = &spec->private_imux[0];
4803 int i, err, idx = 0;
4804
4805 /* for internal loopback recording select */
4806 imux->items[imux->num_items].label = "Stereo Mixer";
4807 imux->items[imux->num_items].index = 5;
4808 imux->num_items++;
4809
4810 for (i = 0; i < AUTO_PIN_LAST; i++) {
4811 if (!cfg->input_pins[i])
4812 continue;
4813
4814 switch (cfg->input_pins[i]) {
4815 case 0x2b: /* Mic */
4816 idx = 1;
4817 break;
4818
4819 case 0x2a: /* Line In */
4820 idx = 2;
4821 break;
4822
4823 case 0x29: /* Front Mic */
4824 idx = 3;
4825 break;
4826
4827 case 0x2c: /* CD */
4828 idx = 0;
4829 break;
4830 }
4831 err = via_new_analog_input(spec, labels[i], idx, 0x21);
4832 if (err < 0)
4833 return err;
4834 imux->items[imux->num_items].label = labels[i];
4835 imux->items[imux->num_items].index = idx;
4836 imux->num_items++;
4837 }
4838 return 0;
4839}
4840
4841static int vt1718S_parse_auto_config(struct hda_codec *codec)
4842{
4843 struct via_spec *spec = codec->spec;
4844 int err;
4845
4846 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4847
4848 if (err < 0)
4849 return err;
4850 err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
4851 if (err < 0)
4852 return err;
4853 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4854 return 0; /* can't find valid BIOS pin config */
4855
4856 err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4857 if (err < 0)
4858 return err;
4859 err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4860 if (err < 0)
4861 return err;
4862 err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4863 if (err < 0)
4864 return err;
4865
4866 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4867
4868 fill_dig_outs(codec);
4869
4870 if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
4871 spec->dig_in_nid = 0x13;
4872
4873 if (spec->kctls.list)
4874 spec->mixers[spec->num_mixers++] = spec->kctls.list;
4875
4876 spec->input_mux = &spec->private_imux[0];
4877
4878 if (spec->hp_mux)
4879 spec->mixers[spec->num_mixers++] = via_hp_mixer;
4880
4881 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
4882
4883 return 1;
4884}
4885
4886#ifdef CONFIG_SND_HDA_POWER_SAVE
4887static struct hda_amp_list vt1718S_loopbacks[] = {
4888 { 0x21, HDA_INPUT, 1 },
4889 { 0x21, HDA_INPUT, 2 },
4890 { 0x21, HDA_INPUT, 3 },
4891 { 0x21, HDA_INPUT, 4 },
4892 { } /* end */
4893};
4894#endif
4895
4896static int patch_vt1718S(struct hda_codec *codec)
4897{
4898 struct via_spec *spec;
4899 int err;
4900
4901 /* create a codec specific record */
4902 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4903 if (spec == NULL)
4904 return -ENOMEM;
4905
4906 codec->spec = spec;
4907
4908 /* automatic parse from the BIOS config */
4909 err = vt1718S_parse_auto_config(codec);
4910 if (err < 0) {
4911 via_free(codec);
4912 return err;
4913 } else if (!err) {
4914 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4915 "from BIOS. Using genenic mode...\n");
4916 }
4917
4918 spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
4919 spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
4920
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004921 if (codec->vendor_id == 0x11060441)
4922 spec->stream_name_analog = "VT2020 Analog";
4923 else if (codec->vendor_id == 0x11064441)
4924 spec->stream_name_analog = "VT1828S Analog";
4925 else
4926 spec->stream_name_analog = "VT1718S Analog";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004927 spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
4928 spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
4929
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004930 if (codec->vendor_id == 0x11060441)
4931 spec->stream_name_digital = "VT2020 Digital";
4932 else if (codec->vendor_id == 0x11064441)
4933 spec->stream_name_digital = "VT1828S Digital";
4934 else
4935 spec->stream_name_digital = "VT1718S Digital";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004936 spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004937 if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
Lydia Wangeb7188c2009-10-10 19:08:34 +08004938 spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
4939
4940 if (!spec->adc_nids && spec->input_mux) {
4941 spec->adc_nids = vt1718S_adc_nids;
4942 spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
4943 get_mux_nids(codec);
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004944 override_mic_boost(codec, 0x2b, 0, 3, 40);
4945 override_mic_boost(codec, 0x29, 0, 3, 40);
Lydia Wangeb7188c2009-10-10 19:08:34 +08004946 spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
4947 spec->num_mixers++;
4948 }
4949
4950 codec->patch_ops = via_patch_ops;
4951
4952 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11004953 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wangeb7188c2009-10-10 19:08:34 +08004954
4955#ifdef CONFIG_SND_HDA_POWER_SAVE
4956 spec->loopback.amplist = vt1718S_loopbacks;
4957#endif
4958
4959 return 0;
4960}
Lydia Wangf3db4232009-10-10 19:08:41 +08004961
4962/* Patch for VT1716S */
4963
4964static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
4965 struct snd_ctl_elem_info *uinfo)
4966{
4967 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4968 uinfo->count = 1;
4969 uinfo->value.integer.min = 0;
4970 uinfo->value.integer.max = 1;
4971 return 0;
4972}
4973
4974static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
4975 struct snd_ctl_elem_value *ucontrol)
4976{
4977 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4978 int index = 0;
4979
4980 index = snd_hda_codec_read(codec, 0x26, 0,
4981 AC_VERB_GET_CONNECT_SEL, 0);
4982 if (index != -1)
4983 *ucontrol->value.integer.value = index;
4984
4985 return 0;
4986}
4987
4988static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
4989 struct snd_ctl_elem_value *ucontrol)
4990{
4991 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4992 struct via_spec *spec = codec->spec;
4993 int index = *ucontrol->value.integer.value;
4994
4995 snd_hda_codec_write(codec, 0x26, 0,
4996 AC_VERB_SET_CONNECT_SEL, index);
4997 spec->dmic_enabled = index;
4998 set_jack_power_state(codec);
4999
5000 return 1;
5001}
5002
5003/* capture mixer elements */
5004static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
5005 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
5006 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
5007 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
5008 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
5009 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
5010 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
5011 HDA_INPUT),
5012 {
5013 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5014 .name = "Input Source",
5015 .count = 1,
5016 .info = via_mux_enum_info,
5017 .get = via_mux_enum_get,
5018 .put = via_mux_enum_put,
5019 },
5020 { } /* end */
5021};
5022
5023static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
5024 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
5025 {
5026 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5027 .name = "Digital Mic Capture Switch",
5028 .count = 1,
5029 .info = vt1716s_dmic_info,
5030 .get = vt1716s_dmic_get,
5031 .put = vt1716s_dmic_put,
5032 },
5033 {} /* end */
5034};
5035
5036
5037/* mono-out mixer elements */
5038static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
5039 HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
5040 { } /* end */
5041};
5042
5043static struct hda_verb vt1716S_volume_init_verbs[] = {
5044 /*
5045 * Unmute ADC0-1 and set the default input to mic-in
5046 */
5047 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5048 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5049
5050
5051 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5052 * mixer widget
5053 */
5054 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5055 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5056 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5057 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5058 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5059 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5060
5061 /* MUX Indices: Stereo Mixer = 5 */
5062 {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
5063
5064 /* Setup default input of PW4 to MW0 */
5065 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
5066
5067 /* Setup default input of SW1 as MW0 */
5068 {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
5069
5070 /* Setup default input of SW4 as AOW0 */
5071 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
5072
5073 /* PW9 PW10 Output enable */
5074 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5075 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5076
5077 /* Unmute SW1, PW12 */
5078 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5079 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5080 /* PW12 Output enable */
5081 {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5082 /* Enable Boost Volume backdoor */
5083 {0x1, 0xf8a, 0x80},
5084 /* don't bybass mixer */
5085 {0x1, 0xf88, 0xc0},
5086 /* Enable mono output */
5087 {0x1, 0xf90, 0x08},
5088 { }
5089};
5090
5091
5092static struct hda_verb vt1716S_uniwill_init_verbs[] = {
5093 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
5094 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
5095 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5096 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5097 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5098 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
5099 AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
5100 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5101 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5102 { }
5103};
5104
5105static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
5106 .substreams = 2,
5107 .channels_min = 2,
5108 .channels_max = 6,
5109 .nid = 0x10, /* NID to query formats and rates */
5110 .ops = {
5111 .open = via_playback_pcm_open,
5112 .prepare = via_playback_multi_pcm_prepare,
5113 .cleanup = via_playback_multi_pcm_cleanup,
5114 .close = via_pcm_open_close,
5115 },
5116};
5117
5118static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
5119 .substreams = 2,
5120 .channels_min = 2,
5121 .channels_max = 2,
5122 .nid = 0x13, /* NID to query formats and rates */
5123 .ops = {
5124 .open = via_pcm_open_close,
5125 .prepare = via_capture_pcm_prepare,
5126 .cleanup = via_capture_pcm_cleanup,
5127 .close = via_pcm_open_close,
5128 },
5129};
5130
5131static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
5132 .substreams = 2,
5133 .channels_min = 2,
5134 .channels_max = 2,
Lydia Wangf3db4232009-10-10 19:08:41 +08005135 /* NID is set in via_build_pcms */
5136 .ops = {
5137 .open = via_dig_playback_pcm_open,
5138 .close = via_dig_playback_pcm_close,
5139 .prepare = via_dig_playback_pcm_prepare,
5140 .cleanup = via_dig_playback_pcm_cleanup
5141 },
5142};
5143
5144/* fill in the dac_nids table from the parsed pin configuration */
5145static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
5146 const struct auto_pin_cfg *cfg)
5147{ int i;
5148 hda_nid_t nid;
5149
5150 spec->multiout.num_dacs = cfg->line_outs;
5151
5152 spec->multiout.dac_nids = spec->private_dac_nids;
5153
5154 for (i = 0; i < 3; i++) {
5155 nid = cfg->line_out_pins[i];
5156 if (nid) {
5157 /* config dac list */
5158 switch (i) {
5159 case AUTO_SEQ_FRONT:
5160 spec->multiout.dac_nids[i] = 0x10;
5161 break;
5162 case AUTO_SEQ_CENLFE:
5163 spec->multiout.dac_nids[i] = 0x25;
5164 break;
5165 case AUTO_SEQ_SURROUND:
5166 spec->multiout.dac_nids[i] = 0x11;
5167 break;
5168 }
5169 }
5170 }
5171
5172 return 0;
5173}
5174
5175/* add playback controls from the parsed DAC table */
5176static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
5177 const struct auto_pin_cfg *cfg)
5178{
5179 char name[32];
5180 static const char *chname[3] = { "Front", "Surround", "C/LFE" };
5181 hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
5182 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
5183 hda_nid_t nid, nid_vol, nid_mute;
5184 int i, err;
5185
5186 for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
5187 nid = cfg->line_out_pins[i];
5188
5189 if (!nid)
5190 continue;
5191
5192 nid_vol = nid_vols[i];
5193 nid_mute = nid_mutes[i];
5194
5195 if (i == AUTO_SEQ_CENLFE) {
5196 err = via_add_control(
5197 spec, VIA_CTL_WIDGET_VOL,
5198 "Center Playback Volume",
5199 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
5200 if (err < 0)
5201 return err;
5202 err = via_add_control(
5203 spec, VIA_CTL_WIDGET_VOL,
5204 "LFE Playback Volume",
5205 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
5206 if (err < 0)
5207 return err;
5208 err = via_add_control(
5209 spec, VIA_CTL_WIDGET_MUTE,
5210 "Center Playback Switch",
5211 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
5212 HDA_OUTPUT));
5213 if (err < 0)
5214 return err;
5215 err = via_add_control(
5216 spec, VIA_CTL_WIDGET_MUTE,
5217 "LFE Playback Switch",
5218 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
5219 HDA_OUTPUT));
5220 if (err < 0)
5221 return err;
5222 } else if (i == AUTO_SEQ_FRONT) {
5223
5224 err = via_add_control(
5225 spec, VIA_CTL_WIDGET_VOL,
5226 "Master Front Playback Volume",
5227 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5228 if (err < 0)
5229 return err;
5230 err = via_add_control(
5231 spec, VIA_CTL_WIDGET_MUTE,
5232 "Master Front Playback Switch",
5233 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5234 if (err < 0)
5235 return err;
5236
5237 sprintf(name, "%s Playback Volume", chname[i]);
5238 err = via_add_control(
5239 spec, VIA_CTL_WIDGET_VOL, name,
5240 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5241 if (err < 0)
5242 return err;
5243 sprintf(name, "%s Playback Switch", chname[i]);
5244 err = via_add_control(
5245 spec, VIA_CTL_WIDGET_MUTE, name,
5246 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5247 HDA_OUTPUT));
5248 if (err < 0)
5249 return err;
5250 } else {
5251 sprintf(name, "%s Playback Volume", chname[i]);
5252 err = via_add_control(
5253 spec, VIA_CTL_WIDGET_VOL, name,
5254 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5255 if (err < 0)
5256 return err;
5257 sprintf(name, "%s Playback Switch", chname[i]);
5258 err = via_add_control(
5259 spec, VIA_CTL_WIDGET_MUTE, name,
5260 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5261 HDA_OUTPUT));
5262 if (err < 0)
5263 return err;
5264 }
5265 }
5266 return 0;
5267}
5268
5269static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5270{
5271 int err;
5272
5273 if (!pin)
5274 return 0;
5275
5276 spec->multiout.hp_nid = 0x25; /* AOW3 */
5277 spec->hp_independent_mode_index = 1;
5278
5279 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5280 "Headphone Playback Volume",
5281 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5282 if (err < 0)
5283 return err;
5284
5285 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5286 "Headphone Playback Switch",
5287 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5288 if (err < 0)
5289 return err;
5290
5291 create_hp_imux(spec);
5292 return 0;
5293}
5294
5295/* create playback/capture controls for input pins */
5296static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
5297 const struct auto_pin_cfg *cfg)
5298{
5299 static char *labels[] = {
5300 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5301 };
5302 struct hda_input_mux *imux = &spec->private_imux[0];
5303 int i, err, idx = 0;
5304
5305 /* for internal loopback recording select */
5306 imux->items[imux->num_items].label = "Stereo Mixer";
5307 imux->items[imux->num_items].index = 5;
5308 imux->num_items++;
5309
5310 for (i = 0; i < AUTO_PIN_LAST; i++) {
5311 if (!cfg->input_pins[i])
5312 continue;
5313
5314 switch (cfg->input_pins[i]) {
5315 case 0x1a: /* Mic */
5316 idx = 2;
5317 break;
5318
5319 case 0x1b: /* Line In */
5320 idx = 3;
5321 break;
5322
5323 case 0x1e: /* Front Mic */
5324 idx = 4;
5325 break;
5326
5327 case 0x1f: /* CD */
5328 idx = 1;
5329 break;
5330 }
5331 err = via_new_analog_input(spec, labels[i], idx, 0x16);
5332 if (err < 0)
5333 return err;
5334 imux->items[imux->num_items].label = labels[i];
5335 imux->items[imux->num_items].index = idx-1;
5336 imux->num_items++;
5337 }
5338 return 0;
5339}
5340
5341static int vt1716S_parse_auto_config(struct hda_codec *codec)
5342{
5343 struct via_spec *spec = codec->spec;
5344 int err;
5345
5346 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5347 if (err < 0)
5348 return err;
5349 err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
5350 if (err < 0)
5351 return err;
5352 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5353 return 0; /* can't find valid BIOS pin config */
5354
5355 err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
5356 if (err < 0)
5357 return err;
5358 err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5359 if (err < 0)
5360 return err;
5361 err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
5362 if (err < 0)
5363 return err;
5364
5365 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5366
5367 fill_dig_outs(codec);
5368
5369 if (spec->kctls.list)
5370 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5371
5372 spec->input_mux = &spec->private_imux[0];
5373
5374 if (spec->hp_mux)
5375 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5376
5377 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
5378
5379 return 1;
5380}
5381
5382#ifdef CONFIG_SND_HDA_POWER_SAVE
5383static struct hda_amp_list vt1716S_loopbacks[] = {
5384 { 0x16, HDA_INPUT, 1 },
5385 { 0x16, HDA_INPUT, 2 },
5386 { 0x16, HDA_INPUT, 3 },
5387 { 0x16, HDA_INPUT, 4 },
5388 { } /* end */
5389};
5390#endif
5391
5392static int patch_vt1716S(struct hda_codec *codec)
5393{
5394 struct via_spec *spec;
5395 int err;
5396
5397 /* create a codec specific record */
5398 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5399 if (spec == NULL)
5400 return -ENOMEM;
5401
5402 codec->spec = spec;
5403
5404 /* automatic parse from the BIOS config */
5405 err = vt1716S_parse_auto_config(codec);
5406 if (err < 0) {
5407 via_free(codec);
5408 return err;
5409 } else if (!err) {
5410 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5411 "from BIOS. Using genenic mode...\n");
5412 }
5413
5414 spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs;
5415 spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
5416
5417 spec->stream_name_analog = "VT1716S Analog";
5418 spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
5419 spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
5420
5421 spec->stream_name_digital = "VT1716S Digital";
5422 spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
5423
5424 if (!spec->adc_nids && spec->input_mux) {
5425 spec->adc_nids = vt1716S_adc_nids;
5426 spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
5427 get_mux_nids(codec);
5428 override_mic_boost(codec, 0x1a, 0, 3, 40);
5429 override_mic_boost(codec, 0x1e, 0, 3, 40);
5430 spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
5431 spec->num_mixers++;
5432 }
5433
5434 spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
5435 spec->num_mixers++;
5436
5437 spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
5438
5439 codec->patch_ops = via_patch_ops;
5440
5441 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11005442 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wangf3db4232009-10-10 19:08:41 +08005443
5444#ifdef CONFIG_SND_HDA_POWER_SAVE
5445 spec->loopback.amplist = vt1716S_loopbacks;
5446#endif
5447
5448 return 0;
5449}
Lydia Wang25eaba22009-10-10 19:08:43 +08005450
5451/* for vt2002P */
5452
5453/* capture mixer elements */
5454static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
5455 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5456 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5457 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5458 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5459 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5460 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
5461 HDA_INPUT),
5462 {
5463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5464 /* The multiple "Capture Source" controls confuse alsamixer
5465 * So call somewhat different..
5466 */
5467 /* .name = "Capture Source", */
5468 .name = "Input Source",
5469 .count = 2,
5470 .info = via_mux_enum_info,
5471 .get = via_mux_enum_get,
5472 .put = via_mux_enum_put,
5473 },
5474 { } /* end */
5475};
5476
5477static struct hda_verb vt2002P_volume_init_verbs[] = {
5478 /*
5479 * Unmute ADC0-1 and set the default input to mic-in
5480 */
5481 {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5482 {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5483
5484
5485 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5486 * mixer widget
5487 */
5488 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5489 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5490 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5491 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5492 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5493 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5494
5495 /* MUX Indices: Mic = 0 */
5496 {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5497 {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5498
5499 /* PW9 Output enable */
5500 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5501
5502 /* Enable Boost Volume backdoor */
5503 {0x1, 0xfb9, 0x24},
5504
5505 /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5506 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5507 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5508 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5509 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5510 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5511 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5512 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5513 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5514
5515 /* set MUX0/1/4/8 = 0 (AOW0) */
5516 {0x34, AC_VERB_SET_CONNECT_SEL, 0},
5517 {0x35, AC_VERB_SET_CONNECT_SEL, 0},
5518 {0x37, AC_VERB_SET_CONNECT_SEL, 0},
5519 {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
5520
5521 /* set PW0 index=0 (MW0) */
5522 {0x24, AC_VERB_SET_CONNECT_SEL, 0},
5523
5524 /* Enable AOW0 to MW9 */
5525 {0x1, 0xfb8, 0x88},
5526 { }
5527};
5528
5529
5530static struct hda_verb vt2002P_uniwill_init_verbs[] = {
5531 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
5532 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5533 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
5534 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5535 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5536 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5537 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5538 { }
5539};
5540
5541static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
5542 .substreams = 2,
5543 .channels_min = 2,
5544 .channels_max = 2,
5545 .nid = 0x8, /* NID to query formats and rates */
5546 .ops = {
5547 .open = via_playback_pcm_open,
5548 .prepare = via_playback_multi_pcm_prepare,
5549 .cleanup = via_playback_multi_pcm_cleanup,
5550 .close = via_pcm_open_close,
5551 },
5552};
5553
5554static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
5555 .substreams = 2,
5556 .channels_min = 2,
5557 .channels_max = 2,
5558 .nid = 0x10, /* NID to query formats and rates */
5559 .ops = {
5560 .open = via_pcm_open_close,
5561 .prepare = via_capture_pcm_prepare,
5562 .cleanup = via_capture_pcm_cleanup,
5563 .close = via_pcm_open_close,
5564 },
5565};
5566
5567static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
5568 .substreams = 1,
5569 .channels_min = 2,
5570 .channels_max = 2,
Lydia Wang25eaba22009-10-10 19:08:43 +08005571 /* NID is set in via_build_pcms */
5572 .ops = {
5573 .open = via_dig_playback_pcm_open,
5574 .close = via_dig_playback_pcm_close,
5575 .prepare = via_dig_playback_pcm_prepare,
5576 .cleanup = via_dig_playback_pcm_cleanup
5577 },
5578};
5579
5580/* fill in the dac_nids table from the parsed pin configuration */
5581static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
5582 const struct auto_pin_cfg *cfg)
5583{
5584 spec->multiout.num_dacs = 1;
5585 spec->multiout.dac_nids = spec->private_dac_nids;
5586 if (cfg->line_out_pins[0])
5587 spec->multiout.dac_nids[0] = 0x8;
5588 return 0;
5589}
5590
5591/* add playback controls from the parsed DAC table */
5592static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
5593 const struct auto_pin_cfg *cfg)
5594{
5595 int err;
5596
5597 if (!cfg->line_out_pins[0])
5598 return -1;
5599
5600
5601 /* Line-Out: PortE */
5602 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5603 "Master Front Playback Volume",
5604 HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5605 if (err < 0)
5606 return err;
5607 err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
5608 "Master Front Playback Switch",
5609 HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
5610 if (err < 0)
5611 return err;
5612
5613 return 0;
5614}
5615
5616static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5617{
5618 int err;
5619
5620 if (!pin)
5621 return 0;
5622
5623 spec->multiout.hp_nid = 0x9;
5624 spec->hp_independent_mode_index = 1;
5625
5626 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5627 "Headphone Playback Volume",
5628 HDA_COMPOSE_AMP_VAL(
5629 spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
5630 if (err < 0)
5631 return err;
5632
5633 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5634 "Headphone Playback Switch",
5635 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5636 if (err < 0)
5637 return err;
5638
5639 create_hp_imux(spec);
5640 return 0;
5641}
5642
5643/* create playback/capture controls for input pins */
5644static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
5645 const struct auto_pin_cfg *cfg)
5646{
5647 static char *labels[] = {
5648 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5649 };
5650 struct hda_input_mux *imux = &spec->private_imux[0];
5651 int i, err, idx = 0;
5652
5653 for (i = 0; i < AUTO_PIN_LAST; i++) {
5654 if (!cfg->input_pins[i])
5655 continue;
5656
5657 switch (cfg->input_pins[i]) {
5658 case 0x2b: /* Mic */
5659 idx = 0;
5660 break;
5661
5662 case 0x2a: /* Line In */
5663 idx = 1;
5664 break;
5665
5666 case 0x29: /* Front Mic */
5667 idx = 2;
5668 break;
5669 }
5670 err = via_new_analog_input(spec, labels[i], idx, 0x21);
5671 if (err < 0)
5672 return err;
5673 imux->items[imux->num_items].label = labels[i];
5674 imux->items[imux->num_items].index = idx;
5675 imux->num_items++;
5676 }
5677
5678 /* build volume/mute control of loopback */
5679 err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
5680 if (err < 0)
5681 return err;
5682
5683 /* for internal loopback recording select */
5684 imux->items[imux->num_items].label = "Stereo Mixer";
5685 imux->items[imux->num_items].index = 3;
5686 imux->num_items++;
5687
5688 /* for digital mic select */
5689 imux->items[imux->num_items].label = "Digital Mic";
5690 imux->items[imux->num_items].index = 4;
5691 imux->num_items++;
5692
5693 return 0;
5694}
5695
5696static int vt2002P_parse_auto_config(struct hda_codec *codec)
5697{
5698 struct via_spec *spec = codec->spec;
5699 int err;
5700
5701
5702 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5703 if (err < 0)
5704 return err;
5705
5706 err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
5707 if (err < 0)
5708 return err;
5709
5710 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5711 return 0; /* can't find valid BIOS pin config */
5712
5713 err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
5714 if (err < 0)
5715 return err;
5716 err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5717 if (err < 0)
5718 return err;
5719 err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
5720 if (err < 0)
5721 return err;
5722
5723 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5724
5725 fill_dig_outs(codec);
5726
5727 if (spec->kctls.list)
5728 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5729
5730 spec->input_mux = &spec->private_imux[0];
5731
5732 if (spec->hp_mux)
5733 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5734
5735 return 1;
5736}
5737
5738#ifdef CONFIG_SND_HDA_POWER_SAVE
5739static struct hda_amp_list vt2002P_loopbacks[] = {
5740 { 0x21, HDA_INPUT, 0 },
5741 { 0x21, HDA_INPUT, 1 },
5742 { 0x21, HDA_INPUT, 2 },
5743 { } /* end */
5744};
5745#endif
5746
5747
5748/* patch for vt2002P */
5749static int patch_vt2002P(struct hda_codec *codec)
5750{
5751 struct via_spec *spec;
5752 int err;
5753
5754 /* create a codec specific record */
5755 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5756 if (spec == NULL)
5757 return -ENOMEM;
5758
5759 codec->spec = spec;
5760
5761 /* automatic parse from the BIOS config */
5762 err = vt2002P_parse_auto_config(codec);
5763 if (err < 0) {
5764 via_free(codec);
5765 return err;
5766 } else if (!err) {
5767 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5768 "from BIOS. Using genenic mode...\n");
5769 }
5770
5771 spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs;
5772 spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
5773
5774 spec->stream_name_analog = "VT2002P Analog";
5775 spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
5776 spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
5777
5778 spec->stream_name_digital = "VT2002P Digital";
5779 spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
5780
5781 if (!spec->adc_nids && spec->input_mux) {
5782 spec->adc_nids = vt2002P_adc_nids;
5783 spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
5784 get_mux_nids(codec);
5785 override_mic_boost(codec, 0x2b, 0, 3, 40);
5786 override_mic_boost(codec, 0x29, 0, 3, 40);
5787 spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
5788 spec->num_mixers++;
5789 }
5790
5791 codec->patch_ops = via_patch_ops;
5792
5793 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11005794 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wang25eaba22009-10-10 19:08:43 +08005795
5796#ifdef CONFIG_SND_HDA_POWER_SAVE
5797 spec->loopback.amplist = vt2002P_loopbacks;
5798#endif
5799
5800 return 0;
5801}
Lydia Wangab6734e2009-10-10 19:08:46 +08005802
5803/* for vt1812 */
5804
5805/* capture mixer elements */
5806static struct snd_kcontrol_new vt1812_capture_mixer[] = {
5807 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5808 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5809 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5810 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5811 HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5812 HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
5813 HDA_INPUT),
5814 {
5815 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5816 /* The multiple "Capture Source" controls confuse alsamixer
5817 * So call somewhat different..
5818 */
5819 .name = "Input Source",
5820 .count = 2,
5821 .info = via_mux_enum_info,
5822 .get = via_mux_enum_get,
5823 .put = via_mux_enum_put,
5824 },
5825 { } /* end */
5826};
5827
5828static struct hda_verb vt1812_volume_init_verbs[] = {
5829 /*
5830 * Unmute ADC0-1 and set the default input to mic-in
5831 */
5832 {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5833 {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5834
5835
5836 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5837 * mixer widget
5838 */
5839 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5840 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5841 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5842 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5843 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5844 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5845
5846 /* MUX Indices: Mic = 0 */
5847 {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5848 {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5849
5850 /* PW9 Output enable */
5851 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5852
5853 /* Enable Boost Volume backdoor */
5854 {0x1, 0xfb9, 0x24},
5855
5856 /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5857 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5858 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5859 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5860 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5861 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5862 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5863 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5864 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5865 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5866 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5867
5868 /* set MUX0/1/4/13/15 = 0 (AOW0) */
5869 {0x34, AC_VERB_SET_CONNECT_SEL, 0},
5870 {0x35, AC_VERB_SET_CONNECT_SEL, 0},
5871 {0x38, AC_VERB_SET_CONNECT_SEL, 0},
5872 {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
5873 {0x3d, AC_VERB_SET_CONNECT_SEL, 0},
5874
5875 /* Enable AOW0 to MW9 */
5876 {0x1, 0xfb8, 0xa8},
5877 { }
5878};
5879
5880
5881static struct hda_verb vt1812_uniwill_init_verbs[] = {
5882 {0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
5883 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5884 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
5885 {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
5886 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5887 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5888 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5889 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5890 { }
5891};
5892
5893static struct hda_pcm_stream vt1812_pcm_analog_playback = {
5894 .substreams = 2,
5895 .channels_min = 2,
5896 .channels_max = 2,
5897 .nid = 0x8, /* NID to query formats and rates */
5898 .ops = {
5899 .open = via_playback_pcm_open,
5900 .prepare = via_playback_multi_pcm_prepare,
5901 .cleanup = via_playback_multi_pcm_cleanup,
5902 .close = via_pcm_open_close,
5903 },
5904};
5905
5906static struct hda_pcm_stream vt1812_pcm_analog_capture = {
5907 .substreams = 2,
5908 .channels_min = 2,
5909 .channels_max = 2,
5910 .nid = 0x10, /* NID to query formats and rates */
5911 .ops = {
5912 .open = via_pcm_open_close,
5913 .prepare = via_capture_pcm_prepare,
5914 .cleanup = via_capture_pcm_cleanup,
5915 .close = via_pcm_open_close,
5916 },
5917};
5918
5919static struct hda_pcm_stream vt1812_pcm_digital_playback = {
5920 .substreams = 1,
5921 .channels_min = 2,
5922 .channels_max = 2,
Lydia Wangab6734e2009-10-10 19:08:46 +08005923 /* NID is set in via_build_pcms */
5924 .ops = {
5925 .open = via_dig_playback_pcm_open,
5926 .close = via_dig_playback_pcm_close,
5927 .prepare = via_dig_playback_pcm_prepare,
5928 .cleanup = via_dig_playback_pcm_cleanup
5929 },
5930};
5931/* fill in the dac_nids table from the parsed pin configuration */
5932static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
5933 const struct auto_pin_cfg *cfg)
5934{
5935 spec->multiout.num_dacs = 1;
5936 spec->multiout.dac_nids = spec->private_dac_nids;
5937 if (cfg->line_out_pins[0])
5938 spec->multiout.dac_nids[0] = 0x8;
5939 return 0;
5940}
5941
5942
5943/* add playback controls from the parsed DAC table */
5944static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
5945 const struct auto_pin_cfg *cfg)
5946{
5947 int err;
5948
5949 if (!cfg->line_out_pins[0])
5950 return -1;
5951
5952 /* Line-Out: PortE */
5953 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5954 "Master Front Playback Volume",
5955 HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5956 if (err < 0)
5957 return err;
5958 err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
5959 "Master Front Playback Switch",
5960 HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
5961 if (err < 0)
5962 return err;
5963
5964 return 0;
5965}
5966
5967static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5968{
5969 int err;
5970
5971 if (!pin)
5972 return 0;
5973
5974 spec->multiout.hp_nid = 0x9;
5975 spec->hp_independent_mode_index = 1;
5976
5977
5978 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5979 "Headphone Playback Volume",
5980 HDA_COMPOSE_AMP_VAL(
5981 spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
5982 if (err < 0)
5983 return err;
5984
5985 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5986 "Headphone Playback Switch",
5987 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5988 if (err < 0)
5989 return err;
5990
5991 create_hp_imux(spec);
5992 return 0;
5993}
5994
5995/* create playback/capture controls for input pins */
5996static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
5997 const struct auto_pin_cfg *cfg)
5998{
5999 static char *labels[] = {
6000 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
6001 };
6002 struct hda_input_mux *imux = &spec->private_imux[0];
6003 int i, err, idx = 0;
6004
6005 for (i = 0; i < AUTO_PIN_LAST; i++) {
6006 if (!cfg->input_pins[i])
6007 continue;
6008
6009 switch (cfg->input_pins[i]) {
6010 case 0x2b: /* Mic */
6011 idx = 0;
6012 break;
6013
6014 case 0x2a: /* Line In */
6015 idx = 1;
6016 break;
6017
6018 case 0x29: /* Front Mic */
6019 idx = 2;
6020 break;
6021 }
6022 err = via_new_analog_input(spec, labels[i], idx, 0x21);
6023 if (err < 0)
6024 return err;
6025 imux->items[imux->num_items].label = labels[i];
6026 imux->items[imux->num_items].index = idx;
6027 imux->num_items++;
6028 }
6029 /* build volume/mute control of loopback */
6030 err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
6031 if (err < 0)
6032 return err;
6033
6034 /* for internal loopback recording select */
6035 imux->items[imux->num_items].label = "Stereo Mixer";
6036 imux->items[imux->num_items].index = 5;
6037 imux->num_items++;
6038
6039 /* for digital mic select */
6040 imux->items[imux->num_items].label = "Digital Mic";
6041 imux->items[imux->num_items].index = 6;
6042 imux->num_items++;
6043
6044 return 0;
6045}
6046
6047static int vt1812_parse_auto_config(struct hda_codec *codec)
6048{
6049 struct via_spec *spec = codec->spec;
6050 int err;
6051
6052
6053 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
6054 if (err < 0)
6055 return err;
6056 fill_dig_outs(codec);
6057 err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
6058 if (err < 0)
6059 return err;
6060
6061 if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
6062 return 0; /* can't find valid BIOS pin config */
6063
6064 err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
6065 if (err < 0)
6066 return err;
6067 err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
6068 if (err < 0)
6069 return err;
6070 err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
6071 if (err < 0)
6072 return err;
6073
6074 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
6075
6076 fill_dig_outs(codec);
6077
6078 if (spec->kctls.list)
6079 spec->mixers[spec->num_mixers++] = spec->kctls.list;
6080
6081 spec->input_mux = &spec->private_imux[0];
6082
6083 if (spec->hp_mux)
6084 spec->mixers[spec->num_mixers++] = via_hp_mixer;
6085
6086 return 1;
6087}
6088
6089#ifdef CONFIG_SND_HDA_POWER_SAVE
6090static struct hda_amp_list vt1812_loopbacks[] = {
6091 { 0x21, HDA_INPUT, 0 },
6092 { 0x21, HDA_INPUT, 1 },
6093 { 0x21, HDA_INPUT, 2 },
6094 { } /* end */
6095};
6096#endif
6097
6098
6099/* patch for vt1812 */
6100static int patch_vt1812(struct hda_codec *codec)
6101{
6102 struct via_spec *spec;
6103 int err;
6104
6105 /* create a codec specific record */
6106 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6107 if (spec == NULL)
6108 return -ENOMEM;
6109
6110 codec->spec = spec;
6111
6112 /* automatic parse from the BIOS config */
6113 err = vt1812_parse_auto_config(codec);
6114 if (err < 0) {
6115 via_free(codec);
6116 return err;
6117 } else if (!err) {
6118 printk(KERN_INFO "hda_codec: Cannot set up configuration "
6119 "from BIOS. Using genenic mode...\n");
6120 }
6121
6122
6123 spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs;
6124 spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
6125
6126 spec->stream_name_analog = "VT1812 Analog";
6127 spec->stream_analog_playback = &vt1812_pcm_analog_playback;
6128 spec->stream_analog_capture = &vt1812_pcm_analog_capture;
6129
6130 spec->stream_name_digital = "VT1812 Digital";
6131 spec->stream_digital_playback = &vt1812_pcm_digital_playback;
6132
6133
6134 if (!spec->adc_nids && spec->input_mux) {
6135 spec->adc_nids = vt1812_adc_nids;
6136 spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
6137 get_mux_nids(codec);
6138 override_mic_boost(codec, 0x2b, 0, 3, 40);
6139 override_mic_boost(codec, 0x29, 0, 3, 40);
6140 spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
6141 spec->num_mixers++;
6142 }
6143
6144 codec->patch_ops = via_patch_ops;
6145
6146 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11006147 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wangab6734e2009-10-10 19:08:46 +08006148
6149#ifdef CONFIG_SND_HDA_POWER_SAVE
6150 spec->loopback.amplist = vt1812_loopbacks;
6151#endif
6152
6153 return 0;
6154}
6155
Joseph Chanc577b8a2006-11-29 15:29:40 +01006156/*
6157 * patch entries
6158 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01006159static struct hda_codec_preset snd_hda_preset_via[] = {
Takashi Iwai3218c172008-12-18 09:17:56 +01006160 { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
6161 { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
6162 { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
6163 { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
6164 { .id = 0x1106e710, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006165 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006166 { .id = 0x1106e711, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006167 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006168 { .id = 0x1106e712, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006169 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006170 { .id = 0x1106e713, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006171 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006172 { .id = 0x1106e714, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006173 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006174 { .id = 0x1106e715, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006175 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006176 { .id = 0x1106e716, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006177 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006178 { .id = 0x1106e717, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006179 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006180 { .id = 0x1106e720, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006181 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006182 { .id = 0x1106e721, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006183 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006184 { .id = 0x1106e722, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006185 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006186 { .id = 0x1106e723, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006187 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006188 { .id = 0x1106e724, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006189 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006190 { .id = 0x1106e725, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006191 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006192 { .id = 0x1106e726, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006193 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006194 { .id = 0x1106e727, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006195 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006196 { .id = 0x11060397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006197 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006198 { .id = 0x11061397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006199 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006200 { .id = 0x11062397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006201 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006202 { .id = 0x11063397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006203 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006204 { .id = 0x11064397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006205 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006206 { .id = 0x11065397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006207 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006208 { .id = 0x11066397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006209 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006210 { .id = 0x11067397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006211 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006212 { .id = 0x11060398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006213 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006214 { .id = 0x11061398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006215 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006216 { .id = 0x11062398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006217 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006218 { .id = 0x11063398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006219 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006220 { .id = 0x11064398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006221 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006222 { .id = 0x11065398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006223 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006224 { .id = 0x11066398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006225 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006226 { .id = 0x11067398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006227 .patch = patch_vt1702},
Lydia Wangeb7188c2009-10-10 19:08:34 +08006228 { .id = 0x11060428, .name = "VT1718S",
6229 .patch = patch_vt1718S},
6230 { .id = 0x11064428, .name = "VT1718S",
6231 .patch = patch_vt1718S},
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08006232 { .id = 0x11060441, .name = "VT2020",
6233 .patch = patch_vt1718S},
6234 { .id = 0x11064441, .name = "VT1828S",
6235 .patch = patch_vt1718S},
Lydia Wangf3db4232009-10-10 19:08:41 +08006236 { .id = 0x11060433, .name = "VT1716S",
6237 .patch = patch_vt1716S},
6238 { .id = 0x1106a721, .name = "VT1716S",
6239 .patch = patch_vt1716S},
Lydia Wang25eaba22009-10-10 19:08:43 +08006240 { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
6241 { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
Lydia Wangab6734e2009-10-10 19:08:46 +08006242 { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
Lydia Wang36dd5c42009-10-20 13:18:04 +08006243 { .id = 0x11060440, .name = "VT1818S",
6244 .patch = patch_vt1708S},
Joseph Chanc577b8a2006-11-29 15:29:40 +01006245 {} /* terminator */
6246};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01006247
6248MODULE_ALIAS("snd-hda-codec-id:1106*");
6249
6250static struct hda_codec_preset_list via_list = {
6251 .preset = snd_hda_preset_via,
6252 .owner = THIS_MODULE,
6253};
6254
6255MODULE_LICENSE("GPL");
6256MODULE_DESCRIPTION("VIA HD-audio codec");
6257
6258static int __init patch_via_init(void)
6259{
6260 return snd_hda_add_codec_preset(&via_list);
6261}
6262
6263static void __exit patch_via_exit(void)
6264{
6265 snd_hda_delete_codec_preset(&via_list);
6266}
6267
6268module_init(patch_via_init)
6269module_exit(patch_via_exit)