diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 210 |
1 files changed, 167 insertions, 43 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2d603f6aba63..e9fdfc4b1c57 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -72,7 +72,8 @@ struct ad198x_spec { | |||
72 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 72 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
73 | 73 | ||
74 | unsigned int jack_present :1; | 74 | unsigned int jack_present :1; |
75 | unsigned int inv_jack_detect:1; | 75 | unsigned int inv_jack_detect:1; /* inverted jack-detection */ |
76 | unsigned int inv_eapd:1; /* inverted EAPD implementation */ | ||
76 | 77 | ||
77 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 78 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
78 | struct hda_loopback_check loopback; | 79 | struct hda_loopback_check loopback; |
@@ -156,19 +157,24 @@ static const char *ad_slave_sws[] = { | |||
156 | 157 | ||
157 | static void ad198x_free_kctls(struct hda_codec *codec); | 158 | static void ad198x_free_kctls(struct hda_codec *codec); |
158 | 159 | ||
160 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
159 | /* additional beep mixers; the actual parameters are overwritten at build */ | 161 | /* additional beep mixers; the actual parameters are overwritten at build */ |
160 | static struct snd_kcontrol_new ad_beep_mixer[] = { | 162 | static struct snd_kcontrol_new ad_beep_mixer[] = { |
161 | HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), | 163 | HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), |
162 | HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT), | 164 | HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT), |
163 | { } /* end */ | 165 | { } /* end */ |
164 | }; | 166 | }; |
165 | 167 | ||
166 | #define set_beep_amp(spec, nid, idx, dir) \ | 168 | #define set_beep_amp(spec, nid, idx, dir) \ |
167 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ | 169 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ |
170 | #else | ||
171 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ | ||
172 | #endif | ||
168 | 173 | ||
169 | static int ad198x_build_controls(struct hda_codec *codec) | 174 | static int ad198x_build_controls(struct hda_codec *codec) |
170 | { | 175 | { |
171 | struct ad198x_spec *spec = codec->spec; | 176 | struct ad198x_spec *spec = codec->spec; |
177 | struct snd_kcontrol *kctl; | ||
172 | unsigned int i; | 178 | unsigned int i; |
173 | int err; | 179 | int err; |
174 | 180 | ||
@@ -194,6 +200,7 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
194 | } | 200 | } |
195 | 201 | ||
196 | /* create beep controls if needed */ | 202 | /* create beep controls if needed */ |
203 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
197 | if (spec->beep_amp) { | 204 | if (spec->beep_amp) { |
198 | struct snd_kcontrol_new *knew; | 205 | struct snd_kcontrol_new *knew; |
199 | for (knew = ad_beep_mixer; knew->name; knew++) { | 206 | for (knew = ad_beep_mixer; knew->name; knew++) { |
@@ -202,11 +209,12 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
202 | if (!kctl) | 209 | if (!kctl) |
203 | return -ENOMEM; | 210 | return -ENOMEM; |
204 | kctl->private_value = spec->beep_amp; | 211 | kctl->private_value = spec->beep_amp; |
205 | err = snd_hda_ctl_add(codec, kctl); | 212 | err = snd_hda_ctl_add(codec, 0, kctl); |
206 | if (err < 0) | 213 | if (err < 0) |
207 | return err; | 214 | return err; |
208 | } | 215 | } |
209 | } | 216 | } |
217 | #endif | ||
210 | 218 | ||
211 | /* if we have no master control, let's create it */ | 219 | /* if we have no master control, let's create it */ |
212 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | 220 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { |
@@ -230,6 +238,27 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
230 | } | 238 | } |
231 | 239 | ||
232 | ad198x_free_kctls(codec); /* no longer needed */ | 240 | ad198x_free_kctls(codec); /* no longer needed */ |
241 | |||
242 | /* assign Capture Source enums to NID */ | ||
243 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
244 | if (!kctl) | ||
245 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
246 | for (i = 0; kctl && i < kctl->count; i++) { | ||
247 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); | ||
248 | if (err < 0) | ||
249 | return err; | ||
250 | } | ||
251 | |||
252 | /* assign IEC958 enums to NID */ | ||
253 | kctl = snd_hda_find_mixer_ctl(codec, | ||
254 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
255 | if (kctl) { | ||
256 | err = snd_hda_add_nid(codec, kctl, 0, | ||
257 | spec->multiout.dig_out_nid); | ||
258 | if (err < 0) | ||
259 | return err; | ||
260 | } | ||
261 | |||
233 | return 0; | 262 | return 0; |
234 | } | 263 | } |
235 | 264 | ||
@@ -412,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
412 | return 0; | 441 | return 0; |
413 | } | 442 | } |
414 | 443 | ||
444 | static inline void ad198x_shutup(struct hda_codec *codec) | ||
445 | { | ||
446 | snd_hda_shutup_pins(codec); | ||
447 | } | ||
448 | |||
415 | static void ad198x_free_kctls(struct hda_codec *codec) | 449 | static void ad198x_free_kctls(struct hda_codec *codec) |
416 | { | 450 | { |
417 | struct ad198x_spec *spec = codec->spec; | 451 | struct ad198x_spec *spec = codec->spec; |
@@ -425,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec) | |||
425 | snd_array_free(&spec->kctls); | 459 | snd_array_free(&spec->kctls); |
426 | } | 460 | } |
427 | 461 | ||
462 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | ||
463 | hda_nid_t hp) | ||
464 | { | ||
465 | struct ad198x_spec *spec = codec->spec; | ||
466 | snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
467 | !spec->inv_eapd ? 0x00 : 0x02); | ||
468 | snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
469 | !spec->inv_eapd ? 0x00 : 0x02); | ||
470 | } | ||
471 | |||
472 | static void ad198x_power_eapd(struct hda_codec *codec) | ||
473 | { | ||
474 | /* We currently only handle front, HP */ | ||
475 | switch (codec->vendor_id) { | ||
476 | case 0x11d41882: | ||
477 | case 0x11d4882a: | ||
478 | case 0x11d41884: | ||
479 | case 0x11d41984: | ||
480 | case 0x11d41883: | ||
481 | case 0x11d4184a: | ||
482 | case 0x11d4194a: | ||
483 | case 0x11d4194b: | ||
484 | ad198x_power_eapd_write(codec, 0x12, 0x11); | ||
485 | break; | ||
486 | case 0x11d41981: | ||
487 | case 0x11d41983: | ||
488 | ad198x_power_eapd_write(codec, 0x05, 0x06); | ||
489 | break; | ||
490 | case 0x11d41986: | ||
491 | ad198x_power_eapd_write(codec, 0x1b, 0x1a); | ||
492 | break; | ||
493 | case 0x11d41988: | ||
494 | case 0x11d4198b: | ||
495 | case 0x11d4989a: | ||
496 | case 0x11d4989b: | ||
497 | ad198x_power_eapd_write(codec, 0x29, 0x22); | ||
498 | break; | ||
499 | } | ||
500 | } | ||
501 | |||
428 | static void ad198x_free(struct hda_codec *codec) | 502 | static void ad198x_free(struct hda_codec *codec) |
429 | { | 503 | { |
430 | struct ad198x_spec *spec = codec->spec; | 504 | struct ad198x_spec *spec = codec->spec; |
@@ -432,11 +506,21 @@ static void ad198x_free(struct hda_codec *codec) | |||
432 | if (!spec) | 506 | if (!spec) |
433 | return; | 507 | return; |
434 | 508 | ||
509 | ad198x_shutup(codec); | ||
435 | ad198x_free_kctls(codec); | 510 | ad198x_free_kctls(codec); |
436 | kfree(spec); | 511 | kfree(spec); |
437 | snd_hda_detach_beep_device(codec); | 512 | snd_hda_detach_beep_device(codec); |
438 | } | 513 | } |
439 | 514 | ||
515 | #ifdef SND_HDA_NEEDS_RESUME | ||
516 | static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) | ||
517 | { | ||
518 | ad198x_shutup(codec); | ||
519 | ad198x_power_eapd(codec); | ||
520 | return 0; | ||
521 | } | ||
522 | #endif | ||
523 | |||
440 | static struct hda_codec_ops ad198x_patch_ops = { | 524 | static struct hda_codec_ops ad198x_patch_ops = { |
441 | .build_controls = ad198x_build_controls, | 525 | .build_controls = ad198x_build_controls, |
442 | .build_pcms = ad198x_build_pcms, | 526 | .build_pcms = ad198x_build_pcms, |
@@ -445,12 +529,16 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
445 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 529 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
446 | .check_power_status = ad198x_check_power_status, | 530 | .check_power_status = ad198x_check_power_status, |
447 | #endif | 531 | #endif |
532 | #ifdef SND_HDA_NEEDS_RESUME | ||
533 | .suspend = ad198x_suspend, | ||
534 | #endif | ||
535 | .reboot_notify = ad198x_shutup, | ||
448 | }; | 536 | }; |
449 | 537 | ||
450 | 538 | ||
451 | /* | 539 | /* |
452 | * EAPD control | 540 | * EAPD control |
453 | * the private value = nid | (invert << 8) | 541 | * the private value = nid |
454 | */ | 542 | */ |
455 | #define ad198x_eapd_info snd_ctl_boolean_mono_info | 543 | #define ad198x_eapd_info snd_ctl_boolean_mono_info |
456 | 544 | ||
@@ -459,8 +547,7 @@ static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | |||
459 | { | 547 | { |
460 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 548 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
461 | struct ad198x_spec *spec = codec->spec; | 549 | struct ad198x_spec *spec = codec->spec; |
462 | int invert = (kcontrol->private_value >> 8) & 1; | 550 | if (spec->inv_eapd) |
463 | if (invert) | ||
464 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; | 551 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; |
465 | else | 552 | else |
466 | ucontrol->value.integer.value[0] = spec->cur_eapd; | 553 | ucontrol->value.integer.value[0] = spec->cur_eapd; |
@@ -472,11 +559,10 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | |||
472 | { | 559 | { |
473 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 560 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
474 | struct ad198x_spec *spec = codec->spec; | 561 | struct ad198x_spec *spec = codec->spec; |
475 | int invert = (kcontrol->private_value >> 8) & 1; | ||
476 | hda_nid_t nid = kcontrol->private_value & 0xff; | 562 | hda_nid_t nid = kcontrol->private_value & 0xff; |
477 | unsigned int eapd; | 563 | unsigned int eapd; |
478 | eapd = !!ucontrol->value.integer.value[0]; | 564 | eapd = !!ucontrol->value.integer.value[0]; |
479 | if (invert) | 565 | if (spec->inv_eapd) |
480 | eapd = !eapd; | 566 | eapd = !eapd; |
481 | if (eapd == spec->cur_eapd) | 567 | if (eapd == spec->cur_eapd) |
482 | return 0; | 568 | return 0; |
@@ -694,10 +780,11 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
694 | { | 780 | { |
695 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 781 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
696 | .name = "External Amplifier", | 782 | .name = "External Amplifier", |
783 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
697 | .info = ad198x_eapd_info, | 784 | .info = ad198x_eapd_info, |
698 | .get = ad198x_eapd_get, | 785 | .get = ad198x_eapd_get, |
699 | .put = ad198x_eapd_put, | 786 | .put = ad198x_eapd_put, |
700 | .private_value = 0x1b | (1 << 8), /* port-D, inversed */ | 787 | .private_value = 0x1b, /* port-D */ |
701 | }, | 788 | }, |
702 | { } /* end */ | 789 | { } /* end */ |
703 | }; | 790 | }; |
@@ -712,10 +799,10 @@ static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { | |||
712 | static void ad1986a_automic(struct hda_codec *codec) | 799 | static void ad1986a_automic(struct hda_codec *codec) |
713 | { | 800 | { |
714 | unsigned int present; | 801 | unsigned int present; |
715 | present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0); | 802 | present = snd_hda_jack_detect(codec, 0x1f); |
716 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ | 803 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ |
717 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, | 804 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, |
718 | (present & AC_PINSENSE_PRESENCE) ? 0 : 2); | 805 | present ? 0 : 2); |
719 | } | 806 | } |
720 | 807 | ||
721 | #define AD1986A_MIC_EVENT 0x36 | 808 | #define AD1986A_MIC_EVENT 0x36 |
@@ -754,10 +841,8 @@ static void ad1986a_update_hp(struct hda_codec *codec) | |||
754 | static void ad1986a_hp_automute(struct hda_codec *codec) | 841 | static void ad1986a_hp_automute(struct hda_codec *codec) |
755 | { | 842 | { |
756 | struct ad198x_spec *spec = codec->spec; | 843 | struct ad198x_spec *spec = codec->spec; |
757 | unsigned int present; | ||
758 | 844 | ||
759 | present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); | 845 | spec->jack_present = snd_hda_jack_detect(codec, 0x1a); |
760 | spec->jack_present = !!(present & 0x80000000); | ||
761 | if (spec->inv_jack_detect) | 846 | if (spec->inv_jack_detect) |
762 | spec->jack_present = !spec->jack_present; | 847 | spec->jack_present = !spec->jack_present; |
763 | ad1986a_update_hp(codec); | 848 | ad1986a_update_hp(codec); |
@@ -803,6 +888,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | |||
803 | { | 888 | { |
804 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 889 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
805 | .name = "Master Playback Switch", | 890 | .name = "Master Playback Switch", |
891 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
806 | .info = snd_hda_mixer_amp_switch_info, | 892 | .info = snd_hda_mixer_amp_switch_info, |
807 | .get = snd_hda_mixer_amp_switch_get, | 893 | .get = snd_hda_mixer_amp_switch_get, |
808 | .put = ad1986a_hp_master_sw_put, | 894 | .put = ad1986a_hp_master_sw_put, |
@@ -1003,7 +1089,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | |||
1003 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | 1089 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), |
1004 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | 1090 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), |
1005 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | 1091 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), |
1006 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), | 1092 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), |
1007 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | 1093 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), |
1008 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | 1094 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), |
1009 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), | 1095 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), |
@@ -1068,6 +1154,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
1068 | spec->loopback.amplist = ad1986a_loopbacks; | 1154 | spec->loopback.amplist = ad1986a_loopbacks; |
1069 | #endif | 1155 | #endif |
1070 | spec->vmaster_nid = 0x1b; | 1156 | spec->vmaster_nid = 0x1b; |
1157 | spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ | ||
1071 | 1158 | ||
1072 | codec->patch_ops = ad198x_patch_ops; | 1159 | codec->patch_ops = ad198x_patch_ops; |
1073 | 1160 | ||
@@ -1180,6 +1267,8 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
1180 | */ | 1267 | */ |
1181 | spec->multiout.no_share_stream = 1; | 1268 | spec->multiout.no_share_stream = 1; |
1182 | 1269 | ||
1270 | codec->no_trigger_sense = 1; | ||
1271 | |||
1183 | return 0; | 1272 | return 0; |
1184 | } | 1273 | } |
1185 | 1274 | ||
@@ -1365,6 +1454,8 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1365 | 1454 | ||
1366 | codec->patch_ops = ad198x_patch_ops; | 1455 | codec->patch_ops = ad198x_patch_ops; |
1367 | 1456 | ||
1457 | codec->no_trigger_sense = 1; | ||
1458 | |||
1368 | return 0; | 1459 | return 0; |
1369 | } | 1460 | } |
1370 | 1461 | ||
@@ -1547,8 +1638,7 @@ static void ad1981_hp_automute(struct hda_codec *codec) | |||
1547 | { | 1638 | { |
1548 | unsigned int present; | 1639 | unsigned int present; |
1549 | 1640 | ||
1550 | present = snd_hda_codec_read(codec, 0x06, 0, | 1641 | present = snd_hda_jack_detect(codec, 0x06); |
1551 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1552 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, | 1642 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, |
1553 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 1643 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
1554 | } | 1644 | } |
@@ -1568,8 +1658,7 @@ static void ad1981_hp_automic(struct hda_codec *codec) | |||
1568 | }; | 1658 | }; |
1569 | unsigned int present; | 1659 | unsigned int present; |
1570 | 1660 | ||
1571 | present = snd_hda_codec_read(codec, 0x08, 0, | 1661 | present = snd_hda_jack_detect(codec, 0x08); |
1572 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1573 | if (present) | 1662 | if (present) |
1574 | snd_hda_sequence_write(codec, mic_jack_on); | 1663 | snd_hda_sequence_write(codec, mic_jack_on); |
1575 | else | 1664 | else |
@@ -1604,6 +1693,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { | |||
1604 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | 1693 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), |
1605 | { | 1694 | { |
1606 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1695 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1696 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
1607 | .name = "Master Playback Switch", | 1697 | .name = "Master Playback Switch", |
1608 | .info = ad198x_eapd_info, | 1698 | .info = ad198x_eapd_info, |
1609 | .get = ad198x_eapd_get, | 1699 | .get = ad198x_eapd_get, |
@@ -1785,10 +1875,26 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1785 | 1875 | ||
1786 | codec->patch_ops.init = ad1981_hp_init; | 1876 | codec->patch_ops.init = ad1981_hp_init; |
1787 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | 1877 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; |
1878 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
1879 | * possible damage by overloading | ||
1880 | */ | ||
1881 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
1882 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
1883 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
1884 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
1885 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
1788 | break; | 1886 | break; |
1789 | case AD1981_THINKPAD: | 1887 | case AD1981_THINKPAD: |
1790 | spec->mixers[0] = ad1981_thinkpad_mixers; | 1888 | spec->mixers[0] = ad1981_thinkpad_mixers; |
1791 | spec->input_mux = &ad1981_thinkpad_capture_source; | 1889 | spec->input_mux = &ad1981_thinkpad_capture_source; |
1890 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
1891 | * possible damage by overloading | ||
1892 | */ | ||
1893 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
1894 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
1895 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
1896 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
1897 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
1792 | break; | 1898 | break; |
1793 | case AD1981_TOSHIBA: | 1899 | case AD1981_TOSHIBA: |
1794 | spec->mixers[0] = ad1981_hp_mixers; | 1900 | spec->mixers[0] = ad1981_hp_mixers; |
@@ -1801,6 +1907,9 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1801 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | 1907 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; |
1802 | break; | 1908 | break; |
1803 | } | 1909 | } |
1910 | |||
1911 | codec->no_trigger_sense = 1; | ||
1912 | |||
1804 | return 0; | 1913 | return 0; |
1805 | } | 1914 | } |
1806 | 1915 | ||
@@ -2117,10 +2226,11 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | |||
2117 | { | 2226 | { |
2118 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2227 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2119 | .name = "External Amplifier", | 2228 | .name = "External Amplifier", |
2229 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
2120 | .info = ad198x_eapd_info, | 2230 | .info = ad198x_eapd_info, |
2121 | .get = ad198x_eapd_get, | 2231 | .get = ad198x_eapd_get, |
2122 | .put = ad198x_eapd_put, | 2232 | .put = ad198x_eapd_put, |
2123 | .private_value = 0x12 | (1 << 8), /* port-D, inversed */ | 2233 | .private_value = 0x12, /* port-D */ |
2124 | }, | 2234 | }, |
2125 | 2235 | ||
2126 | { } /* end */ | 2236 | { } /* end */ |
@@ -2238,6 +2348,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | |||
2238 | { | 2348 | { |
2239 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2349 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2240 | .name = "IEC958 Playback Source", | 2350 | .name = "IEC958 Playback Source", |
2351 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
2241 | .info = ad1988_spdif_playback_source_info, | 2352 | .info = ad1988_spdif_playback_source_info, |
2242 | .get = ad1988_spdif_playback_source_get, | 2353 | .get = ad1988_spdif_playback_source_get, |
2243 | .put = ad1988_spdif_playback_source_put, | 2354 | .put = ad1988_spdif_playback_source_put, |
@@ -2353,6 +2464,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { | |||
2353 | { } | 2464 | { } |
2354 | }; | 2465 | }; |
2355 | 2466 | ||
2467 | static struct hda_verb ad1988_spdif_in_init_verbs[] = { | ||
2468 | /* unmute SPDIF input pin */ | ||
2469 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2470 | { } | ||
2471 | }; | ||
2472 | |||
2356 | /* AD1989 has no ADC -> SPDIF route */ | 2473 | /* AD1989 has no ADC -> SPDIF route */ |
2357 | static struct hda_verb ad1989_spdif_init_verbs[] = { | 2474 | static struct hda_verb ad1989_spdif_init_verbs[] = { |
2358 | /* SPDIF-1 out pin */ | 2475 | /* SPDIF-1 out pin */ |
@@ -2524,7 +2641,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2524 | { | 2641 | { |
2525 | if ((res >> 26) != AD1988_HP_EVENT) | 2642 | if ((res >> 26) != AD1988_HP_EVENT) |
2526 | return; | 2643 | return; |
2527 | if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31)) | 2644 | if (snd_hda_jack_detect(codec, 0x11)) |
2528 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); | 2645 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); |
2529 | else | 2646 | else |
2530 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | 2647 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); |
@@ -2569,6 +2686,8 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, | |||
2569 | knew->name = kstrdup(name, GFP_KERNEL); | 2686 | knew->name = kstrdup(name, GFP_KERNEL); |
2570 | if (! knew->name) | 2687 | if (! knew->name) |
2571 | return -ENOMEM; | 2688 | return -ENOMEM; |
2689 | if (get_amp_nid_(val)) | ||
2690 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; | ||
2572 | knew->private_value = val; | 2691 | knew->private_value = val; |
2573 | return 0; | 2692 | return 0; |
2574 | } | 2693 | } |
@@ -3059,6 +3178,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3059 | spec->input_mux = &ad1988_laptop_capture_source; | 3178 | spec->input_mux = &ad1988_laptop_capture_source; |
3060 | spec->num_mixers = 1; | 3179 | spec->num_mixers = 1; |
3061 | spec->mixers[0] = ad1988_laptop_mixers; | 3180 | spec->mixers[0] = ad1988_laptop_mixers; |
3181 | spec->inv_eapd = 1; /* inverted EAPD */ | ||
3062 | spec->num_init_verbs = 1; | 3182 | spec->num_init_verbs = 1; |
3063 | spec->init_verbs[0] = ad1988_laptop_init_verbs; | 3183 | spec->init_verbs[0] = ad1988_laptop_init_verbs; |
3064 | if (board_config == AD1988_LAPTOP_DIG) | 3184 | if (board_config == AD1988_LAPTOP_DIG) |
@@ -3085,8 +3205,11 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3085 | ad1988_spdif_init_verbs; | 3205 | ad1988_spdif_init_verbs; |
3086 | } | 3206 | } |
3087 | } | 3207 | } |
3088 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) | 3208 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { |
3089 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | 3209 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; |
3210 | spec->init_verbs[spec->num_init_verbs++] = | ||
3211 | ad1988_spdif_in_init_verbs; | ||
3212 | } | ||
3090 | 3213 | ||
3091 | codec->patch_ops = ad198x_patch_ops; | 3214 | codec->patch_ops = ad198x_patch_ops; |
3092 | switch (board_config) { | 3215 | switch (board_config) { |
@@ -3103,6 +3226,8 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3103 | #endif | 3226 | #endif |
3104 | spec->vmaster_nid = 0x04; | 3227 | spec->vmaster_nid = 0x04; |
3105 | 3228 | ||
3229 | codec->no_trigger_sense = 1; | ||
3230 | |||
3106 | return 0; | 3231 | return 0; |
3107 | } | 3232 | } |
3108 | 3233 | ||
@@ -3315,6 +3440,8 @@ static int patch_ad1884(struct hda_codec *codec) | |||
3315 | 3440 | ||
3316 | codec->patch_ops = ad198x_patch_ops; | 3441 | codec->patch_ops = ad198x_patch_ops; |
3317 | 3442 | ||
3443 | codec->no_trigger_sense = 1; | ||
3444 | |||
3318 | return 0; | 3445 | return 0; |
3319 | } | 3446 | } |
3320 | 3447 | ||
@@ -3721,6 +3848,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | |||
3721 | { | 3848 | { |
3722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3849 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3723 | .name = "Master Playback Switch", | 3850 | .name = "Master Playback Switch", |
3851 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
3724 | .info = snd_hda_mixer_amp_switch_info, | 3852 | .info = snd_hda_mixer_amp_switch_info, |
3725 | .get = snd_hda_mixer_amp_switch_get, | 3853 | .get = snd_hda_mixer_amp_switch_get, |
3726 | .put = ad1884a_mobile_master_sw_put, | 3854 | .put = ad1884a_mobile_master_sw_put, |
@@ -3749,6 +3877,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | |||
3749 | { | 3877 | { |
3750 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3878 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3751 | .name = "Master Playback Switch", | 3879 | .name = "Master Playback Switch", |
3880 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
3752 | .info = snd_hda_mixer_amp_switch_info, | 3881 | .info = snd_hda_mixer_amp_switch_info, |
3753 | .get = snd_hda_mixer_amp_switch_get, | 3882 | .get = snd_hda_mixer_amp_switch_get, |
3754 | .put = ad1884a_mobile_master_sw_put, | 3883 | .put = ad1884a_mobile_master_sw_put, |
@@ -3768,8 +3897,7 @@ static void ad1884a_hp_automute(struct hda_codec *codec) | |||
3768 | { | 3897 | { |
3769 | unsigned int present; | 3898 | unsigned int present; |
3770 | 3899 | ||
3771 | present = snd_hda_codec_read(codec, 0x11, 0, | 3900 | present = snd_hda_jack_detect(codec, 0x11); |
3772 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
3773 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | 3901 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, |
3774 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 3902 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
3775 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | 3903 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, |
@@ -3781,8 +3909,7 @@ static void ad1884a_hp_automic(struct hda_codec *codec) | |||
3781 | { | 3909 | { |
3782 | unsigned int present; | 3910 | unsigned int present; |
3783 | 3911 | ||
3784 | present = snd_hda_codec_read(codec, 0x14, 0, | 3912 | present = snd_hda_jack_detect(codec, 0x14); |
3785 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
3786 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, | 3913 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, |
3787 | present ? 0 : 1); | 3914 | present ? 0 : 1); |
3788 | } | 3915 | } |
@@ -3817,13 +3944,9 @@ static void ad1884a_laptop_automute(struct hda_codec *codec) | |||
3817 | { | 3944 | { |
3818 | unsigned int present; | 3945 | unsigned int present; |
3819 | 3946 | ||
3820 | present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0); | 3947 | present = snd_hda_jack_detect(codec, 0x11); |
3821 | present &= AC_PINSENSE_PRESENCE; | 3948 | if (!present) |
3822 | if (!present) { | 3949 | present = snd_hda_jack_detect(codec, 0x12); |
3823 | present = snd_hda_codec_read(codec, 0x12, 0, | ||
3824 | AC_VERB_GET_PIN_SENSE, 0); | ||
3825 | present &= AC_PINSENSE_PRESENCE; | ||
3826 | } | ||
3827 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | 3950 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, |
3828 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 3951 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
3829 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | 3952 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, |
@@ -3835,11 +3958,9 @@ static void ad1884a_laptop_automic(struct hda_codec *codec) | |||
3835 | { | 3958 | { |
3836 | unsigned int idx; | 3959 | unsigned int idx; |
3837 | 3960 | ||
3838 | if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & | 3961 | if (snd_hda_jack_detect(codec, 0x14)) |
3839 | AC_PINSENSE_PRESENCE) | ||
3840 | idx = 0; | 3962 | idx = 0; |
3841 | else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & | 3963 | else if (snd_hda_jack_detect(codec, 0x1c)) |
3842 | AC_PINSENSE_PRESENCE) | ||
3843 | idx = 4; | 3964 | idx = 4; |
3844 | else | 3965 | else |
3845 | idx = 1; | 3966 | idx = 1; |
@@ -4008,8 +4129,7 @@ static void ad1984a_thinkpad_automute(struct hda_codec *codec) | |||
4008 | { | 4129 | { |
4009 | unsigned int present; | 4130 | unsigned int present; |
4010 | 4131 | ||
4011 | present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) | 4132 | present = snd_hda_jack_detect(codec, 0x11); |
4012 | & AC_PINSENSE_PRESENCE; | ||
4013 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | 4133 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, |
4014 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 4134 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
4015 | } | 4135 | } |
@@ -4099,6 +4219,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | |||
4099 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | 4219 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ |
4100 | { | 4220 | { |
4101 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4221 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
4222 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4102 | .name = "Master Playback Switch", | 4223 | .name = "Master Playback Switch", |
4103 | .info = snd_hda_mixer_amp_switch_info, | 4224 | .info = snd_hda_mixer_amp_switch_info, |
4104 | .get = snd_hda_mixer_amp_switch_get, | 4225 | .get = snd_hda_mixer_amp_switch_get, |
@@ -4117,14 +4238,12 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | |||
4117 | /* switch to external mic if plugged */ | 4238 | /* switch to external mic if plugged */ |
4118 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) | 4239 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) |
4119 | { | 4240 | { |
4120 | if (snd_hda_codec_read(codec, 0x1c, 0, | 4241 | if (snd_hda_jack_detect(codec, 0x1c)) |
4121 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) { | ||
4122 | snd_hda_codec_write(codec, 0x0c, 0, | 4242 | snd_hda_codec_write(codec, 0x0c, 0, |
4123 | AC_VERB_SET_CONNECT_SEL, 0x4); | 4243 | AC_VERB_SET_CONNECT_SEL, 0x4); |
4124 | } else { | 4244 | else |
4125 | snd_hda_codec_write(codec, 0x0c, 0, | 4245 | snd_hda_codec_write(codec, 0x0c, 0, |
4126 | AC_VERB_SET_CONNECT_SEL, 0x5); | 4246 | AC_VERB_SET_CONNECT_SEL, 0x5); |
4127 | } | ||
4128 | } | 4247 | } |
4129 | 4248 | ||
4130 | 4249 | ||
@@ -4283,6 +4402,8 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
4283 | break; | 4402 | break; |
4284 | } | 4403 | } |
4285 | 4404 | ||
4405 | codec->no_trigger_sense = 1; | ||
4406 | |||
4286 | return 0; | 4407 | return 0; |
4287 | } | 4408 | } |
4288 | 4409 | ||
@@ -4619,6 +4740,9 @@ static int patch_ad1882(struct hda_codec *codec) | |||
4619 | spec->mixers[2] = ad1882_6stack_mixers; | 4740 | spec->mixers[2] = ad1882_6stack_mixers; |
4620 | break; | 4741 | break; |
4621 | } | 4742 | } |
4743 | |||
4744 | codec->no_trigger_sense = 1; | ||
4745 | |||
4622 | return 0; | 4746 | return 0; |
4623 | } | 4747 | } |
4624 | 4748 | ||