blob: a94cc91c18ffe41791b0a5180ad241d5e647ff15 [file] [log] [blame]
Joseph Chanc577b8a2006-11-29 15:29:40 +01001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
Harald Welted949cac2008-09-09 15:56:01 +08004 * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
Joseph Chanc577b8a2006-11-29 15:29:40 +01005 *
Harald Welte76d9b0d2008-09-09 15:50:37 +08006 * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
7 * Takashi Iwai <tiwai@suse.de>
Joseph Chanc577b8a2006-11-29 15:29:40 +01008 *
9 * This driver is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This driver is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
25/* */
26/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
27/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
28/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
29/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
Josepch Chanf7278fd2007-12-13 16:40:40 +010030/* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */
31/* 2007-09-17 Lydia Wang Add VT1708B codec support */
Harald Welte76d9b0d2008-09-09 15:50:37 +080032/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */
Harald Weltefb4cb772008-09-09 15:53:36 +080033/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */
Harald Welted949cac2008-09-09 15:56:01 +080034/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
Harald Welte69e52a82008-09-09 15:57:32 +080035/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */
Harald Welte0aa62ae2008-09-09 15:58:27 +080036/* 2008-04-09 Lydia Wang Add Independent HP feature */
Harald Welte98aa34c2008-09-09 16:02:09 +080037/* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */
Harald Welted7426322008-09-15 22:43:23 +080038/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */
Joseph Chanc577b8a2006-11-29 15:29:40 +010039/* */
40/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42
Joseph Chanc577b8a2006-11-29 15:29:40 +010043#include <linux/init.h>
44#include <linux/delay.h>
45#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010046#include <sound/core.h>
Harald Welte0aa62ae2008-09-09 15:58:27 +080047#include <sound/asoundef.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010048#include "hda_codec.h"
49#include "hda_local.h"
Joseph Chanc577b8a2006-11-29 15:29:40 +010050
51/* amp values */
52#define AMP_VAL_IDX_SHIFT 19
53#define AMP_VAL_IDX_MASK (0x0f<<19)
54
Joseph Chanc577b8a2006-11-29 15:29:40 +010055/* Pin Widget NID */
56#define VT1708_HP_NID 0x13
57#define VT1708_DIGOUT_NID 0x14
58#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010059#define VT1708_DIGIN_PIN 0x26
Harald Welted949cac2008-09-09 15:56:01 +080060#define VT1708_HP_PIN_NID 0x20
61#define VT1708_CD_PIN_NID 0x24
Joseph Chanc577b8a2006-11-29 15:29:40 +010062
63#define VT1709_HP_DAC_NID 0x28
64#define VT1709_DIGOUT_NID 0x13
65#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010066#define VT1709_DIGIN_PIN 0x25
67
68#define VT1708B_HP_NID 0x25
69#define VT1708B_DIGOUT_NID 0x12
70#define VT1708B_DIGIN_NID 0x15
71#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010072
Harald Welted949cac2008-09-09 15:56:01 +080073#define VT1708S_HP_NID 0x25
74#define VT1708S_DIGOUT_NID 0x12
75
76#define VT1702_HP_NID 0x17
77#define VT1702_DIGOUT_NID 0x11
78
Harald Welted7426322008-09-15 22:43:23 +080079enum VIA_HDA_CODEC {
80 UNKNOWN = -1,
81 VT1708,
82 VT1709_10CH,
83 VT1709_6CH,
84 VT1708B_8CH,
85 VT1708B_4CH,
86 VT1708S,
Lydia Wang518bf3b2009-10-10 19:07:29 +080087 VT1708BCE,
Harald Welted7426322008-09-15 22:43:23 +080088 VT1702,
Lydia Wangeb7188c2009-10-10 19:08:34 +080089 VT1718S,
Lydia Wangf3db4232009-10-10 19:08:41 +080090 VT1716S,
Lydia Wang25eaba22009-10-10 19:08:43 +080091 VT2002P,
Harald Welted7426322008-09-15 22:43:23 +080092 CODEC_TYPES,
93};
94
Lydia Wang1f2e99f2009-10-10 19:08:17 +080095struct via_spec {
96 /* codec parameterization */
Lydia Wangf3db4232009-10-10 19:08:41 +080097 struct snd_kcontrol_new *mixers[6];
Lydia Wang1f2e99f2009-10-10 19:08:17 +080098 unsigned int num_mixers;
99
100 struct hda_verb *init_verbs[5];
101 unsigned int num_iverbs;
102
103 char *stream_name_analog;
104 struct hda_pcm_stream *stream_analog_playback;
105 struct hda_pcm_stream *stream_analog_capture;
106
107 char *stream_name_digital;
108 struct hda_pcm_stream *stream_digital_playback;
109 struct hda_pcm_stream *stream_digital_capture;
110
111 /* playback */
112 struct hda_multi_out multiout;
113 hda_nid_t slave_dig_outs[2];
114
115 /* capture */
116 unsigned int num_adc_nids;
117 hda_nid_t *adc_nids;
118 hda_nid_t mux_nids[3];
119 hda_nid_t dig_in_nid;
120 hda_nid_t dig_in_pin;
121
122 /* capture source */
123 const struct hda_input_mux *input_mux;
124 unsigned int cur_mux[3];
125
126 /* PCM information */
127 struct hda_pcm pcm_rec[3];
128
129 /* dynamic controls, init_verbs and input_mux */
130 struct auto_pin_cfg autocfg;
131 struct snd_array kctls;
132 struct hda_input_mux private_imux[2];
133 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
134
135 /* HP mode source */
136 const struct hda_input_mux *hp_mux;
137 unsigned int hp_independent_mode;
138 unsigned int hp_independent_mode_index;
139 unsigned int smart51_enabled;
Lydia Wangf3db4232009-10-10 19:08:41 +0800140 unsigned int dmic_enabled;
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800141 enum VIA_HDA_CODEC codec_type;
142
143 /* work to check hp jack state */
144 struct hda_codec *codec;
145 struct delayed_work vt1708_hp_work;
146 int vt1708_jack_detectect;
147 int vt1708_hp_present;
148#ifdef CONFIG_SND_HDA_POWER_SAVE
149 struct hda_loopback_check loopback;
150#endif
151};
152
Lydia Wang744ff5f2009-10-10 19:07:26 +0800153static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
Harald Welted7426322008-09-15 22:43:23 +0800154{
Lydia Wang744ff5f2009-10-10 19:07:26 +0800155 u32 vendor_id = codec->vendor_id;
Harald Welted7426322008-09-15 22:43:23 +0800156 u16 ven_id = vendor_id >> 16;
157 u16 dev_id = vendor_id & 0xffff;
158 enum VIA_HDA_CODEC codec_type;
159
160 /* get codec type */
161 if (ven_id != 0x1106)
162 codec_type = UNKNOWN;
163 else if (dev_id >= 0x1708 && dev_id <= 0x170b)
164 codec_type = VT1708;
165 else if (dev_id >= 0xe710 && dev_id <= 0xe713)
166 codec_type = VT1709_10CH;
167 else if (dev_id >= 0xe714 && dev_id <= 0xe717)
168 codec_type = VT1709_6CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800169 else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
Harald Welted7426322008-09-15 22:43:23 +0800170 codec_type = VT1708B_8CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800171 if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
172 codec_type = VT1708BCE;
173 } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
Harald Welted7426322008-09-15 22:43:23 +0800174 codec_type = VT1708B_4CH;
175 else if ((dev_id & 0xfff) == 0x397
176 && (dev_id >> 12) < 8)
177 codec_type = VT1708S;
178 else if ((dev_id & 0xfff) == 0x398
179 && (dev_id >> 12) < 8)
180 codec_type = VT1702;
Lydia Wangeb7188c2009-10-10 19:08:34 +0800181 else if ((dev_id & 0xfff) == 0x428
182 && (dev_id >> 12) < 8)
183 codec_type = VT1718S;
Lydia Wangf3db4232009-10-10 19:08:41 +0800184 else if (dev_id == 0x0433 || dev_id == 0xa721)
185 codec_type = VT1716S;
Lydia Wangbb3c6bf2009-10-10 19:08:39 +0800186 else if (dev_id == 0x0441 || dev_id == 0x4441)
187 codec_type = VT1718S;
Lydia Wang25eaba22009-10-10 19:08:43 +0800188 else if (dev_id == 0x0438 || dev_id == 0x4438)
189 codec_type = VT2002P;
Harald Welted7426322008-09-15 22:43:23 +0800190 else
191 codec_type = UNKNOWN;
192 return codec_type;
193};
194
Harald Welte69e52a82008-09-09 15:57:32 +0800195#define VIA_HP_EVENT 0x01
196#define VIA_GPIO_EVENT 0x02
Lydia Wanga34df192009-10-10 19:08:01 +0800197#define VIA_JACK_EVENT 0x04
Lydia Wangf3db4232009-10-10 19:08:41 +0800198#define VIA_MONO_EVENT 0x08
Lydia Wang25eaba22009-10-10 19:08:43 +0800199#define VIA_SPEAKER_EVENT 0x10
200#define VIA_BIND_HP_EVENT 0x20
Harald Welte69e52a82008-09-09 15:57:32 +0800201
Joseph Chanc577b8a2006-11-29 15:29:40 +0100202enum {
203 VIA_CTL_WIDGET_VOL,
204 VIA_CTL_WIDGET_MUTE,
Lydia Wangf5271102009-10-10 19:07:35 +0800205 VIA_CTL_WIDGET_ANALOG_MUTE,
Lydia Wang25eaba22009-10-10 19:08:43 +0800206 VIA_CTL_WIDGET_BIND_PIN_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100207};
208
209enum {
Harald Welteeb14a462008-09-09 15:40:38 +0800210 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100211 AUTO_SEQ_SURROUND,
212 AUTO_SEQ_CENLFE,
213 AUTO_SEQ_SIDE
214};
215
Lydia Wangf5271102009-10-10 19:07:35 +0800216static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
217static void set_jack_power_state(struct hda_codec *codec);
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800218static int is_aa_path_mute(struct hda_codec *codec);
219
220static void vt1708_start_hp_work(struct via_spec *spec)
221{
222 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
223 return;
224 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
225 !spec->vt1708_jack_detectect);
226 if (!delayed_work_pending(&spec->vt1708_hp_work))
227 schedule_delayed_work(&spec->vt1708_hp_work,
228 msecs_to_jiffies(100));
229}
230
231static void vt1708_stop_hp_work(struct via_spec *spec)
232{
233 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
234 return;
235 if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
236 && !is_aa_path_mute(spec->codec))
237 return;
238 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
239 !spec->vt1708_jack_detectect);
240 cancel_delayed_work(&spec->vt1708_hp_work);
241 flush_scheduled_work();
242}
Lydia Wangf5271102009-10-10 19:07:35 +0800243
Lydia Wang25eaba22009-10-10 19:08:43 +0800244
Lydia Wangf5271102009-10-10 19:07:35 +0800245static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
246 struct snd_ctl_elem_value *ucontrol)
247{
248 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
249 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
250
251 set_jack_power_state(codec);
252 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800253 if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
254 if (is_aa_path_mute(codec))
255 vt1708_start_hp_work(codec->spec);
256 else
257 vt1708_stop_hp_work(codec->spec);
258 }
Lydia Wangf5271102009-10-10 19:07:35 +0800259 return change;
260}
261
262/* modify .put = snd_hda_mixer_amp_switch_put */
263#define ANALOG_INPUT_MUTE \
264 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
265 .name = NULL, \
266 .index = 0, \
267 .info = snd_hda_mixer_amp_switch_info, \
268 .get = snd_hda_mixer_amp_switch_get, \
269 .put = analog_input_switch_put, \
270 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
271
Lydia Wang25eaba22009-10-10 19:08:43 +0800272static void via_hp_bind_automute(struct hda_codec *codec);
273
274static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
275 struct snd_ctl_elem_value *ucontrol)
276{
277 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
278 struct via_spec *spec = codec->spec;
279 int i;
280 int change = 0;
281
282 long *valp = ucontrol->value.integer.value;
283 int lmute, rmute;
284 if (strstr(kcontrol->id.name, "Switch") == NULL) {
285 snd_printd("Invalid control!\n");
286 return change;
287 }
288 change = snd_hda_mixer_amp_switch_put(kcontrol,
289 ucontrol);
290 /* Get mute value */
291 lmute = *valp ? 0 : HDA_AMP_MUTE;
292 valp++;
293 rmute = *valp ? 0 : HDA_AMP_MUTE;
294
295 /* Set hp pins */
296 if (!spec->hp_independent_mode) {
297 for (i = 0; i < spec->autocfg.hp_outs; i++) {
298 snd_hda_codec_amp_update(
299 codec, spec->autocfg.hp_pins[i],
300 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
301 lmute);
302 snd_hda_codec_amp_update(
303 codec, spec->autocfg.hp_pins[i],
304 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
305 rmute);
306 }
307 }
308
309 if (!lmute && !rmute) {
310 /* Line Outs */
311 for (i = 0; i < spec->autocfg.line_outs; i++)
312 snd_hda_codec_amp_stereo(
313 codec, spec->autocfg.line_out_pins[i],
314 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
315 /* Speakers */
316 for (i = 0; i < spec->autocfg.speaker_outs; i++)
317 snd_hda_codec_amp_stereo(
318 codec, spec->autocfg.speaker_pins[i],
319 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
320 /* unmute */
321 via_hp_bind_automute(codec);
322
323 } else {
324 if (lmute) {
325 /* Mute all left channels */
326 for (i = 1; i < spec->autocfg.line_outs; i++)
327 snd_hda_codec_amp_update(
328 codec,
329 spec->autocfg.line_out_pins[i],
330 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
331 lmute);
332 for (i = 0; i < spec->autocfg.speaker_outs; i++)
333 snd_hda_codec_amp_update(
334 codec,
335 spec->autocfg.speaker_pins[i],
336 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
337 lmute);
338 }
339 if (rmute) {
340 /* mute all right channels */
341 for (i = 1; i < spec->autocfg.line_outs; i++)
342 snd_hda_codec_amp_update(
343 codec,
344 spec->autocfg.line_out_pins[i],
345 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
346 rmute);
347 for (i = 0; i < spec->autocfg.speaker_outs; i++)
348 snd_hda_codec_amp_update(
349 codec,
350 spec->autocfg.speaker_pins[i],
351 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
352 rmute);
353 }
354 }
355 return change;
356}
357
358#define BIND_PIN_MUTE \
359 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
360 .name = NULL, \
361 .index = 0, \
362 .info = snd_hda_mixer_amp_switch_info, \
363 .get = snd_hda_mixer_amp_switch_get, \
364 .put = bind_pin_switch_put, \
365 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
366
Joseph Chanc577b8a2006-11-29 15:29:40 +0100367static struct snd_kcontrol_new vt1708_control_templates[] = {
368 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
369 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Lydia Wangf5271102009-10-10 19:07:35 +0800370 ANALOG_INPUT_MUTE,
Lydia Wang25eaba22009-10-10 19:08:43 +0800371 BIND_PIN_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100372};
373
Joseph Chanc577b8a2006-11-29 15:29:40 +0100374static hda_nid_t vt1708_adc_nids[2] = {
375 /* ADC1-2 */
376 0x15, 0x27
377};
378
379static hda_nid_t vt1709_adc_nids[3] = {
380 /* ADC1-2 */
381 0x14, 0x15, 0x16
382};
383
Josepch Chanf7278fd2007-12-13 16:40:40 +0100384static hda_nid_t vt1708B_adc_nids[2] = {
385 /* ADC1-2 */
386 0x13, 0x14
387};
388
Harald Welted949cac2008-09-09 15:56:01 +0800389static hda_nid_t vt1708S_adc_nids[2] = {
390 /* ADC1-2 */
391 0x13, 0x14
392};
393
394static hda_nid_t vt1702_adc_nids[3] = {
395 /* ADC1-2 */
396 0x12, 0x20, 0x1F
397};
398
Lydia Wangeb7188c2009-10-10 19:08:34 +0800399static hda_nid_t vt1718S_adc_nids[2] = {
400 /* ADC1-2 */
401 0x10, 0x11
402};
403
Lydia Wangf3db4232009-10-10 19:08:41 +0800404static hda_nid_t vt1716S_adc_nids[2] = {
405 /* ADC1-2 */
406 0x13, 0x14
407};
408
Lydia Wang25eaba22009-10-10 19:08:43 +0800409static hda_nid_t vt2002P_adc_nids[2] = {
410 /* ADC1-2 */
411 0x10, 0x11
412};
413
Joseph Chanc577b8a2006-11-29 15:29:40 +0100414/* add dynamic controls */
415static int via_add_control(struct via_spec *spec, int type, const char *name,
416 unsigned long val)
417{
418 struct snd_kcontrol_new *knew;
419
Takashi Iwai603c4012008-07-30 15:01:44 +0200420 snd_array_init(&spec->kctls, sizeof(*knew), 32);
421 knew = snd_array_new(&spec->kctls);
422 if (!knew)
423 return -ENOMEM;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100424 *knew = vt1708_control_templates[type];
425 knew->name = kstrdup(name, GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100426 if (!knew->name)
427 return -ENOMEM;
428 knew->private_value = val;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100429 return 0;
430}
431
Takashi Iwai603c4012008-07-30 15:01:44 +0200432static void via_free_kctls(struct hda_codec *codec)
433{
434 struct via_spec *spec = codec->spec;
435
436 if (spec->kctls.list) {
437 struct snd_kcontrol_new *kctl = spec->kctls.list;
438 int i;
439 for (i = 0; i < spec->kctls.used; i++)
440 kfree(kctl[i].name);
441 }
442 snd_array_free(&spec->kctls);
443}
444
Joseph Chanc577b8a2006-11-29 15:29:40 +0100445/* create input playback/capture controls for the given pin */
Lydia Wang9510e8d2009-10-10 19:07:39 +0800446static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
447 int idx, int mix_nid)
Joseph Chanc577b8a2006-11-29 15:29:40 +0100448{
449 char name[32];
450 int err;
451
452 sprintf(name, "%s Playback Volume", ctlname);
453 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
454 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
455 if (err < 0)
456 return err;
457 sprintf(name, "%s Playback Switch", ctlname);
Lydia Wangf5271102009-10-10 19:07:35 +0800458 err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100459 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
460 if (err < 0)
461 return err;
462 return 0;
463}
464
465static void via_auto_set_output_and_unmute(struct hda_codec *codec,
466 hda_nid_t nid, int pin_type,
467 int dac_idx)
468{
469 /* set as output */
470 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
471 pin_type);
472 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
473 AMP_OUT_UNMUTE);
Takashi Iwaid3a11e62009-07-07 13:43:35 +0200474 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
475 snd_hda_codec_write(codec, nid, 0,
476 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100477}
478
479
480static void via_auto_init_multi_out(struct hda_codec *codec)
481{
482 struct via_spec *spec = codec->spec;
483 int i;
484
485 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
486 hda_nid_t nid = spec->autocfg.line_out_pins[i];
487 if (nid)
488 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
489 }
490}
491
492static void via_auto_init_hp_out(struct hda_codec *codec)
493{
494 struct via_spec *spec = codec->spec;
495 hda_nid_t pin;
Lydia Wang25eaba22009-10-10 19:08:43 +0800496 int i;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100497
Lydia Wang25eaba22009-10-10 19:08:43 +0800498 for (i = 0; i < spec->autocfg.hp_outs; i++) {
499 pin = spec->autocfg.hp_pins[i];
500 if (pin) /* connect to front */
501 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
502 }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100503}
504
505static void via_auto_init_analog_input(struct hda_codec *codec)
506{
507 struct via_spec *spec = codec->spec;
508 int i;
509
510 for (i = 0; i < AUTO_PIN_LAST; i++) {
511 hda_nid_t nid = spec->autocfg.input_pins[i];
512
513 snd_hda_codec_write(codec, nid, 0,
514 AC_VERB_SET_PIN_WIDGET_CONTROL,
515 (i <= AUTO_PIN_FRONT_MIC ?
516 PIN_VREF50 : PIN_IN));
517
518 }
519}
Lydia Wangf5271102009-10-10 19:07:35 +0800520
Lydia Wang1564b282009-10-10 19:07:52 +0800521static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
522
Lydia Wangf5271102009-10-10 19:07:35 +0800523static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
524 unsigned int *affected_parm)
525{
526 unsigned parm;
527 unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
528 unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
529 >> AC_DEFCFG_MISC_SHIFT
530 & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
531 unsigned present = snd_hda_codec_read(codec, nid, 0,
532 AC_VERB_GET_PIN_SENSE, 0) >> 31;
Lydia Wang1564b282009-10-10 19:07:52 +0800533 struct via_spec *spec = codec->spec;
534 if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
535 || ((no_presence || present)
536 && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
Lydia Wangf5271102009-10-10 19:07:35 +0800537 *affected_parm = AC_PWRST_D0; /* if it's connected */
538 parm = AC_PWRST_D0;
539 } else
540 parm = AC_PWRST_D3;
541
542 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
543}
544
545static void set_jack_power_state(struct hda_codec *codec)
546{
547 struct via_spec *spec = codec->spec;
548 int imux_is_smixer;
549 unsigned int parm;
550
551 if (spec->codec_type == VT1702) {
552 imux_is_smixer = snd_hda_codec_read(
553 codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
554 /* inputs */
555 /* PW 1/2/5 (14h/15h/18h) */
556 parm = AC_PWRST_D3;
557 set_pin_power_state(codec, 0x14, &parm);
558 set_pin_power_state(codec, 0x15, &parm);
559 set_pin_power_state(codec, 0x18, &parm);
560 if (imux_is_smixer)
561 parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
562 /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
563 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
564 parm);
565 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
566 parm);
567 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
568 parm);
569 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
570 parm);
571
572 /* outputs */
573 /* PW 3/4 (16h/17h) */
574 parm = AC_PWRST_D3;
575 set_pin_power_state(codec, 0x16, &parm);
576 set_pin_power_state(codec, 0x17, &parm);
577 /* MW0 (1ah), AOW 0/1 (10h/1dh) */
578 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
579 imux_is_smixer ? AC_PWRST_D0 : parm);
580 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
581 parm);
582 snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
583 parm);
584 } else if (spec->codec_type == VT1708B_8CH
585 || spec->codec_type == VT1708B_4CH
586 || spec->codec_type == VT1708S) {
587 /* SW0 (17h) = stereo mixer */
588 int is_8ch = spec->codec_type != VT1708B_4CH;
589 imux_is_smixer = snd_hda_codec_read(
590 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
591 == ((spec->codec_type == VT1708S) ? 5 : 0);
592 /* inputs */
593 /* PW 1/2/5 (1ah/1bh/1eh) */
594 parm = AC_PWRST_D3;
595 set_pin_power_state(codec, 0x1a, &parm);
596 set_pin_power_state(codec, 0x1b, &parm);
597 set_pin_power_state(codec, 0x1e, &parm);
598 if (imux_is_smixer)
599 parm = AC_PWRST_D0;
600 /* SW0 (17h), AIW 0/1 (13h/14h) */
601 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
602 parm);
603 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
604 parm);
605 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
606 parm);
607
608 /* outputs */
609 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
610 parm = AC_PWRST_D3;
611 set_pin_power_state(codec, 0x19, &parm);
612 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
613 parm);
614 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
615 parm);
616
617 /* PW6 (22h), SW2 (26h), AOW2 (24h) */
618 if (is_8ch) {
619 parm = AC_PWRST_D3;
620 set_pin_power_state(codec, 0x22, &parm);
621 snd_hda_codec_write(codec, 0x26, 0,
622 AC_VERB_SET_POWER_STATE, parm);
623 snd_hda_codec_write(codec, 0x24, 0,
624 AC_VERB_SET_POWER_STATE, parm);
625 }
626
627 /* PW 3/4/7 (1ch/1dh/23h) */
628 parm = AC_PWRST_D3;
629 /* force to D0 for internal Speaker */
630 set_pin_power_state(codec, 0x1c, &parm);
631 set_pin_power_state(codec, 0x1d, &parm);
632 if (is_8ch)
633 set_pin_power_state(codec, 0x23, &parm);
634 /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
635 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
636 imux_is_smixer ? AC_PWRST_D0 : parm);
637 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
638 parm);
639 if (is_8ch) {
640 snd_hda_codec_write(codec, 0x25, 0,
641 AC_VERB_SET_POWER_STATE, parm);
642 snd_hda_codec_write(codec, 0x27, 0,
643 AC_VERB_SET_POWER_STATE, parm);
644 }
Lydia Wangeb7188c2009-10-10 19:08:34 +0800645 } else if (spec->codec_type == VT1718S) {
646 /* MUX6 (1eh) = stereo mixer */
647 imux_is_smixer = snd_hda_codec_read(
648 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
649 /* inputs */
650 /* PW 5/6/7 (29h/2ah/2bh) */
651 parm = AC_PWRST_D3;
652 set_pin_power_state(codec, 0x29, &parm);
653 set_pin_power_state(codec, 0x2a, &parm);
654 set_pin_power_state(codec, 0x2b, &parm);
655 if (imux_is_smixer)
656 parm = AC_PWRST_D0;
657 /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
658 snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
659 parm);
660 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
661 parm);
662 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
663 parm);
664 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
665 parm);
666
667 /* outputs */
668 /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
669 parm = AC_PWRST_D3;
670 set_pin_power_state(codec, 0x27, &parm);
671 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
672 parm);
673 snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
674 parm);
675
676 /* PW2 (26h), AOW2 (ah) */
677 parm = AC_PWRST_D3;
678 set_pin_power_state(codec, 0x26, &parm);
679 snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
680 parm);
681
682 /* PW0/1 (24h/25h) */
683 parm = AC_PWRST_D3;
684 set_pin_power_state(codec, 0x24, &parm);
685 set_pin_power_state(codec, 0x25, &parm);
686 if (!spec->hp_independent_mode) /* check for redirected HP */
687 set_pin_power_state(codec, 0x28, &parm);
688 snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
689 parm);
690 snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
691 parm);
692 /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
693 snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
694 imux_is_smixer ? AC_PWRST_D0 : parm);
695 if (spec->hp_independent_mode) {
696 /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
697 parm = AC_PWRST_D3;
698 set_pin_power_state(codec, 0x28, &parm);
699 snd_hda_codec_write(codec, 0x1b, 0,
700 AC_VERB_SET_POWER_STATE, parm);
701 snd_hda_codec_write(codec, 0x34, 0,
702 AC_VERB_SET_POWER_STATE, parm);
703 snd_hda_codec_write(codec, 0xc, 0,
704 AC_VERB_SET_POWER_STATE, parm);
705 }
Lydia Wangf3db4232009-10-10 19:08:41 +0800706 } else if (spec->codec_type == VT1716S) {
707 unsigned int mono_out, present;
708 /* SW0 (17h) = stereo mixer */
709 imux_is_smixer = snd_hda_codec_read(
710 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
711 /* inputs */
712 /* PW 1/2/5 (1ah/1bh/1eh) */
713 parm = AC_PWRST_D3;
714 set_pin_power_state(codec, 0x1a, &parm);
715 set_pin_power_state(codec, 0x1b, &parm);
716 set_pin_power_state(codec, 0x1e, &parm);
717 if (imux_is_smixer)
718 parm = AC_PWRST_D0;
719 /* SW0 (17h), AIW0(13h) */
720 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
721 parm);
722 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
723 parm);
724
725 parm = AC_PWRST_D3;
726 set_pin_power_state(codec, 0x1e, &parm);
727 /* PW11 (22h) */
728 if (spec->dmic_enabled)
729 set_pin_power_state(codec, 0x22, &parm);
730 else
731 snd_hda_codec_write(
732 codec, 0x22, 0,
733 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
734
735 /* SW2(26h), AIW1(14h) */
736 snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
737 parm);
738 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
739 parm);
740
741 /* outputs */
742 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
743 parm = AC_PWRST_D3;
744 set_pin_power_state(codec, 0x19, &parm);
745 /* Smart 5.1 PW2(1bh) */
746 if (spec->smart51_enabled)
747 set_pin_power_state(codec, 0x1b, &parm);
748 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
749 parm);
750 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
751 parm);
752
753 /* PW7 (23h), SW3 (27h), AOW3 (25h) */
754 parm = AC_PWRST_D3;
755 set_pin_power_state(codec, 0x23, &parm);
756 /* Smart 5.1 PW1(1ah) */
757 if (spec->smart51_enabled)
758 set_pin_power_state(codec, 0x1a, &parm);
759 snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
760 parm);
761
762 /* Smart 5.1 PW5(1eh) */
763 if (spec->smart51_enabled)
764 set_pin_power_state(codec, 0x1e, &parm);
765 snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
766 parm);
767
768 /* Mono out */
769 /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
770 present = snd_hda_codec_read(
771 codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
772 if (present)
773 mono_out = 0;
774 else {
775 present = snd_hda_codec_read(
776 codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0)
777 & 0x80000000;
778 if (!spec->hp_independent_mode && present)
779 mono_out = 0;
780 else
781 mono_out = 1;
782 }
783 parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
784 snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
785 parm);
786 snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
787 parm);
788 snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
789 parm);
790
791 /* PW 3/4 (1ch/1dh) */
792 parm = AC_PWRST_D3;
793 set_pin_power_state(codec, 0x1c, &parm);
794 set_pin_power_state(codec, 0x1d, &parm);
795 /* HP Independent Mode, power on AOW3 */
796 if (spec->hp_independent_mode)
797 snd_hda_codec_write(codec, 0x25, 0,
798 AC_VERB_SET_POWER_STATE, parm);
799
800 /* force to D0 for internal Speaker */
801 /* MW0 (16h), AOW0 (10h) */
802 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
803 imux_is_smixer ? AC_PWRST_D0 : parm);
804 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
805 mono_out ? AC_PWRST_D0 : parm);
Lydia Wang25eaba22009-10-10 19:08:43 +0800806 } else if (spec->codec_type == VT2002P) {
807 unsigned int present;
808 /* MUX9 (1eh) = stereo mixer */
809 imux_is_smixer = snd_hda_codec_read(
810 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
811 /* inputs */
812 /* PW 5/6/7 (29h/2ah/2bh) */
813 parm = AC_PWRST_D3;
814 set_pin_power_state(codec, 0x29, &parm);
815 set_pin_power_state(codec, 0x2a, &parm);
816 set_pin_power_state(codec, 0x2b, &parm);
817 if (imux_is_smixer)
818 parm = AC_PWRST_D0;
819 /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
820 snd_hda_codec_write(codec, 0x1e, 0,
821 AC_VERB_SET_POWER_STATE, parm);
822 snd_hda_codec_write(codec, 0x1f, 0,
823 AC_VERB_SET_POWER_STATE, parm);
824 snd_hda_codec_write(codec, 0x10, 0,
825 AC_VERB_SET_POWER_STATE, parm);
826 snd_hda_codec_write(codec, 0x11, 0,
827 AC_VERB_SET_POWER_STATE, parm);
828
829 /* outputs */
830 /* AOW0 (8h)*/
831 snd_hda_codec_write(codec, 0x8, 0,
832 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
833
834 /* PW4 (26h), MW4 (1ch), MUX4(37h) */
835 parm = AC_PWRST_D3;
836 set_pin_power_state(codec, 0x26, &parm);
837 snd_hda_codec_write(codec, 0x1c, 0,
838 AC_VERB_SET_POWER_STATE, parm);
839 snd_hda_codec_write(codec, 0x37,
840 0, AC_VERB_SET_POWER_STATE, parm);
841
842 /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
843 parm = AC_PWRST_D3;
844 set_pin_power_state(codec, 0x25, &parm);
845 snd_hda_codec_write(codec, 0x19, 0,
846 AC_VERB_SET_POWER_STATE, parm);
847 snd_hda_codec_write(codec, 0x35, 0,
848 AC_VERB_SET_POWER_STATE, parm);
849 if (spec->hp_independent_mode) {
850 snd_hda_codec_write(codec, 0x9, 0,
851 AC_VERB_SET_POWER_STATE, parm);
852 }
853
854 /* Class-D */
855 /* PW0 (24h), MW0(18h), MUX0(34h) */
856 present = snd_hda_codec_read(
857 codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
858 parm = AC_PWRST_D3;
859 set_pin_power_state(codec, 0x24, &parm);
860 if (present) {
861 snd_hda_codec_write(
862 codec, 0x18, 0,
863 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
864 snd_hda_codec_write(
865 codec, 0x34, 0,
866 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
867 } else {
868 snd_hda_codec_write(
869 codec, 0x18, 0,
870 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
871 snd_hda_codec_write(
872 codec, 0x34, 0,
873 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
874 }
875
876 /* Mono Out */
877 /* PW15 (31h), MW8(17h), MUX8(3bh) */
878 present = snd_hda_codec_read(
879 codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
880 parm = AC_PWRST_D3;
881 set_pin_power_state(codec, 0x31, &parm);
882 if (present) {
883 snd_hda_codec_write(
884 codec, 0x17, 0,
885 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
886 snd_hda_codec_write(
887 codec, 0x3b, 0,
888 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
889 } else {
890 snd_hda_codec_write(
891 codec, 0x17, 0,
892 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
893 snd_hda_codec_write(
894 codec, 0x3b, 0,
895 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
896 }
897
898 /* MW9 (21h) */
899 if (imux_is_smixer || !is_aa_path_mute(codec))
900 snd_hda_codec_write(
901 codec, 0x21, 0,
902 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
903 else
904 snd_hda_codec_write(
905 codec, 0x21, 0,
906 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Lydia Wangf5271102009-10-10 19:07:35 +0800907 }
908}
909
Joseph Chanc577b8a2006-11-29 15:29:40 +0100910/*
911 * input MUX handling
912 */
913static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
914 struct snd_ctl_elem_info *uinfo)
915{
916 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
917 struct via_spec *spec = codec->spec;
918 return snd_hda_input_mux_info(spec->input_mux, uinfo);
919}
920
921static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
922 struct snd_ctl_elem_value *ucontrol)
923{
924 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
925 struct via_spec *spec = codec->spec;
926 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
927
928 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
929 return 0;
930}
931
932static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
933 struct snd_ctl_elem_value *ucontrol)
934{
935 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
936 struct via_spec *spec = codec->spec;
937 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100938
Takashi Iwai337b9d02009-07-07 18:18:59 +0200939 if (!spec->mux_nids[adc_idx])
940 return -EINVAL;
Lydia Wanga80e6e32009-10-10 19:07:55 +0800941 /* switch to D0 beofre change index */
942 if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
943 AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
944 snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
945 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
946 /* update jack power state */
947 set_jack_power_state(codec);
948
Takashi Iwai337b9d02009-07-07 18:18:59 +0200949 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
950 spec->mux_nids[adc_idx],
951 &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100952}
953
Harald Welte0aa62ae2008-09-09 15:58:27 +0800954static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
955 struct snd_ctl_elem_info *uinfo)
956{
957 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
958 struct via_spec *spec = codec->spec;
959 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
960}
961
962static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
963 struct snd_ctl_elem_value *ucontrol)
964{
965 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
966 struct via_spec *spec = codec->spec;
Lydia Wangeb7188c2009-10-10 19:08:34 +0800967 hda_nid_t nid;
968 unsigned int pinsel;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800969
Lydia Wangeb7188c2009-10-10 19:08:34 +0800970 switch (spec->codec_type) {
971 case VT1718S:
972 nid = 0x34;
973 break;
Lydia Wang25eaba22009-10-10 19:08:43 +0800974 case VT2002P:
975 nid = 0x35;
976 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +0800977 default:
978 nid = spec->autocfg.hp_pins[0];
979 break;
980 }
981 /* use !! to translate conn sel 2 for VT1718S */
982 pinsel = !!snd_hda_codec_read(codec, nid, 0,
983 AC_VERB_GET_CONNECT_SEL,
984 0x00);
Harald Welte0aa62ae2008-09-09 15:58:27 +0800985 ucontrol->value.enumerated.item[0] = pinsel;
986
987 return 0;
988}
989
Lydia Wang0713efe2009-10-10 19:07:43 +0800990static void activate_ctl(struct hda_codec *codec, const char *name, int active)
991{
992 struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
993 if (ctl) {
994 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
995 ctl->vd[0].access |= active
996 ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
997 snd_ctl_notify(codec->bus->card,
998 SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
999 }
1000}
1001
Lydia Wangcdc17842009-10-10 19:07:47 +08001002static int update_side_mute_status(struct hda_codec *codec)
1003{
1004 /* mute side channel */
1005 struct via_spec *spec = codec->spec;
1006 unsigned int parm = spec->hp_independent_mode
1007 ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
1008 hda_nid_t sw3;
1009
1010 switch (spec->codec_type) {
1011 case VT1708:
1012 sw3 = 0x1b;
1013 break;
1014 case VT1709_10CH:
1015 sw3 = 0x29;
1016 break;
1017 case VT1708B_8CH:
1018 case VT1708S:
1019 sw3 = 0x27;
1020 break;
1021 default:
1022 sw3 = 0;
1023 break;
1024 }
1025
1026 if (sw3)
1027 snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1028 parm);
1029 return 0;
1030}
1031
Harald Welte0aa62ae2008-09-09 15:58:27 +08001032static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
1033 struct snd_ctl_elem_value *ucontrol)
1034{
1035 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1036 struct via_spec *spec = codec->spec;
1037 hda_nid_t nid = spec->autocfg.hp_pins[0];
1038 unsigned int pinsel = ucontrol->value.enumerated.item[0];
Lydia Wangcdc17842009-10-10 19:07:47 +08001039 /* Get Independent Mode index of headphone pin widget */
1040 spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
1041 ? 1 : 0;
Harald Welte0aa62ae2008-09-09 15:58:27 +08001042
Lydia Wangeb7188c2009-10-10 19:08:34 +08001043 switch (spec->codec_type) {
1044 case VT1718S:
1045 nid = 0x34;
1046 pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
1047 spec->multiout.num_dacs = 4;
1048 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001049 case VT2002P:
1050 nid = 0x35;
1051 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001052 default:
1053 nid = spec->autocfg.hp_pins[0];
1054 break;
1055 }
Lydia Wangcdc17842009-10-10 19:07:47 +08001056 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001057
Lydia Wangcdc17842009-10-10 19:07:47 +08001058 if (spec->multiout.hp_nid && spec->multiout.hp_nid
1059 != spec->multiout.dac_nids[HDA_FRONT])
1060 snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
1061 0, 0, 0);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001062
Lydia Wangcdc17842009-10-10 19:07:47 +08001063 update_side_mute_status(codec);
Lydia Wang0713efe2009-10-10 19:07:43 +08001064 /* update HP volume/swtich active state */
1065 if (spec->codec_type == VT1708S
Lydia Wangeb7188c2009-10-10 19:08:34 +08001066 || spec->codec_type == VT1702
Lydia Wangf3db4232009-10-10 19:08:41 +08001067 || spec->codec_type == VT1718S
Lydia Wang25eaba22009-10-10 19:08:43 +08001068 || spec->codec_type == VT1716S
1069 || spec->codec_type == VT2002P) {
Lydia Wang0713efe2009-10-10 19:07:43 +08001070 activate_ctl(codec, "Headphone Playback Volume",
1071 spec->hp_independent_mode);
1072 activate_ctl(codec, "Headphone Playback Switch",
1073 spec->hp_independent_mode);
1074 }
Harald Welte0aa62ae2008-09-09 15:58:27 +08001075 return 0;
1076}
1077
1078static struct snd_kcontrol_new via_hp_mixer[] = {
1079 {
1080 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1081 .name = "Independent HP",
1082 .count = 1,
1083 .info = via_independent_hp_info,
1084 .get = via_independent_hp_get,
1085 .put = via_independent_hp_put,
1086 },
1087 { } /* end */
1088};
1089
Lydia Wang1564b282009-10-10 19:07:52 +08001090static void notify_aa_path_ctls(struct hda_codec *codec)
1091{
1092 int i;
1093 struct snd_ctl_elem_id id;
1094 const char *labels[] = {"Mic", "Front Mic", "Line"};
1095
1096 memset(&id, 0, sizeof(id));
1097 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1098 for (i = 0; i < ARRAY_SIZE(labels); i++) {
1099 sprintf(id.name, "%s Playback Volume", labels[i]);
1100 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1101 &id);
1102 }
1103}
1104
1105static void mute_aa_path(struct hda_codec *codec, int mute)
1106{
1107 struct via_spec *spec = codec->spec;
1108 hda_nid_t nid_mixer;
1109 int start_idx;
1110 int end_idx;
1111 int i;
1112 /* get nid of MW0 and start & end index */
1113 switch (spec->codec_type) {
1114 case VT1708:
1115 nid_mixer = 0x17;
1116 start_idx = 2;
1117 end_idx = 4;
1118 break;
1119 case VT1709_10CH:
1120 case VT1709_6CH:
1121 nid_mixer = 0x18;
1122 start_idx = 2;
1123 end_idx = 4;
1124 break;
1125 case VT1708B_8CH:
1126 case VT1708B_4CH:
1127 case VT1708S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001128 case VT1716S:
Lydia Wang1564b282009-10-10 19:07:52 +08001129 nid_mixer = 0x16;
1130 start_idx = 2;
1131 end_idx = 4;
1132 break;
1133 default:
1134 return;
1135 }
1136 /* check AA path's mute status */
1137 for (i = start_idx; i <= end_idx; i++) {
1138 int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
1139 snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
1140 HDA_AMP_MUTE, val);
1141 }
1142}
1143static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
1144{
1145 int res = 0;
1146 int index;
1147 for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
1148 if (pin == spec->autocfg.input_pins[index]) {
1149 res = 1;
1150 break;
1151 }
1152 }
1153 return res;
1154}
1155
1156static int via_smart51_info(struct snd_kcontrol *kcontrol,
1157 struct snd_ctl_elem_info *uinfo)
1158{
1159 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1160 uinfo->count = 1;
1161 uinfo->value.integer.min = 0;
1162 uinfo->value.integer.max = 1;
1163 return 0;
1164}
1165
1166static int via_smart51_get(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 int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
1172 int on = 1;
1173 int i;
1174
1175 for (i = 0; i < ARRAY_SIZE(index); i++) {
1176 hda_nid_t nid = spec->autocfg.input_pins[index[i]];
1177 if (nid) {
1178 int ctl =
1179 snd_hda_codec_read(codec, nid, 0,
1180 AC_VERB_GET_PIN_WIDGET_CONTROL,
1181 0);
1182 if (i == AUTO_PIN_FRONT_MIC
Lydia Wangeb7188c2009-10-10 19:08:34 +08001183 && spec->hp_independent_mode
1184 && spec->codec_type != VT1718S)
Lydia Wang1564b282009-10-10 19:07:52 +08001185 continue; /* ignore FMic for independent HP */
1186 if (ctl & AC_PINCTL_IN_EN
1187 && !(ctl & AC_PINCTL_OUT_EN))
1188 on = 0;
1189 }
1190 }
1191 *ucontrol->value.integer.value = on;
1192 return 0;
1193}
1194
1195static int via_smart51_put(struct snd_kcontrol *kcontrol,
1196 struct snd_ctl_elem_value *ucontrol)
1197{
1198 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1199 struct via_spec *spec = codec->spec;
1200 int out_in = *ucontrol->value.integer.value
1201 ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
1202 int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
1203 int i;
1204
1205 for (i = 0; i < ARRAY_SIZE(index); i++) {
1206 hda_nid_t nid = spec->autocfg.input_pins[index[i]];
1207 if (i == AUTO_PIN_FRONT_MIC
Lydia Wangeb7188c2009-10-10 19:08:34 +08001208 && spec->hp_independent_mode
1209 && spec->codec_type != VT1718S)
Lydia Wang1564b282009-10-10 19:07:52 +08001210 continue; /* don't retask FMic for independent HP */
1211 if (nid) {
1212 unsigned int parm = snd_hda_codec_read(
1213 codec, nid, 0,
1214 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1215 parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
1216 parm |= out_in;
1217 snd_hda_codec_write(codec, nid, 0,
1218 AC_VERB_SET_PIN_WIDGET_CONTROL,
1219 parm);
1220 if (out_in == AC_PINCTL_OUT_EN) {
1221 mute_aa_path(codec, 1);
1222 notify_aa_path_ctls(codec);
1223 }
Lydia Wangeb7188c2009-10-10 19:08:34 +08001224 if (spec->codec_type == VT1718S)
1225 snd_hda_codec_amp_stereo(
1226 codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1227 HDA_AMP_UNMUTE);
Lydia Wang1564b282009-10-10 19:07:52 +08001228 }
1229 if (i == AUTO_PIN_FRONT_MIC) {
Lydia Wangf3db4232009-10-10 19:08:41 +08001230 if (spec->codec_type == VT1708S
1231 || spec->codec_type == VT1716S) {
Lydia Wang1564b282009-10-10 19:07:52 +08001232 /* input = index 1 (AOW3) */
1233 snd_hda_codec_write(
1234 codec, nid, 0,
1235 AC_VERB_SET_CONNECT_SEL, 1);
1236 snd_hda_codec_amp_stereo(
1237 codec, nid, HDA_OUTPUT,
1238 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
1239 }
1240 }
1241 }
1242 spec->smart51_enabled = *ucontrol->value.integer.value;
1243 set_jack_power_state(codec);
1244 return 1;
1245}
1246
1247static struct snd_kcontrol_new via_smart51_mixer[] = {
1248 {
1249 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1250 .name = "Smart 5.1",
1251 .count = 1,
1252 .info = via_smart51_info,
1253 .get = via_smart51_get,
1254 .put = via_smart51_put,
1255 },
1256 {} /* end */
1257};
1258
Joseph Chanc577b8a2006-11-29 15:29:40 +01001259/* capture mixer elements */
1260static struct snd_kcontrol_new vt1708_capture_mixer[] = {
1261 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
1262 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
1263 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
1264 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
1265 {
1266 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1267 /* The multiple "Capture Source" controls confuse alsamixer
1268 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001269 */
1270 /* .name = "Capture Source", */
1271 .name = "Input Source",
1272 .count = 1,
1273 .info = via_mux_enum_info,
1274 .get = via_mux_enum_get,
1275 .put = via_mux_enum_put,
1276 },
1277 { } /* end */
1278};
Lydia Wangf5271102009-10-10 19:07:35 +08001279
1280/* check AA path's mute statue */
1281static int is_aa_path_mute(struct hda_codec *codec)
1282{
1283 int mute = 1;
1284 hda_nid_t nid_mixer;
1285 int start_idx;
1286 int end_idx;
1287 int i;
1288 struct via_spec *spec = codec->spec;
1289 /* get nid of MW0 and start & end index */
1290 switch (spec->codec_type) {
1291 case VT1708B_8CH:
1292 case VT1708B_4CH:
1293 case VT1708S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001294 case VT1716S:
Lydia Wangf5271102009-10-10 19:07:35 +08001295 nid_mixer = 0x16;
1296 start_idx = 2;
1297 end_idx = 4;
1298 break;
1299 case VT1702:
1300 nid_mixer = 0x1a;
1301 start_idx = 1;
1302 end_idx = 3;
1303 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001304 case VT1718S:
1305 nid_mixer = 0x21;
1306 start_idx = 1;
1307 end_idx = 3;
1308 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001309 case VT2002P:
1310 nid_mixer = 0x21;
1311 start_idx = 0;
1312 end_idx = 2;
1313 break;
Lydia Wangf5271102009-10-10 19:07:35 +08001314 default:
1315 return 0;
1316 }
1317 /* check AA path's mute status */
1318 for (i = start_idx; i <= end_idx; i++) {
1319 unsigned int con_list = snd_hda_codec_read(
1320 codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
1321 int shift = 8 * (i % 4);
1322 hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
1323 unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
1324 if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
1325 /* check mute status while the pin is connected */
1326 int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
1327 HDA_INPUT, i) >> 7;
1328 int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
1329 HDA_INPUT, i) >> 7;
1330 if (!mute_l || !mute_r) {
1331 mute = 0;
1332 break;
1333 }
1334 }
1335 }
1336 return mute;
1337}
1338
1339/* enter/exit analog low-current mode */
1340static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
1341{
1342 struct via_spec *spec = codec->spec;
1343 static int saved_stream_idle = 1; /* saved stream idle status */
1344 int enable = is_aa_path_mute(codec);
1345 unsigned int verb = 0;
1346 unsigned int parm = 0;
1347
1348 if (stream_idle == -1) /* stream status did not change */
1349 enable = enable && saved_stream_idle;
1350 else {
1351 enable = enable && stream_idle;
1352 saved_stream_idle = stream_idle;
1353 }
1354
1355 /* decide low current mode's verb & parameter */
1356 switch (spec->codec_type) {
1357 case VT1708B_8CH:
1358 case VT1708B_4CH:
1359 verb = 0xf70;
1360 parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
1361 break;
1362 case VT1708S:
Lydia Wangeb7188c2009-10-10 19:08:34 +08001363 case VT1718S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001364 case VT1716S:
Lydia Wangf5271102009-10-10 19:07:35 +08001365 verb = 0xf73;
1366 parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
1367 break;
1368 case VT1702:
1369 verb = 0xf73;
1370 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
1371 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001372 case VT2002P:
1373 verb = 0xf93;
1374 parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
1375 break;
Lydia Wangf5271102009-10-10 19:07:35 +08001376 default:
1377 return; /* other codecs are not supported */
1378 }
1379 /* send verb */
1380 snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
1381}
1382
Joseph Chanc577b8a2006-11-29 15:29:40 +01001383/*
1384 * generic initialization of ADC, input mixers and output mixers
1385 */
1386static struct hda_verb vt1708_volume_init_verbs[] = {
1387 /*
1388 * Unmute ADC0-1 and set the default input to mic-in
1389 */
1390 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1391 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1392
1393
Josepch Chanf7278fd2007-12-13 16:40:40 +01001394 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001395 * mixer widget
1396 */
1397 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001398 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1399 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1400 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1401 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1402 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001403
1404 /*
1405 * Set up output mixers (0x19 - 0x1b)
1406 */
1407 /* set vol=0 to output mixers */
1408 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1409 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1410 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1411
1412 /* Setup default input to PW4 */
1413 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001414 /* PW9 Output enable */
1415 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001416 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +01001417};
1418
1419static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
1420 struct hda_codec *codec,
1421 struct snd_pcm_substream *substream)
1422{
1423 struct via_spec *spec = codec->spec;
Lydia Wang17314372009-10-10 19:07:37 +08001424 int idle = substream->pstr->substream_opened == 1
1425 && substream->ref_count == 0;
Lydia Wang17314372009-10-10 19:07:37 +08001426 analog_low_current_mode(codec, idle);
Takashi Iwai9a081602008-02-12 18:37:26 +01001427 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1428 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001429}
1430
Harald Welte0aa62ae2008-09-09 15:58:27 +08001431static void playback_multi_pcm_prep_0(struct hda_codec *codec,
1432 unsigned int stream_tag,
1433 unsigned int format,
1434 struct snd_pcm_substream *substream)
1435{
1436 struct via_spec *spec = codec->spec;
1437 struct hda_multi_out *mout = &spec->multiout;
1438 hda_nid_t *nids = mout->dac_nids;
1439 int chs = substream->runtime->channels;
1440 int i;
1441
1442 mutex_lock(&codec->spdif_mutex);
1443 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
1444 if (chs == 2 &&
1445 snd_hda_is_supported_format(codec, mout->dig_out_nid,
1446 format) &&
1447 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
1448 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
1449 /* turn off SPDIF once; otherwise the IEC958 bits won't
1450 * be updated */
1451 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1452 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
1453 AC_VERB_SET_DIGI_CONVERT_1,
1454 codec->spdif_ctls &
1455 ~AC_DIG1_ENABLE & 0xff);
1456 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1457 stream_tag, 0, format);
1458 /* turn on again (if needed) */
1459 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1460 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
1461 AC_VERB_SET_DIGI_CONVERT_1,
1462 codec->spdif_ctls & 0xff);
1463 } else {
1464 mout->dig_out_used = 0;
1465 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1466 0, 0, 0);
1467 }
1468 }
1469 mutex_unlock(&codec->spdif_mutex);
1470
1471 /* front */
1472 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
1473 0, format);
1474
Lydia Wangeb7188c2009-10-10 19:08:34 +08001475 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
1476 && !spec->hp_independent_mode)
Harald Welte0aa62ae2008-09-09 15:58:27 +08001477 /* headphone out will just decode front left/right (stereo) */
1478 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
1479 0, format);
1480
1481 /* extra outputs copied from front */
1482 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
1483 if (mout->extra_out_nid[i])
1484 snd_hda_codec_setup_stream(codec,
1485 mout->extra_out_nid[i],
1486 stream_tag, 0, format);
1487
1488 /* surrounds */
1489 for (i = 1; i < mout->num_dacs; i++) {
1490 if (chs >= (i + 1) * 2) /* independent out */
1491 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
1492 i * 2, format);
1493 else /* copy front */
1494 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
1495 0, format);
1496 }
1497}
1498
1499static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
1500 struct hda_codec *codec,
1501 unsigned int stream_tag,
1502 unsigned int format,
1503 struct snd_pcm_substream *substream)
1504{
1505 struct via_spec *spec = codec->spec;
1506 struct hda_multi_out *mout = &spec->multiout;
1507 hda_nid_t *nids = mout->dac_nids;
1508
1509 if (substream->number == 0)
1510 playback_multi_pcm_prep_0(codec, stream_tag, format,
1511 substream);
1512 else {
1513 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
1514 spec->hp_independent_mode)
1515 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1516 stream_tag, 0, format);
1517 }
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001518 vt1708_start_hp_work(spec);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001519 return 0;
1520}
1521
1522static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
1523 struct hda_codec *codec,
1524 struct snd_pcm_substream *substream)
1525{
1526 struct via_spec *spec = codec->spec;
1527 struct hda_multi_out *mout = &spec->multiout;
1528 hda_nid_t *nids = mout->dac_nids;
1529 int i;
1530
1531 if (substream->number == 0) {
1532 for (i = 0; i < mout->num_dacs; i++)
1533 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
1534
1535 if (mout->hp_nid && !spec->hp_independent_mode)
1536 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1537 0, 0, 0);
1538
1539 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
1540 if (mout->extra_out_nid[i])
1541 snd_hda_codec_setup_stream(codec,
1542 mout->extra_out_nid[i],
1543 0, 0, 0);
1544 mutex_lock(&codec->spdif_mutex);
1545 if (mout->dig_out_nid &&
1546 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
1547 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1548 0, 0, 0);
1549 mout->dig_out_used = 0;
1550 }
1551 mutex_unlock(&codec->spdif_mutex);
1552 } else {
1553 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
1554 spec->hp_independent_mode)
1555 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1556 0, 0, 0);
1557 }
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001558 vt1708_stop_hp_work(spec);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001559 return 0;
1560}
1561
Joseph Chanc577b8a2006-11-29 15:29:40 +01001562/*
1563 * Digital out
1564 */
1565static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1566 struct hda_codec *codec,
1567 struct snd_pcm_substream *substream)
1568{
1569 struct via_spec *spec = codec->spec;
1570 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1571}
1572
1573static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1574 struct hda_codec *codec,
1575 struct snd_pcm_substream *substream)
1576{
1577 struct via_spec *spec = codec->spec;
1578 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1579}
1580
Harald Welte5691ec72008-09-15 22:42:26 +08001581static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Harald Welte98aa34c2008-09-09 16:02:09 +08001582 struct hda_codec *codec,
1583 unsigned int stream_tag,
1584 unsigned int format,
1585 struct snd_pcm_substream *substream)
1586{
1587 struct via_spec *spec = codec->spec;
Takashi Iwai9da29272009-05-07 16:31:14 +02001588 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1589 stream_tag, format, substream);
1590}
Harald Welte5691ec72008-09-15 22:42:26 +08001591
Takashi Iwai9da29272009-05-07 16:31:14 +02001592static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1593 struct hda_codec *codec,
1594 struct snd_pcm_substream *substream)
1595{
1596 struct via_spec *spec = codec->spec;
1597 snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
Harald Welte98aa34c2008-09-09 16:02:09 +08001598 return 0;
1599}
1600
Joseph Chanc577b8a2006-11-29 15:29:40 +01001601/*
1602 * Analog capture
1603 */
1604static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1605 struct hda_codec *codec,
1606 unsigned int stream_tag,
1607 unsigned int format,
1608 struct snd_pcm_substream *substream)
1609{
1610 struct via_spec *spec = codec->spec;
1611
1612 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1613 stream_tag, 0, format);
1614 return 0;
1615}
1616
1617static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1618 struct hda_codec *codec,
1619 struct snd_pcm_substream *substream)
1620{
1621 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +01001622 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001623 return 0;
1624}
1625
1626static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08001627 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +01001628 .channels_min = 2,
1629 .channels_max = 8,
1630 .nid = 0x10, /* NID to query formats and rates */
1631 .ops = {
1632 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08001633 .prepare = via_playback_multi_pcm_prepare,
1634 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001635 },
1636};
1637
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001638static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
Lydia Wangc873cc22009-10-10 19:08:21 +08001639 .substreams = 2,
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001640 .channels_min = 2,
1641 .channels_max = 8,
1642 .nid = 0x10, /* NID to query formats and rates */
1643 /* We got noisy outputs on the right channel on VT1708 when
1644 * 24bit samples are used. Until any workaround is found,
1645 * disable the 24bit format, so far.
1646 */
1647 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1648 .ops = {
1649 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08001650 .prepare = via_playback_multi_pcm_prepare,
1651 .cleanup = via_playback_multi_pcm_cleanup
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001652 },
1653};
1654
Joseph Chanc577b8a2006-11-29 15:29:40 +01001655static struct hda_pcm_stream vt1708_pcm_analog_capture = {
1656 .substreams = 2,
1657 .channels_min = 2,
1658 .channels_max = 2,
1659 .nid = 0x15, /* NID to query formats and rates */
1660 .ops = {
1661 .prepare = via_capture_pcm_prepare,
1662 .cleanup = via_capture_pcm_cleanup
1663 },
1664};
1665
1666static struct hda_pcm_stream vt1708_pcm_digital_playback = {
1667 .substreams = 1,
1668 .channels_min = 2,
1669 .channels_max = 2,
1670 /* NID is set in via_build_pcms */
1671 .ops = {
1672 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001673 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02001674 .prepare = via_dig_playback_pcm_prepare,
1675 .cleanup = via_dig_playback_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001676 },
1677};
1678
1679static struct hda_pcm_stream vt1708_pcm_digital_capture = {
1680 .substreams = 1,
1681 .channels_min = 2,
1682 .channels_max = 2,
1683};
1684
1685static int via_build_controls(struct hda_codec *codec)
1686{
1687 struct via_spec *spec = codec->spec;
1688 int err;
1689 int i;
1690
1691 for (i = 0; i < spec->num_mixers; i++) {
1692 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1693 if (err < 0)
1694 return err;
1695 }
1696
1697 if (spec->multiout.dig_out_nid) {
1698 err = snd_hda_create_spdif_out_ctls(codec,
1699 spec->multiout.dig_out_nid);
1700 if (err < 0)
1701 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001702 err = snd_hda_create_spdif_share_sw(codec,
1703 &spec->multiout);
1704 if (err < 0)
1705 return err;
1706 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001707 }
1708 if (spec->dig_in_nid) {
1709 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1710 if (err < 0)
1711 return err;
1712 }
Lydia Wang17314372009-10-10 19:07:37 +08001713
1714 /* init power states */
1715 set_jack_power_state(codec);
1716 analog_low_current_mode(codec, 1);
1717
Takashi Iwai603c4012008-07-30 15:01:44 +02001718 via_free_kctls(codec); /* no longer needed */
Joseph Chanc577b8a2006-11-29 15:29:40 +01001719 return 0;
1720}
1721
1722static int via_build_pcms(struct hda_codec *codec)
1723{
1724 struct via_spec *spec = codec->spec;
1725 struct hda_pcm *info = spec->pcm_rec;
1726
1727 codec->num_pcms = 1;
1728 codec->pcm_info = info;
1729
1730 info->name = spec->stream_name_analog;
1731 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
1732 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
1733 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1734 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1735
1736 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
1737 spec->multiout.max_channels;
1738
1739 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1740 codec->num_pcms++;
1741 info++;
1742 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001743 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001744 if (spec->multiout.dig_out_nid) {
1745 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1746 *(spec->stream_digital_playback);
1747 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1748 spec->multiout.dig_out_nid;
1749 }
1750 if (spec->dig_in_nid) {
1751 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
1752 *(spec->stream_digital_capture);
1753 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
1754 spec->dig_in_nid;
1755 }
1756 }
1757
1758 return 0;
1759}
1760
1761static void via_free(struct hda_codec *codec)
1762{
1763 struct via_spec *spec = codec->spec;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001764
1765 if (!spec)
1766 return;
1767
Takashi Iwai603c4012008-07-30 15:01:44 +02001768 via_free_kctls(codec);
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001769 vt1708_stop_hp_work(spec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001770 kfree(codec->spec);
1771}
1772
Harald Welte69e52a82008-09-09 15:57:32 +08001773/* mute internal speaker if HP is plugged */
1774static void via_hp_automute(struct hda_codec *codec)
1775{
Lydia Wangdcf34c82009-10-10 19:08:15 +08001776 unsigned int present = 0;
Harald Welte69e52a82008-09-09 15:57:32 +08001777 struct via_spec *spec = codec->spec;
1778
1779 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1780 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Lydia Wangdcf34c82009-10-10 19:08:15 +08001781
1782 if (!spec->hp_independent_mode) {
1783 struct snd_ctl_elem_id id;
1784 /* auto mute */
1785 snd_hda_codec_amp_stereo(
1786 codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
1787 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1788 /* notify change */
1789 memset(&id, 0, sizeof(id));
1790 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1791 strcpy(id.name, "Front Playback Switch");
1792 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1793 &id);
1794 }
Harald Welte69e52a82008-09-09 15:57:32 +08001795}
1796
Lydia Wangf3db4232009-10-10 19:08:41 +08001797/* mute mono out if HP or Line out is plugged */
1798static void via_mono_automute(struct hda_codec *codec)
1799{
1800 unsigned int hp_present, lineout_present;
1801 struct via_spec *spec = codec->spec;
1802
1803 if (spec->codec_type != VT1716S)
1804 return;
1805
1806 lineout_present = snd_hda_codec_read(
1807 codec, spec->autocfg.line_out_pins[0], 0,
1808 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1809
1810 /* Mute Mono Out if Line Out is plugged */
1811 if (lineout_present) {
1812 snd_hda_codec_amp_stereo(
1813 codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
1814 return;
1815 }
1816
1817 hp_present = snd_hda_codec_read(
1818 codec, spec->autocfg.hp_pins[0], 0,
1819 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1820
1821 if (!spec->hp_independent_mode)
1822 snd_hda_codec_amp_stereo(
1823 codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1824 hp_present ? HDA_AMP_MUTE : 0);
1825}
1826
Harald Welte69e52a82008-09-09 15:57:32 +08001827static void via_gpio_control(struct hda_codec *codec)
1828{
1829 unsigned int gpio_data;
1830 unsigned int vol_counter;
1831 unsigned int vol;
1832 unsigned int master_vol;
1833
1834 struct via_spec *spec = codec->spec;
1835
1836 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
1837 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
1838
1839 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
1840 0xF84, 0) & 0x3F0000) >> 16;
1841
1842 vol = vol_counter & 0x1F;
1843 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
1844 AC_VERB_GET_AMP_GAIN_MUTE,
1845 AC_AMP_GET_INPUT);
1846
1847 if (gpio_data == 0x02) {
1848 /* unmute line out */
1849 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
1850 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
1851
1852 if (vol_counter & 0x20) {
1853 /* decrease volume */
1854 if (vol > master_vol)
1855 vol = master_vol;
1856 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
1857 0, HDA_AMP_VOLMASK,
1858 master_vol-vol);
1859 } else {
1860 /* increase volume */
1861 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
1862 HDA_AMP_VOLMASK,
1863 ((master_vol+vol) > 0x2A) ? 0x2A :
1864 (master_vol+vol));
1865 }
1866 } else if (!(gpio_data & 0x02)) {
1867 /* mute line out */
1868 snd_hda_codec_amp_stereo(codec,
1869 spec->autocfg.line_out_pins[0],
1870 HDA_OUTPUT, 0, HDA_AMP_MUTE,
1871 HDA_AMP_MUTE);
1872 }
1873}
1874
Lydia Wang25eaba22009-10-10 19:08:43 +08001875/* mute Internal-Speaker if HP is plugged */
1876static void via_speaker_automute(struct hda_codec *codec)
1877{
1878 unsigned int hp_present;
1879 struct via_spec *spec = codec->spec;
1880
1881 if (spec->codec_type != VT2002P)
1882 return;
1883
1884 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1885 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1886
1887 if (!spec->hp_independent_mode) {
1888 struct snd_ctl_elem_id id;
1889 snd_hda_codec_amp_stereo(
1890 codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
1891 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
1892 /* notify change */
1893 memset(&id, 0, sizeof(id));
1894 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1895 strcpy(id.name, "Speaker Playback Switch");
1896 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1897 &id);
1898 }
1899}
1900
1901/* mute line-out and internal speaker if HP is plugged */
1902static void via_hp_bind_automute(struct hda_codec *codec)
1903{
1904 unsigned int hp_present, present = 0;
1905 struct via_spec *spec = codec->spec;
1906 int i;
1907
1908 if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
1909 return;
1910
1911 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1912 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1913
1914 present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0,
1915 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1916
1917 if (!spec->hp_independent_mode) {
1918 /* Mute Line-Outs */
1919 for (i = 0; i < spec->autocfg.line_outs; i++)
1920 snd_hda_codec_amp_stereo(
1921 codec, spec->autocfg.line_out_pins[i],
1922 HDA_OUTPUT, 0,
1923 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
1924 if (hp_present)
1925 present = hp_present;
1926 }
1927 /* Speakers */
1928 for (i = 0; i < spec->autocfg.speaker_outs; i++)
1929 snd_hda_codec_amp_stereo(
1930 codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
1931 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1932}
1933
1934
Harald Welte69e52a82008-09-09 15:57:32 +08001935/* unsolicited event for jack sensing */
1936static void via_unsol_event(struct hda_codec *codec,
1937 unsigned int res)
1938{
1939 res >>= 26;
Lydia Wanga34df192009-10-10 19:08:01 +08001940 if (res & VIA_HP_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08001941 via_hp_automute(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08001942 if (res & VIA_GPIO_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08001943 via_gpio_control(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08001944 if (res & VIA_JACK_EVENT)
1945 set_jack_power_state(codec);
Lydia Wangf3db4232009-10-10 19:08:41 +08001946 if (res & VIA_MONO_EVENT)
1947 via_mono_automute(codec);
Lydia Wang25eaba22009-10-10 19:08:43 +08001948 if (res & VIA_SPEAKER_EVENT)
1949 via_speaker_automute(codec);
1950 if (res & VIA_BIND_HP_EVENT)
1951 via_hp_bind_automute(codec);
Harald Welte69e52a82008-09-09 15:57:32 +08001952}
1953
Joseph Chanc577b8a2006-11-29 15:29:40 +01001954static int via_init(struct hda_codec *codec)
1955{
1956 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +08001957 int i;
1958 for (i = 0; i < spec->num_iverbs; i++)
1959 snd_hda_sequence_write(codec, spec->init_verbs[i]);
1960
Lydia Wang518bf3b2009-10-10 19:07:29 +08001961 spec->codec_type = get_codec_type(codec);
1962 if (spec->codec_type == VT1708BCE)
1963 spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
1964 same */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001965 /* Lydia Add for EAPD enable */
1966 if (!spec->dig_in_nid) { /* No Digital In connection */
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001967 if (spec->dig_in_pin) {
1968 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001969 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +01001970 PIN_OUT);
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001971 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001972 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
1973 }
Takashi Iwai12b74c82008-01-15 12:39:38 +01001974 } else /* enable SPDIF-input pin */
1975 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
1976 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001977
Takashi Iwai9da29272009-05-07 16:31:14 +02001978 /* assign slave outs */
1979 if (spec->slave_dig_outs[0])
1980 codec->slave_dig_outs = spec->slave_dig_outs;
Harald Welte5691ec72008-09-15 22:42:26 +08001981
Joseph Chanc577b8a2006-11-29 15:29:40 +01001982 return 0;
1983}
1984
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001985#ifdef SND_HDA_NEEDS_RESUME
1986static int via_suspend(struct hda_codec *codec, pm_message_t state)
1987{
1988 struct via_spec *spec = codec->spec;
1989 vt1708_stop_hp_work(spec);
1990 return 0;
1991}
1992#endif
1993
Takashi Iwaicb53c622007-08-10 17:21:45 +02001994#ifdef CONFIG_SND_HDA_POWER_SAVE
1995static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1996{
1997 struct via_spec *spec = codec->spec;
1998 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
1999}
2000#endif
2001
Joseph Chanc577b8a2006-11-29 15:29:40 +01002002/*
2003 */
2004static struct hda_codec_ops via_patch_ops = {
2005 .build_controls = via_build_controls,
2006 .build_pcms = via_build_pcms,
2007 .init = via_init,
2008 .free = via_free,
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002009#ifdef SND_HDA_NEEDS_RESUME
2010 .suspend = via_suspend,
2011#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002012#ifdef CONFIG_SND_HDA_POWER_SAVE
2013 .check_power_status = via_check_power_status,
2014#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002015};
2016
2017/* fill in the dac_nids table from the parsed pin configuration */
2018static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
2019 const struct auto_pin_cfg *cfg)
2020{
2021 int i;
2022 hda_nid_t nid;
2023
2024 spec->multiout.num_dacs = cfg->line_outs;
2025
2026 spec->multiout.dac_nids = spec->private_dac_nids;
2027
2028 for(i = 0; i < 4; i++) {
2029 nid = cfg->line_out_pins[i];
2030 if (nid) {
2031 /* config dac list */
2032 switch (i) {
2033 case AUTO_SEQ_FRONT:
2034 spec->multiout.dac_nids[i] = 0x10;
2035 break;
2036 case AUTO_SEQ_CENLFE:
2037 spec->multiout.dac_nids[i] = 0x12;
2038 break;
2039 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002040 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002041 break;
2042 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002043 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002044 break;
2045 }
2046 }
2047 }
2048
2049 return 0;
2050}
2051
2052/* add playback controls from the parsed DAC table */
2053static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
2054 const struct auto_pin_cfg *cfg)
2055{
2056 char name[32];
2057 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang9645c202009-10-10 19:08:27 +08002058 hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002059 int i, err;
2060
2061 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2062 nid = cfg->line_out_pins[i];
2063
2064 if (!nid)
2065 continue;
2066
Lydia Wang9645c202009-10-10 19:08:27 +08002067 nid_vol = nid_vols[i];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002068
2069 if (i == AUTO_SEQ_CENLFE) {
2070 /* Center/LFE */
2071 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002072 "Center Playback Volume",
2073 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2074 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002075 if (err < 0)
2076 return err;
2077 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2078 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002079 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2080 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002081 if (err < 0)
2082 return err;
2083 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2084 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002085 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2086 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002087 if (err < 0)
2088 return err;
2089 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2090 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002091 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2092 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002093 if (err < 0)
2094 return err;
2095 } else if (i == AUTO_SEQ_FRONT){
2096 /* add control to mixer index 0 */
2097 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2098 "Master Front Playback Volume",
Lydia Wang9645c202009-10-10 19:08:27 +08002099 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002100 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002101 if (err < 0)
2102 return err;
2103 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2104 "Master Front Playback Switch",
Lydia Wang9645c202009-10-10 19:08:27 +08002105 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002106 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002107 if (err < 0)
2108 return err;
2109
2110 /* add control to PW3 */
2111 sprintf(name, "%s Playback Volume", chname[i]);
2112 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002113 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2114 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002115 if (err < 0)
2116 return err;
2117 sprintf(name, "%s Playback Switch", chname[i]);
2118 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002119 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2120 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002121 if (err < 0)
2122 return err;
2123 } else {
2124 sprintf(name, "%s Playback Volume", chname[i]);
2125 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002126 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2127 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002128 if (err < 0)
2129 return err;
2130 sprintf(name, "%s Playback Switch", chname[i]);
2131 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002132 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2133 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002134 if (err < 0)
2135 return err;
2136 }
2137 }
2138
2139 return 0;
2140}
2141
Harald Welte0aa62ae2008-09-09 15:58:27 +08002142static void create_hp_imux(struct via_spec *spec)
2143{
2144 int i;
2145 struct hda_input_mux *imux = &spec->private_imux[1];
2146 static const char *texts[] = { "OFF", "ON", NULL};
2147
2148 /* for hp mode select */
2149 i = 0;
2150 while (texts[i] != NULL) {
2151 imux->items[imux->num_items].label = texts[i];
2152 imux->items[imux->num_items].index = i;
2153 imux->num_items++;
2154 i++;
2155 }
2156
2157 spec->hp_mux = &spec->private_imux[1];
2158}
2159
Joseph Chanc577b8a2006-11-29 15:29:40 +01002160static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2161{
2162 int err;
2163
2164 if (!pin)
2165 return 0;
2166
2167 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08002168 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002169
2170 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2171 "Headphone Playback Volume",
2172 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2173 if (err < 0)
2174 return err;
2175 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2176 "Headphone Playback Switch",
2177 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2178 if (err < 0)
2179 return err;
2180
Harald Welte0aa62ae2008-09-09 15:58:27 +08002181 create_hp_imux(spec);
2182
Joseph Chanc577b8a2006-11-29 15:29:40 +01002183 return 0;
2184}
2185
2186/* create playback/capture controls for input pins */
2187static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
2188 const struct auto_pin_cfg *cfg)
2189{
2190 static char *labels[] = {
2191 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2192 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002193 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002194 int i, err, idx = 0;
2195
2196 /* for internal loopback recording select */
2197 imux->items[imux->num_items].label = "Stereo Mixer";
2198 imux->items[imux->num_items].index = idx;
2199 imux->num_items++;
2200
2201 for (i = 0; i < AUTO_PIN_LAST; i++) {
2202 if (!cfg->input_pins[i])
2203 continue;
2204
2205 switch (cfg->input_pins[i]) {
2206 case 0x1d: /* Mic */
2207 idx = 2;
2208 break;
2209
2210 case 0x1e: /* Line In */
2211 idx = 3;
2212 break;
2213
2214 case 0x21: /* Front Mic */
2215 idx = 4;
2216 break;
2217
2218 case 0x24: /* CD */
2219 idx = 1;
2220 break;
2221 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002222 err = via_new_analog_input(spec, labels[i], idx, 0x17);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002223 if (err < 0)
2224 return err;
2225 imux->items[imux->num_items].label = labels[i];
2226 imux->items[imux->num_items].index = idx;
2227 imux->num_items++;
2228 }
2229 return 0;
2230}
2231
Takashi Iwaicb53c622007-08-10 17:21:45 +02002232#ifdef CONFIG_SND_HDA_POWER_SAVE
2233static struct hda_amp_list vt1708_loopbacks[] = {
2234 { 0x17, HDA_INPUT, 1 },
2235 { 0x17, HDA_INPUT, 2 },
2236 { 0x17, HDA_INPUT, 3 },
2237 { 0x17, HDA_INPUT, 4 },
2238 { } /* end */
2239};
2240#endif
2241
Harald Welte76d9b0d2008-09-09 15:50:37 +08002242static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
2243{
2244 unsigned int def_conf;
2245 unsigned char seqassoc;
2246
Takashi Iwai2f334f92009-02-20 14:37:42 +01002247 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Harald Welte76d9b0d2008-09-09 15:50:37 +08002248 seqassoc = (unsigned char) get_defcfg_association(def_conf);
2249 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
Lydia Wang82ef9e42009-10-10 19:08:19 +08002250 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
2251 && (seqassoc == 0xf0 || seqassoc == 0xff)) {
2252 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
2253 snd_hda_codec_set_pincfg(codec, nid, def_conf);
Harald Welte76d9b0d2008-09-09 15:50:37 +08002254 }
2255
2256 return;
2257}
2258
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002259static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
2260 struct snd_ctl_elem_value *ucontrol)
2261{
2262 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2263 struct via_spec *spec = codec->spec;
2264
2265 if (spec->codec_type != VT1708)
2266 return 0;
2267 spec->vt1708_jack_detectect =
2268 !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
2269 ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
2270 return 0;
2271}
2272
2273static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
2274 struct snd_ctl_elem_value *ucontrol)
2275{
2276 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2277 struct via_spec *spec = codec->spec;
2278 int change;
2279
2280 if (spec->codec_type != VT1708)
2281 return 0;
2282 spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
2283 change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
2284 == !spec->vt1708_jack_detectect;
2285 if (spec->vt1708_jack_detectect) {
2286 mute_aa_path(codec, 1);
2287 notify_aa_path_ctls(codec);
2288 }
2289 return change;
2290}
2291
2292static struct snd_kcontrol_new vt1708_jack_detectect[] = {
2293 {
2294 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2295 .name = "Jack Detect",
2296 .count = 1,
2297 .info = snd_ctl_boolean_mono_info,
2298 .get = vt1708_jack_detectect_get,
2299 .put = vt1708_jack_detectect_put,
2300 },
2301 {} /* end */
2302};
2303
Joseph Chanc577b8a2006-11-29 15:29:40 +01002304static int vt1708_parse_auto_config(struct hda_codec *codec)
2305{
2306 struct via_spec *spec = codec->spec;
2307 int err;
2308
Harald Welte76d9b0d2008-09-09 15:50:37 +08002309 /* Add HP and CD pin config connect bit re-config action */
2310 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
2311 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
2312
Joseph Chanc577b8a2006-11-29 15:29:40 +01002313 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2314 if (err < 0)
2315 return err;
2316 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
2317 if (err < 0)
2318 return err;
2319 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2320 return 0; /* can't find valid BIOS pin config */
2321
2322 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
2323 if (err < 0)
2324 return err;
2325 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2326 if (err < 0)
2327 return err;
2328 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
2329 if (err < 0)
2330 return err;
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002331 /* add jack detect on/off control */
2332 err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
2333 if (err < 0)
2334 return err;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002335
2336 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2337
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002338 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002339 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002340 spec->dig_in_pin = VT1708_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002341 if (spec->autocfg.dig_in_pin)
2342 spec->dig_in_nid = VT1708_DIGIN_NID;
2343
Takashi Iwai603c4012008-07-30 15:01:44 +02002344 if (spec->kctls.list)
2345 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002346
Harald Welte69e52a82008-09-09 15:57:32 +08002347 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002348
Harald Welte0aa62ae2008-09-09 15:58:27 +08002349 spec->input_mux = &spec->private_imux[0];
2350
Harald Weltef8fdd492008-09-15 22:41:31 +08002351 if (spec->hp_mux)
2352 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002353
Lydia Wang1564b282009-10-10 19:07:52 +08002354 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002355 return 1;
2356}
2357
2358/* init callback for auto-configuration model -- overriding the default init */
2359static int via_auto_init(struct hda_codec *codec)
2360{
Lydia Wang25eaba22009-10-10 19:08:43 +08002361 struct via_spec *spec = codec->spec;
2362
Joseph Chanc577b8a2006-11-29 15:29:40 +01002363 via_init(codec);
2364 via_auto_init_multi_out(codec);
2365 via_auto_init_hp_out(codec);
2366 via_auto_init_analog_input(codec);
Lydia Wang25eaba22009-10-10 19:08:43 +08002367 if (spec->codec_type == VT2002P) {
2368 via_hp_bind_automute(codec);
2369 } else {
2370 via_hp_automute(codec);
2371 via_speaker_automute(codec);
2372 }
2373
Joseph Chanc577b8a2006-11-29 15:29:40 +01002374 return 0;
2375}
2376
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002377static void vt1708_update_hp_jack_state(struct work_struct *work)
2378{
2379 struct via_spec *spec = container_of(work, struct via_spec,
2380 vt1708_hp_work.work);
2381 if (spec->codec_type != VT1708)
2382 return;
2383 /* if jack state toggled */
2384 if (spec->vt1708_hp_present
2385 != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0,
2386 AC_VERB_GET_PIN_SENSE, 0) >> 31)) {
2387 spec->vt1708_hp_present ^= 1;
2388 via_hp_automute(spec->codec);
2389 }
2390 vt1708_start_hp_work(spec);
2391}
2392
Takashi Iwai337b9d02009-07-07 18:18:59 +02002393static int get_mux_nids(struct hda_codec *codec)
2394{
2395 struct via_spec *spec = codec->spec;
2396 hda_nid_t nid, conn[8];
2397 unsigned int type;
2398 int i, n;
2399
2400 for (i = 0; i < spec->num_adc_nids; i++) {
2401 nid = spec->adc_nids[i];
2402 while (nid) {
Takashi Iwaia22d5432009-07-27 12:54:26 +02002403 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai1c55d522009-07-08 07:45:46 +02002404 if (type == AC_WID_PIN)
2405 break;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002406 n = snd_hda_get_connections(codec, nid, conn,
2407 ARRAY_SIZE(conn));
2408 if (n <= 0)
2409 break;
2410 if (n > 1) {
2411 spec->mux_nids[i] = nid;
2412 break;
2413 }
2414 nid = conn[0];
2415 }
2416 }
Takashi Iwai1c55d522009-07-08 07:45:46 +02002417 return 0;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002418}
2419
Joseph Chanc577b8a2006-11-29 15:29:40 +01002420static int patch_vt1708(struct hda_codec *codec)
2421{
2422 struct via_spec *spec;
2423 int err;
2424
2425 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002426 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002427 if (spec == NULL)
2428 return -ENOMEM;
2429
2430 codec->spec = spec;
2431
2432 /* automatic parse from the BIOS config */
2433 err = vt1708_parse_auto_config(codec);
2434 if (err < 0) {
2435 via_free(codec);
2436 return err;
2437 } else if (!err) {
2438 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2439 "from BIOS. Using genenic mode...\n");
2440 }
2441
2442
2443 spec->stream_name_analog = "VT1708 Analog";
2444 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +02002445 /* disable 32bit format on VT1708 */
2446 if (codec->vendor_id == 0x11061708)
2447 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002448 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
2449
2450 spec->stream_name_digital = "VT1708 Digital";
2451 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
2452 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
2453
2454
2455 if (!spec->adc_nids && spec->input_mux) {
2456 spec->adc_nids = vt1708_adc_nids;
2457 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
Takashi Iwai0f67a612009-08-31 08:12:29 +02002458 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002459 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
2460 spec->num_mixers++;
2461 }
2462
2463 codec->patch_ops = via_patch_ops;
2464
2465 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002466#ifdef CONFIG_SND_HDA_POWER_SAVE
2467 spec->loopback.amplist = vt1708_loopbacks;
2468#endif
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002469 spec->codec = codec;
2470 INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002471 return 0;
2472}
2473
2474/* capture mixer elements */
2475static struct snd_kcontrol_new vt1709_capture_mixer[] = {
2476 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
2477 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
2478 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
2479 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
2480 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
2481 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
2482 {
2483 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2484 /* The multiple "Capture Source" controls confuse alsamixer
2485 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01002486 */
2487 /* .name = "Capture Source", */
2488 .name = "Input Source",
2489 .count = 1,
2490 .info = via_mux_enum_info,
2491 .get = via_mux_enum_get,
2492 .put = via_mux_enum_put,
2493 },
2494 { } /* end */
2495};
2496
Harald Welte69e52a82008-09-09 15:57:32 +08002497static struct hda_verb vt1709_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08002498 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
2499 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08002500 { }
2501};
2502
Joseph Chanc577b8a2006-11-29 15:29:40 +01002503/*
2504 * generic initialization of ADC, input mixers and output mixers
2505 */
2506static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
2507 /*
2508 * Unmute ADC0-2 and set the default input to mic-in
2509 */
2510 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2511 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2512 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2513
2514
Josepch Chanf7278fd2007-12-13 16:40:40 +01002515 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01002516 * mixer widget
2517 */
2518 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01002519 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2520 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2521 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2522 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2523 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002524
2525 /*
2526 * Set up output selector (0x1a, 0x1b, 0x29)
2527 */
2528 /* set vol=0 to output mixers */
2529 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2530 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2531 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2532
2533 /*
2534 * Unmute PW3 and PW4
2535 */
2536 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2537 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2538
2539 /* Set input of PW4 as AOW4 */
2540 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002541 /* PW9 Output enable */
2542 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2543 { }
2544};
2545
2546static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
2547 .substreams = 1,
2548 .channels_min = 2,
2549 .channels_max = 10,
2550 .nid = 0x10, /* NID to query formats and rates */
2551 .ops = {
2552 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002553 .prepare = via_playback_multi_pcm_prepare,
2554 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002555 },
2556};
2557
2558static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
2559 .substreams = 1,
2560 .channels_min = 2,
2561 .channels_max = 6,
2562 .nid = 0x10, /* NID to query formats and rates */
2563 .ops = {
2564 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002565 .prepare = via_playback_multi_pcm_prepare,
2566 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002567 },
2568};
2569
2570static struct hda_pcm_stream vt1709_pcm_analog_capture = {
2571 .substreams = 2,
2572 .channels_min = 2,
2573 .channels_max = 2,
2574 .nid = 0x14, /* NID to query formats and rates */
2575 .ops = {
2576 .prepare = via_capture_pcm_prepare,
2577 .cleanup = via_capture_pcm_cleanup
2578 },
2579};
2580
2581static struct hda_pcm_stream vt1709_pcm_digital_playback = {
2582 .substreams = 1,
2583 .channels_min = 2,
2584 .channels_max = 2,
2585 /* NID is set in via_build_pcms */
2586 .ops = {
2587 .open = via_dig_playback_pcm_open,
2588 .close = via_dig_playback_pcm_close
2589 },
2590};
2591
2592static struct hda_pcm_stream vt1709_pcm_digital_capture = {
2593 .substreams = 1,
2594 .channels_min = 2,
2595 .channels_max = 2,
2596};
2597
2598static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
2599 const struct auto_pin_cfg *cfg)
2600{
2601 int i;
2602 hda_nid_t nid;
2603
2604 if (cfg->line_outs == 4) /* 10 channels */
2605 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
2606 else if (cfg->line_outs == 3) /* 6 channels */
2607 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
2608
2609 spec->multiout.dac_nids = spec->private_dac_nids;
2610
2611 if (cfg->line_outs == 4) { /* 10 channels */
2612 for (i = 0; i < cfg->line_outs; i++) {
2613 nid = cfg->line_out_pins[i];
2614 if (nid) {
2615 /* config dac list */
2616 switch (i) {
2617 case AUTO_SEQ_FRONT:
2618 /* AOW0 */
2619 spec->multiout.dac_nids[i] = 0x10;
2620 break;
2621 case AUTO_SEQ_CENLFE:
2622 /* AOW2 */
2623 spec->multiout.dac_nids[i] = 0x12;
2624 break;
2625 case AUTO_SEQ_SURROUND:
2626 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002627 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002628 break;
2629 case AUTO_SEQ_SIDE:
2630 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002631 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002632 break;
2633 default:
2634 break;
2635 }
2636 }
2637 }
2638 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
2639
2640 } else if (cfg->line_outs == 3) { /* 6 channels */
2641 for(i = 0; i < cfg->line_outs; i++) {
2642 nid = cfg->line_out_pins[i];
2643 if (nid) {
2644 /* config dac list */
2645 switch(i) {
2646 case AUTO_SEQ_FRONT:
2647 /* AOW0 */
2648 spec->multiout.dac_nids[i] = 0x10;
2649 break;
2650 case AUTO_SEQ_CENLFE:
2651 /* AOW2 */
2652 spec->multiout.dac_nids[i] = 0x12;
2653 break;
2654 case AUTO_SEQ_SURROUND:
2655 /* AOW1 */
2656 spec->multiout.dac_nids[i] = 0x11;
2657 break;
2658 default:
2659 break;
2660 }
2661 }
2662 }
2663 }
2664
2665 return 0;
2666}
2667
2668/* add playback controls from the parsed DAC table */
2669static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
2670 const struct auto_pin_cfg *cfg)
2671{
2672 char name[32];
2673 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang4483a2f2009-10-10 19:08:29 +08002674 hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002675 int i, err;
2676
2677 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2678 nid = cfg->line_out_pins[i];
2679
2680 if (!nid)
2681 continue;
2682
Lydia Wang4483a2f2009-10-10 19:08:29 +08002683 nid_vol = nid_vols[i];
2684
Joseph Chanc577b8a2006-11-29 15:29:40 +01002685 if (i == AUTO_SEQ_CENLFE) {
2686 /* Center/LFE */
2687 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2688 "Center Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002689 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002690 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002691 if (err < 0)
2692 return err;
2693 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2694 "LFE Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002695 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002696 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002697 if (err < 0)
2698 return err;
2699 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2700 "Center Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002701 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002702 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002703 if (err < 0)
2704 return err;
2705 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2706 "LFE Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002707 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002708 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002709 if (err < 0)
2710 return err;
2711 } else if (i == AUTO_SEQ_FRONT){
Lydia Wang4483a2f2009-10-10 19:08:29 +08002712 /* ADD control to mixer index 0 */
Joseph Chanc577b8a2006-11-29 15:29:40 +01002713 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2714 "Master Front Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002715 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002716 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002717 if (err < 0)
2718 return err;
2719 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2720 "Master Front Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002721 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002722 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002723 if (err < 0)
2724 return err;
2725
2726 /* add control to PW3 */
2727 sprintf(name, "%s Playback Volume", chname[i]);
2728 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002729 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2730 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002731 if (err < 0)
2732 return err;
2733 sprintf(name, "%s Playback Switch", chname[i]);
2734 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002735 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2736 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002737 if (err < 0)
2738 return err;
2739 } else if (i == AUTO_SEQ_SURROUND) {
2740 sprintf(name, "%s Playback Volume", chname[i]);
2741 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002742 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002743 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002744 if (err < 0)
2745 return err;
2746 sprintf(name, "%s Playback Switch", chname[i]);
2747 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002748 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002749 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002750 if (err < 0)
2751 return err;
2752 } else if (i == AUTO_SEQ_SIDE) {
2753 sprintf(name, "%s Playback Volume", chname[i]);
2754 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002755 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002756 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002757 if (err < 0)
2758 return err;
2759 sprintf(name, "%s Playback Switch", chname[i]);
2760 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002761 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002762 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002763 if (err < 0)
2764 return err;
2765 }
2766 }
2767
2768 return 0;
2769}
2770
2771static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2772{
2773 int err;
2774
2775 if (!pin)
2776 return 0;
2777
2778 if (spec->multiout.num_dacs == 5) /* 10 channels */
2779 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
2780 else if (spec->multiout.num_dacs == 3) /* 6 channels */
2781 spec->multiout.hp_nid = 0;
Lydia Wangcdc17842009-10-10 19:07:47 +08002782 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002783
2784 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2785 "Headphone Playback Volume",
2786 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2787 if (err < 0)
2788 return err;
2789 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2790 "Headphone Playback Switch",
2791 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2792 if (err < 0)
2793 return err;
2794
2795 return 0;
2796}
2797
2798/* create playback/capture controls for input pins */
2799static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
2800 const struct auto_pin_cfg *cfg)
2801{
2802 static char *labels[] = {
2803 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2804 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002805 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002806 int i, err, idx = 0;
2807
2808 /* for internal loopback recording select */
2809 imux->items[imux->num_items].label = "Stereo Mixer";
2810 imux->items[imux->num_items].index = idx;
2811 imux->num_items++;
2812
2813 for (i = 0; i < AUTO_PIN_LAST; i++) {
2814 if (!cfg->input_pins[i])
2815 continue;
2816
2817 switch (cfg->input_pins[i]) {
2818 case 0x1d: /* Mic */
2819 idx = 2;
2820 break;
2821
2822 case 0x1e: /* Line In */
2823 idx = 3;
2824 break;
2825
2826 case 0x21: /* Front Mic */
2827 idx = 4;
2828 break;
2829
2830 case 0x23: /* CD */
2831 idx = 1;
2832 break;
2833 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002834 err = via_new_analog_input(spec, labels[i], idx, 0x18);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002835 if (err < 0)
2836 return err;
2837 imux->items[imux->num_items].label = labels[i];
2838 imux->items[imux->num_items].index = idx;
2839 imux->num_items++;
2840 }
2841 return 0;
2842}
2843
2844static int vt1709_parse_auto_config(struct hda_codec *codec)
2845{
2846 struct via_spec *spec = codec->spec;
2847 int err;
2848
2849 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2850 if (err < 0)
2851 return err;
2852 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
2853 if (err < 0)
2854 return err;
2855 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2856 return 0; /* can't find valid BIOS pin config */
2857
2858 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
2859 if (err < 0)
2860 return err;
2861 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2862 if (err < 0)
2863 return err;
2864 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
2865 if (err < 0)
2866 return err;
2867
2868 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2869
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002870 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002871 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002872 spec->dig_in_pin = VT1709_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002873 if (spec->autocfg.dig_in_pin)
2874 spec->dig_in_nid = VT1709_DIGIN_NID;
2875
Takashi Iwai603c4012008-07-30 15:01:44 +02002876 if (spec->kctls.list)
2877 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002878
Harald Welte0aa62ae2008-09-09 15:58:27 +08002879 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002880
Harald Weltef8fdd492008-09-15 22:41:31 +08002881 if (spec->hp_mux)
2882 spec->mixers[spec->num_mixers++] = via_hp_mixer;
2883
Lydia Wang1564b282009-10-10 19:07:52 +08002884 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002885 return 1;
2886}
2887
Takashi Iwaicb53c622007-08-10 17:21:45 +02002888#ifdef CONFIG_SND_HDA_POWER_SAVE
2889static struct hda_amp_list vt1709_loopbacks[] = {
2890 { 0x18, HDA_INPUT, 1 },
2891 { 0x18, HDA_INPUT, 2 },
2892 { 0x18, HDA_INPUT, 3 },
2893 { 0x18, HDA_INPUT, 4 },
2894 { } /* end */
2895};
2896#endif
2897
Joseph Chanc577b8a2006-11-29 15:29:40 +01002898static int patch_vt1709_10ch(struct hda_codec *codec)
2899{
2900 struct via_spec *spec;
2901 int err;
2902
2903 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002904 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002905 if (spec == NULL)
2906 return -ENOMEM;
2907
2908 codec->spec = spec;
2909
2910 err = vt1709_parse_auto_config(codec);
2911 if (err < 0) {
2912 via_free(codec);
2913 return err;
2914 } else if (!err) {
2915 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
2916 "Using genenic mode...\n");
2917 }
2918
Harald Welte69e52a82008-09-09 15:57:32 +08002919 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
2920 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002921
2922 spec->stream_name_analog = "VT1709 Analog";
2923 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
2924 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2925
2926 spec->stream_name_digital = "VT1709 Digital";
2927 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2928 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2929
2930
2931 if (!spec->adc_nids && spec->input_mux) {
2932 spec->adc_nids = vt1709_adc_nids;
2933 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002934 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002935 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2936 spec->num_mixers++;
2937 }
2938
2939 codec->patch_ops = via_patch_ops;
2940
2941 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002942 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002943#ifdef CONFIG_SND_HDA_POWER_SAVE
2944 spec->loopback.amplist = vt1709_loopbacks;
2945#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002946
2947 return 0;
2948}
2949/*
2950 * generic initialization of ADC, input mixers and output mixers
2951 */
2952static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
2953 /*
2954 * Unmute ADC0-2 and set the default input to mic-in
2955 */
2956 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2957 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2958 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2959
2960
2961 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2962 * mixer widget
2963 */
2964 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2965 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2966 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2967 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2968 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2969 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2970
2971 /*
2972 * Set up output selector (0x1a, 0x1b, 0x29)
2973 */
2974 /* set vol=0 to output mixers */
2975 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2976 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2977 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2978
2979 /*
2980 * Unmute PW3 and PW4
2981 */
2982 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2983 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2984
2985 /* Set input of PW4 as MW0 */
2986 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002987 /* PW9 Output enable */
2988 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2989 { }
2990};
2991
2992static int patch_vt1709_6ch(struct hda_codec *codec)
2993{
2994 struct via_spec *spec;
2995 int err;
2996
2997 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002998 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002999 if (spec == NULL)
3000 return -ENOMEM;
3001
3002 codec->spec = spec;
3003
3004 err = vt1709_parse_auto_config(codec);
3005 if (err < 0) {
3006 via_free(codec);
3007 return err;
3008 } else if (!err) {
3009 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
3010 "Using genenic mode...\n");
3011 }
3012
Harald Welte69e52a82008-09-09 15:57:32 +08003013 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
3014 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003015
3016 spec->stream_name_analog = "VT1709 Analog";
3017 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
3018 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
3019
3020 spec->stream_name_digital = "VT1709 Digital";
3021 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
3022 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
3023
3024
3025 if (!spec->adc_nids && spec->input_mux) {
3026 spec->adc_nids = vt1709_adc_nids;
3027 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003028 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003029 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
3030 spec->num_mixers++;
3031 }
3032
3033 codec->patch_ops = via_patch_ops;
3034
3035 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003036 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003037#ifdef CONFIG_SND_HDA_POWER_SAVE
3038 spec->loopback.amplist = vt1709_loopbacks;
3039#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01003040 return 0;
3041}
3042
3043/* capture mixer elements */
3044static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
3045 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3046 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3047 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3048 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
3049 {
3050 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3051 /* The multiple "Capture Source" controls confuse alsamixer
3052 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01003053 */
3054 /* .name = "Capture Source", */
3055 .name = "Input Source",
3056 .count = 1,
3057 .info = via_mux_enum_info,
3058 .get = via_mux_enum_get,
3059 .put = via_mux_enum_put,
3060 },
3061 { } /* end */
3062};
3063/*
3064 * generic initialization of ADC, input mixers and output mixers
3065 */
3066static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
3067 /*
3068 * Unmute ADC0-1 and set the default input to mic-in
3069 */
3070 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3071 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3072
3073
3074 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3075 * mixer widget
3076 */
3077 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3078 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3079 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3080 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3081 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3082 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3083
3084 /*
3085 * Set up output mixers
3086 */
3087 /* set vol=0 to output mixers */
3088 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3089 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3090 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3091
3092 /* Setup default input to PW4 */
3093 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
3094 /* PW9 Output enable */
3095 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3096 /* PW10 Input enable */
3097 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3098 { }
3099};
3100
3101static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
3102 /*
3103 * Unmute ADC0-1 and set the default input to mic-in
3104 */
3105 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3106 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3107
3108
3109 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3110 * mixer widget
3111 */
3112 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3113 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3114 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3115 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3116 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3117 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3118
3119 /*
3120 * Set up output mixers
3121 */
3122 /* set vol=0 to output mixers */
3123 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3124 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3125 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3126
3127 /* Setup default input of PW4 to MW0 */
3128 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
3129 /* PW9 Output enable */
3130 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3131 /* PW10 Input enable */
3132 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3133 { }
3134};
3135
Harald Welte69e52a82008-09-09 15:57:32 +08003136static struct hda_verb vt1708B_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003137 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3138 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3139 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3140 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3141 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3142 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3143 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3144 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3145 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003146 { }
3147};
3148
Lydia Wang17314372009-10-10 19:07:37 +08003149static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
3150 struct hda_codec *codec,
3151 struct snd_pcm_substream *substream)
3152{
3153 int idle = substream->pstr->substream_opened == 1
3154 && substream->ref_count == 0;
3155
3156 analog_low_current_mode(codec, idle);
3157 return 0;
3158}
3159
Josepch Chanf7278fd2007-12-13 16:40:40 +01003160static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003161 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003162 .channels_min = 2,
3163 .channels_max = 8,
3164 .nid = 0x10, /* NID to query formats and rates */
3165 .ops = {
3166 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003167 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003168 .cleanup = via_playback_multi_pcm_cleanup,
3169 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01003170 },
3171};
3172
3173static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003174 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003175 .channels_min = 2,
3176 .channels_max = 4,
3177 .nid = 0x10, /* NID to query formats and rates */
3178 .ops = {
3179 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003180 .prepare = via_playback_multi_pcm_prepare,
3181 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01003182 },
3183};
3184
3185static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
3186 .substreams = 2,
3187 .channels_min = 2,
3188 .channels_max = 2,
3189 .nid = 0x13, /* NID to query formats and rates */
3190 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003191 .open = via_pcm_open_close,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003192 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003193 .cleanup = via_capture_pcm_cleanup,
3194 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01003195 },
3196};
3197
3198static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
3199 .substreams = 1,
3200 .channels_min = 2,
3201 .channels_max = 2,
3202 /* NID is set in via_build_pcms */
3203 .ops = {
3204 .open = via_dig_playback_pcm_open,
3205 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003206 .prepare = via_dig_playback_pcm_prepare,
3207 .cleanup = via_dig_playback_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01003208 },
3209};
3210
3211static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
3212 .substreams = 1,
3213 .channels_min = 2,
3214 .channels_max = 2,
3215};
3216
3217/* fill in the dac_nids table from the parsed pin configuration */
3218static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
3219 const struct auto_pin_cfg *cfg)
3220{
3221 int i;
3222 hda_nid_t nid;
3223
3224 spec->multiout.num_dacs = cfg->line_outs;
3225
3226 spec->multiout.dac_nids = spec->private_dac_nids;
3227
3228 for (i = 0; i < 4; i++) {
3229 nid = cfg->line_out_pins[i];
3230 if (nid) {
3231 /* config dac list */
3232 switch (i) {
3233 case AUTO_SEQ_FRONT:
3234 spec->multiout.dac_nids[i] = 0x10;
3235 break;
3236 case AUTO_SEQ_CENLFE:
3237 spec->multiout.dac_nids[i] = 0x24;
3238 break;
3239 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08003240 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003241 break;
3242 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08003243 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003244 break;
3245 }
3246 }
3247 }
3248
3249 return 0;
3250}
3251
3252/* add playback controls from the parsed DAC table */
3253static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
3254 const struct auto_pin_cfg *cfg)
3255{
3256 char name[32];
3257 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08003258 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01003259 hda_nid_t nid, nid_vol = 0;
3260 int i, err;
3261
3262 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3263 nid = cfg->line_out_pins[i];
3264
3265 if (!nid)
3266 continue;
3267
3268 nid_vol = nid_vols[i];
3269
3270 if (i == AUTO_SEQ_CENLFE) {
3271 /* Center/LFE */
3272 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3273 "Center Playback Volume",
3274 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3275 HDA_OUTPUT));
3276 if (err < 0)
3277 return err;
3278 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3279 "LFE Playback Volume",
3280 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3281 HDA_OUTPUT));
3282 if (err < 0)
3283 return err;
3284 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3285 "Center Playback Switch",
3286 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3287 HDA_OUTPUT));
3288 if (err < 0)
3289 return err;
3290 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3291 "LFE Playback Switch",
3292 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3293 HDA_OUTPUT));
3294 if (err < 0)
3295 return err;
3296 } else if (i == AUTO_SEQ_FRONT) {
3297 /* add control to mixer index 0 */
3298 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3299 "Master Front Playback Volume",
3300 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3301 HDA_INPUT));
3302 if (err < 0)
3303 return err;
3304 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3305 "Master Front Playback Switch",
3306 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3307 HDA_INPUT));
3308 if (err < 0)
3309 return err;
3310
3311 /* add control to PW3 */
3312 sprintf(name, "%s Playback Volume", chname[i]);
3313 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3314 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3315 HDA_OUTPUT));
3316 if (err < 0)
3317 return err;
3318 sprintf(name, "%s Playback Switch", chname[i]);
3319 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3320 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3321 HDA_OUTPUT));
3322 if (err < 0)
3323 return err;
3324 } else {
3325 sprintf(name, "%s Playback Volume", chname[i]);
3326 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3327 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3328 HDA_OUTPUT));
3329 if (err < 0)
3330 return err;
3331 sprintf(name, "%s Playback Switch", chname[i]);
3332 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3333 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3334 HDA_OUTPUT));
3335 if (err < 0)
3336 return err;
3337 }
3338 }
3339
3340 return 0;
3341}
3342
3343static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3344{
3345 int err;
3346
3347 if (!pin)
3348 return 0;
3349
3350 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003351 spec->hp_independent_mode_index = 1;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003352
3353 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3354 "Headphone Playback Volume",
3355 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3356 if (err < 0)
3357 return err;
3358 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3359 "Headphone Playback Switch",
3360 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3361 if (err < 0)
3362 return err;
3363
Harald Welte0aa62ae2008-09-09 15:58:27 +08003364 create_hp_imux(spec);
3365
Josepch Chanf7278fd2007-12-13 16:40:40 +01003366 return 0;
3367}
3368
3369/* create playback/capture controls for input pins */
3370static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
3371 const struct auto_pin_cfg *cfg)
3372{
3373 static char *labels[] = {
3374 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3375 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003376 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01003377 int i, err, idx = 0;
3378
3379 /* for internal loopback recording select */
3380 imux->items[imux->num_items].label = "Stereo Mixer";
3381 imux->items[imux->num_items].index = idx;
3382 imux->num_items++;
3383
3384 for (i = 0; i < AUTO_PIN_LAST; i++) {
3385 if (!cfg->input_pins[i])
3386 continue;
3387
3388 switch (cfg->input_pins[i]) {
3389 case 0x1a: /* Mic */
3390 idx = 2;
3391 break;
3392
3393 case 0x1b: /* Line In */
3394 idx = 3;
3395 break;
3396
3397 case 0x1e: /* Front Mic */
3398 idx = 4;
3399 break;
3400
3401 case 0x1f: /* CD */
3402 idx = 1;
3403 break;
3404 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003405 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003406 if (err < 0)
3407 return err;
3408 imux->items[imux->num_items].label = labels[i];
3409 imux->items[imux->num_items].index = idx;
3410 imux->num_items++;
3411 }
3412 return 0;
3413}
3414
3415static int vt1708B_parse_auto_config(struct hda_codec *codec)
3416{
3417 struct via_spec *spec = codec->spec;
3418 int err;
3419
3420 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3421 if (err < 0)
3422 return err;
3423 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
3424 if (err < 0)
3425 return err;
3426 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3427 return 0; /* can't find valid BIOS pin config */
3428
3429 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
3430 if (err < 0)
3431 return err;
3432 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3433 if (err < 0)
3434 return err;
3435 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
3436 if (err < 0)
3437 return err;
3438
3439 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3440
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003441 if (spec->autocfg.dig_outs)
Josepch Chanf7278fd2007-12-13 16:40:40 +01003442 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02003443 spec->dig_in_pin = VT1708B_DIGIN_PIN;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003444 if (spec->autocfg.dig_in_pin)
3445 spec->dig_in_nid = VT1708B_DIGIN_NID;
3446
Takashi Iwai603c4012008-07-30 15:01:44 +02003447 if (spec->kctls.list)
3448 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003449
Harald Welte0aa62ae2008-09-09 15:58:27 +08003450 spec->input_mux = &spec->private_imux[0];
3451
Harald Weltef8fdd492008-09-15 22:41:31 +08003452 if (spec->hp_mux)
3453 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003454
Lydia Wang1564b282009-10-10 19:07:52 +08003455 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003456 return 1;
3457}
3458
3459#ifdef CONFIG_SND_HDA_POWER_SAVE
3460static struct hda_amp_list vt1708B_loopbacks[] = {
3461 { 0x16, HDA_INPUT, 1 },
3462 { 0x16, HDA_INPUT, 2 },
3463 { 0x16, HDA_INPUT, 3 },
3464 { 0x16, HDA_INPUT, 4 },
3465 { } /* end */
3466};
3467#endif
Lydia Wang518bf3b2009-10-10 19:07:29 +08003468static int patch_vt1708S(struct hda_codec *codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003469static int patch_vt1708B_8ch(struct hda_codec *codec)
3470{
3471 struct via_spec *spec;
3472 int err;
3473
Lydia Wang518bf3b2009-10-10 19:07:29 +08003474 if (get_codec_type(codec) == VT1708BCE)
3475 return patch_vt1708S(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003476 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003477 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003478 if (spec == NULL)
3479 return -ENOMEM;
3480
3481 codec->spec = spec;
3482
3483 /* automatic parse from the BIOS config */
3484 err = vt1708B_parse_auto_config(codec);
3485 if (err < 0) {
3486 via_free(codec);
3487 return err;
3488 } else if (!err) {
3489 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3490 "from BIOS. Using genenic mode...\n");
3491 }
3492
Harald Welte69e52a82008-09-09 15:57:32 +08003493 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
3494 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003495
3496 spec->stream_name_analog = "VT1708B Analog";
3497 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
3498 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3499
3500 spec->stream_name_digital = "VT1708B Digital";
3501 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3502 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3503
3504 if (!spec->adc_nids && spec->input_mux) {
3505 spec->adc_nids = vt1708B_adc_nids;
3506 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003507 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003508 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3509 spec->num_mixers++;
3510 }
3511
3512 codec->patch_ops = via_patch_ops;
3513
3514 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003515 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003516#ifdef CONFIG_SND_HDA_POWER_SAVE
3517 spec->loopback.amplist = vt1708B_loopbacks;
3518#endif
3519
3520 return 0;
3521}
3522
3523static int patch_vt1708B_4ch(struct hda_codec *codec)
3524{
3525 struct via_spec *spec;
3526 int err;
3527
3528 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003529 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003530 if (spec == NULL)
3531 return -ENOMEM;
3532
3533 codec->spec = spec;
3534
3535 /* automatic parse from the BIOS config */
3536 err = vt1708B_parse_auto_config(codec);
3537 if (err < 0) {
3538 via_free(codec);
3539 return err;
3540 } else if (!err) {
3541 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3542 "from BIOS. Using genenic mode...\n");
3543 }
3544
Harald Welte69e52a82008-09-09 15:57:32 +08003545 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
3546 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003547
3548 spec->stream_name_analog = "VT1708B Analog";
3549 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
3550 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3551
3552 spec->stream_name_digital = "VT1708B Digital";
3553 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3554 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3555
3556 if (!spec->adc_nids && spec->input_mux) {
3557 spec->adc_nids = vt1708B_adc_nids;
3558 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003559 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003560 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3561 spec->num_mixers++;
3562 }
3563
3564 codec->patch_ops = via_patch_ops;
3565
3566 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003567 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003568#ifdef CONFIG_SND_HDA_POWER_SAVE
3569 spec->loopback.amplist = vt1708B_loopbacks;
3570#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01003571
3572 return 0;
3573}
3574
Harald Welted949cac2008-09-09 15:56:01 +08003575/* Patch for VT1708S */
3576
3577/* capture mixer elements */
3578static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
3579 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3580 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3581 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3582 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
Lydia Wang6369bcf2009-10-10 19:08:31 +08003583 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
3584 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
3585 HDA_INPUT),
Harald Welted949cac2008-09-09 15:56:01 +08003586 {
3587 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3588 /* The multiple "Capture Source" controls confuse alsamixer
3589 * So call somewhat different..
3590 */
3591 /* .name = "Capture Source", */
3592 .name = "Input Source",
3593 .count = 1,
3594 .info = via_mux_enum_info,
3595 .get = via_mux_enum_get,
3596 .put = via_mux_enum_put,
3597 },
3598 { } /* end */
3599};
3600
3601static struct hda_verb vt1708S_volume_init_verbs[] = {
3602 /* Unmute ADC0-1 and set the default input to mic-in */
3603 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3604 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3605
3606 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
3607 * analog-loopback mixer widget */
3608 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3609 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3610 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3611 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3612 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3613 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3614
3615 /* Setup default input of PW4 to MW0 */
3616 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08003617 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08003618 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08003619 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted7426322008-09-15 22:43:23 +08003620 /* Enable Mic Boost Volume backdoor */
3621 {0x1, 0xf98, 0x1},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08003622 /* don't bybass mixer */
3623 {0x1, 0xf88, 0xc0},
Harald Welted949cac2008-09-09 15:56:01 +08003624 { }
3625};
3626
Harald Welte69e52a82008-09-09 15:57:32 +08003627static struct hda_verb vt1708S_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003628 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3629 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3630 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3631 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3632 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3633 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3634 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3635 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3636 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003637 { }
3638};
3639
Harald Welted949cac2008-09-09 15:56:01 +08003640static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
3641 .substreams = 2,
3642 .channels_min = 2,
3643 .channels_max = 8,
3644 .nid = 0x10, /* NID to query formats and rates */
3645 .ops = {
3646 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08003647 .prepare = via_playback_multi_pcm_prepare,
3648 .cleanup = via_playback_multi_pcm_cleanup,
Lydia Wang17314372009-10-10 19:07:37 +08003649 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003650 },
3651};
3652
3653static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
3654 .substreams = 2,
3655 .channels_min = 2,
3656 .channels_max = 2,
3657 .nid = 0x13, /* NID to query formats and rates */
3658 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003659 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08003660 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003661 .cleanup = via_capture_pcm_cleanup,
3662 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003663 },
3664};
3665
3666static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Takashi Iwai9da29272009-05-07 16:31:14 +02003667 .substreams = 1,
Harald Welted949cac2008-09-09 15:56:01 +08003668 .channels_min = 2,
3669 .channels_max = 2,
3670 /* NID is set in via_build_pcms */
3671 .ops = {
3672 .open = via_dig_playback_pcm_open,
3673 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003674 .prepare = via_dig_playback_pcm_prepare,
3675 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003676 },
3677};
3678
3679/* fill in the dac_nids table from the parsed pin configuration */
3680static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
3681 const struct auto_pin_cfg *cfg)
3682{
3683 int i;
3684 hda_nid_t nid;
3685
3686 spec->multiout.num_dacs = cfg->line_outs;
3687
3688 spec->multiout.dac_nids = spec->private_dac_nids;
3689
3690 for (i = 0; i < 4; i++) {
3691 nid = cfg->line_out_pins[i];
3692 if (nid) {
3693 /* config dac list */
3694 switch (i) {
3695 case AUTO_SEQ_FRONT:
3696 spec->multiout.dac_nids[i] = 0x10;
3697 break;
3698 case AUTO_SEQ_CENLFE:
3699 spec->multiout.dac_nids[i] = 0x24;
3700 break;
3701 case AUTO_SEQ_SURROUND:
3702 spec->multiout.dac_nids[i] = 0x11;
3703 break;
3704 case AUTO_SEQ_SIDE:
3705 spec->multiout.dac_nids[i] = 0x25;
3706 break;
3707 }
3708 }
3709 }
3710
3711 return 0;
3712}
3713
3714/* add playback controls from the parsed DAC table */
3715static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
3716 const struct auto_pin_cfg *cfg)
3717{
3718 char name[32];
3719 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
3720 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
3721 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
3722 hda_nid_t nid, nid_vol, nid_mute;
3723 int i, err;
3724
3725 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3726 nid = cfg->line_out_pins[i];
3727
3728 if (!nid)
3729 continue;
3730
3731 nid_vol = nid_vols[i];
3732 nid_mute = nid_mutes[i];
3733
3734 if (i == AUTO_SEQ_CENLFE) {
3735 /* Center/LFE */
3736 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3737 "Center Playback Volume",
3738 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3739 HDA_OUTPUT));
3740 if (err < 0)
3741 return err;
3742 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3743 "LFE Playback Volume",
3744 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3745 HDA_OUTPUT));
3746 if (err < 0)
3747 return err;
3748 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3749 "Center Playback Switch",
3750 HDA_COMPOSE_AMP_VAL(nid_mute,
3751 1, 0,
3752 HDA_OUTPUT));
3753 if (err < 0)
3754 return err;
3755 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3756 "LFE Playback Switch",
3757 HDA_COMPOSE_AMP_VAL(nid_mute,
3758 2, 0,
3759 HDA_OUTPUT));
3760 if (err < 0)
3761 return err;
3762 } else if (i == AUTO_SEQ_FRONT) {
3763 /* add control to mixer index 0 */
3764 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3765 "Master Front Playback Volume",
3766 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3767 HDA_INPUT));
3768 if (err < 0)
3769 return err;
3770 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3771 "Master Front Playback Switch",
3772 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3773 HDA_INPUT));
3774 if (err < 0)
3775 return err;
3776
3777 /* Front */
3778 sprintf(name, "%s Playback Volume", chname[i]);
3779 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3780 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3781 HDA_OUTPUT));
3782 if (err < 0)
3783 return err;
3784 sprintf(name, "%s Playback Switch", chname[i]);
3785 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3786 HDA_COMPOSE_AMP_VAL(nid_mute,
3787 3, 0,
3788 HDA_OUTPUT));
3789 if (err < 0)
3790 return err;
3791 } else {
3792 sprintf(name, "%s Playback Volume", chname[i]);
3793 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3794 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3795 HDA_OUTPUT));
3796 if (err < 0)
3797 return err;
3798 sprintf(name, "%s Playback Switch", chname[i]);
3799 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3800 HDA_COMPOSE_AMP_VAL(nid_mute,
3801 3, 0,
3802 HDA_OUTPUT));
3803 if (err < 0)
3804 return err;
3805 }
3806 }
3807
3808 return 0;
3809}
3810
3811static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3812{
3813 int err;
3814
3815 if (!pin)
3816 return 0;
3817
3818 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003819 spec->hp_independent_mode_index = 1;
Harald Welted949cac2008-09-09 15:56:01 +08003820
3821 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3822 "Headphone Playback Volume",
3823 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
3824 if (err < 0)
3825 return err;
3826
3827 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3828 "Headphone Playback Switch",
3829 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3830 if (err < 0)
3831 return err;
3832
Harald Welte0aa62ae2008-09-09 15:58:27 +08003833 create_hp_imux(spec);
3834
Harald Welted949cac2008-09-09 15:56:01 +08003835 return 0;
3836}
3837
3838/* create playback/capture controls for input pins */
3839static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
3840 const struct auto_pin_cfg *cfg)
3841{
3842 static char *labels[] = {
3843 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3844 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003845 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003846 int i, err, idx = 0;
3847
3848 /* for internal loopback recording select */
3849 imux->items[imux->num_items].label = "Stereo Mixer";
3850 imux->items[imux->num_items].index = 5;
3851 imux->num_items++;
3852
3853 for (i = 0; i < AUTO_PIN_LAST; i++) {
3854 if (!cfg->input_pins[i])
3855 continue;
3856
3857 switch (cfg->input_pins[i]) {
3858 case 0x1a: /* Mic */
3859 idx = 2;
3860 break;
3861
3862 case 0x1b: /* Line In */
3863 idx = 3;
3864 break;
3865
3866 case 0x1e: /* Front Mic */
3867 idx = 4;
3868 break;
3869
3870 case 0x1f: /* CD */
3871 idx = 1;
3872 break;
3873 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003874 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Harald Welted949cac2008-09-09 15:56:01 +08003875 if (err < 0)
3876 return err;
3877 imux->items[imux->num_items].label = labels[i];
3878 imux->items[imux->num_items].index = idx-1;
3879 imux->num_items++;
3880 }
3881 return 0;
3882}
3883
Takashi Iwai9da29272009-05-07 16:31:14 +02003884/* fill out digital output widgets; one for master and one for slave outputs */
3885static void fill_dig_outs(struct hda_codec *codec)
3886{
3887 struct via_spec *spec = codec->spec;
3888 int i;
3889
3890 for (i = 0; i < spec->autocfg.dig_outs; i++) {
3891 hda_nid_t nid;
3892 int conn;
3893
3894 nid = spec->autocfg.dig_out_pins[i];
3895 if (!nid)
3896 continue;
3897 conn = snd_hda_get_connections(codec, nid, &nid, 1);
3898 if (conn < 1)
3899 continue;
3900 if (!spec->multiout.dig_out_nid)
3901 spec->multiout.dig_out_nid = nid;
3902 else {
3903 spec->slave_dig_outs[0] = nid;
3904 break; /* at most two dig outs */
3905 }
3906 }
3907}
3908
Harald Welted949cac2008-09-09 15:56:01 +08003909static int vt1708S_parse_auto_config(struct hda_codec *codec)
3910{
3911 struct via_spec *spec = codec->spec;
3912 int err;
Harald Welted949cac2008-09-09 15:56:01 +08003913
Takashi Iwai9da29272009-05-07 16:31:14 +02003914 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08003915 if (err < 0)
3916 return err;
3917 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
3918 if (err < 0)
3919 return err;
3920 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3921 return 0; /* can't find valid BIOS pin config */
3922
3923 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
3924 if (err < 0)
3925 return err;
3926 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3927 if (err < 0)
3928 return err;
3929 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
3930 if (err < 0)
3931 return err;
3932
3933 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3934
Takashi Iwai9da29272009-05-07 16:31:14 +02003935 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08003936
Takashi Iwai603c4012008-07-30 15:01:44 +02003937 if (spec->kctls.list)
3938 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08003939
Harald Welte0aa62ae2008-09-09 15:58:27 +08003940 spec->input_mux = &spec->private_imux[0];
3941
Harald Weltef8fdd492008-09-15 22:41:31 +08003942 if (spec->hp_mux)
3943 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003944
Lydia Wang1564b282009-10-10 19:07:52 +08003945 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003946 return 1;
3947}
3948
3949#ifdef CONFIG_SND_HDA_POWER_SAVE
3950static struct hda_amp_list vt1708S_loopbacks[] = {
3951 { 0x16, HDA_INPUT, 1 },
3952 { 0x16, HDA_INPUT, 2 },
3953 { 0x16, HDA_INPUT, 3 },
3954 { 0x16, HDA_INPUT, 4 },
3955 { } /* end */
3956};
3957#endif
3958
Lydia Wang6369bcf2009-10-10 19:08:31 +08003959static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
3960 int offset, int num_steps, int step_size)
3961{
3962 snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
3963 (offset << AC_AMPCAP_OFFSET_SHIFT) |
3964 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
3965 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
3966 (0 << AC_AMPCAP_MUTE_SHIFT));
3967}
3968
Harald Welted949cac2008-09-09 15:56:01 +08003969static int patch_vt1708S(struct hda_codec *codec)
3970{
3971 struct via_spec *spec;
3972 int err;
3973
3974 /* create a codec specific record */
3975 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3976 if (spec == NULL)
3977 return -ENOMEM;
3978
3979 codec->spec = spec;
3980
3981 /* automatic parse from the BIOS config */
3982 err = vt1708S_parse_auto_config(codec);
3983 if (err < 0) {
3984 via_free(codec);
3985 return err;
3986 } else if (!err) {
3987 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3988 "from BIOS. Using genenic mode...\n");
3989 }
3990
Harald Welte69e52a82008-09-09 15:57:32 +08003991 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
3992 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003993
3994 spec->stream_name_analog = "VT1708S Analog";
3995 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
3996 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
3997
3998 spec->stream_name_digital = "VT1708S Digital";
3999 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
4000
4001 if (!spec->adc_nids && spec->input_mux) {
4002 spec->adc_nids = vt1708S_adc_nids;
4003 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004004 get_mux_nids(codec);
Lydia Wang6369bcf2009-10-10 19:08:31 +08004005 override_mic_boost(codec, 0x1a, 0, 3, 40);
4006 override_mic_boost(codec, 0x1e, 0, 3, 40);
Harald Welted949cac2008-09-09 15:56:01 +08004007 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
4008 spec->num_mixers++;
4009 }
4010
4011 codec->patch_ops = via_patch_ops;
4012
4013 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004014 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004015#ifdef CONFIG_SND_HDA_POWER_SAVE
4016 spec->loopback.amplist = vt1708S_loopbacks;
4017#endif
4018
Lydia Wang518bf3b2009-10-10 19:07:29 +08004019 /* correct names for VT1708BCE */
4020 if (get_codec_type(codec) == VT1708BCE) {
4021 kfree(codec->chip_name);
4022 codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
4023 snprintf(codec->bus->card->mixername,
4024 sizeof(codec->bus->card->mixername),
4025 "%s %s", codec->vendor_name, codec->chip_name);
4026 spec->stream_name_analog = "VT1708BCE Analog";
4027 spec->stream_name_digital = "VT1708BCE Digital";
4028 }
Harald Welted949cac2008-09-09 15:56:01 +08004029 return 0;
4030}
4031
4032/* Patch for VT1702 */
4033
4034/* capture mixer elements */
4035static struct snd_kcontrol_new vt1702_capture_mixer[] = {
4036 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
4037 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
4038 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
4039 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
4040 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
4041 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
4042 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
4043 HDA_INPUT),
4044 {
4045 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4046 /* The multiple "Capture Source" controls confuse alsamixer
4047 * So call somewhat different..
4048 */
4049 /* .name = "Capture Source", */
4050 .name = "Input Source",
4051 .count = 1,
4052 .info = via_mux_enum_info,
4053 .get = via_mux_enum_get,
4054 .put = via_mux_enum_put,
4055 },
4056 { } /* end */
4057};
4058
4059static struct hda_verb vt1702_volume_init_verbs[] = {
4060 /*
4061 * Unmute ADC0-1 and set the default input to mic-in
4062 */
4063 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4064 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4065 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4066
4067
4068 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4069 * mixer widget
4070 */
4071 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
4072 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4073 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4074 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4075 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4076 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4077
4078 /* Setup default input of PW4 to MW0 */
4079 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
4080 /* PW6 PW7 Output enable */
4081 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4082 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08004083 /* mixer enable */
4084 {0x1, 0xF88, 0x3},
4085 /* GPIO 0~2 */
4086 {0x1, 0xF82, 0x3F},
Harald Welted949cac2008-09-09 15:56:01 +08004087 { }
4088};
4089
Harald Welte69e52a82008-09-09 15:57:32 +08004090static struct hda_verb vt1702_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08004091 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
4092 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4093 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4094 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4095 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4096 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08004097 { }
4098};
4099
Harald Welted949cac2008-09-09 15:56:01 +08004100static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08004101 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08004102 .channels_min = 2,
4103 .channels_max = 2,
4104 .nid = 0x10, /* NID to query formats and rates */
4105 .ops = {
4106 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08004107 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08004108 .cleanup = via_playback_multi_pcm_cleanup,
4109 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08004110 },
4111};
4112
4113static struct hda_pcm_stream vt1702_pcm_analog_capture = {
4114 .substreams = 3,
4115 .channels_min = 2,
4116 .channels_max = 2,
4117 .nid = 0x12, /* NID to query formats and rates */
4118 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08004119 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08004120 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08004121 .cleanup = via_capture_pcm_cleanup,
4122 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08004123 },
4124};
4125
4126static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08004127 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08004128 .channels_min = 2,
4129 .channels_max = 2,
4130 /* NID is set in via_build_pcms */
4131 .ops = {
4132 .open = via_dig_playback_pcm_open,
4133 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02004134 .prepare = via_dig_playback_pcm_prepare,
4135 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08004136 },
4137};
4138
4139/* fill in the dac_nids table from the parsed pin configuration */
4140static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
4141 const struct auto_pin_cfg *cfg)
4142{
4143 spec->multiout.num_dacs = 1;
4144 spec->multiout.dac_nids = spec->private_dac_nids;
4145
4146 if (cfg->line_out_pins[0]) {
4147 /* config dac list */
4148 spec->multiout.dac_nids[0] = 0x10;
4149 }
4150
4151 return 0;
4152}
4153
4154/* add playback controls from the parsed DAC table */
4155static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
4156 const struct auto_pin_cfg *cfg)
4157{
4158 int err;
4159
4160 if (!cfg->line_out_pins[0])
4161 return -1;
4162
4163 /* add control to mixer index 0 */
4164 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4165 "Master Front Playback Volume",
4166 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4167 if (err < 0)
4168 return err;
4169 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4170 "Master Front Playback Switch",
4171 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4172 if (err < 0)
4173 return err;
4174
4175 /* Front */
4176 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4177 "Front Playback Volume",
4178 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
4179 if (err < 0)
4180 return err;
4181 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4182 "Front Playback Switch",
4183 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
4184 if (err < 0)
4185 return err;
4186
4187 return 0;
4188}
4189
4190static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4191{
Lydia Wang0713efe2009-10-10 19:07:43 +08004192 int err, i;
4193 struct hda_input_mux *imux;
4194 static const char *texts[] = { "ON", "OFF", NULL};
Harald Welted949cac2008-09-09 15:56:01 +08004195 if (!pin)
4196 return 0;
Harald Welted949cac2008-09-09 15:56:01 +08004197 spec->multiout.hp_nid = 0x1D;
Lydia Wangcdc17842009-10-10 19:07:47 +08004198 spec->hp_independent_mode_index = 0;
Harald Welted949cac2008-09-09 15:56:01 +08004199
4200 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4201 "Headphone Playback Volume",
4202 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
4203 if (err < 0)
4204 return err;
4205
4206 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4207 "Headphone Playback Switch",
4208 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4209 if (err < 0)
4210 return err;
4211
Lydia Wang0713efe2009-10-10 19:07:43 +08004212 imux = &spec->private_imux[1];
Harald Welte0aa62ae2008-09-09 15:58:27 +08004213
Lydia Wang0713efe2009-10-10 19:07:43 +08004214 /* for hp mode select */
4215 i = 0;
4216 while (texts[i] != NULL) {
4217 imux->items[imux->num_items].label = texts[i];
4218 imux->items[imux->num_items].index = i;
4219 imux->num_items++;
4220 i++;
4221 }
4222
4223 spec->hp_mux = &spec->private_imux[1];
Harald Welted949cac2008-09-09 15:56:01 +08004224 return 0;
4225}
4226
4227/* create playback/capture controls for input pins */
4228static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
4229 const struct auto_pin_cfg *cfg)
4230{
4231 static char *labels[] = {
4232 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4233 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08004234 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08004235 int i, err, idx = 0;
4236
4237 /* for internal loopback recording select */
4238 imux->items[imux->num_items].label = "Stereo Mixer";
4239 imux->items[imux->num_items].index = 3;
4240 imux->num_items++;
4241
4242 for (i = 0; i < AUTO_PIN_LAST; i++) {
4243 if (!cfg->input_pins[i])
4244 continue;
4245
4246 switch (cfg->input_pins[i]) {
4247 case 0x14: /* Mic */
4248 idx = 1;
4249 break;
4250
4251 case 0x15: /* Line In */
4252 idx = 2;
4253 break;
4254
4255 case 0x18: /* Front Mic */
4256 idx = 3;
4257 break;
4258 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08004259 err = via_new_analog_input(spec, labels[i], idx, 0x1A);
Harald Welted949cac2008-09-09 15:56:01 +08004260 if (err < 0)
4261 return err;
4262 imux->items[imux->num_items].label = labels[i];
4263 imux->items[imux->num_items].index = idx-1;
4264 imux->num_items++;
4265 }
4266 return 0;
4267}
4268
4269static int vt1702_parse_auto_config(struct hda_codec *codec)
4270{
4271 struct via_spec *spec = codec->spec;
4272 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004273
Takashi Iwai9da29272009-05-07 16:31:14 +02004274 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08004275 if (err < 0)
4276 return err;
4277 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
4278 if (err < 0)
4279 return err;
4280 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4281 return 0; /* can't find valid BIOS pin config */
4282
4283 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
4284 if (err < 0)
4285 return err;
4286 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4287 if (err < 0)
4288 return err;
Lydia Wangc2c02ea2009-10-10 19:07:32 +08004289 /* limit AA path volume to 0 dB */
4290 snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
4291 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4292 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4293 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4294 (1 << AC_AMPCAP_MUTE_SHIFT));
Harald Welted949cac2008-09-09 15:56:01 +08004295 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
4296 if (err < 0)
4297 return err;
4298
4299 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4300
Takashi Iwai9da29272009-05-07 16:31:14 +02004301 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08004302
Takashi Iwai603c4012008-07-30 15:01:44 +02004303 if (spec->kctls.list)
4304 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08004305
Harald Welte0aa62ae2008-09-09 15:58:27 +08004306 spec->input_mux = &spec->private_imux[0];
4307
Harald Weltef8fdd492008-09-15 22:41:31 +08004308 if (spec->hp_mux)
4309 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004310
4311 return 1;
4312}
4313
4314#ifdef CONFIG_SND_HDA_POWER_SAVE
4315static struct hda_amp_list vt1702_loopbacks[] = {
4316 { 0x1A, HDA_INPUT, 1 },
4317 { 0x1A, HDA_INPUT, 2 },
4318 { 0x1A, HDA_INPUT, 3 },
4319 { 0x1A, HDA_INPUT, 4 },
4320 { } /* end */
4321};
4322#endif
4323
4324static int patch_vt1702(struct hda_codec *codec)
4325{
4326 struct via_spec *spec;
4327 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004328
4329 /* create a codec specific record */
4330 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4331 if (spec == NULL)
4332 return -ENOMEM;
4333
4334 codec->spec = spec;
4335
4336 /* automatic parse from the BIOS config */
4337 err = vt1702_parse_auto_config(codec);
4338 if (err < 0) {
4339 via_free(codec);
4340 return err;
4341 } else if (!err) {
4342 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4343 "from BIOS. Using genenic mode...\n");
4344 }
4345
Harald Welte69e52a82008-09-09 15:57:32 +08004346 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
4347 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08004348
4349 spec->stream_name_analog = "VT1702 Analog";
4350 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
4351 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
4352
4353 spec->stream_name_digital = "VT1702 Digital";
4354 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
4355
4356 if (!spec->adc_nids && spec->input_mux) {
4357 spec->adc_nids = vt1702_adc_nids;
4358 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004359 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08004360 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
4361 spec->num_mixers++;
4362 }
4363
4364 codec->patch_ops = via_patch_ops;
4365
4366 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004367 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004368#ifdef CONFIG_SND_HDA_POWER_SAVE
4369 spec->loopback.amplist = vt1702_loopbacks;
4370#endif
4371
Harald Welted949cac2008-09-09 15:56:01 +08004372 return 0;
4373}
4374
Lydia Wangeb7188c2009-10-10 19:08:34 +08004375/* Patch for VT1718S */
4376
4377/* capture mixer elements */
4378static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
4379 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
4380 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
4381 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
4382 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
4383 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
4384 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
4385 HDA_INPUT),
4386 {
4387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4388 /* The multiple "Capture Source" controls confuse alsamixer
4389 * So call somewhat different..
4390 */
4391 .name = "Input Source",
4392 .count = 2,
4393 .info = via_mux_enum_info,
4394 .get = via_mux_enum_get,
4395 .put = via_mux_enum_put,
4396 },
4397 { } /* end */
4398};
4399
4400static struct hda_verb vt1718S_volume_init_verbs[] = {
4401 /*
4402 * Unmute ADC0-1 and set the default input to mic-in
4403 */
4404 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4405 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4406
4407
4408 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4409 * mixer widget
4410 */
4411 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4412 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4413 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4414 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4415 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4416 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4417
4418 /* Setup default input of Front HP to MW9 */
4419 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4420 /* PW9 PW10 Output enable */
4421 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4422 {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4423 /* PW11 Input enable */
4424 {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
4425 /* Enable Boost Volume backdoor */
4426 {0x1, 0xf88, 0x8},
4427 /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
4428 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4429 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4430 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4431 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4432 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4433 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4434 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4435 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4436 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4437 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4438 /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
4439 {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
4440 {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
4441 /* Unmute MW4's index 0 */
4442 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4443 { }
4444};
4445
4446
4447static struct hda_verb vt1718S_uniwill_init_verbs[] = {
4448 {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
4449 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4450 {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4451 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4452 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4453 {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4454 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4455 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4456 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4457 { }
4458};
4459
4460static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
4461 .substreams = 2,
4462 .channels_min = 2,
4463 .channels_max = 10,
4464 .nid = 0x8, /* NID to query formats and rates */
4465 .ops = {
4466 .open = via_playback_pcm_open,
4467 .prepare = via_playback_multi_pcm_prepare,
4468 .cleanup = via_playback_multi_pcm_cleanup,
4469 .close = via_pcm_open_close,
4470 },
4471};
4472
4473static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
4474 .substreams = 2,
4475 .channels_min = 2,
4476 .channels_max = 2,
4477 .nid = 0x10, /* NID to query formats and rates */
4478 .ops = {
4479 .open = via_pcm_open_close,
4480 .prepare = via_capture_pcm_prepare,
4481 .cleanup = via_capture_pcm_cleanup,
4482 .close = via_pcm_open_close,
4483 },
4484};
4485
4486static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
4487 .substreams = 2,
4488 .channels_min = 2,
4489 .channels_max = 2,
4490 .rates = SNDRV_PCM_RATE_48000,
4491 /* NID is set in via_build_pcms */
4492 .ops = {
4493 .open = via_dig_playback_pcm_open,
4494 .close = via_dig_playback_pcm_close,
4495 .prepare = via_dig_playback_pcm_prepare,
4496 .cleanup = via_dig_playback_pcm_cleanup
4497 },
4498};
4499
4500static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
4501 .substreams = 1,
4502 .channels_min = 2,
4503 .channels_max = 2,
4504};
4505
4506/* fill in the dac_nids table from the parsed pin configuration */
4507static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
4508 const struct auto_pin_cfg *cfg)
4509{
4510 int i;
4511 hda_nid_t nid;
4512
4513 spec->multiout.num_dacs = cfg->line_outs;
4514
4515 spec->multiout.dac_nids = spec->private_dac_nids;
4516
4517 for (i = 0; i < 4; i++) {
4518 nid = cfg->line_out_pins[i];
4519 if (nid) {
4520 /* config dac list */
4521 switch (i) {
4522 case AUTO_SEQ_FRONT:
4523 spec->multiout.dac_nids[i] = 0x8;
4524 break;
4525 case AUTO_SEQ_CENLFE:
4526 spec->multiout.dac_nids[i] = 0xa;
4527 break;
4528 case AUTO_SEQ_SURROUND:
4529 spec->multiout.dac_nids[i] = 0x9;
4530 break;
4531 case AUTO_SEQ_SIDE:
4532 spec->multiout.dac_nids[i] = 0xb;
4533 break;
4534 }
4535 }
4536 }
4537
4538 return 0;
4539}
4540
4541/* add playback controls from the parsed DAC table */
4542static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
4543 const struct auto_pin_cfg *cfg)
4544{
4545 char name[32];
4546 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
4547 hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
4548 hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
4549 hda_nid_t nid, nid_vol, nid_mute = 0;
4550 int i, err;
4551
4552 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
4553 nid = cfg->line_out_pins[i];
4554
4555 if (!nid)
4556 continue;
4557 nid_vol = nid_vols[i];
4558 nid_mute = nid_mutes[i];
4559
4560 if (i == AUTO_SEQ_CENLFE) {
4561 /* Center/LFE */
4562 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4563 "Center Playback Volume",
4564 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
4565 HDA_OUTPUT));
4566 if (err < 0)
4567 return err;
4568 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4569 "LFE Playback Volume",
4570 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
4571 HDA_OUTPUT));
4572 if (err < 0)
4573 return err;
4574 err = via_add_control(
4575 spec, VIA_CTL_WIDGET_MUTE,
4576 "Center Playback Switch",
4577 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
4578 HDA_OUTPUT));
4579 if (err < 0)
4580 return err;
4581 err = via_add_control(
4582 spec, VIA_CTL_WIDGET_MUTE,
4583 "LFE Playback Switch",
4584 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
4585 HDA_OUTPUT));
4586 if (err < 0)
4587 return err;
4588 } else if (i == AUTO_SEQ_FRONT) {
4589 /* Front */
4590 sprintf(name, "%s Playback Volume", chname[i]);
4591 err = via_add_control(
4592 spec, VIA_CTL_WIDGET_VOL, name,
4593 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4594 if (err < 0)
4595 return err;
4596 sprintf(name, "%s Playback Switch", chname[i]);
4597 err = via_add_control(
4598 spec, VIA_CTL_WIDGET_MUTE, name,
4599 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4600 HDA_OUTPUT));
4601 if (err < 0)
4602 return err;
4603 } else {
4604 sprintf(name, "%s Playback Volume", chname[i]);
4605 err = via_add_control(
4606 spec, VIA_CTL_WIDGET_VOL, name,
4607 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4608 if (err < 0)
4609 return err;
4610 sprintf(name, "%s Playback Switch", chname[i]);
4611 err = via_add_control(
4612 spec, VIA_CTL_WIDGET_MUTE, name,
4613 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4614 HDA_OUTPUT));
4615 if (err < 0)
4616 return err;
4617 }
4618 }
4619 return 0;
4620}
4621
4622static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4623{
4624 int err;
4625
4626 if (!pin)
4627 return 0;
4628
4629 spec->multiout.hp_nid = 0xc; /* AOW4 */
4630 spec->hp_independent_mode_index = 1;
4631
4632 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4633 "Headphone Playback Volume",
4634 HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
4635 if (err < 0)
4636 return err;
4637
4638 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4639 "Headphone Playback Switch",
4640 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4641 if (err < 0)
4642 return err;
4643
4644 create_hp_imux(spec);
4645 return 0;
4646}
4647
4648/* create playback/capture controls for input pins */
4649static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
4650 const struct auto_pin_cfg *cfg)
4651{
4652 static char *labels[] = {
4653 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4654 };
4655 struct hda_input_mux *imux = &spec->private_imux[0];
4656 int i, err, idx = 0;
4657
4658 /* for internal loopback recording select */
4659 imux->items[imux->num_items].label = "Stereo Mixer";
4660 imux->items[imux->num_items].index = 5;
4661 imux->num_items++;
4662
4663 for (i = 0; i < AUTO_PIN_LAST; i++) {
4664 if (!cfg->input_pins[i])
4665 continue;
4666
4667 switch (cfg->input_pins[i]) {
4668 case 0x2b: /* Mic */
4669 idx = 1;
4670 break;
4671
4672 case 0x2a: /* Line In */
4673 idx = 2;
4674 break;
4675
4676 case 0x29: /* Front Mic */
4677 idx = 3;
4678 break;
4679
4680 case 0x2c: /* CD */
4681 idx = 0;
4682 break;
4683 }
4684 err = via_new_analog_input(spec, labels[i], idx, 0x21);
4685 if (err < 0)
4686 return err;
4687 imux->items[imux->num_items].label = labels[i];
4688 imux->items[imux->num_items].index = idx;
4689 imux->num_items++;
4690 }
4691 return 0;
4692}
4693
4694static int vt1718S_parse_auto_config(struct hda_codec *codec)
4695{
4696 struct via_spec *spec = codec->spec;
4697 int err;
4698
4699 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4700
4701 if (err < 0)
4702 return err;
4703 err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
4704 if (err < 0)
4705 return err;
4706 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4707 return 0; /* can't find valid BIOS pin config */
4708
4709 err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4710 if (err < 0)
4711 return err;
4712 err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4713 if (err < 0)
4714 return err;
4715 err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4716 if (err < 0)
4717 return err;
4718
4719 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4720
4721 fill_dig_outs(codec);
4722
4723 if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
4724 spec->dig_in_nid = 0x13;
4725
4726 if (spec->kctls.list)
4727 spec->mixers[spec->num_mixers++] = spec->kctls.list;
4728
4729 spec->input_mux = &spec->private_imux[0];
4730
4731 if (spec->hp_mux)
4732 spec->mixers[spec->num_mixers++] = via_hp_mixer;
4733
4734 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
4735
4736 return 1;
4737}
4738
4739#ifdef CONFIG_SND_HDA_POWER_SAVE
4740static struct hda_amp_list vt1718S_loopbacks[] = {
4741 { 0x21, HDA_INPUT, 1 },
4742 { 0x21, HDA_INPUT, 2 },
4743 { 0x21, HDA_INPUT, 3 },
4744 { 0x21, HDA_INPUT, 4 },
4745 { } /* end */
4746};
4747#endif
4748
4749static int patch_vt1718S(struct hda_codec *codec)
4750{
4751 struct via_spec *spec;
4752 int err;
4753
4754 /* create a codec specific record */
4755 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4756 if (spec == NULL)
4757 return -ENOMEM;
4758
4759 codec->spec = spec;
4760
4761 /* automatic parse from the BIOS config */
4762 err = vt1718S_parse_auto_config(codec);
4763 if (err < 0) {
4764 via_free(codec);
4765 return err;
4766 } else if (!err) {
4767 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4768 "from BIOS. Using genenic mode...\n");
4769 }
4770
4771 spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
4772 spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
4773
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004774 if (codec->vendor_id == 0x11060441)
4775 spec->stream_name_analog = "VT2020 Analog";
4776 else if (codec->vendor_id == 0x11064441)
4777 spec->stream_name_analog = "VT1828S Analog";
4778 else
4779 spec->stream_name_analog = "VT1718S Analog";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004780 spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
4781 spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
4782
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004783 if (codec->vendor_id == 0x11060441)
4784 spec->stream_name_digital = "VT2020 Digital";
4785 else if (codec->vendor_id == 0x11064441)
4786 spec->stream_name_digital = "VT1828S Digital";
4787 else
4788 spec->stream_name_digital = "VT1718S Digital";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004789 spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004790 if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
Lydia Wangeb7188c2009-10-10 19:08:34 +08004791 spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
4792
4793 if (!spec->adc_nids && spec->input_mux) {
4794 spec->adc_nids = vt1718S_adc_nids;
4795 spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
4796 get_mux_nids(codec);
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004797 override_mic_boost(codec, 0x2b, 0, 3, 40);
4798 override_mic_boost(codec, 0x29, 0, 3, 40);
Lydia Wangeb7188c2009-10-10 19:08:34 +08004799 spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
4800 spec->num_mixers++;
4801 }
4802
4803 codec->patch_ops = via_patch_ops;
4804
4805 codec->patch_ops.init = via_auto_init;
4806 codec->patch_ops.unsol_event = via_unsol_event,
4807
4808#ifdef CONFIG_SND_HDA_POWER_SAVE
4809 spec->loopback.amplist = vt1718S_loopbacks;
4810#endif
4811
4812 return 0;
4813}
Lydia Wangf3db4232009-10-10 19:08:41 +08004814
4815/* Patch for VT1716S */
4816
4817static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
4818 struct snd_ctl_elem_info *uinfo)
4819{
4820 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4821 uinfo->count = 1;
4822 uinfo->value.integer.min = 0;
4823 uinfo->value.integer.max = 1;
4824 return 0;
4825}
4826
4827static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
4828 struct snd_ctl_elem_value *ucontrol)
4829{
4830 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4831 int index = 0;
4832
4833 index = snd_hda_codec_read(codec, 0x26, 0,
4834 AC_VERB_GET_CONNECT_SEL, 0);
4835 if (index != -1)
4836 *ucontrol->value.integer.value = index;
4837
4838 return 0;
4839}
4840
4841static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
4842 struct snd_ctl_elem_value *ucontrol)
4843{
4844 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4845 struct via_spec *spec = codec->spec;
4846 int index = *ucontrol->value.integer.value;
4847
4848 snd_hda_codec_write(codec, 0x26, 0,
4849 AC_VERB_SET_CONNECT_SEL, index);
4850 spec->dmic_enabled = index;
4851 set_jack_power_state(codec);
4852
4853 return 1;
4854}
4855
4856/* capture mixer elements */
4857static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
4858 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
4859 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
4860 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
4861 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
4862 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
4863 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
4864 HDA_INPUT),
4865 {
4866 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4867 .name = "Input Source",
4868 .count = 1,
4869 .info = via_mux_enum_info,
4870 .get = via_mux_enum_get,
4871 .put = via_mux_enum_put,
4872 },
4873 { } /* end */
4874};
4875
4876static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
4877 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
4878 {
4879 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4880 .name = "Digital Mic Capture Switch",
4881 .count = 1,
4882 .info = vt1716s_dmic_info,
4883 .get = vt1716s_dmic_get,
4884 .put = vt1716s_dmic_put,
4885 },
4886 {} /* end */
4887};
4888
4889
4890/* mono-out mixer elements */
4891static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
4892 HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
4893 { } /* end */
4894};
4895
4896static struct hda_verb vt1716S_volume_init_verbs[] = {
4897 /*
4898 * Unmute ADC0-1 and set the default input to mic-in
4899 */
4900 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4901 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4902
4903
4904 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4905 * mixer widget
4906 */
4907 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4908 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4909 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4910 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4911 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4912 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4913
4914 /* MUX Indices: Stereo Mixer = 5 */
4915 {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
4916
4917 /* Setup default input of PW4 to MW0 */
4918 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
4919
4920 /* Setup default input of SW1 as MW0 */
4921 {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
4922
4923 /* Setup default input of SW4 as AOW0 */
4924 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4925
4926 /* PW9 PW10 Output enable */
4927 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4928 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4929
4930 /* Unmute SW1, PW12 */
4931 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4932 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4933 /* PW12 Output enable */
4934 {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4935 /* Enable Boost Volume backdoor */
4936 {0x1, 0xf8a, 0x80},
4937 /* don't bybass mixer */
4938 {0x1, 0xf88, 0xc0},
4939 /* Enable mono output */
4940 {0x1, 0xf90, 0x08},
4941 { }
4942};
4943
4944
4945static struct hda_verb vt1716S_uniwill_init_verbs[] = {
4946 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
4947 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4948 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4949 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4950 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4951 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
4952 AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
4953 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4954 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4955 { }
4956};
4957
4958static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
4959 .substreams = 2,
4960 .channels_min = 2,
4961 .channels_max = 6,
4962 .nid = 0x10, /* NID to query formats and rates */
4963 .ops = {
4964 .open = via_playback_pcm_open,
4965 .prepare = via_playback_multi_pcm_prepare,
4966 .cleanup = via_playback_multi_pcm_cleanup,
4967 .close = via_pcm_open_close,
4968 },
4969};
4970
4971static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
4972 .substreams = 2,
4973 .channels_min = 2,
4974 .channels_max = 2,
4975 .nid = 0x13, /* NID to query formats and rates */
4976 .ops = {
4977 .open = via_pcm_open_close,
4978 .prepare = via_capture_pcm_prepare,
4979 .cleanup = via_capture_pcm_cleanup,
4980 .close = via_pcm_open_close,
4981 },
4982};
4983
4984static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
4985 .substreams = 2,
4986 .channels_min = 2,
4987 .channels_max = 2,
4988 .rates = SNDRV_PCM_RATE_48000,
4989 /* NID is set in via_build_pcms */
4990 .ops = {
4991 .open = via_dig_playback_pcm_open,
4992 .close = via_dig_playback_pcm_close,
4993 .prepare = via_dig_playback_pcm_prepare,
4994 .cleanup = via_dig_playback_pcm_cleanup
4995 },
4996};
4997
4998/* fill in the dac_nids table from the parsed pin configuration */
4999static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
5000 const struct auto_pin_cfg *cfg)
5001{ int i;
5002 hda_nid_t nid;
5003
5004 spec->multiout.num_dacs = cfg->line_outs;
5005
5006 spec->multiout.dac_nids = spec->private_dac_nids;
5007
5008 for (i = 0; i < 3; i++) {
5009 nid = cfg->line_out_pins[i];
5010 if (nid) {
5011 /* config dac list */
5012 switch (i) {
5013 case AUTO_SEQ_FRONT:
5014 spec->multiout.dac_nids[i] = 0x10;
5015 break;
5016 case AUTO_SEQ_CENLFE:
5017 spec->multiout.dac_nids[i] = 0x25;
5018 break;
5019 case AUTO_SEQ_SURROUND:
5020 spec->multiout.dac_nids[i] = 0x11;
5021 break;
5022 }
5023 }
5024 }
5025
5026 return 0;
5027}
5028
5029/* add playback controls from the parsed DAC table */
5030static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
5031 const struct auto_pin_cfg *cfg)
5032{
5033 char name[32];
5034 static const char *chname[3] = { "Front", "Surround", "C/LFE" };
5035 hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
5036 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
5037 hda_nid_t nid, nid_vol, nid_mute;
5038 int i, err;
5039
5040 for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
5041 nid = cfg->line_out_pins[i];
5042
5043 if (!nid)
5044 continue;
5045
5046 nid_vol = nid_vols[i];
5047 nid_mute = nid_mutes[i];
5048
5049 if (i == AUTO_SEQ_CENLFE) {
5050 err = via_add_control(
5051 spec, VIA_CTL_WIDGET_VOL,
5052 "Center Playback Volume",
5053 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
5054 if (err < 0)
5055 return err;
5056 err = via_add_control(
5057 spec, VIA_CTL_WIDGET_VOL,
5058 "LFE Playback Volume",
5059 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
5060 if (err < 0)
5061 return err;
5062 err = via_add_control(
5063 spec, VIA_CTL_WIDGET_MUTE,
5064 "Center Playback Switch",
5065 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
5066 HDA_OUTPUT));
5067 if (err < 0)
5068 return err;
5069 err = via_add_control(
5070 spec, VIA_CTL_WIDGET_MUTE,
5071 "LFE Playback Switch",
5072 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
5073 HDA_OUTPUT));
5074 if (err < 0)
5075 return err;
5076 } else if (i == AUTO_SEQ_FRONT) {
5077
5078 err = via_add_control(
5079 spec, VIA_CTL_WIDGET_VOL,
5080 "Master Front Playback Volume",
5081 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5082 if (err < 0)
5083 return err;
5084 err = via_add_control(
5085 spec, VIA_CTL_WIDGET_MUTE,
5086 "Master Front Playback Switch",
5087 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5088 if (err < 0)
5089 return err;
5090
5091 sprintf(name, "%s Playback Volume", chname[i]);
5092 err = via_add_control(
5093 spec, VIA_CTL_WIDGET_VOL, name,
5094 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5095 if (err < 0)
5096 return err;
5097 sprintf(name, "%s Playback Switch", chname[i]);
5098 err = via_add_control(
5099 spec, VIA_CTL_WIDGET_MUTE, name,
5100 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5101 HDA_OUTPUT));
5102 if (err < 0)
5103 return err;
5104 } else {
5105 sprintf(name, "%s Playback Volume", chname[i]);
5106 err = via_add_control(
5107 spec, VIA_CTL_WIDGET_VOL, name,
5108 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5109 if (err < 0)
5110 return err;
5111 sprintf(name, "%s Playback Switch", chname[i]);
5112 err = via_add_control(
5113 spec, VIA_CTL_WIDGET_MUTE, name,
5114 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5115 HDA_OUTPUT));
5116 if (err < 0)
5117 return err;
5118 }
5119 }
5120 return 0;
5121}
5122
5123static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5124{
5125 int err;
5126
5127 if (!pin)
5128 return 0;
5129
5130 spec->multiout.hp_nid = 0x25; /* AOW3 */
5131 spec->hp_independent_mode_index = 1;
5132
5133 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5134 "Headphone Playback Volume",
5135 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5136 if (err < 0)
5137 return err;
5138
5139 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5140 "Headphone Playback Switch",
5141 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5142 if (err < 0)
5143 return err;
5144
5145 create_hp_imux(spec);
5146 return 0;
5147}
5148
5149/* create playback/capture controls for input pins */
5150static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
5151 const struct auto_pin_cfg *cfg)
5152{
5153 static char *labels[] = {
5154 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5155 };
5156 struct hda_input_mux *imux = &spec->private_imux[0];
5157 int i, err, idx = 0;
5158
5159 /* for internal loopback recording select */
5160 imux->items[imux->num_items].label = "Stereo Mixer";
5161 imux->items[imux->num_items].index = 5;
5162 imux->num_items++;
5163
5164 for (i = 0; i < AUTO_PIN_LAST; i++) {
5165 if (!cfg->input_pins[i])
5166 continue;
5167
5168 switch (cfg->input_pins[i]) {
5169 case 0x1a: /* Mic */
5170 idx = 2;
5171 break;
5172
5173 case 0x1b: /* Line In */
5174 idx = 3;
5175 break;
5176
5177 case 0x1e: /* Front Mic */
5178 idx = 4;
5179 break;
5180
5181 case 0x1f: /* CD */
5182 idx = 1;
5183 break;
5184 }
5185 err = via_new_analog_input(spec, labels[i], idx, 0x16);
5186 if (err < 0)
5187 return err;
5188 imux->items[imux->num_items].label = labels[i];
5189 imux->items[imux->num_items].index = idx-1;
5190 imux->num_items++;
5191 }
5192 return 0;
5193}
5194
5195static int vt1716S_parse_auto_config(struct hda_codec *codec)
5196{
5197 struct via_spec *spec = codec->spec;
5198 int err;
5199
5200 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5201 if (err < 0)
5202 return err;
5203 err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
5204 if (err < 0)
5205 return err;
5206 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5207 return 0; /* can't find valid BIOS pin config */
5208
5209 err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
5210 if (err < 0)
5211 return err;
5212 err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5213 if (err < 0)
5214 return err;
5215 err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
5216 if (err < 0)
5217 return err;
5218
5219 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5220
5221 fill_dig_outs(codec);
5222
5223 if (spec->kctls.list)
5224 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5225
5226 spec->input_mux = &spec->private_imux[0];
5227
5228 if (spec->hp_mux)
5229 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5230
5231 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
5232
5233 return 1;
5234}
5235
5236#ifdef CONFIG_SND_HDA_POWER_SAVE
5237static struct hda_amp_list vt1716S_loopbacks[] = {
5238 { 0x16, HDA_INPUT, 1 },
5239 { 0x16, HDA_INPUT, 2 },
5240 { 0x16, HDA_INPUT, 3 },
5241 { 0x16, HDA_INPUT, 4 },
5242 { } /* end */
5243};
5244#endif
5245
5246static int patch_vt1716S(struct hda_codec *codec)
5247{
5248 struct via_spec *spec;
5249 int err;
5250
5251 /* create a codec specific record */
5252 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5253 if (spec == NULL)
5254 return -ENOMEM;
5255
5256 codec->spec = spec;
5257
5258 /* automatic parse from the BIOS config */
5259 err = vt1716S_parse_auto_config(codec);
5260 if (err < 0) {
5261 via_free(codec);
5262 return err;
5263 } else if (!err) {
5264 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5265 "from BIOS. Using genenic mode...\n");
5266 }
5267
5268 spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs;
5269 spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
5270
5271 spec->stream_name_analog = "VT1716S Analog";
5272 spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
5273 spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
5274
5275 spec->stream_name_digital = "VT1716S Digital";
5276 spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
5277
5278 if (!spec->adc_nids && spec->input_mux) {
5279 spec->adc_nids = vt1716S_adc_nids;
5280 spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
5281 get_mux_nids(codec);
5282 override_mic_boost(codec, 0x1a, 0, 3, 40);
5283 override_mic_boost(codec, 0x1e, 0, 3, 40);
5284 spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
5285 spec->num_mixers++;
5286 }
5287
5288 spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
5289 spec->num_mixers++;
5290
5291 spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
5292
5293 codec->patch_ops = via_patch_ops;
5294
5295 codec->patch_ops.init = via_auto_init;
5296 codec->patch_ops.unsol_event = via_unsol_event,
5297
5298#ifdef CONFIG_SND_HDA_POWER_SAVE
5299 spec->loopback.amplist = vt1716S_loopbacks;
5300#endif
5301
5302 return 0;
5303}
Lydia Wang25eaba22009-10-10 19:08:43 +08005304
5305/* for vt2002P */
5306
5307/* capture mixer elements */
5308static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
5309 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5310 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5311 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5312 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5313 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5314 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
5315 HDA_INPUT),
5316 {
5317 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5318 /* The multiple "Capture Source" controls confuse alsamixer
5319 * So call somewhat different..
5320 */
5321 /* .name = "Capture Source", */
5322 .name = "Input Source",
5323 .count = 2,
5324 .info = via_mux_enum_info,
5325 .get = via_mux_enum_get,
5326 .put = via_mux_enum_put,
5327 },
5328 { } /* end */
5329};
5330
5331static struct hda_verb vt2002P_volume_init_verbs[] = {
5332 /*
5333 * Unmute ADC0-1 and set the default input to mic-in
5334 */
5335 {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5336 {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5337
5338
5339 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5340 * mixer widget
5341 */
5342 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5343 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5344 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5345 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5346 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5347 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5348
5349 /* MUX Indices: Mic = 0 */
5350 {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5351 {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5352
5353 /* PW9 Output enable */
5354 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5355
5356 /* Enable Boost Volume backdoor */
5357 {0x1, 0xfb9, 0x24},
5358
5359 /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5360 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5361 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5362 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5363 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5364 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5365 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5366 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5367 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5368
5369 /* set MUX0/1/4/8 = 0 (AOW0) */
5370 {0x34, AC_VERB_SET_CONNECT_SEL, 0},
5371 {0x35, AC_VERB_SET_CONNECT_SEL, 0},
5372 {0x37, AC_VERB_SET_CONNECT_SEL, 0},
5373 {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
5374
5375 /* set PW0 index=0 (MW0) */
5376 {0x24, AC_VERB_SET_CONNECT_SEL, 0},
5377
5378 /* Enable AOW0 to MW9 */
5379 {0x1, 0xfb8, 0x88},
5380 { }
5381};
5382
5383
5384static struct hda_verb vt2002P_uniwill_init_verbs[] = {
5385 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
5386 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5387 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
5388 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5389 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5390 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5391 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5392 { }
5393};
5394
5395static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
5396 .substreams = 2,
5397 .channels_min = 2,
5398 .channels_max = 2,
5399 .nid = 0x8, /* NID to query formats and rates */
5400 .ops = {
5401 .open = via_playback_pcm_open,
5402 .prepare = via_playback_multi_pcm_prepare,
5403 .cleanup = via_playback_multi_pcm_cleanup,
5404 .close = via_pcm_open_close,
5405 },
5406};
5407
5408static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
5409 .substreams = 2,
5410 .channels_min = 2,
5411 .channels_max = 2,
5412 .nid = 0x10, /* NID to query formats and rates */
5413 .ops = {
5414 .open = via_pcm_open_close,
5415 .prepare = via_capture_pcm_prepare,
5416 .cleanup = via_capture_pcm_cleanup,
5417 .close = via_pcm_open_close,
5418 },
5419};
5420
5421static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
5422 .substreams = 1,
5423 .channels_min = 2,
5424 .channels_max = 2,
5425 .rates = SNDRV_PCM_RATE_48000,
5426 /* NID is set in via_build_pcms */
5427 .ops = {
5428 .open = via_dig_playback_pcm_open,
5429 .close = via_dig_playback_pcm_close,
5430 .prepare = via_dig_playback_pcm_prepare,
5431 .cleanup = via_dig_playback_pcm_cleanup
5432 },
5433};
5434
5435/* fill in the dac_nids table from the parsed pin configuration */
5436static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
5437 const struct auto_pin_cfg *cfg)
5438{
5439 spec->multiout.num_dacs = 1;
5440 spec->multiout.dac_nids = spec->private_dac_nids;
5441 if (cfg->line_out_pins[0])
5442 spec->multiout.dac_nids[0] = 0x8;
5443 return 0;
5444}
5445
5446/* add playback controls from the parsed DAC table */
5447static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
5448 const struct auto_pin_cfg *cfg)
5449{
5450 int err;
5451
5452 if (!cfg->line_out_pins[0])
5453 return -1;
5454
5455
5456 /* Line-Out: PortE */
5457 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5458 "Master Front Playback Volume",
5459 HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5460 if (err < 0)
5461 return err;
5462 err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
5463 "Master Front Playback Switch",
5464 HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
5465 if (err < 0)
5466 return err;
5467
5468 return 0;
5469}
5470
5471static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5472{
5473 int err;
5474
5475 if (!pin)
5476 return 0;
5477
5478 spec->multiout.hp_nid = 0x9;
5479 spec->hp_independent_mode_index = 1;
5480
5481 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5482 "Headphone Playback Volume",
5483 HDA_COMPOSE_AMP_VAL(
5484 spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
5485 if (err < 0)
5486 return err;
5487
5488 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5489 "Headphone Playback Switch",
5490 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5491 if (err < 0)
5492 return err;
5493
5494 create_hp_imux(spec);
5495 return 0;
5496}
5497
5498/* create playback/capture controls for input pins */
5499static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
5500 const struct auto_pin_cfg *cfg)
5501{
5502 static char *labels[] = {
5503 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5504 };
5505 struct hda_input_mux *imux = &spec->private_imux[0];
5506 int i, err, idx = 0;
5507
5508 for (i = 0; i < AUTO_PIN_LAST; i++) {
5509 if (!cfg->input_pins[i])
5510 continue;
5511
5512 switch (cfg->input_pins[i]) {
5513 case 0x2b: /* Mic */
5514 idx = 0;
5515 break;
5516
5517 case 0x2a: /* Line In */
5518 idx = 1;
5519 break;
5520
5521 case 0x29: /* Front Mic */
5522 idx = 2;
5523 break;
5524 }
5525 err = via_new_analog_input(spec, labels[i], idx, 0x21);
5526 if (err < 0)
5527 return err;
5528 imux->items[imux->num_items].label = labels[i];
5529 imux->items[imux->num_items].index = idx;
5530 imux->num_items++;
5531 }
5532
5533 /* build volume/mute control of loopback */
5534 err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
5535 if (err < 0)
5536 return err;
5537
5538 /* for internal loopback recording select */
5539 imux->items[imux->num_items].label = "Stereo Mixer";
5540 imux->items[imux->num_items].index = 3;
5541 imux->num_items++;
5542
5543 /* for digital mic select */
5544 imux->items[imux->num_items].label = "Digital Mic";
5545 imux->items[imux->num_items].index = 4;
5546 imux->num_items++;
5547
5548 return 0;
5549}
5550
5551static int vt2002P_parse_auto_config(struct hda_codec *codec)
5552{
5553 struct via_spec *spec = codec->spec;
5554 int err;
5555
5556
5557 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5558 if (err < 0)
5559 return err;
5560
5561 err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
5562 if (err < 0)
5563 return err;
5564
5565 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5566 return 0; /* can't find valid BIOS pin config */
5567
5568 err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
5569 if (err < 0)
5570 return err;
5571 err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5572 if (err < 0)
5573 return err;
5574 err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
5575 if (err < 0)
5576 return err;
5577
5578 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5579
5580 fill_dig_outs(codec);
5581
5582 if (spec->kctls.list)
5583 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5584
5585 spec->input_mux = &spec->private_imux[0];
5586
5587 if (spec->hp_mux)
5588 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5589
5590 return 1;
5591}
5592
5593#ifdef CONFIG_SND_HDA_POWER_SAVE
5594static struct hda_amp_list vt2002P_loopbacks[] = {
5595 { 0x21, HDA_INPUT, 0 },
5596 { 0x21, HDA_INPUT, 1 },
5597 { 0x21, HDA_INPUT, 2 },
5598 { } /* end */
5599};
5600#endif
5601
5602
5603/* patch for vt2002P */
5604static int patch_vt2002P(struct hda_codec *codec)
5605{
5606 struct via_spec *spec;
5607 int err;
5608
5609 /* create a codec specific record */
5610 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5611 if (spec == NULL)
5612 return -ENOMEM;
5613
5614 codec->spec = spec;
5615
5616 /* automatic parse from the BIOS config */
5617 err = vt2002P_parse_auto_config(codec);
5618 if (err < 0) {
5619 via_free(codec);
5620 return err;
5621 } else if (!err) {
5622 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5623 "from BIOS. Using genenic mode...\n");
5624 }
5625
5626 spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs;
5627 spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
5628
5629 spec->stream_name_analog = "VT2002P Analog";
5630 spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
5631 spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
5632
5633 spec->stream_name_digital = "VT2002P Digital";
5634 spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
5635
5636 if (!spec->adc_nids && spec->input_mux) {
5637 spec->adc_nids = vt2002P_adc_nids;
5638 spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
5639 get_mux_nids(codec);
5640 override_mic_boost(codec, 0x2b, 0, 3, 40);
5641 override_mic_boost(codec, 0x29, 0, 3, 40);
5642 spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
5643 spec->num_mixers++;
5644 }
5645
5646 codec->patch_ops = via_patch_ops;
5647
5648 codec->patch_ops.init = via_auto_init;
5649 codec->patch_ops.unsol_event = via_unsol_event,
5650
5651#ifdef CONFIG_SND_HDA_POWER_SAVE
5652 spec->loopback.amplist = vt2002P_loopbacks;
5653#endif
5654
5655 return 0;
5656}
Joseph Chanc577b8a2006-11-29 15:29:40 +01005657/*
5658 * patch entries
5659 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005660static struct hda_codec_preset snd_hda_preset_via[] = {
Takashi Iwai3218c172008-12-18 09:17:56 +01005661 { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
5662 { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
5663 { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
5664 { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
5665 { .id = 0x1106e710, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005666 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005667 { .id = 0x1106e711, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005668 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005669 { .id = 0x1106e712, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005670 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005671 { .id = 0x1106e713, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005672 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005673 { .id = 0x1106e714, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005674 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005675 { .id = 0x1106e715, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005676 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005677 { .id = 0x1106e716, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005678 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005679 { .id = 0x1106e717, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005680 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005681 { .id = 0x1106e720, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005682 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005683 { .id = 0x1106e721, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005684 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005685 { .id = 0x1106e722, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005686 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005687 { .id = 0x1106e723, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005688 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005689 { .id = 0x1106e724, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005690 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005691 { .id = 0x1106e725, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005692 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005693 { .id = 0x1106e726, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005694 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005695 { .id = 0x1106e727, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005696 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005697 { .id = 0x11060397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005698 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005699 { .id = 0x11061397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005700 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005701 { .id = 0x11062397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005702 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005703 { .id = 0x11063397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005704 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005705 { .id = 0x11064397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005706 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005707 { .id = 0x11065397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005708 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005709 { .id = 0x11066397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005710 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005711 { .id = 0x11067397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005712 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005713 { .id = 0x11060398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005714 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005715 { .id = 0x11061398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005716 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005717 { .id = 0x11062398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005718 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005719 { .id = 0x11063398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005720 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005721 { .id = 0x11064398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005722 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005723 { .id = 0x11065398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005724 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005725 { .id = 0x11066398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005726 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005727 { .id = 0x11067398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005728 .patch = patch_vt1702},
Lydia Wangeb7188c2009-10-10 19:08:34 +08005729 { .id = 0x11060428, .name = "VT1718S",
5730 .patch = patch_vt1718S},
5731 { .id = 0x11064428, .name = "VT1718S",
5732 .patch = patch_vt1718S},
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08005733 { .id = 0x11060441, .name = "VT2020",
5734 .patch = patch_vt1718S},
5735 { .id = 0x11064441, .name = "VT1828S",
5736 .patch = patch_vt1718S},
Lydia Wangf3db4232009-10-10 19:08:41 +08005737 { .id = 0x11060433, .name = "VT1716S",
5738 .patch = patch_vt1716S},
5739 { .id = 0x1106a721, .name = "VT1716S",
5740 .patch = patch_vt1716S},
Lydia Wang25eaba22009-10-10 19:08:43 +08005741 { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
5742 { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
Joseph Chanc577b8a2006-11-29 15:29:40 +01005743 {} /* terminator */
5744};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005745
5746MODULE_ALIAS("snd-hda-codec-id:1106*");
5747
5748static struct hda_codec_preset_list via_list = {
5749 .preset = snd_hda_preset_via,
5750 .owner = THIS_MODULE,
5751};
5752
5753MODULE_LICENSE("GPL");
5754MODULE_DESCRIPTION("VIA HD-audio codec");
5755
5756static int __init patch_via_init(void)
5757{
5758 return snd_hda_add_codec_preset(&via_list);
5759}
5760
5761static void __exit patch_via_exit(void)
5762{
5763 snd_hda_delete_codec_preset(&via_list);
5764}
5765
5766module_init(patch_via_init)
5767module_exit(patch_via_exit)