diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 86 |
1 files changed, 45 insertions, 41 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2d603f6aba63..1a36137e13ec 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,15 +157,19 @@ 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 | { |
@@ -194,6 +199,7 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
194 | } | 199 | } |
195 | 200 | ||
196 | /* create beep controls if needed */ | 201 | /* create beep controls if needed */ |
202 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
197 | if (spec->beep_amp) { | 203 | if (spec->beep_amp) { |
198 | struct snd_kcontrol_new *knew; | 204 | struct snd_kcontrol_new *knew; |
199 | for (knew = ad_beep_mixer; knew->name; knew++) { | 205 | for (knew = ad_beep_mixer; knew->name; knew++) { |
@@ -202,11 +208,14 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
202 | if (!kctl) | 208 | if (!kctl) |
203 | return -ENOMEM; | 209 | return -ENOMEM; |
204 | kctl->private_value = spec->beep_amp; | 210 | kctl->private_value = spec->beep_amp; |
205 | err = snd_hda_ctl_add(codec, kctl); | 211 | err = snd_hda_ctl_add(codec, |
212 | get_amp_nid_(spec->beep_amp), | ||
213 | kctl); | ||
206 | if (err < 0) | 214 | if (err < 0) |
207 | return err; | 215 | return err; |
208 | } | 216 | } |
209 | } | 217 | } |
218 | #endif | ||
210 | 219 | ||
211 | /* if we have no master control, let's create it */ | 220 | /* if we have no master control, let's create it */ |
212 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | 221 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { |
@@ -450,7 +459,7 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
450 | 459 | ||
451 | /* | 460 | /* |
452 | * EAPD control | 461 | * EAPD control |
453 | * the private value = nid | (invert << 8) | 462 | * the private value = nid |
454 | */ | 463 | */ |
455 | #define ad198x_eapd_info snd_ctl_boolean_mono_info | 464 | #define ad198x_eapd_info snd_ctl_boolean_mono_info |
456 | 465 | ||
@@ -459,8 +468,7 @@ static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | |||
459 | { | 468 | { |
460 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 469 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
461 | struct ad198x_spec *spec = codec->spec; | 470 | struct ad198x_spec *spec = codec->spec; |
462 | int invert = (kcontrol->private_value >> 8) & 1; | 471 | if (spec->inv_eapd) |
463 | if (invert) | ||
464 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; | 472 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; |
465 | else | 473 | else |
466 | ucontrol->value.integer.value[0] = spec->cur_eapd; | 474 | ucontrol->value.integer.value[0] = spec->cur_eapd; |
@@ -472,11 +480,10 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | |||
472 | { | 480 | { |
473 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 481 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
474 | struct ad198x_spec *spec = codec->spec; | 482 | struct ad198x_spec *spec = codec->spec; |
475 | int invert = (kcontrol->private_value >> 8) & 1; | ||
476 | hda_nid_t nid = kcontrol->private_value & 0xff; | 483 | hda_nid_t nid = kcontrol->private_value & 0xff; |
477 | unsigned int eapd; | 484 | unsigned int eapd; |
478 | eapd = !!ucontrol->value.integer.value[0]; | 485 | eapd = !!ucontrol->value.integer.value[0]; |
479 | if (invert) | 486 | if (spec->inv_eapd) |
480 | eapd = !eapd; | 487 | eapd = !eapd; |
481 | if (eapd == spec->cur_eapd) | 488 | if (eapd == spec->cur_eapd) |
482 | return 0; | 489 | return 0; |
@@ -697,7 +704,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
697 | .info = ad198x_eapd_info, | 704 | .info = ad198x_eapd_info, |
698 | .get = ad198x_eapd_get, | 705 | .get = ad198x_eapd_get, |
699 | .put = ad198x_eapd_put, | 706 | .put = ad198x_eapd_put, |
700 | .private_value = 0x1b | (1 << 8), /* port-D, inversed */ | 707 | .private_value = 0x1b, /* port-D */ |
701 | }, | 708 | }, |
702 | { } /* end */ | 709 | { } /* end */ |
703 | }; | 710 | }; |
@@ -712,10 +719,10 @@ static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { | |||
712 | static void ad1986a_automic(struct hda_codec *codec) | 719 | static void ad1986a_automic(struct hda_codec *codec) |
713 | { | 720 | { |
714 | unsigned int present; | 721 | unsigned int present; |
715 | present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0); | 722 | present = snd_hda_jack_detect(codec, 0x1f); |
716 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ | 723 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ |
717 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, | 724 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, |
718 | (present & AC_PINSENSE_PRESENCE) ? 0 : 2); | 725 | present ? 0 : 2); |
719 | } | 726 | } |
720 | 727 | ||
721 | #define AD1986A_MIC_EVENT 0x36 | 728 | #define AD1986A_MIC_EVENT 0x36 |
@@ -754,10 +761,8 @@ static void ad1986a_update_hp(struct hda_codec *codec) | |||
754 | static void ad1986a_hp_automute(struct hda_codec *codec) | 761 | static void ad1986a_hp_automute(struct hda_codec *codec) |
755 | { | 762 | { |
756 | struct ad198x_spec *spec = codec->spec; | 763 | struct ad198x_spec *spec = codec->spec; |
757 | unsigned int present; | ||
758 | 764 | ||
759 | present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); | 765 | spec->jack_present = snd_hda_jack_detect(codec, 0x1a); |
760 | spec->jack_present = !!(present & 0x80000000); | ||
761 | if (spec->inv_jack_detect) | 766 | if (spec->inv_jack_detect) |
762 | spec->jack_present = !spec->jack_present; | 767 | spec->jack_present = !spec->jack_present; |
763 | ad1986a_update_hp(codec); | 768 | ad1986a_update_hp(codec); |
@@ -1068,6 +1073,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
1068 | spec->loopback.amplist = ad1986a_loopbacks; | 1073 | spec->loopback.amplist = ad1986a_loopbacks; |
1069 | #endif | 1074 | #endif |
1070 | spec->vmaster_nid = 0x1b; | 1075 | spec->vmaster_nid = 0x1b; |
1076 | spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ | ||
1071 | 1077 | ||
1072 | codec->patch_ops = ad198x_patch_ops; | 1078 | codec->patch_ops = ad198x_patch_ops; |
1073 | 1079 | ||
@@ -1547,8 +1553,7 @@ static void ad1981_hp_automute(struct hda_codec *codec) | |||
1547 | { | 1553 | { |
1548 | unsigned int present; | 1554 | unsigned int present; |
1549 | 1555 | ||
1550 | present = snd_hda_codec_read(codec, 0x06, 0, | 1556 | 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, | 1557 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, |
1553 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 1558 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
1554 | } | 1559 | } |
@@ -1568,8 +1573,7 @@ static void ad1981_hp_automic(struct hda_codec *codec) | |||
1568 | }; | 1573 | }; |
1569 | unsigned int present; | 1574 | unsigned int present; |
1570 | 1575 | ||
1571 | present = snd_hda_codec_read(codec, 0x08, 0, | 1576 | present = snd_hda_jack_detect(codec, 0x08); |
1572 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1573 | if (present) | 1577 | if (present) |
1574 | snd_hda_sequence_write(codec, mic_jack_on); | 1578 | snd_hda_sequence_write(codec, mic_jack_on); |
1575 | else | 1579 | else |
@@ -1785,6 +1789,14 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1785 | 1789 | ||
1786 | codec->patch_ops.init = ad1981_hp_init; | 1790 | codec->patch_ops.init = ad1981_hp_init; |
1787 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | 1791 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; |
1792 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
1793 | * possible damage by overloading | ||
1794 | */ | ||
1795 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
1796 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
1797 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
1798 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
1799 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
1788 | break; | 1800 | break; |
1789 | case AD1981_THINKPAD: | 1801 | case AD1981_THINKPAD: |
1790 | spec->mixers[0] = ad1981_thinkpad_mixers; | 1802 | spec->mixers[0] = ad1981_thinkpad_mixers; |
@@ -2120,7 +2132,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | |||
2120 | .info = ad198x_eapd_info, | 2132 | .info = ad198x_eapd_info, |
2121 | .get = ad198x_eapd_get, | 2133 | .get = ad198x_eapd_get, |
2122 | .put = ad198x_eapd_put, | 2134 | .put = ad198x_eapd_put, |
2123 | .private_value = 0x12 | (1 << 8), /* port-D, inversed */ | 2135 | .private_value = 0x12, /* port-D */ |
2124 | }, | 2136 | }, |
2125 | 2137 | ||
2126 | { } /* end */ | 2138 | { } /* end */ |
@@ -2524,7 +2536,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2524 | { | 2536 | { |
2525 | if ((res >> 26) != AD1988_HP_EVENT) | 2537 | if ((res >> 26) != AD1988_HP_EVENT) |
2526 | return; | 2538 | return; |
2527 | if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31)) | 2539 | if (snd_hda_jack_detect(codec, 0x11)) |
2528 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); | 2540 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); |
2529 | else | 2541 | else |
2530 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | 2542 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); |
@@ -2569,6 +2581,8 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, | |||
2569 | knew->name = kstrdup(name, GFP_KERNEL); | 2581 | knew->name = kstrdup(name, GFP_KERNEL); |
2570 | if (! knew->name) | 2582 | if (! knew->name) |
2571 | return -ENOMEM; | 2583 | return -ENOMEM; |
2584 | if (get_amp_nid_(val)) | ||
2585 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | ||
2572 | knew->private_value = val; | 2586 | knew->private_value = val; |
2573 | return 0; | 2587 | return 0; |
2574 | } | 2588 | } |
@@ -3059,6 +3073,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3059 | spec->input_mux = &ad1988_laptop_capture_source; | 3073 | spec->input_mux = &ad1988_laptop_capture_source; |
3060 | spec->num_mixers = 1; | 3074 | spec->num_mixers = 1; |
3061 | spec->mixers[0] = ad1988_laptop_mixers; | 3075 | spec->mixers[0] = ad1988_laptop_mixers; |
3076 | spec->inv_eapd = 1; /* inverted EAPD */ | ||
3062 | spec->num_init_verbs = 1; | 3077 | spec->num_init_verbs = 1; |
3063 | spec->init_verbs[0] = ad1988_laptop_init_verbs; | 3078 | spec->init_verbs[0] = ad1988_laptop_init_verbs; |
3064 | if (board_config == AD1988_LAPTOP_DIG) | 3079 | if (board_config == AD1988_LAPTOP_DIG) |
@@ -3768,8 +3783,7 @@ static void ad1884a_hp_automute(struct hda_codec *codec) | |||
3768 | { | 3783 | { |
3769 | unsigned int present; | 3784 | unsigned int present; |
3770 | 3785 | ||
3771 | present = snd_hda_codec_read(codec, 0x11, 0, | 3786 | 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, | 3787 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, |
3774 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 3788 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
3775 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | 3789 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, |
@@ -3781,8 +3795,7 @@ static void ad1884a_hp_automic(struct hda_codec *codec) | |||
3781 | { | 3795 | { |
3782 | unsigned int present; | 3796 | unsigned int present; |
3783 | 3797 | ||
3784 | present = snd_hda_codec_read(codec, 0x14, 0, | 3798 | 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, | 3799 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, |
3787 | present ? 0 : 1); | 3800 | present ? 0 : 1); |
3788 | } | 3801 | } |
@@ -3817,13 +3830,9 @@ static void ad1884a_laptop_automute(struct hda_codec *codec) | |||
3817 | { | 3830 | { |
3818 | unsigned int present; | 3831 | unsigned int present; |
3819 | 3832 | ||
3820 | present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0); | 3833 | present = snd_hda_jack_detect(codec, 0x11); |
3821 | present &= AC_PINSENSE_PRESENCE; | 3834 | if (!present) |
3822 | if (!present) { | 3835 | 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, | 3836 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, |
3828 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 3837 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
3829 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | 3838 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, |
@@ -3835,11 +3844,9 @@ static void ad1884a_laptop_automic(struct hda_codec *codec) | |||
3835 | { | 3844 | { |
3836 | unsigned int idx; | 3845 | unsigned int idx; |
3837 | 3846 | ||
3838 | if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & | 3847 | if (snd_hda_jack_detect(codec, 0x14)) |
3839 | AC_PINSENSE_PRESENCE) | ||
3840 | idx = 0; | 3848 | idx = 0; |
3841 | else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & | 3849 | else if (snd_hda_jack_detect(codec, 0x1c)) |
3842 | AC_PINSENSE_PRESENCE) | ||
3843 | idx = 4; | 3850 | idx = 4; |
3844 | else | 3851 | else |
3845 | idx = 1; | 3852 | idx = 1; |
@@ -4008,8 +4015,7 @@ static void ad1984a_thinkpad_automute(struct hda_codec *codec) | |||
4008 | { | 4015 | { |
4009 | unsigned int present; | 4016 | unsigned int present; |
4010 | 4017 | ||
4011 | present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) | 4018 | present = snd_hda_jack_detect(codec, 0x11); |
4012 | & AC_PINSENSE_PRESENCE; | ||
4013 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | 4019 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, |
4014 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 4020 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
4015 | } | 4021 | } |
@@ -4117,14 +4123,12 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | |||
4117 | /* switch to external mic if plugged */ | 4123 | /* switch to external mic if plugged */ |
4118 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) | 4124 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) |
4119 | { | 4125 | { |
4120 | if (snd_hda_codec_read(codec, 0x1c, 0, | 4126 | if (snd_hda_jack_detect(codec, 0x1c)) |
4121 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) { | ||
4122 | snd_hda_codec_write(codec, 0x0c, 0, | 4127 | snd_hda_codec_write(codec, 0x0c, 0, |
4123 | AC_VERB_SET_CONNECT_SEL, 0x4); | 4128 | AC_VERB_SET_CONNECT_SEL, 0x4); |
4124 | } else { | 4129 | else |
4125 | snd_hda_codec_write(codec, 0x0c, 0, | 4130 | snd_hda_codec_write(codec, 0x0c, 0, |
4126 | AC_VERB_SET_CONNECT_SEL, 0x5); | 4131 | AC_VERB_SET_CONNECT_SEL, 0x5); |
4127 | } | ||
4128 | } | 4132 | } |
4129 | 4133 | ||
4130 | 4134 | ||