diff options
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r-- | sound/pci/hda/patch_via.c | 1407 |
1 files changed, 1358 insertions, 49 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e7e43524f8c7..63e4871e5d8f 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Universal Interface for Intel High Definition Audio Codec | 2 | * Universal Interface for Intel High Definition Audio Codec |
3 | * | 3 | * |
4 | * HD audio interface patch for VIA VT1708 codec | 4 | * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec |
5 | * | 5 | * |
6 | * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com> | 6 | * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com> |
7 | * Takashi Iwai <tiwai@suse.de> | 7 | * Takashi Iwai <tiwai@suse.de> |
8 | * | 8 | * |
9 | * This driver is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License as published by |
@@ -29,6 +29,13 @@ | |||
29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ | 29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ |
30 | /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ | 30 | /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ |
31 | /* 2007-09-17 Lydia Wang Add VT1708B codec support */ | 31 | /* 2007-09-17 Lydia Wang Add VT1708B codec support */ |
32 | /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ | ||
33 | /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ | ||
34 | /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ | ||
35 | /* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ | ||
36 | /* 2008-04-09 Lydia Wang Add Independent HP feature */ | ||
37 | /* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ | ||
38 | /* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ | ||
32 | /* */ | 39 | /* */ |
33 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 40 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
34 | 41 | ||
@@ -37,6 +44,7 @@ | |||
37 | #include <linux/delay.h> | 44 | #include <linux/delay.h> |
38 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
39 | #include <sound/core.h> | 46 | #include <sound/core.h> |
47 | #include <sound/asoundef.h> | ||
40 | #include "hda_codec.h" | 48 | #include "hda_codec.h" |
41 | #include "hda_local.h" | 49 | #include "hda_local.h" |
42 | #include "hda_patch.h" | 50 | #include "hda_patch.h" |
@@ -53,6 +61,8 @@ | |||
53 | #define VT1708_DIGOUT_NID 0x14 | 61 | #define VT1708_DIGOUT_NID 0x14 |
54 | #define VT1708_DIGIN_NID 0x16 | 62 | #define VT1708_DIGIN_NID 0x16 |
55 | #define VT1708_DIGIN_PIN 0x26 | 63 | #define VT1708_DIGIN_PIN 0x26 |
64 | #define VT1708_HP_PIN_NID 0x20 | ||
65 | #define VT1708_CD_PIN_NID 0x24 | ||
56 | 66 | ||
57 | #define VT1709_HP_DAC_NID 0x28 | 67 | #define VT1709_HP_DAC_NID 0x28 |
58 | #define VT1709_DIGOUT_NID 0x13 | 68 | #define VT1709_DIGOUT_NID 0x13 |
@@ -64,12 +74,64 @@ | |||
64 | #define VT1708B_DIGIN_NID 0x15 | 74 | #define VT1708B_DIGIN_NID 0x15 |
65 | #define VT1708B_DIGIN_PIN 0x21 | 75 | #define VT1708B_DIGIN_PIN 0x21 |
66 | 76 | ||
77 | #define VT1708S_HP_NID 0x25 | ||
78 | #define VT1708S_DIGOUT_NID 0x12 | ||
79 | |||
80 | #define VT1702_HP_NID 0x17 | ||
81 | #define VT1702_DIGOUT_NID 0x11 | ||
82 | |||
67 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) | 83 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) |
68 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) | 84 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) |
69 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) | 85 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) |
70 | #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) | 86 | #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) |
71 | #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) | 87 | #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) |
88 | #define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) | ||
89 | #define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398) | ||
90 | |||
91 | enum VIA_HDA_CODEC { | ||
92 | UNKNOWN = -1, | ||
93 | VT1708, | ||
94 | VT1709_10CH, | ||
95 | VT1709_6CH, | ||
96 | VT1708B_8CH, | ||
97 | VT1708B_4CH, | ||
98 | VT1708S, | ||
99 | VT1702, | ||
100 | CODEC_TYPES, | ||
101 | }; | ||
102 | |||
103 | static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) | ||
104 | { | ||
105 | u16 ven_id = vendor_id >> 16; | ||
106 | u16 dev_id = vendor_id & 0xffff; | ||
107 | enum VIA_HDA_CODEC codec_type; | ||
108 | |||
109 | /* get codec type */ | ||
110 | if (ven_id != 0x1106) | ||
111 | codec_type = UNKNOWN; | ||
112 | else if (dev_id >= 0x1708 && dev_id <= 0x170b) | ||
113 | codec_type = VT1708; | ||
114 | else if (dev_id >= 0xe710 && dev_id <= 0xe713) | ||
115 | codec_type = VT1709_10CH; | ||
116 | else if (dev_id >= 0xe714 && dev_id <= 0xe717) | ||
117 | codec_type = VT1709_6CH; | ||
118 | else if (dev_id >= 0xe720 && dev_id <= 0xe723) | ||
119 | codec_type = VT1708B_8CH; | ||
120 | else if (dev_id >= 0xe724 && dev_id <= 0xe727) | ||
121 | codec_type = VT1708B_4CH; | ||
122 | else if ((dev_id & 0xfff) == 0x397 | ||
123 | && (dev_id >> 12) < 8) | ||
124 | codec_type = VT1708S; | ||
125 | else if ((dev_id & 0xfff) == 0x398 | ||
126 | && (dev_id >> 12) < 8) | ||
127 | codec_type = VT1702; | ||
128 | else | ||
129 | codec_type = UNKNOWN; | ||
130 | return codec_type; | ||
131 | }; | ||
72 | 132 | ||
133 | #define VIA_HP_EVENT 0x01 | ||
134 | #define VIA_GPIO_EVENT 0x02 | ||
73 | 135 | ||
74 | enum { | 136 | enum { |
75 | VIA_CTL_WIDGET_VOL, | 137 | VIA_CTL_WIDGET_VOL, |
@@ -77,12 +139,54 @@ enum { | |||
77 | }; | 139 | }; |
78 | 140 | ||
79 | enum { | 141 | enum { |
80 | AUTO_SEQ_FRONT, | 142 | AUTO_SEQ_FRONT = 0, |
81 | AUTO_SEQ_SURROUND, | 143 | AUTO_SEQ_SURROUND, |
82 | AUTO_SEQ_CENLFE, | 144 | AUTO_SEQ_CENLFE, |
83 | AUTO_SEQ_SIDE | 145 | AUTO_SEQ_SIDE |
84 | }; | 146 | }; |
85 | 147 | ||
148 | #define get_amp_nid(kc) ((kc)->private_value & 0xffff) | ||
149 | |||
150 | /* Some VT1708S based boards gets the micboost setting wrong, so we have | ||
151 | * to apply some brute-force and re-write the TLV's by software. */ | ||
152 | static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
153 | unsigned int size, unsigned int __user *_tlv) | ||
154 | { | ||
155 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
156 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
157 | |||
158 | if (get_codec_type(codec->vendor_id) == VT1708S | ||
159 | && (nid == 0x1a || nid == 0x1e)) { | ||
160 | if (size < 4 * sizeof(unsigned int)) | ||
161 | return -ENOMEM; | ||
162 | if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */ | ||
163 | return -EFAULT; | ||
164 | if (put_user(2 * sizeof(unsigned int), _tlv + 1)) | ||
165 | return -EFAULT; | ||
166 | if (put_user(0, _tlv + 2)) /* offset = 0 */ | ||
167 | return -EFAULT; | ||
168 | if (put_user(1000, _tlv + 3)) /* step size = 10 dB */ | ||
169 | return -EFAULT; | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, | ||
175 | struct snd_ctl_elem_info *uinfo) | ||
176 | { | ||
177 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
178 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
179 | |||
180 | if (get_codec_type(codec->vendor_id) == VT1708S | ||
181 | && (nid == 0x1a || nid == 0x1e)) { | ||
182 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
183 | uinfo->count = 2; | ||
184 | uinfo->value.integer.min = 0; | ||
185 | uinfo->value.integer.max = 3; | ||
186 | } | ||
187 | return 0; | ||
188 | } | ||
189 | |||
86 | static struct snd_kcontrol_new vt1708_control_templates[] = { | 190 | static struct snd_kcontrol_new vt1708_control_templates[] = { |
87 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 191 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
88 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 192 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
@@ -94,7 +198,8 @@ struct via_spec { | |||
94 | struct snd_kcontrol_new *mixers[3]; | 198 | struct snd_kcontrol_new *mixers[3]; |
95 | unsigned int num_mixers; | 199 | unsigned int num_mixers; |
96 | 200 | ||
97 | struct hda_verb *init_verbs; | 201 | struct hda_verb *init_verbs[5]; |
202 | unsigned int num_iverbs; | ||
98 | 203 | ||
99 | char *stream_name_analog; | 204 | char *stream_name_analog; |
100 | struct hda_pcm_stream *stream_analog_playback; | 205 | struct hda_pcm_stream *stream_analog_playback; |
@@ -106,6 +211,7 @@ struct via_spec { | |||
106 | 211 | ||
107 | /* playback */ | 212 | /* playback */ |
108 | struct hda_multi_out multiout; | 213 | struct hda_multi_out multiout; |
214 | hda_nid_t extra_dig_out_nid; | ||
109 | 215 | ||
110 | /* capture */ | 216 | /* capture */ |
111 | unsigned int num_adc_nids; | 217 | unsigned int num_adc_nids; |
@@ -117,15 +223,19 @@ struct via_spec { | |||
117 | unsigned int cur_mux[3]; | 223 | unsigned int cur_mux[3]; |
118 | 224 | ||
119 | /* PCM information */ | 225 | /* PCM information */ |
120 | struct hda_pcm pcm_rec[2]; | 226 | struct hda_pcm pcm_rec[3]; |
121 | 227 | ||
122 | /* dynamic controls, init_verbs and input_mux */ | 228 | /* dynamic controls, init_verbs and input_mux */ |
123 | struct auto_pin_cfg autocfg; | 229 | struct auto_pin_cfg autocfg; |
124 | unsigned int num_kctl_alloc, num_kctl_used; | 230 | unsigned int num_kctl_alloc, num_kctl_used; |
125 | struct snd_kcontrol_new *kctl_alloc; | 231 | struct snd_kcontrol_new *kctl_alloc; |
126 | struct hda_input_mux private_imux; | 232 | struct hda_input_mux private_imux[2]; |
127 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 233 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
128 | 234 | ||
235 | /* HP mode source */ | ||
236 | const struct hda_input_mux *hp_mux; | ||
237 | unsigned int hp_independent_mode; | ||
238 | |||
129 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 239 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
130 | struct hda_loopback_check loopback; | 240 | struct hda_loopback_check loopback; |
131 | #endif | 241 | #endif |
@@ -146,6 +256,16 @@ static hda_nid_t vt1708B_adc_nids[2] = { | |||
146 | 0x13, 0x14 | 256 | 0x13, 0x14 |
147 | }; | 257 | }; |
148 | 258 | ||
259 | static hda_nid_t vt1708S_adc_nids[2] = { | ||
260 | /* ADC1-2 */ | ||
261 | 0x13, 0x14 | ||
262 | }; | ||
263 | |||
264 | static hda_nid_t vt1702_adc_nids[3] = { | ||
265 | /* ADC1-2 */ | ||
266 | 0x12, 0x20, 0x1F | ||
267 | }; | ||
268 | |||
149 | /* add dynamic controls */ | 269 | /* add dynamic controls */ |
150 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 270 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
151 | unsigned long val) | 271 | unsigned long val) |
@@ -283,19 +403,108 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
283 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 403 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
284 | 0x18, &spec->cur_mux[adc_idx]); | 404 | 0x18, &spec->cur_mux[adc_idx]); |
285 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || | 405 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || |
286 | IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0) | 406 | IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0)) |
287 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 407 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
288 | 0x19, &spec->cur_mux[adc_idx]); | 408 | 0x19, &spec->cur_mux[adc_idx]); |
289 | else if ((IS_VT1708B_8CH_VENDORID(vendor_id) || | 409 | else if ((IS_VT1708B_8CH_VENDORID(vendor_id) || |
290 | IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0) | 410 | IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0)) |
291 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 411 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
292 | 0x17, &spec->cur_mux[adc_idx]); | 412 | 0x17, &spec->cur_mux[adc_idx]); |
413 | else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0)) | ||
414 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
415 | 0x13, &spec->cur_mux[adc_idx]); | ||
293 | else | 416 | else |
294 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 417 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
295 | spec->adc_nids[adc_idx], | 418 | spec->adc_nids[adc_idx], |
296 | &spec->cur_mux[adc_idx]); | 419 | &spec->cur_mux[adc_idx]); |
297 | } | 420 | } |
298 | 421 | ||
422 | static int via_independent_hp_info(struct snd_kcontrol *kcontrol, | ||
423 | struct snd_ctl_elem_info *uinfo) | ||
424 | { | ||
425 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
426 | struct via_spec *spec = codec->spec; | ||
427 | return snd_hda_input_mux_info(spec->hp_mux, uinfo); | ||
428 | } | ||
429 | |||
430 | static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | ||
431 | struct snd_ctl_elem_value *ucontrol) | ||
432 | { | ||
433 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
434 | struct via_spec *spec = codec->spec; | ||
435 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | ||
436 | unsigned int pinsel = snd_hda_codec_read(codec, nid, 0, | ||
437 | AC_VERB_GET_CONNECT_SEL, | ||
438 | 0x00); | ||
439 | |||
440 | ucontrol->value.enumerated.item[0] = pinsel; | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | ||
446 | struct snd_ctl_elem_value *ucontrol) | ||
447 | { | ||
448 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
449 | struct via_spec *spec = codec->spec; | ||
450 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | ||
451 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; | ||
452 | unsigned int con_nid = snd_hda_codec_read(codec, nid, 0, | ||
453 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
454 | |||
455 | if (con_nid == spec->multiout.hp_nid) { | ||
456 | if (pinsel == 0) { | ||
457 | if (!spec->hp_independent_mode) { | ||
458 | if (spec->multiout.num_dacs > 1) | ||
459 | spec->multiout.num_dacs -= 1; | ||
460 | spec->hp_independent_mode = 1; | ||
461 | } | ||
462 | } else if (pinsel == 1) { | ||
463 | if (spec->hp_independent_mode) { | ||
464 | if (spec->multiout.num_dacs > 1) | ||
465 | spec->multiout.num_dacs += 1; | ||
466 | spec->hp_independent_mode = 0; | ||
467 | } | ||
468 | } | ||
469 | } else { | ||
470 | if (pinsel == 0) { | ||
471 | if (spec->hp_independent_mode) { | ||
472 | if (spec->multiout.num_dacs > 1) | ||
473 | spec->multiout.num_dacs += 1; | ||
474 | spec->hp_independent_mode = 0; | ||
475 | } | ||
476 | } else if (pinsel == 1) { | ||
477 | if (!spec->hp_independent_mode) { | ||
478 | if (spec->multiout.num_dacs > 1) | ||
479 | spec->multiout.num_dacs -= 1; | ||
480 | spec->hp_independent_mode = 1; | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | ||
485 | pinsel); | ||
486 | |||
487 | if (spec->multiout.hp_nid && | ||
488 | spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT]) | ||
489 | snd_hda_codec_setup_stream(codec, | ||
490 | spec->multiout.hp_nid, | ||
491 | 0, 0, 0); | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static struct snd_kcontrol_new via_hp_mixer[] = { | ||
497 | { | ||
498 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
499 | .name = "Independent HP", | ||
500 | .count = 1, | ||
501 | .info = via_independent_hp_info, | ||
502 | .get = via_independent_hp_get, | ||
503 | .put = via_independent_hp_put, | ||
504 | }, | ||
505 | { } /* end */ | ||
506 | }; | ||
507 | |||
299 | /* capture mixer elements */ | 508 | /* capture mixer elements */ |
300 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | 509 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { |
301 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | 510 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), |
@@ -380,6 +589,138 @@ static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
380 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | 589 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); |
381 | } | 590 | } |
382 | 591 | ||
592 | |||
593 | static void playback_multi_pcm_prep_0(struct hda_codec *codec, | ||
594 | unsigned int stream_tag, | ||
595 | unsigned int format, | ||
596 | struct snd_pcm_substream *substream) | ||
597 | { | ||
598 | struct via_spec *spec = codec->spec; | ||
599 | struct hda_multi_out *mout = &spec->multiout; | ||
600 | hda_nid_t *nids = mout->dac_nids; | ||
601 | int chs = substream->runtime->channels; | ||
602 | int i; | ||
603 | |||
604 | mutex_lock(&codec->spdif_mutex); | ||
605 | if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { | ||
606 | if (chs == 2 && | ||
607 | snd_hda_is_supported_format(codec, mout->dig_out_nid, | ||
608 | format) && | ||
609 | !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { | ||
610 | mout->dig_out_used = HDA_DIG_ANALOG_DUP; | ||
611 | /* turn off SPDIF once; otherwise the IEC958 bits won't | ||
612 | * be updated */ | ||
613 | if (codec->spdif_ctls & AC_DIG1_ENABLE) | ||
614 | snd_hda_codec_write(codec, mout->dig_out_nid, 0, | ||
615 | AC_VERB_SET_DIGI_CONVERT_1, | ||
616 | codec->spdif_ctls & | ||
617 | ~AC_DIG1_ENABLE & 0xff); | ||
618 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
619 | stream_tag, 0, format); | ||
620 | /* turn on again (if needed) */ | ||
621 | if (codec->spdif_ctls & AC_DIG1_ENABLE) | ||
622 | snd_hda_codec_write(codec, mout->dig_out_nid, 0, | ||
623 | AC_VERB_SET_DIGI_CONVERT_1, | ||
624 | codec->spdif_ctls & 0xff); | ||
625 | } else { | ||
626 | mout->dig_out_used = 0; | ||
627 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
628 | 0, 0, 0); | ||
629 | } | ||
630 | } | ||
631 | mutex_unlock(&codec->spdif_mutex); | ||
632 | |||
633 | /* front */ | ||
634 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, | ||
635 | 0, format); | ||
636 | |||
637 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | ||
638 | !spec->hp_independent_mode) | ||
639 | /* headphone out will just decode front left/right (stereo) */ | ||
640 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, | ||
641 | 0, format); | ||
642 | |||
643 | /* extra outputs copied from front */ | ||
644 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) | ||
645 | if (mout->extra_out_nid[i]) | ||
646 | snd_hda_codec_setup_stream(codec, | ||
647 | mout->extra_out_nid[i], | ||
648 | stream_tag, 0, format); | ||
649 | |||
650 | /* surrounds */ | ||
651 | for (i = 1; i < mout->num_dacs; i++) { | ||
652 | if (chs >= (i + 1) * 2) /* independent out */ | ||
653 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | ||
654 | i * 2, format); | ||
655 | else /* copy front */ | ||
656 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | ||
657 | 0, format); | ||
658 | } | ||
659 | } | ||
660 | |||
661 | static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
662 | struct hda_codec *codec, | ||
663 | unsigned int stream_tag, | ||
664 | unsigned int format, | ||
665 | struct snd_pcm_substream *substream) | ||
666 | { | ||
667 | struct via_spec *spec = codec->spec; | ||
668 | struct hda_multi_out *mout = &spec->multiout; | ||
669 | hda_nid_t *nids = mout->dac_nids; | ||
670 | |||
671 | if (substream->number == 0) | ||
672 | playback_multi_pcm_prep_0(codec, stream_tag, format, | ||
673 | substream); | ||
674 | else { | ||
675 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | ||
676 | spec->hp_independent_mode) | ||
677 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | ||
678 | stream_tag, 0, format); | ||
679 | } | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
685 | struct hda_codec *codec, | ||
686 | struct snd_pcm_substream *substream) | ||
687 | { | ||
688 | struct via_spec *spec = codec->spec; | ||
689 | struct hda_multi_out *mout = &spec->multiout; | ||
690 | hda_nid_t *nids = mout->dac_nids; | ||
691 | int i; | ||
692 | |||
693 | if (substream->number == 0) { | ||
694 | for (i = 0; i < mout->num_dacs; i++) | ||
695 | snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); | ||
696 | |||
697 | if (mout->hp_nid && !spec->hp_independent_mode) | ||
698 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | ||
699 | 0, 0, 0); | ||
700 | |||
701 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) | ||
702 | if (mout->extra_out_nid[i]) | ||
703 | snd_hda_codec_setup_stream(codec, | ||
704 | mout->extra_out_nid[i], | ||
705 | 0, 0, 0); | ||
706 | mutex_lock(&codec->spdif_mutex); | ||
707 | if (mout->dig_out_nid && | ||
708 | mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | ||
709 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
710 | 0, 0, 0); | ||
711 | mout->dig_out_used = 0; | ||
712 | } | ||
713 | mutex_unlock(&codec->spdif_mutex); | ||
714 | } else { | ||
715 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | ||
716 | spec->hp_independent_mode) | ||
717 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | ||
718 | 0, 0, 0); | ||
719 | } | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | |||
383 | /* | 724 | /* |
384 | * Digital out | 725 | * Digital out |
385 | */ | 726 | */ |
@@ -399,6 +740,21 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | |||
399 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | 740 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); |
400 | } | 741 | } |
401 | 742 | ||
743 | /* setup SPDIF output stream */ | ||
744 | static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, | ||
745 | unsigned int stream_tag, unsigned int format) | ||
746 | { | ||
747 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ | ||
748 | if (codec->spdif_ctls & AC_DIG1_ENABLE) | ||
749 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | ||
750 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | ||
751 | snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); | ||
752 | /* turn on again (if needed) */ | ||
753 | if (codec->spdif_ctls & AC_DIG1_ENABLE) | ||
754 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | ||
755 | codec->spdif_ctls & 0xff); | ||
756 | } | ||
757 | |||
402 | static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 758 | static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
403 | struct hda_codec *codec, | 759 | struct hda_codec *codec, |
404 | unsigned int stream_tag, | 760 | unsigned int stream_tag, |
@@ -406,8 +762,20 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
406 | struct snd_pcm_substream *substream) | 762 | struct snd_pcm_substream *substream) |
407 | { | 763 | { |
408 | struct via_spec *spec = codec->spec; | 764 | struct via_spec *spec = codec->spec; |
409 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, | 765 | hda_nid_t nid; |
410 | stream_tag, format, substream); | 766 | |
767 | /* 1st or 2nd S/PDIF */ | ||
768 | if (substream->number == 0) | ||
769 | nid = spec->multiout.dig_out_nid; | ||
770 | else if (substream->number == 1) | ||
771 | nid = spec->extra_dig_out_nid; | ||
772 | else | ||
773 | return -1; | ||
774 | |||
775 | mutex_lock(&codec->spdif_mutex); | ||
776 | setup_dig_playback_stream(codec, nid, stream_tag, format); | ||
777 | mutex_unlock(&codec->spdif_mutex); | ||
778 | return 0; | ||
411 | } | 779 | } |
412 | 780 | ||
413 | /* | 781 | /* |
@@ -436,14 +804,14 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
436 | } | 804 | } |
437 | 805 | ||
438 | static struct hda_pcm_stream vt1708_pcm_analog_playback = { | 806 | static struct hda_pcm_stream vt1708_pcm_analog_playback = { |
439 | .substreams = 1, | 807 | .substreams = 2, |
440 | .channels_min = 2, | 808 | .channels_min = 2, |
441 | .channels_max = 8, | 809 | .channels_max = 8, |
442 | .nid = 0x10, /* NID to query formats and rates */ | 810 | .nid = 0x10, /* NID to query formats and rates */ |
443 | .ops = { | 811 | .ops = { |
444 | .open = via_playback_pcm_open, | 812 | .open = via_playback_pcm_open, |
445 | .prepare = via_playback_pcm_prepare, | 813 | .prepare = via_playback_multi_pcm_prepare, |
446 | .cleanup = via_playback_pcm_cleanup | 814 | .cleanup = via_playback_multi_pcm_cleanup |
447 | }, | 815 | }, |
448 | }; | 816 | }; |
449 | 817 | ||
@@ -515,6 +883,13 @@ static int via_build_controls(struct hda_codec *codec) | |||
515 | if (err < 0) | 883 | if (err < 0) |
516 | return err; | 884 | return err; |
517 | spec->multiout.share_spdif = 1; | 885 | spec->multiout.share_spdif = 1; |
886 | |||
887 | if (spec->extra_dig_out_nid) { | ||
888 | err = snd_hda_create_spdif_out_ctls(codec, | ||
889 | spec->extra_dig_out_nid); | ||
890 | if (err < 0) | ||
891 | return err; | ||
892 | } | ||
518 | } | 893 | } |
519 | if (spec->dig_in_nid) { | 894 | if (spec->dig_in_nid) { |
520 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | 895 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); |
@@ -580,10 +955,89 @@ static void via_free(struct hda_codec *codec) | |||
580 | kfree(codec->spec); | 955 | kfree(codec->spec); |
581 | } | 956 | } |
582 | 957 | ||
958 | /* mute internal speaker if HP is plugged */ | ||
959 | static void via_hp_automute(struct hda_codec *codec) | ||
960 | { | ||
961 | unsigned int present; | ||
962 | struct via_spec *spec = codec->spec; | ||
963 | |||
964 | present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, | ||
965 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
966 | snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], | ||
967 | HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
968 | present ? HDA_AMP_MUTE : 0); | ||
969 | } | ||
970 | |||
971 | static void via_gpio_control(struct hda_codec *codec) | ||
972 | { | ||
973 | unsigned int gpio_data; | ||
974 | unsigned int vol_counter; | ||
975 | unsigned int vol; | ||
976 | unsigned int master_vol; | ||
977 | |||
978 | struct via_spec *spec = codec->spec; | ||
979 | |||
980 | gpio_data = snd_hda_codec_read(codec, codec->afg, 0, | ||
981 | AC_VERB_GET_GPIO_DATA, 0) & 0x03; | ||
982 | |||
983 | vol_counter = (snd_hda_codec_read(codec, codec->afg, 0, | ||
984 | 0xF84, 0) & 0x3F0000) >> 16; | ||
985 | |||
986 | vol = vol_counter & 0x1F; | ||
987 | master_vol = snd_hda_codec_read(codec, 0x1A, 0, | ||
988 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
989 | AC_AMP_GET_INPUT); | ||
990 | |||
991 | if (gpio_data == 0x02) { | ||
992 | /* unmute line out */ | ||
993 | snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], | ||
994 | HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); | ||
995 | |||
996 | if (vol_counter & 0x20) { | ||
997 | /* decrease volume */ | ||
998 | if (vol > master_vol) | ||
999 | vol = master_vol; | ||
1000 | snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, | ||
1001 | 0, HDA_AMP_VOLMASK, | ||
1002 | master_vol-vol); | ||
1003 | } else { | ||
1004 | /* increase volume */ | ||
1005 | snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0, | ||
1006 | HDA_AMP_VOLMASK, | ||
1007 | ((master_vol+vol) > 0x2A) ? 0x2A : | ||
1008 | (master_vol+vol)); | ||
1009 | } | ||
1010 | } else if (!(gpio_data & 0x02)) { | ||
1011 | /* mute line out */ | ||
1012 | snd_hda_codec_amp_stereo(codec, | ||
1013 | spec->autocfg.line_out_pins[0], | ||
1014 | HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
1015 | HDA_AMP_MUTE); | ||
1016 | } | ||
1017 | } | ||
1018 | |||
1019 | /* unsolicited event for jack sensing */ | ||
1020 | static void via_unsol_event(struct hda_codec *codec, | ||
1021 | unsigned int res) | ||
1022 | { | ||
1023 | res >>= 26; | ||
1024 | if (res == VIA_HP_EVENT) | ||
1025 | via_hp_automute(codec); | ||
1026 | else if (res == VIA_GPIO_EVENT) | ||
1027 | via_gpio_control(codec); | ||
1028 | } | ||
1029 | |||
1030 | static hda_nid_t slave_dig_outs[] = { | ||
1031 | 0, | ||
1032 | }; | ||
1033 | |||
583 | static int via_init(struct hda_codec *codec) | 1034 | static int via_init(struct hda_codec *codec) |
584 | { | 1035 | { |
585 | struct via_spec *spec = codec->spec; | 1036 | struct via_spec *spec = codec->spec; |
586 | snd_hda_sequence_write(codec, spec->init_verbs); | 1037 | int i; |
1038 | for (i = 0; i < spec->num_iverbs; i++) | ||
1039 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
1040 | |||
587 | /* Lydia Add for EAPD enable */ | 1041 | /* Lydia Add for EAPD enable */ |
588 | if (!spec->dig_in_nid) { /* No Digital In connection */ | 1042 | if (!spec->dig_in_nid) { /* No Digital In connection */ |
589 | if (IS_VT1708_VENDORID(codec->vendor_id)) { | 1043 | if (IS_VT1708_VENDORID(codec->vendor_id)) { |
@@ -611,6 +1065,9 @@ static int via_init(struct hda_codec *codec) | |||
611 | snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, | 1065 | snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, |
612 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | 1066 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); |
613 | 1067 | ||
1068 | /* no slave outs */ | ||
1069 | codec->slave_dig_outs = slave_dig_outs; | ||
1070 | |||
614 | return 0; | 1071 | return 0; |
615 | } | 1072 | } |
616 | 1073 | ||
@@ -657,10 +1114,10 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec, | |||
657 | spec->multiout.dac_nids[i] = 0x12; | 1114 | spec->multiout.dac_nids[i] = 0x12; |
658 | break; | 1115 | break; |
659 | case AUTO_SEQ_SURROUND: | 1116 | case AUTO_SEQ_SURROUND: |
660 | spec->multiout.dac_nids[i] = 0x13; | 1117 | spec->multiout.dac_nids[i] = 0x11; |
661 | break; | 1118 | break; |
662 | case AUTO_SEQ_SIDE: | 1119 | case AUTO_SEQ_SIDE: |
663 | spec->multiout.dac_nids[i] = 0x11; | 1120 | spec->multiout.dac_nids[i] = 0x13; |
664 | break; | 1121 | break; |
665 | } | 1122 | } |
666 | } | 1123 | } |
@@ -685,7 +1142,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
685 | continue; | 1142 | continue; |
686 | 1143 | ||
687 | if (i != AUTO_SEQ_FRONT) | 1144 | if (i != AUTO_SEQ_FRONT) |
688 | nid_vol = 0x1b - i + 1; | 1145 | nid_vol = 0x18 + i; |
689 | 1146 | ||
690 | if (i == AUTO_SEQ_CENLFE) { | 1147 | if (i == AUTO_SEQ_CENLFE) { |
691 | /* Center/LFE */ | 1148 | /* Center/LFE */ |
@@ -760,6 +1217,24 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
760 | return 0; | 1217 | return 0; |
761 | } | 1218 | } |
762 | 1219 | ||
1220 | static void create_hp_imux(struct via_spec *spec) | ||
1221 | { | ||
1222 | int i; | ||
1223 | struct hda_input_mux *imux = &spec->private_imux[1]; | ||
1224 | static const char *texts[] = { "OFF", "ON", NULL}; | ||
1225 | |||
1226 | /* for hp mode select */ | ||
1227 | i = 0; | ||
1228 | while (texts[i] != NULL) { | ||
1229 | imux->items[imux->num_items].label = texts[i]; | ||
1230 | imux->items[imux->num_items].index = i; | ||
1231 | imux->num_items++; | ||
1232 | i++; | ||
1233 | } | ||
1234 | |||
1235 | spec->hp_mux = &spec->private_imux[1]; | ||
1236 | } | ||
1237 | |||
763 | static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | 1238 | static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) |
764 | { | 1239 | { |
765 | int err; | 1240 | int err; |
@@ -780,6 +1255,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
780 | if (err < 0) | 1255 | if (err < 0) |
781 | return err; | 1256 | return err; |
782 | 1257 | ||
1258 | create_hp_imux(spec); | ||
1259 | |||
783 | return 0; | 1260 | return 0; |
784 | } | 1261 | } |
785 | 1262 | ||
@@ -790,7 +1267,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, | |||
790 | static char *labels[] = { | 1267 | static char *labels[] = { |
791 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | 1268 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL |
792 | }; | 1269 | }; |
793 | struct hda_input_mux *imux = &spec->private_imux; | 1270 | struct hda_input_mux *imux = &spec->private_imux[0]; |
794 | int i, err, idx = 0; | 1271 | int i, err, idx = 0; |
795 | 1272 | ||
796 | /* for internal loopback recording select */ | 1273 | /* for internal loopback recording select */ |
@@ -840,11 +1317,36 @@ static struct hda_amp_list vt1708_loopbacks[] = { | |||
840 | }; | 1317 | }; |
841 | #endif | 1318 | #endif |
842 | 1319 | ||
1320 | static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) | ||
1321 | { | ||
1322 | unsigned int def_conf; | ||
1323 | unsigned char seqassoc; | ||
1324 | |||
1325 | def_conf = snd_hda_codec_read(codec, nid, 0, | ||
1326 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
1327 | seqassoc = (unsigned char) get_defcfg_association(def_conf); | ||
1328 | seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); | ||
1329 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { | ||
1330 | if (seqassoc == 0xff) { | ||
1331 | def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); | ||
1332 | snd_hda_codec_write(codec, nid, 0, | ||
1333 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, | ||
1334 | def_conf >> 24); | ||
1335 | } | ||
1336 | } | ||
1337 | |||
1338 | return; | ||
1339 | } | ||
1340 | |||
843 | static int vt1708_parse_auto_config(struct hda_codec *codec) | 1341 | static int vt1708_parse_auto_config(struct hda_codec *codec) |
844 | { | 1342 | { |
845 | struct via_spec *spec = codec->spec; | 1343 | struct via_spec *spec = codec->spec; |
846 | int err; | 1344 | int err; |
847 | 1345 | ||
1346 | /* Add HP and CD pin config connect bit re-config action */ | ||
1347 | vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); | ||
1348 | vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); | ||
1349 | |||
848 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | 1350 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); |
849 | if (err < 0) | 1351 | if (err < 0) |
850 | return err; | 1352 | return err; |
@@ -874,9 +1376,12 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
874 | if (spec->kctl_alloc) | 1376 | if (spec->kctl_alloc) |
875 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 1377 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
876 | 1378 | ||
877 | spec->init_verbs = vt1708_volume_init_verbs; | 1379 | spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; |
1380 | |||
1381 | spec->input_mux = &spec->private_imux[0]; | ||
878 | 1382 | ||
879 | spec->input_mux = &spec->private_imux; | 1383 | if (spec->hp_mux) |
1384 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
880 | 1385 | ||
881 | return 1; | 1386 | return 1; |
882 | } | 1387 | } |
@@ -897,7 +1402,7 @@ static int patch_vt1708(struct hda_codec *codec) | |||
897 | int err; | 1402 | int err; |
898 | 1403 | ||
899 | /* create a codec specific record */ | 1404 | /* create a codec specific record */ |
900 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 1405 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
901 | if (spec == NULL) | 1406 | if (spec == NULL) |
902 | return -ENOMEM; | 1407 | return -ENOMEM; |
903 | 1408 | ||
@@ -966,6 +1471,11 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { | |||
966 | { } /* end */ | 1471 | { } /* end */ |
967 | }; | 1472 | }; |
968 | 1473 | ||
1474 | static struct hda_verb vt1709_uniwill_init_verbs[] = { | ||
1475 | {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | ||
1476 | { } | ||
1477 | }; | ||
1478 | |||
969 | /* | 1479 | /* |
970 | * generic initialization of ADC, input mixers and output mixers | 1480 | * generic initialization of ADC, input mixers and output mixers |
971 | */ | 1481 | */ |
@@ -1090,11 +1600,11 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, | |||
1090 | break; | 1600 | break; |
1091 | case AUTO_SEQ_SURROUND: | 1601 | case AUTO_SEQ_SURROUND: |
1092 | /* AOW3 */ | 1602 | /* AOW3 */ |
1093 | spec->multiout.dac_nids[i] = 0x27; | 1603 | spec->multiout.dac_nids[i] = 0x11; |
1094 | break; | 1604 | break; |
1095 | case AUTO_SEQ_SIDE: | 1605 | case AUTO_SEQ_SIDE: |
1096 | /* AOW1 */ | 1606 | /* AOW1 */ |
1097 | spec->multiout.dac_nids[i] = 0x11; | 1607 | spec->multiout.dac_nids[i] = 0x27; |
1098 | break; | 1608 | break; |
1099 | default: | 1609 | default: |
1100 | break; | 1610 | break; |
@@ -1203,26 +1713,26 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1203 | } else if (i == AUTO_SEQ_SURROUND) { | 1713 | } else if (i == AUTO_SEQ_SURROUND) { |
1204 | sprintf(name, "%s Playback Volume", chname[i]); | 1714 | sprintf(name, "%s Playback Volume", chname[i]); |
1205 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1715 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1206 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, | 1716 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, |
1207 | HDA_OUTPUT)); | 1717 | HDA_OUTPUT)); |
1208 | if (err < 0) | 1718 | if (err < 0) |
1209 | return err; | 1719 | return err; |
1210 | sprintf(name, "%s Playback Switch", chname[i]); | 1720 | sprintf(name, "%s Playback Switch", chname[i]); |
1211 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1721 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1212 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, | 1722 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, |
1213 | HDA_OUTPUT)); | 1723 | HDA_OUTPUT)); |
1214 | if (err < 0) | 1724 | if (err < 0) |
1215 | return err; | 1725 | return err; |
1216 | } else if (i == AUTO_SEQ_SIDE) { | 1726 | } else if (i == AUTO_SEQ_SIDE) { |
1217 | sprintf(name, "%s Playback Volume", chname[i]); | 1727 | sprintf(name, "%s Playback Volume", chname[i]); |
1218 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1728 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1219 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, | 1729 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, |
1220 | HDA_OUTPUT)); | 1730 | HDA_OUTPUT)); |
1221 | if (err < 0) | 1731 | if (err < 0) |
1222 | return err; | 1732 | return err; |
1223 | sprintf(name, "%s Playback Switch", chname[i]); | 1733 | sprintf(name, "%s Playback Switch", chname[i]); |
1224 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1734 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1225 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, | 1735 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, |
1226 | HDA_OUTPUT)); | 1736 | HDA_OUTPUT)); |
1227 | if (err < 0) | 1737 | if (err < 0) |
1228 | return err; | 1738 | return err; |
@@ -1265,7 +1775,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, | |||
1265 | static char *labels[] = { | 1775 | static char *labels[] = { |
1266 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | 1776 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL |
1267 | }; | 1777 | }; |
1268 | struct hda_input_mux *imux = &spec->private_imux; | 1778 | struct hda_input_mux *imux = &spec->private_imux[0]; |
1269 | int i, err, idx = 0; | 1779 | int i, err, idx = 0; |
1270 | 1780 | ||
1271 | /* for internal loopback recording select */ | 1781 | /* for internal loopback recording select */ |
@@ -1339,7 +1849,10 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
1339 | if (spec->kctl_alloc) | 1849 | if (spec->kctl_alloc) |
1340 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 1850 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
1341 | 1851 | ||
1342 | spec->input_mux = &spec->private_imux; | 1852 | spec->input_mux = &spec->private_imux[0]; |
1853 | |||
1854 | if (spec->hp_mux) | ||
1855 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
1343 | 1856 | ||
1344 | return 1; | 1857 | return 1; |
1345 | } | 1858 | } |
@@ -1360,7 +1873,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
1360 | int err; | 1873 | int err; |
1361 | 1874 | ||
1362 | /* create a codec specific record */ | 1875 | /* create a codec specific record */ |
1363 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 1876 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1364 | if (spec == NULL) | 1877 | if (spec == NULL) |
1365 | return -ENOMEM; | 1878 | return -ENOMEM; |
1366 | 1879 | ||
@@ -1375,7 +1888,8 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
1375 | "Using genenic mode...\n"); | 1888 | "Using genenic mode...\n"); |
1376 | } | 1889 | } |
1377 | 1890 | ||
1378 | spec->init_verbs = vt1709_10ch_volume_init_verbs; | 1891 | spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs; |
1892 | spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; | ||
1379 | 1893 | ||
1380 | spec->stream_name_analog = "VT1709 Analog"; | 1894 | spec->stream_name_analog = "VT1709 Analog"; |
1381 | spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; | 1895 | spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; |
@@ -1396,6 +1910,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
1396 | codec->patch_ops = via_patch_ops; | 1910 | codec->patch_ops = via_patch_ops; |
1397 | 1911 | ||
1398 | codec->patch_ops.init = via_auto_init; | 1912 | codec->patch_ops.init = via_auto_init; |
1913 | codec->patch_ops.unsol_event = via_unsol_event; | ||
1399 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1914 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1400 | spec->loopback.amplist = vt1709_loopbacks; | 1915 | spec->loopback.amplist = vt1709_loopbacks; |
1401 | #endif | 1916 | #endif |
@@ -1451,7 +1966,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1451 | int err; | 1966 | int err; |
1452 | 1967 | ||
1453 | /* create a codec specific record */ | 1968 | /* create a codec specific record */ |
1454 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 1969 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1455 | if (spec == NULL) | 1970 | if (spec == NULL) |
1456 | return -ENOMEM; | 1971 | return -ENOMEM; |
1457 | 1972 | ||
@@ -1466,7 +1981,8 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1466 | "Using genenic mode...\n"); | 1981 | "Using genenic mode...\n"); |
1467 | } | 1982 | } |
1468 | 1983 | ||
1469 | spec->init_verbs = vt1709_6ch_volume_init_verbs; | 1984 | spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs; |
1985 | spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; | ||
1470 | 1986 | ||
1471 | spec->stream_name_analog = "VT1709 Analog"; | 1987 | spec->stream_name_analog = "VT1709 Analog"; |
1472 | spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; | 1988 | spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; |
@@ -1487,6 +2003,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1487 | codec->patch_ops = via_patch_ops; | 2003 | codec->patch_ops = via_patch_ops; |
1488 | 2004 | ||
1489 | codec->patch_ops.init = via_auto_init; | 2005 | codec->patch_ops.init = via_auto_init; |
2006 | codec->patch_ops.unsol_event = via_unsol_event; | ||
1490 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2007 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1491 | spec->loopback.amplist = vt1709_loopbacks; | 2008 | spec->loopback.amplist = vt1709_loopbacks; |
1492 | #endif | 2009 | #endif |
@@ -1586,27 +2103,32 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { | |||
1586 | { } | 2103 | { } |
1587 | }; | 2104 | }; |
1588 | 2105 | ||
2106 | static struct hda_verb vt1708B_uniwill_init_verbs[] = { | ||
2107 | {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | ||
2108 | { } | ||
2109 | }; | ||
2110 | |||
1589 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { | 2111 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { |
1590 | .substreams = 1, | 2112 | .substreams = 2, |
1591 | .channels_min = 2, | 2113 | .channels_min = 2, |
1592 | .channels_max = 8, | 2114 | .channels_max = 8, |
1593 | .nid = 0x10, /* NID to query formats and rates */ | 2115 | .nid = 0x10, /* NID to query formats and rates */ |
1594 | .ops = { | 2116 | .ops = { |
1595 | .open = via_playback_pcm_open, | 2117 | .open = via_playback_pcm_open, |
1596 | .prepare = via_playback_pcm_prepare, | 2118 | .prepare = via_playback_multi_pcm_prepare, |
1597 | .cleanup = via_playback_pcm_cleanup | 2119 | .cleanup = via_playback_multi_pcm_cleanup |
1598 | }, | 2120 | }, |
1599 | }; | 2121 | }; |
1600 | 2122 | ||
1601 | static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { | 2123 | static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { |
1602 | .substreams = 1, | 2124 | .substreams = 2, |
1603 | .channels_min = 2, | 2125 | .channels_min = 2, |
1604 | .channels_max = 4, | 2126 | .channels_max = 4, |
1605 | .nid = 0x10, /* NID to query formats and rates */ | 2127 | .nid = 0x10, /* NID to query formats and rates */ |
1606 | .ops = { | 2128 | .ops = { |
1607 | .open = via_playback_pcm_open, | 2129 | .open = via_playback_pcm_open, |
1608 | .prepare = via_playback_pcm_prepare, | 2130 | .prepare = via_playback_multi_pcm_prepare, |
1609 | .cleanup = via_playback_pcm_cleanup | 2131 | .cleanup = via_playback_multi_pcm_cleanup |
1610 | }, | 2132 | }, |
1611 | }; | 2133 | }; |
1612 | 2134 | ||
@@ -1662,10 +2184,10 @@ static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, | |||
1662 | spec->multiout.dac_nids[i] = 0x24; | 2184 | spec->multiout.dac_nids[i] = 0x24; |
1663 | break; | 2185 | break; |
1664 | case AUTO_SEQ_SURROUND: | 2186 | case AUTO_SEQ_SURROUND: |
1665 | spec->multiout.dac_nids[i] = 0x25; | 2187 | spec->multiout.dac_nids[i] = 0x11; |
1666 | break; | 2188 | break; |
1667 | case AUTO_SEQ_SIDE: | 2189 | case AUTO_SEQ_SIDE: |
1668 | spec->multiout.dac_nids[i] = 0x11; | 2190 | spec->multiout.dac_nids[i] = 0x25; |
1669 | break; | 2191 | break; |
1670 | } | 2192 | } |
1671 | } | 2193 | } |
@@ -1680,7 +2202,7 @@ static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1680 | { | 2202 | { |
1681 | char name[32]; | 2203 | char name[32]; |
1682 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | 2204 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; |
1683 | hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18}; | 2205 | hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; |
1684 | hda_nid_t nid, nid_vol = 0; | 2206 | hda_nid_t nid, nid_vol = 0; |
1685 | int i, err; | 2207 | int i, err; |
1686 | 2208 | ||
@@ -1785,6 +2307,8 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
1785 | if (err < 0) | 2307 | if (err < 0) |
1786 | return err; | 2308 | return err; |
1787 | 2309 | ||
2310 | create_hp_imux(spec); | ||
2311 | |||
1788 | return 0; | 2312 | return 0; |
1789 | } | 2313 | } |
1790 | 2314 | ||
@@ -1795,7 +2319,7 @@ static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, | |||
1795 | static char *labels[] = { | 2319 | static char *labels[] = { |
1796 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | 2320 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL |
1797 | }; | 2321 | }; |
1798 | struct hda_input_mux *imux = &spec->private_imux; | 2322 | struct hda_input_mux *imux = &spec->private_imux[0]; |
1799 | int i, err, idx = 0; | 2323 | int i, err, idx = 0; |
1800 | 2324 | ||
1801 | /* for internal loopback recording select */ | 2325 | /* for internal loopback recording select */ |
@@ -1869,7 +2393,10 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | |||
1869 | if (spec->kctl_alloc) | 2393 | if (spec->kctl_alloc) |
1870 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 2394 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
1871 | 2395 | ||
1872 | spec->input_mux = &spec->private_imux; | 2396 | spec->input_mux = &spec->private_imux[0]; |
2397 | |||
2398 | if (spec->hp_mux) | ||
2399 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
1873 | 2400 | ||
1874 | return 1; | 2401 | return 1; |
1875 | } | 2402 | } |
@@ -1890,7 +2417,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) | |||
1890 | int err; | 2417 | int err; |
1891 | 2418 | ||
1892 | /* create a codec specific record */ | 2419 | /* create a codec specific record */ |
1893 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 2420 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1894 | if (spec == NULL) | 2421 | if (spec == NULL) |
1895 | return -ENOMEM; | 2422 | return -ENOMEM; |
1896 | 2423 | ||
@@ -1906,7 +2433,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) | |||
1906 | "from BIOS. Using genenic mode...\n"); | 2433 | "from BIOS. Using genenic mode...\n"); |
1907 | } | 2434 | } |
1908 | 2435 | ||
1909 | spec->init_verbs = vt1708B_8ch_volume_init_verbs; | 2436 | spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs; |
2437 | spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; | ||
1910 | 2438 | ||
1911 | spec->stream_name_analog = "VT1708B Analog"; | 2439 | spec->stream_name_analog = "VT1708B Analog"; |
1912 | spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; | 2440 | spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; |
@@ -1926,6 +2454,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) | |||
1926 | codec->patch_ops = via_patch_ops; | 2454 | codec->patch_ops = via_patch_ops; |
1927 | 2455 | ||
1928 | codec->patch_ops.init = via_auto_init; | 2456 | codec->patch_ops.init = via_auto_init; |
2457 | codec->patch_ops.unsol_event = via_unsol_event; | ||
1929 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2458 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1930 | spec->loopback.amplist = vt1708B_loopbacks; | 2459 | spec->loopback.amplist = vt1708B_loopbacks; |
1931 | #endif | 2460 | #endif |
@@ -1939,7 +2468,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
1939 | int err; | 2468 | int err; |
1940 | 2469 | ||
1941 | /* create a codec specific record */ | 2470 | /* create a codec specific record */ |
1942 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 2471 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1943 | if (spec == NULL) | 2472 | if (spec == NULL) |
1944 | return -ENOMEM; | 2473 | return -ENOMEM; |
1945 | 2474 | ||
@@ -1955,7 +2484,8 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
1955 | "from BIOS. Using genenic mode...\n"); | 2484 | "from BIOS. Using genenic mode...\n"); |
1956 | } | 2485 | } |
1957 | 2486 | ||
1958 | spec->init_verbs = vt1708B_4ch_volume_init_verbs; | 2487 | spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs; |
2488 | spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; | ||
1959 | 2489 | ||
1960 | spec->stream_name_analog = "VT1708B Analog"; | 2490 | spec->stream_name_analog = "VT1708B Analog"; |
1961 | spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; | 2491 | spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; |
@@ -1975,6 +2505,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
1975 | codec->patch_ops = via_patch_ops; | 2505 | codec->patch_ops = via_patch_ops; |
1976 | 2506 | ||
1977 | codec->patch_ops.init = via_auto_init; | 2507 | codec->patch_ops.init = via_auto_init; |
2508 | codec->patch_ops.unsol_event = via_unsol_event; | ||
1978 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2509 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1979 | spec->loopback.amplist = vt1708B_loopbacks; | 2510 | spec->loopback.amplist = vt1708B_loopbacks; |
1980 | #endif | 2511 | #endif |
@@ -1982,6 +2513,752 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
1982 | return 0; | 2513 | return 0; |
1983 | } | 2514 | } |
1984 | 2515 | ||
2516 | /* Patch for VT1708S */ | ||
2517 | |||
2518 | /* VT1708S software backdoor based override for buggy hardware micboost | ||
2519 | * setting */ | ||
2520 | #define MIC_BOOST_VOLUME(xname, nid) { \ | ||
2521 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2522 | .name = xname, \ | ||
2523 | .index = 0, \ | ||
2524 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
2525 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
2526 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
2527 | .info = mic_boost_volume_info, \ | ||
2528 | .get = snd_hda_mixer_amp_volume_get, \ | ||
2529 | .put = snd_hda_mixer_amp_volume_put, \ | ||
2530 | .tlv = { .c = mic_boost_tlv }, \ | ||
2531 | .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) } | ||
2532 | |||
2533 | /* capture mixer elements */ | ||
2534 | static struct snd_kcontrol_new vt1708S_capture_mixer[] = { | ||
2535 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), | ||
2536 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), | ||
2537 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), | ||
2538 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), | ||
2539 | MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A), | ||
2540 | MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E), | ||
2541 | { | ||
2542 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2543 | /* The multiple "Capture Source" controls confuse alsamixer | ||
2544 | * So call somewhat different.. | ||
2545 | */ | ||
2546 | /* .name = "Capture Source", */ | ||
2547 | .name = "Input Source", | ||
2548 | .count = 1, | ||
2549 | .info = via_mux_enum_info, | ||
2550 | .get = via_mux_enum_get, | ||
2551 | .put = via_mux_enum_put, | ||
2552 | }, | ||
2553 | { } /* end */ | ||
2554 | }; | ||
2555 | |||
2556 | static struct hda_verb vt1708S_volume_init_verbs[] = { | ||
2557 | /* Unmute ADC0-1 and set the default input to mic-in */ | ||
2558 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2559 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2560 | |||
2561 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the | ||
2562 | * analog-loopback mixer widget */ | ||
2563 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
2564 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2565 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
2566 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
2567 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
2568 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
2569 | |||
2570 | /* Setup default input of PW4 to MW0 */ | ||
2571 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2572 | /* PW9, PW10 Output enable */ | ||
2573 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2574 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2575 | /* Enable Mic Boost Volume backdoor */ | ||
2576 | {0x1, 0xf98, 0x1}, | ||
2577 | { } | ||
2578 | }; | ||
2579 | |||
2580 | static struct hda_verb vt1708S_uniwill_init_verbs[] = { | ||
2581 | {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | ||
2582 | { } | ||
2583 | }; | ||
2584 | |||
2585 | static struct hda_pcm_stream vt1708S_pcm_analog_playback = { | ||
2586 | .substreams = 2, | ||
2587 | .channels_min = 2, | ||
2588 | .channels_max = 8, | ||
2589 | .nid = 0x10, /* NID to query formats and rates */ | ||
2590 | .ops = { | ||
2591 | .open = via_playback_pcm_open, | ||
2592 | .prepare = via_playback_pcm_prepare, | ||
2593 | .cleanup = via_playback_pcm_cleanup | ||
2594 | }, | ||
2595 | }; | ||
2596 | |||
2597 | static struct hda_pcm_stream vt1708S_pcm_analog_capture = { | ||
2598 | .substreams = 2, | ||
2599 | .channels_min = 2, | ||
2600 | .channels_max = 2, | ||
2601 | .nid = 0x13, /* NID to query formats and rates */ | ||
2602 | .ops = { | ||
2603 | .prepare = via_capture_pcm_prepare, | ||
2604 | .cleanup = via_capture_pcm_cleanup | ||
2605 | }, | ||
2606 | }; | ||
2607 | |||
2608 | static struct hda_pcm_stream vt1708S_pcm_digital_playback = { | ||
2609 | .substreams = 2, | ||
2610 | .channels_min = 2, | ||
2611 | .channels_max = 2, | ||
2612 | /* NID is set in via_build_pcms */ | ||
2613 | .ops = { | ||
2614 | .open = via_dig_playback_pcm_open, | ||
2615 | .close = via_dig_playback_pcm_close, | ||
2616 | .prepare = via_dig_playback_pcm_prepare | ||
2617 | }, | ||
2618 | }; | ||
2619 | |||
2620 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
2621 | static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, | ||
2622 | const struct auto_pin_cfg *cfg) | ||
2623 | { | ||
2624 | int i; | ||
2625 | hda_nid_t nid; | ||
2626 | |||
2627 | spec->multiout.num_dacs = cfg->line_outs; | ||
2628 | |||
2629 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
2630 | |||
2631 | for (i = 0; i < 4; i++) { | ||
2632 | nid = cfg->line_out_pins[i]; | ||
2633 | if (nid) { | ||
2634 | /* config dac list */ | ||
2635 | switch (i) { | ||
2636 | case AUTO_SEQ_FRONT: | ||
2637 | spec->multiout.dac_nids[i] = 0x10; | ||
2638 | break; | ||
2639 | case AUTO_SEQ_CENLFE: | ||
2640 | spec->multiout.dac_nids[i] = 0x24; | ||
2641 | break; | ||
2642 | case AUTO_SEQ_SURROUND: | ||
2643 | spec->multiout.dac_nids[i] = 0x11; | ||
2644 | break; | ||
2645 | case AUTO_SEQ_SIDE: | ||
2646 | spec->multiout.dac_nids[i] = 0x25; | ||
2647 | break; | ||
2648 | } | ||
2649 | } | ||
2650 | } | ||
2651 | |||
2652 | return 0; | ||
2653 | } | ||
2654 | |||
2655 | /* add playback controls from the parsed DAC table */ | ||
2656 | static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, | ||
2657 | const struct auto_pin_cfg *cfg) | ||
2658 | { | ||
2659 | char name[32]; | ||
2660 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
2661 | hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; | ||
2662 | hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; | ||
2663 | hda_nid_t nid, nid_vol, nid_mute; | ||
2664 | int i, err; | ||
2665 | |||
2666 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
2667 | nid = cfg->line_out_pins[i]; | ||
2668 | |||
2669 | if (!nid) | ||
2670 | continue; | ||
2671 | |||
2672 | nid_vol = nid_vols[i]; | ||
2673 | nid_mute = nid_mutes[i]; | ||
2674 | |||
2675 | if (i == AUTO_SEQ_CENLFE) { | ||
2676 | /* Center/LFE */ | ||
2677 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
2678 | "Center Playback Volume", | ||
2679 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
2680 | HDA_OUTPUT)); | ||
2681 | if (err < 0) | ||
2682 | return err; | ||
2683 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
2684 | "LFE Playback Volume", | ||
2685 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
2686 | HDA_OUTPUT)); | ||
2687 | if (err < 0) | ||
2688 | return err; | ||
2689 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
2690 | "Center Playback Switch", | ||
2691 | HDA_COMPOSE_AMP_VAL(nid_mute, | ||
2692 | 1, 0, | ||
2693 | HDA_OUTPUT)); | ||
2694 | if (err < 0) | ||
2695 | return err; | ||
2696 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
2697 | "LFE Playback Switch", | ||
2698 | HDA_COMPOSE_AMP_VAL(nid_mute, | ||
2699 | 2, 0, | ||
2700 | HDA_OUTPUT)); | ||
2701 | if (err < 0) | ||
2702 | return err; | ||
2703 | } else if (i == AUTO_SEQ_FRONT) { | ||
2704 | /* add control to mixer index 0 */ | ||
2705 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
2706 | "Master Front Playback Volume", | ||
2707 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, | ||
2708 | HDA_INPUT)); | ||
2709 | if (err < 0) | ||
2710 | return err; | ||
2711 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
2712 | "Master Front Playback Switch", | ||
2713 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, | ||
2714 | HDA_INPUT)); | ||
2715 | if (err < 0) | ||
2716 | return err; | ||
2717 | |||
2718 | /* Front */ | ||
2719 | sprintf(name, "%s Playback Volume", chname[i]); | ||
2720 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
2721 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
2722 | HDA_OUTPUT)); | ||
2723 | if (err < 0) | ||
2724 | return err; | ||
2725 | sprintf(name, "%s Playback Switch", chname[i]); | ||
2726 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
2727 | HDA_COMPOSE_AMP_VAL(nid_mute, | ||
2728 | 3, 0, | ||
2729 | HDA_OUTPUT)); | ||
2730 | if (err < 0) | ||
2731 | return err; | ||
2732 | } else { | ||
2733 | sprintf(name, "%s Playback Volume", chname[i]); | ||
2734 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
2735 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
2736 | HDA_OUTPUT)); | ||
2737 | if (err < 0) | ||
2738 | return err; | ||
2739 | sprintf(name, "%s Playback Switch", chname[i]); | ||
2740 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
2741 | HDA_COMPOSE_AMP_VAL(nid_mute, | ||
2742 | 3, 0, | ||
2743 | HDA_OUTPUT)); | ||
2744 | if (err < 0) | ||
2745 | return err; | ||
2746 | } | ||
2747 | } | ||
2748 | |||
2749 | return 0; | ||
2750 | } | ||
2751 | |||
2752 | static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
2753 | { | ||
2754 | int err; | ||
2755 | |||
2756 | if (!pin) | ||
2757 | return 0; | ||
2758 | |||
2759 | spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ | ||
2760 | |||
2761 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
2762 | "Headphone Playback Volume", | ||
2763 | HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); | ||
2764 | if (err < 0) | ||
2765 | return err; | ||
2766 | |||
2767 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
2768 | "Headphone Playback Switch", | ||
2769 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
2770 | if (err < 0) | ||
2771 | return err; | ||
2772 | |||
2773 | create_hp_imux(spec); | ||
2774 | |||
2775 | return 0; | ||
2776 | } | ||
2777 | |||
2778 | /* create playback/capture controls for input pins */ | ||
2779 | static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, | ||
2780 | const struct auto_pin_cfg *cfg) | ||
2781 | { | ||
2782 | static char *labels[] = { | ||
2783 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
2784 | }; | ||
2785 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
2786 | int i, err, idx = 0; | ||
2787 | |||
2788 | /* for internal loopback recording select */ | ||
2789 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
2790 | imux->items[imux->num_items].index = 5; | ||
2791 | imux->num_items++; | ||
2792 | |||
2793 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
2794 | if (!cfg->input_pins[i]) | ||
2795 | continue; | ||
2796 | |||
2797 | switch (cfg->input_pins[i]) { | ||
2798 | case 0x1a: /* Mic */ | ||
2799 | idx = 2; | ||
2800 | break; | ||
2801 | |||
2802 | case 0x1b: /* Line In */ | ||
2803 | idx = 3; | ||
2804 | break; | ||
2805 | |||
2806 | case 0x1e: /* Front Mic */ | ||
2807 | idx = 4; | ||
2808 | break; | ||
2809 | |||
2810 | case 0x1f: /* CD */ | ||
2811 | idx = 1; | ||
2812 | break; | ||
2813 | } | ||
2814 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
2815 | idx, 0x16); | ||
2816 | if (err < 0) | ||
2817 | return err; | ||
2818 | imux->items[imux->num_items].label = labels[i]; | ||
2819 | imux->items[imux->num_items].index = idx-1; | ||
2820 | imux->num_items++; | ||
2821 | } | ||
2822 | return 0; | ||
2823 | } | ||
2824 | |||
2825 | static int vt1708S_parse_auto_config(struct hda_codec *codec) | ||
2826 | { | ||
2827 | struct via_spec *spec = codec->spec; | ||
2828 | int err; | ||
2829 | static hda_nid_t vt1708s_ignore[] = {0x21, 0}; | ||
2830 | |||
2831 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
2832 | vt1708s_ignore); | ||
2833 | if (err < 0) | ||
2834 | return err; | ||
2835 | err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); | ||
2836 | if (err < 0) | ||
2837 | return err; | ||
2838 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
2839 | return 0; /* can't find valid BIOS pin config */ | ||
2840 | |||
2841 | err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
2842 | if (err < 0) | ||
2843 | return err; | ||
2844 | err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
2845 | if (err < 0) | ||
2846 | return err; | ||
2847 | err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
2848 | if (err < 0) | ||
2849 | return err; | ||
2850 | |||
2851 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
2852 | |||
2853 | if (spec->autocfg.dig_out_pin) | ||
2854 | spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; | ||
2855 | |||
2856 | spec->extra_dig_out_nid = 0x15; | ||
2857 | |||
2858 | if (spec->kctl_alloc) | ||
2859 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
2860 | |||
2861 | spec->input_mux = &spec->private_imux[0]; | ||
2862 | |||
2863 | if (spec->hp_mux) | ||
2864 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
2865 | |||
2866 | return 1; | ||
2867 | } | ||
2868 | |||
2869 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2870 | static struct hda_amp_list vt1708S_loopbacks[] = { | ||
2871 | { 0x16, HDA_INPUT, 1 }, | ||
2872 | { 0x16, HDA_INPUT, 2 }, | ||
2873 | { 0x16, HDA_INPUT, 3 }, | ||
2874 | { 0x16, HDA_INPUT, 4 }, | ||
2875 | { } /* end */ | ||
2876 | }; | ||
2877 | #endif | ||
2878 | |||
2879 | static int patch_vt1708S(struct hda_codec *codec) | ||
2880 | { | ||
2881 | struct via_spec *spec; | ||
2882 | int err; | ||
2883 | |||
2884 | /* create a codec specific record */ | ||
2885 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
2886 | if (spec == NULL) | ||
2887 | return -ENOMEM; | ||
2888 | |||
2889 | codec->spec = spec; | ||
2890 | |||
2891 | /* automatic parse from the BIOS config */ | ||
2892 | err = vt1708S_parse_auto_config(codec); | ||
2893 | if (err < 0) { | ||
2894 | via_free(codec); | ||
2895 | return err; | ||
2896 | } else if (!err) { | ||
2897 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
2898 | "from BIOS. Using genenic mode...\n"); | ||
2899 | } | ||
2900 | |||
2901 | spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; | ||
2902 | spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; | ||
2903 | |||
2904 | spec->stream_name_analog = "VT1708S Analog"; | ||
2905 | spec->stream_analog_playback = &vt1708S_pcm_analog_playback; | ||
2906 | spec->stream_analog_capture = &vt1708S_pcm_analog_capture; | ||
2907 | |||
2908 | spec->stream_name_digital = "VT1708S Digital"; | ||
2909 | spec->stream_digital_playback = &vt1708S_pcm_digital_playback; | ||
2910 | |||
2911 | if (!spec->adc_nids && spec->input_mux) { | ||
2912 | spec->adc_nids = vt1708S_adc_nids; | ||
2913 | spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); | ||
2914 | spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; | ||
2915 | spec->num_mixers++; | ||
2916 | } | ||
2917 | |||
2918 | codec->patch_ops = via_patch_ops; | ||
2919 | |||
2920 | codec->patch_ops.init = via_auto_init; | ||
2921 | codec->patch_ops.unsol_event = via_unsol_event; | ||
2922 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2923 | spec->loopback.amplist = vt1708S_loopbacks; | ||
2924 | #endif | ||
2925 | |||
2926 | return 0; | ||
2927 | } | ||
2928 | |||
2929 | /* Patch for VT1702 */ | ||
2930 | |||
2931 | /* capture mixer elements */ | ||
2932 | static struct snd_kcontrol_new vt1702_capture_mixer[] = { | ||
2933 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), | ||
2934 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), | ||
2935 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), | ||
2936 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT), | ||
2937 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT), | ||
2938 | HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT), | ||
2939 | HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0, | ||
2940 | HDA_INPUT), | ||
2941 | { | ||
2942 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2943 | /* The multiple "Capture Source" controls confuse alsamixer | ||
2944 | * So call somewhat different.. | ||
2945 | */ | ||
2946 | /* .name = "Capture Source", */ | ||
2947 | .name = "Input Source", | ||
2948 | .count = 1, | ||
2949 | .info = via_mux_enum_info, | ||
2950 | .get = via_mux_enum_get, | ||
2951 | .put = via_mux_enum_put, | ||
2952 | }, | ||
2953 | { } /* end */ | ||
2954 | }; | ||
2955 | |||
2956 | static struct hda_verb vt1702_volume_init_verbs[] = { | ||
2957 | /* | ||
2958 | * Unmute ADC0-1 and set the default input to mic-in | ||
2959 | */ | ||
2960 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2961 | {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2962 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2963 | |||
2964 | |||
2965 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
2966 | * mixer widget | ||
2967 | */ | ||
2968 | /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */ | ||
2969 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2970 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
2971 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
2972 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
2973 | {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2974 | |||
2975 | /* Setup default input of PW4 to MW0 */ | ||
2976 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2977 | /* PW6 PW7 Output enable */ | ||
2978 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2979 | {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2980 | { } | ||
2981 | }; | ||
2982 | |||
2983 | static struct hda_verb vt1702_uniwill_init_verbs[] = { | ||
2984 | {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT}, | ||
2985 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | ||
2986 | { } | ||
2987 | }; | ||
2988 | |||
2989 | static struct hda_pcm_stream vt1702_pcm_analog_playback = { | ||
2990 | .substreams = 2, | ||
2991 | .channels_min = 2, | ||
2992 | .channels_max = 2, | ||
2993 | .nid = 0x10, /* NID to query formats and rates */ | ||
2994 | .ops = { | ||
2995 | .open = via_playback_pcm_open, | ||
2996 | .prepare = via_playback_multi_pcm_prepare, | ||
2997 | .cleanup = via_playback_multi_pcm_cleanup | ||
2998 | }, | ||
2999 | }; | ||
3000 | |||
3001 | static struct hda_pcm_stream vt1702_pcm_analog_capture = { | ||
3002 | .substreams = 3, | ||
3003 | .channels_min = 2, | ||
3004 | .channels_max = 2, | ||
3005 | .nid = 0x12, /* NID to query formats and rates */ | ||
3006 | .ops = { | ||
3007 | .prepare = via_capture_pcm_prepare, | ||
3008 | .cleanup = via_capture_pcm_cleanup | ||
3009 | }, | ||
3010 | }; | ||
3011 | |||
3012 | static struct hda_pcm_stream vt1702_pcm_digital_playback = { | ||
3013 | .substreams = 2, | ||
3014 | .channels_min = 2, | ||
3015 | .channels_max = 2, | ||
3016 | /* NID is set in via_build_pcms */ | ||
3017 | .ops = { | ||
3018 | .open = via_dig_playback_pcm_open, | ||
3019 | .close = via_dig_playback_pcm_close, | ||
3020 | .prepare = via_dig_playback_pcm_prepare | ||
3021 | }, | ||
3022 | }; | ||
3023 | |||
3024 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
3025 | static int vt1702_auto_fill_dac_nids(struct via_spec *spec, | ||
3026 | const struct auto_pin_cfg *cfg) | ||
3027 | { | ||
3028 | spec->multiout.num_dacs = 1; | ||
3029 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
3030 | |||
3031 | if (cfg->line_out_pins[0]) { | ||
3032 | /* config dac list */ | ||
3033 | spec->multiout.dac_nids[0] = 0x10; | ||
3034 | } | ||
3035 | |||
3036 | return 0; | ||
3037 | } | ||
3038 | |||
3039 | /* add playback controls from the parsed DAC table */ | ||
3040 | static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, | ||
3041 | const struct auto_pin_cfg *cfg) | ||
3042 | { | ||
3043 | int err; | ||
3044 | |||
3045 | if (!cfg->line_out_pins[0]) | ||
3046 | return -1; | ||
3047 | |||
3048 | /* add control to mixer index 0 */ | ||
3049 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
3050 | "Master Front Playback Volume", | ||
3051 | HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); | ||
3052 | if (err < 0) | ||
3053 | return err; | ||
3054 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
3055 | "Master Front Playback Switch", | ||
3056 | HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); | ||
3057 | if (err < 0) | ||
3058 | return err; | ||
3059 | |||
3060 | /* Front */ | ||
3061 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
3062 | "Front Playback Volume", | ||
3063 | HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT)); | ||
3064 | if (err < 0) | ||
3065 | return err; | ||
3066 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
3067 | "Front Playback Switch", | ||
3068 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT)); | ||
3069 | if (err < 0) | ||
3070 | return err; | ||
3071 | |||
3072 | return 0; | ||
3073 | } | ||
3074 | |||
3075 | static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
3076 | { | ||
3077 | int err; | ||
3078 | |||
3079 | if (!pin) | ||
3080 | return 0; | ||
3081 | |||
3082 | spec->multiout.hp_nid = 0x1D; | ||
3083 | |||
3084 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
3085 | "Headphone Playback Volume", | ||
3086 | HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT)); | ||
3087 | if (err < 0) | ||
3088 | return err; | ||
3089 | |||
3090 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
3091 | "Headphone Playback Switch", | ||
3092 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
3093 | if (err < 0) | ||
3094 | return err; | ||
3095 | |||
3096 | create_hp_imux(spec); | ||
3097 | |||
3098 | return 0; | ||
3099 | } | ||
3100 | |||
3101 | /* create playback/capture controls for input pins */ | ||
3102 | static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, | ||
3103 | const struct auto_pin_cfg *cfg) | ||
3104 | { | ||
3105 | static char *labels[] = { | ||
3106 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
3107 | }; | ||
3108 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
3109 | int i, err, idx = 0; | ||
3110 | |||
3111 | /* for internal loopback recording select */ | ||
3112 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
3113 | imux->items[imux->num_items].index = 3; | ||
3114 | imux->num_items++; | ||
3115 | |||
3116 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
3117 | if (!cfg->input_pins[i]) | ||
3118 | continue; | ||
3119 | |||
3120 | switch (cfg->input_pins[i]) { | ||
3121 | case 0x14: /* Mic */ | ||
3122 | idx = 1; | ||
3123 | break; | ||
3124 | |||
3125 | case 0x15: /* Line In */ | ||
3126 | idx = 2; | ||
3127 | break; | ||
3128 | |||
3129 | case 0x18: /* Front Mic */ | ||
3130 | idx = 3; | ||
3131 | break; | ||
3132 | } | ||
3133 | err = via_new_analog_input(spec, cfg->input_pins[i], | ||
3134 | labels[i], idx, 0x1A); | ||
3135 | if (err < 0) | ||
3136 | return err; | ||
3137 | imux->items[imux->num_items].label = labels[i]; | ||
3138 | imux->items[imux->num_items].index = idx-1; | ||
3139 | imux->num_items++; | ||
3140 | } | ||
3141 | return 0; | ||
3142 | } | ||
3143 | |||
3144 | static int vt1702_parse_auto_config(struct hda_codec *codec) | ||
3145 | { | ||
3146 | struct via_spec *spec = codec->spec; | ||
3147 | int err; | ||
3148 | static hda_nid_t vt1702_ignore[] = {0x1C, 0}; | ||
3149 | |||
3150 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
3151 | vt1702_ignore); | ||
3152 | if (err < 0) | ||
3153 | return err; | ||
3154 | err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); | ||
3155 | if (err < 0) | ||
3156 | return err; | ||
3157 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
3158 | return 0; /* can't find valid BIOS pin config */ | ||
3159 | |||
3160 | err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg); | ||
3161 | if (err < 0) | ||
3162 | return err; | ||
3163 | err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
3164 | if (err < 0) | ||
3165 | return err; | ||
3166 | err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
3167 | if (err < 0) | ||
3168 | return err; | ||
3169 | |||
3170 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
3171 | |||
3172 | if (spec->autocfg.dig_out_pin) | ||
3173 | spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; | ||
3174 | |||
3175 | spec->extra_dig_out_nid = 0x1B; | ||
3176 | |||
3177 | if (spec->kctl_alloc) | ||
3178 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
3179 | |||
3180 | spec->input_mux = &spec->private_imux[0]; | ||
3181 | |||
3182 | if (spec->hp_mux) | ||
3183 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
3184 | |||
3185 | return 1; | ||
3186 | } | ||
3187 | |||
3188 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3189 | static struct hda_amp_list vt1702_loopbacks[] = { | ||
3190 | { 0x1A, HDA_INPUT, 1 }, | ||
3191 | { 0x1A, HDA_INPUT, 2 }, | ||
3192 | { 0x1A, HDA_INPUT, 3 }, | ||
3193 | { 0x1A, HDA_INPUT, 4 }, | ||
3194 | { } /* end */ | ||
3195 | }; | ||
3196 | #endif | ||
3197 | |||
3198 | static int patch_vt1702(struct hda_codec *codec) | ||
3199 | { | ||
3200 | struct via_spec *spec; | ||
3201 | int err; | ||
3202 | unsigned int response; | ||
3203 | unsigned char control; | ||
3204 | |||
3205 | /* create a codec specific record */ | ||
3206 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
3207 | if (spec == NULL) | ||
3208 | return -ENOMEM; | ||
3209 | |||
3210 | codec->spec = spec; | ||
3211 | |||
3212 | /* automatic parse from the BIOS config */ | ||
3213 | err = vt1702_parse_auto_config(codec); | ||
3214 | if (err < 0) { | ||
3215 | via_free(codec); | ||
3216 | return err; | ||
3217 | } else if (!err) { | ||
3218 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
3219 | "from BIOS. Using genenic mode...\n"); | ||
3220 | } | ||
3221 | |||
3222 | spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs; | ||
3223 | spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs; | ||
3224 | |||
3225 | spec->stream_name_analog = "VT1702 Analog"; | ||
3226 | spec->stream_analog_playback = &vt1702_pcm_analog_playback; | ||
3227 | spec->stream_analog_capture = &vt1702_pcm_analog_capture; | ||
3228 | |||
3229 | spec->stream_name_digital = "VT1702 Digital"; | ||
3230 | spec->stream_digital_playback = &vt1702_pcm_digital_playback; | ||
3231 | |||
3232 | if (!spec->adc_nids && spec->input_mux) { | ||
3233 | spec->adc_nids = vt1702_adc_nids; | ||
3234 | spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids); | ||
3235 | spec->mixers[spec->num_mixers] = vt1702_capture_mixer; | ||
3236 | spec->num_mixers++; | ||
3237 | } | ||
3238 | |||
3239 | codec->patch_ops = via_patch_ops; | ||
3240 | |||
3241 | codec->patch_ops.init = via_auto_init; | ||
3242 | codec->patch_ops.unsol_event = via_unsol_event; | ||
3243 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3244 | spec->loopback.amplist = vt1702_loopbacks; | ||
3245 | #endif | ||
3246 | |||
3247 | /* Open backdoor */ | ||
3248 | response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0); | ||
3249 | control = (unsigned char)(response & 0xff); | ||
3250 | control |= 0x3; | ||
3251 | snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control); | ||
3252 | |||
3253 | /* Enable GPIO 0&1 for volume&mute control */ | ||
3254 | /* Enable GPIO 2 for DMIC-DATA */ | ||
3255 | response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0); | ||
3256 | control = (unsigned char)((response >> 16) & 0x3f); | ||
3257 | snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control); | ||
3258 | |||
3259 | return 0; | ||
3260 | } | ||
3261 | |||
1985 | /* | 3262 | /* |
1986 | * patch entries | 3263 | * patch entries |
1987 | */ | 3264 | */ |
@@ -2022,5 +3299,37 @@ struct hda_codec_preset snd_hda_preset_via[] = { | |||
2022 | .patch = patch_vt1708B_4ch}, | 3299 | .patch = patch_vt1708B_4ch}, |
2023 | { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", | 3300 | { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", |
2024 | .patch = patch_vt1708B_4ch}, | 3301 | .patch = patch_vt1708B_4ch}, |
3302 | { .id = 0x11060397, .name = "VIA VT1708S", | ||
3303 | .patch = patch_vt1708S}, | ||
3304 | { .id = 0x11061397, .name = "VIA VT1708S", | ||
3305 | .patch = patch_vt1708S}, | ||
3306 | { .id = 0x11062397, .name = "VIA VT1708S", | ||
3307 | .patch = patch_vt1708S}, | ||
3308 | { .id = 0x11063397, .name = "VIA VT1708S", | ||
3309 | .patch = patch_vt1708S}, | ||
3310 | { .id = 0x11064397, .name = "VIA VT1708S", | ||
3311 | .patch = patch_vt1708S}, | ||
3312 | { .id = 0x11065397, .name = "VIA VT1708S", | ||
3313 | .patch = patch_vt1708S}, | ||
3314 | { .id = 0x11066397, .name = "VIA VT1708S", | ||
3315 | .patch = patch_vt1708S}, | ||
3316 | { .id = 0x11067397, .name = "VIA VT1708S", | ||
3317 | .patch = patch_vt1708S}, | ||
3318 | { .id = 0x11060398, .name = "VIA VT1702", | ||
3319 | .patch = patch_vt1702}, | ||
3320 | { .id = 0x11061398, .name = "VIA VT1702", | ||
3321 | .patch = patch_vt1702}, | ||
3322 | { .id = 0x11062398, .name = "VIA VT1702", | ||
3323 | .patch = patch_vt1702}, | ||
3324 | { .id = 0x11063398, .name = "VIA VT1702", | ||
3325 | .patch = patch_vt1702}, | ||
3326 | { .id = 0x11064398, .name = "VIA VT1702", | ||
3327 | .patch = patch_vt1702}, | ||
3328 | { .id = 0x11065398, .name = "VIA VT1702", | ||
3329 | .patch = patch_vt1702}, | ||
3330 | { .id = 0x11066398, .name = "VIA VT1702", | ||
3331 | .patch = patch_vt1702}, | ||
3332 | { .id = 0x11067398, .name = "VIA VT1702", | ||
3333 | .patch = patch_vt1702}, | ||
2025 | {} /* terminator */ | 3334 | {} /* terminator */ |
2026 | }; | 3335 | }; |