diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
| -rw-r--r-- | sound/pci/hda/patch_analog.c | 581 |
1 files changed, 564 insertions, 17 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index c8649282c2cf..e0a605adde42 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <sound/core.h> | 28 | #include <sound/core.h> |
| 29 | #include "hda_codec.h" | 29 | #include "hda_codec.h" |
| 30 | #include "hda_local.h" | 30 | #include "hda_local.h" |
| 31 | #include "hda_patch.h" | ||
| 31 | 32 | ||
| 32 | struct ad198x_spec { | 33 | struct ad198x_spec { |
| 33 | struct snd_kcontrol_new *mixers[5]; | 34 | struct snd_kcontrol_new *mixers[5]; |
| @@ -80,7 +81,6 @@ struct ad198x_spec { | |||
| 80 | #endif | 81 | #endif |
| 81 | /* for virtual master */ | 82 | /* for virtual master */ |
| 82 | hda_nid_t vmaster_nid; | 83 | hda_nid_t vmaster_nid; |
| 83 | u32 vmaster_tlv[4]; | ||
| 84 | const char **slave_vols; | 84 | const char **slave_vols; |
| 85 | const char **slave_sws; | 85 | const char **slave_sws; |
| 86 | }; | 86 | }; |
| @@ -171,6 +171,11 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
| 171 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 171 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); |
| 172 | if (err < 0) | 172 | if (err < 0) |
| 173 | return err; | 173 | return err; |
| 174 | err = snd_hda_create_spdif_share_sw(codec, | ||
| 175 | &spec->multiout); | ||
| 176 | if (err < 0) | ||
| 177 | return err; | ||
| 178 | spec->multiout.share_spdif = 1; | ||
| 174 | } | 179 | } |
| 175 | if (spec->dig_in_nid) { | 180 | if (spec->dig_in_nid) { |
| 176 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | 181 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); |
| @@ -180,10 +185,11 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
| 180 | 185 | ||
| 181 | /* if we have no master control, let's create it */ | 186 | /* if we have no master control, let's create it */ |
| 182 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | 187 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { |
| 188 | unsigned int vmaster_tlv[4]; | ||
| 183 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | 189 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, |
| 184 | HDA_OUTPUT, spec->vmaster_tlv); | 190 | HDA_OUTPUT, vmaster_tlv); |
| 185 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | 191 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", |
| 186 | spec->vmaster_tlv, | 192 | vmaster_tlv, |
| 187 | (spec->slave_vols ? | 193 | (spec->slave_vols ? |
| 188 | spec->slave_vols : ad_slave_vols)); | 194 | spec->slave_vols : ad_slave_vols)); |
| 189 | if (err < 0) | 195 | if (err < 0) |
| @@ -217,7 +223,8 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, | |||
| 217 | struct snd_pcm_substream *substream) | 223 | struct snd_pcm_substream *substream) |
| 218 | { | 224 | { |
| 219 | struct ad198x_spec *spec = codec->spec; | 225 | struct ad198x_spec *spec = codec->spec; |
| 220 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | 226 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, |
| 227 | hinfo); | ||
| 221 | } | 228 | } |
| 222 | 229 | ||
| 223 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 230 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
| @@ -289,8 +296,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
| 289 | struct snd_pcm_substream *substream) | 296 | struct snd_pcm_substream *substream) |
| 290 | { | 297 | { |
| 291 | struct ad198x_spec *spec = codec->spec; | 298 | struct ad198x_spec *spec = codec->spec; |
| 292 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 299 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); |
| 293 | 0, 0, 0); | ||
| 294 | return 0; | 300 | return 0; |
| 295 | } | 301 | } |
| 296 | 302 | ||
| @@ -359,6 +365,7 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
| 359 | info++; | 365 | info++; |
| 360 | codec->num_pcms++; | 366 | codec->num_pcms++; |
| 361 | info->name = "AD198x Digital"; | 367 | info->name = "AD198x Digital"; |
| 368 | info->pcm_type = HDA_PCM_TYPE_SPDIF; | ||
| 362 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; | 369 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; |
| 363 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | 370 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; |
| 364 | if (spec->dig_in_nid) { | 371 | if (spec->dig_in_nid) { |
| @@ -611,13 +618,19 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | |||
| 611 | }, | 618 | }, |
| 612 | }; | 619 | }; |
| 613 | 620 | ||
| 621 | static struct hda_input_mux ad1986a_automic_capture_source = { | ||
| 622 | .num_items = 2, | ||
| 623 | .items = { | ||
| 624 | { "Mic", 0x0 }, | ||
| 625 | { "Mix", 0x5 }, | ||
| 626 | }, | ||
| 627 | }; | ||
| 628 | |||
| 614 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | 629 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { |
| 615 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | 630 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), |
| 616 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | 631 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), |
| 617 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 632 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
| 618 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | 633 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), |
| 619 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
| 620 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
| 621 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | 634 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), |
| 622 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | 635 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), |
| 623 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | 636 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), |
| @@ -641,6 +654,33 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
| 641 | { } /* end */ | 654 | { } /* end */ |
| 642 | }; | 655 | }; |
| 643 | 656 | ||
| 657 | /* re-connect the mic boost input according to the jack sensing */ | ||
| 658 | static void ad1986a_automic(struct hda_codec *codec) | ||
| 659 | { | ||
| 660 | unsigned int present; | ||
| 661 | present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
| 662 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ | ||
| 663 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, | ||
| 664 | (present & AC_PINSENSE_PRESENCE) ? 0 : 2); | ||
| 665 | } | ||
| 666 | |||
| 667 | #define AD1986A_MIC_EVENT 0x36 | ||
| 668 | |||
| 669 | static void ad1986a_automic_unsol_event(struct hda_codec *codec, | ||
| 670 | unsigned int res) | ||
| 671 | { | ||
| 672 | if ((res >> 26) != AD1986A_MIC_EVENT) | ||
| 673 | return; | ||
| 674 | ad1986a_automic(codec); | ||
| 675 | } | ||
| 676 | |||
| 677 | static int ad1986a_automic_init(struct hda_codec *codec) | ||
| 678 | { | ||
| 679 | ad198x_init(codec); | ||
| 680 | ad1986a_automic(codec); | ||
| 681 | return 0; | ||
| 682 | } | ||
| 683 | |||
| 644 | /* laptop-automute - 2ch only */ | 684 | /* laptop-automute - 2ch only */ |
| 645 | 685 | ||
| 646 | static void ad1986a_update_hp(struct hda_codec *codec) | 686 | static void ad1986a_update_hp(struct hda_codec *codec) |
| @@ -844,6 +884,15 @@ static struct hda_verb ad1986a_eapd_init_verbs[] = { | |||
| 844 | {} | 884 | {} |
| 845 | }; | 885 | }; |
| 846 | 886 | ||
| 887 | static struct hda_verb ad1986a_automic_verbs[] = { | ||
| 888 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
| 889 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
| 890 | /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ | ||
| 891 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
| 892 | {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT}, | ||
| 893 | {} | ||
| 894 | }; | ||
| 895 | |||
| 847 | /* Ultra initialization */ | 896 | /* Ultra initialization */ |
| 848 | static struct hda_verb ad1986a_ultra_init[] = { | 897 | static struct hda_verb ad1986a_ultra_init[] = { |
| 849 | /* eapd initialization */ | 898 | /* eapd initialization */ |
| @@ -986,14 +1035,17 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
| 986 | break; | 1035 | break; |
| 987 | case AD1986A_LAPTOP_EAPD: | 1036 | case AD1986A_LAPTOP_EAPD: |
| 988 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | 1037 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; |
| 989 | spec->num_init_verbs = 2; | 1038 | spec->num_init_verbs = 3; |
| 990 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | 1039 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; |
| 1040 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
| 991 | spec->multiout.max_channels = 2; | 1041 | spec->multiout.max_channels = 2; |
| 992 | spec->multiout.num_dacs = 1; | 1042 | spec->multiout.num_dacs = 1; |
| 993 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | 1043 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; |
| 994 | if (!is_jack_available(codec, 0x25)) | 1044 | if (!is_jack_available(codec, 0x25)) |
| 995 | spec->multiout.dig_out_nid = 0; | 1045 | spec->multiout.dig_out_nid = 0; |
| 996 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 1046 | spec->input_mux = &ad1986a_automic_capture_source; |
| 1047 | codec->patch_ops.unsol_event = ad1986a_automic_unsol_event; | ||
| 1048 | codec->patch_ops.init = ad1986a_automic_init; | ||
| 997 | break; | 1049 | break; |
| 998 | case AD1986A_LAPTOP_AUTOMUTE: | 1050 | case AD1986A_LAPTOP_AUTOMUTE: |
| 999 | spec->mixers[0] = ad1986a_laptop_automute_mixers; | 1051 | spec->mixers[0] = ad1986a_laptop_automute_mixers; |
| @@ -1365,7 +1417,10 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
| 1365 | 1417 | ||
| 1366 | if (! ad198x_eapd_put(kcontrol, ucontrol)) | 1418 | if (! ad198x_eapd_put(kcontrol, ucontrol)) |
| 1367 | return 0; | 1419 | return 0; |
| 1368 | 1420 | /* change speaker pin appropriately */ | |
| 1421 | snd_hda_codec_write(codec, 0x05, 0, | ||
| 1422 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 1423 | spec->cur_eapd ? PIN_OUT : 0); | ||
| 1369 | /* toggle HP mute appropriately */ | 1424 | /* toggle HP mute appropriately */ |
| 1370 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, | 1425 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, |
| 1371 | HDA_AMP_MUTE, | 1426 | HDA_AMP_MUTE, |
| @@ -2087,6 +2142,10 @@ static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { | |||
| 2087 | { } /* end */ | 2142 | { } /* end */ |
| 2088 | }; | 2143 | }; |
| 2089 | 2144 | ||
| 2145 | static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { | ||
| 2146 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
| 2147 | { } /* end */ | ||
| 2148 | }; | ||
| 2090 | 2149 | ||
| 2091 | /* | 2150 | /* |
| 2092 | * initialization verbs | 2151 | * initialization verbs |
| @@ -2187,6 +2246,13 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { | |||
| 2187 | { } | 2246 | { } |
| 2188 | }; | 2247 | }; |
| 2189 | 2248 | ||
| 2249 | /* AD1989 has no ADC -> SPDIF route */ | ||
| 2250 | static struct hda_verb ad1989_spdif_init_verbs[] = { | ||
| 2251 | /* SPDIF out pin */ | ||
| 2252 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
| 2253 | { } | ||
| 2254 | }; | ||
| 2255 | |||
| 2190 | /* | 2256 | /* |
| 2191 | * verbs for 3stack (+dig) | 2257 | * verbs for 3stack (+dig) |
| 2192 | */ | 2258 | */ |
| @@ -2894,10 +2960,19 @@ static int patch_ad1988(struct hda_codec *codec) | |||
| 2894 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; | 2960 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; |
| 2895 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; | 2961 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; |
| 2896 | if (spec->multiout.dig_out_nid) { | 2962 | if (spec->multiout.dig_out_nid) { |
| 2897 | spec->mixers[spec->num_mixers++] = ad1988_spdif_out_mixers; | 2963 | if (codec->vendor_id >= 0x11d4989a) { |
| 2898 | spec->init_verbs[spec->num_init_verbs++] = ad1988_spdif_init_verbs; | 2964 | spec->mixers[spec->num_mixers++] = |
| 2965 | ad1989_spdif_out_mixers; | ||
| 2966 | spec->init_verbs[spec->num_init_verbs++] = | ||
| 2967 | ad1989_spdif_init_verbs; | ||
| 2968 | } else { | ||
| 2969 | spec->mixers[spec->num_mixers++] = | ||
| 2970 | ad1988_spdif_out_mixers; | ||
| 2971 | spec->init_verbs[spec->num_init_verbs++] = | ||
| 2972 | ad1988_spdif_init_verbs; | ||
| 2973 | } | ||
| 2899 | } | 2974 | } |
| 2900 | if (spec->dig_in_nid) | 2975 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) |
| 2901 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | 2976 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; |
| 2902 | 2977 | ||
| 2903 | codec->patch_ops = ad198x_patch_ops; | 2978 | codec->patch_ops = ad198x_patch_ops; |
| @@ -3133,11 +3208,12 @@ static int patch_ad1884(struct hda_codec *codec) | |||
| 3133 | * Lenovo Thinkpad T61/X61 | 3208 | * Lenovo Thinkpad T61/X61 |
| 3134 | */ | 3209 | */ |
| 3135 | static struct hda_input_mux ad1984_thinkpad_capture_source = { | 3210 | static struct hda_input_mux ad1984_thinkpad_capture_source = { |
| 3136 | .num_items = 3, | 3211 | .num_items = 4, |
| 3137 | .items = { | 3212 | .items = { |
| 3138 | { "Mic", 0x0 }, | 3213 | { "Mic", 0x0 }, |
| 3139 | { "Internal Mic", 0x1 }, | 3214 | { "Internal Mic", 0x1 }, |
| 3140 | { "Mix", 0x3 }, | 3215 | { "Mix", 0x3 }, |
| 3216 | { "Docking-Station", 0x4 }, | ||
| 3141 | }, | 3217 | }, |
| 3142 | }; | 3218 | }; |
| 3143 | 3219 | ||
| @@ -3268,8 +3344,7 @@ static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, | |||
| 3268 | struct hda_codec *codec, | 3344 | struct hda_codec *codec, |
| 3269 | struct snd_pcm_substream *substream) | 3345 | struct snd_pcm_substream *substream) |
| 3270 | { | 3346 | { |
| 3271 | snd_hda_codec_setup_stream(codec, 0x05 + substream->number, | 3347 | snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); |
| 3272 | 0, 0, 0); | ||
| 3273 | return 0; | 3348 | return 0; |
| 3274 | } | 3349 | } |
| 3275 | 3350 | ||
| @@ -3356,6 +3431,472 @@ static int patch_ad1984(struct hda_codec *codec) | |||
| 3356 | 3431 | ||
| 3357 | 3432 | ||
| 3358 | /* | 3433 | /* |
| 3434 | * AD1883 / AD1884A / AD1984A / AD1984B | ||
| 3435 | * | ||
| 3436 | * port-B (0x14) - front mic-in | ||
| 3437 | * port-E (0x1c) - rear mic-in | ||
| 3438 | * port-F (0x16) - CD / ext out | ||
| 3439 | * port-C (0x15) - rear line-in | ||
| 3440 | * port-D (0x12) - rear line-out | ||
| 3441 | * port-A (0x11) - front hp-out | ||
| 3442 | * | ||
| 3443 | * AD1984A = AD1884A + digital-mic | ||
| 3444 | * AD1883 = equivalent with AD1984A | ||
| 3445 | * AD1984B = AD1984A + extra SPDIF-out | ||
| 3446 | * | ||
| 3447 | * FIXME: | ||
| 3448 | * We share the single DAC for both HP and line-outs (see AD1884/1984). | ||
| 3449 | */ | ||
| 3450 | |||
| 3451 | static hda_nid_t ad1884a_dac_nids[1] = { | ||
| 3452 | 0x03, | ||
| 3453 | }; | ||
| 3454 | |||
| 3455 | #define ad1884a_adc_nids ad1884_adc_nids | ||
| 3456 | #define ad1884a_capsrc_nids ad1884_capsrc_nids | ||
| 3457 | |||
| 3458 | #define AD1884A_SPDIF_OUT 0x02 | ||
| 3459 | |||
| 3460 | static struct hda_input_mux ad1884a_capture_source = { | ||
| 3461 | .num_items = 5, | ||
| 3462 | .items = { | ||
| 3463 | { "Front Mic", 0x0 }, | ||
| 3464 | { "Mic", 0x4 }, | ||
| 3465 | { "Line", 0x1 }, | ||
| 3466 | { "CD", 0x2 }, | ||
| 3467 | { "Mix", 0x3 }, | ||
| 3468 | }, | ||
| 3469 | }; | ||
| 3470 | |||
| 3471 | static struct snd_kcontrol_new ad1884a_base_mixers[] = { | ||
| 3472 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
| 3473 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 3474 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
| 3475 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
| 3476 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
| 3477 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
| 3478 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
| 3479 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
| 3480 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
| 3481 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
| 3482 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
| 3483 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
| 3484 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
| 3485 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
| 3486 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
| 3487 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
| 3488 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
| 3489 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
| 3490 | HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), | ||
| 3491 | HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT), | ||
| 3492 | HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT), | ||
| 3493 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3494 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3495 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
| 3496 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
| 3497 | { | ||
| 3498 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 3499 | /* The multiple "Capture Source" controls confuse alsamixer | ||
| 3500 | * So call somewhat different.. | ||
| 3501 | */ | ||
| 3502 | /* .name = "Capture Source", */ | ||
| 3503 | .name = "Input Source", | ||
| 3504 | .count = 2, | ||
| 3505 | .info = ad198x_mux_enum_info, | ||
| 3506 | .get = ad198x_mux_enum_get, | ||
| 3507 | .put = ad198x_mux_enum_put, | ||
| 3508 | }, | ||
| 3509 | /* SPDIF controls */ | ||
| 3510 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
| 3511 | { | ||
| 3512 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 3513 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
| 3514 | /* identical with ad1983 */ | ||
| 3515 | .info = ad1983_spdif_route_info, | ||
| 3516 | .get = ad1983_spdif_route_get, | ||
| 3517 | .put = ad1983_spdif_route_put, | ||
| 3518 | }, | ||
| 3519 | { } /* end */ | ||
| 3520 | }; | ||
| 3521 | |||
| 3522 | /* | ||
| 3523 | * initialization verbs | ||
| 3524 | */ | ||
| 3525 | static struct hda_verb ad1884a_init_verbs[] = { | ||
| 3526 | /* DACs; unmute as default */ | ||
| 3527 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
| 3528 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
| 3529 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
| 3530 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
| 3531 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
| 3532 | /* Port-A pin */ | ||
| 3533 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 3534 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3535 | /* Port-D (Line-out) mixer - route only from analog mixer */ | ||
| 3536 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
| 3537 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
| 3538 | /* Port-D pin */ | ||
| 3539 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 3540 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3541 | /* Mono-out mixer - route only from analog mixer */ | ||
| 3542 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
| 3543 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
| 3544 | /* Mono-out pin */ | ||
| 3545 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 3546 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3547 | /* Port-B (front mic) pin */ | ||
| 3548 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
| 3549 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3550 | /* Port-C (rear line-in) pin */ | ||
| 3551 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
| 3552 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3553 | /* Port-E (rear mic) pin */ | ||
| 3554 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
| 3555 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3556 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ | ||
| 3557 | /* Port-F (CD) pin */ | ||
| 3558 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
| 3559 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3560 | /* Analog mixer; mute as default */ | ||
| 3561 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
| 3562 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
| 3563 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
| 3564 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
| 3565 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ | ||
| 3566 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
| 3567 | /* Analog Mix output amp */ | ||
| 3568 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3569 | /* capture sources */ | ||
| 3570 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
| 3571 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3572 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
| 3573 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3574 | /* SPDIF output amp */ | ||
| 3575 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
| 3576 | { } /* end */ | ||
| 3577 | }; | ||
| 3578 | |||
| 3579 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 3580 | static struct hda_amp_list ad1884a_loopbacks[] = { | ||
| 3581 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
| 3582 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
| 3583 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
| 3584 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
| 3585 | { } /* end */ | ||
| 3586 | }; | ||
| 3587 | #endif | ||
| 3588 | |||
| 3589 | /* | ||
| 3590 | * Laptop model | ||
| 3591 | * | ||
| 3592 | * Port A: Headphone jack | ||
| 3593 | * Port B: MIC jack | ||
| 3594 | * Port C: Internal MIC | ||
| 3595 | * Port D: Dock Line Out (if enabled) | ||
| 3596 | * Port E: Dock Line In (if enabled) | ||
| 3597 | * Port F: Internal speakers | ||
| 3598 | */ | ||
| 3599 | |||
| 3600 | static struct hda_input_mux ad1884a_laptop_capture_source = { | ||
| 3601 | .num_items = 4, | ||
| 3602 | .items = { | ||
| 3603 | { "Mic", 0x0 }, /* port-B */ | ||
| 3604 | { "Internal Mic", 0x1 }, /* port-C */ | ||
| 3605 | { "Dock Mic", 0x4 }, /* port-E */ | ||
| 3606 | { "Mix", 0x3 }, | ||
| 3607 | }, | ||
| 3608 | }; | ||
| 3609 | |||
| 3610 | static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | ||
| 3611 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
| 3612 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 3613 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
| 3614 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
| 3615 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
| 3616 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
| 3617 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
| 3618 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
| 3619 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
| 3620 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
| 3621 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
| 3622 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
| 3623 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
| 3624 | HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), | ||
| 3625 | HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT), | ||
| 3626 | HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT), | ||
| 3627 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3628 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3629 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
| 3630 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
| 3631 | { | ||
| 3632 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 3633 | /* The multiple "Capture Source" controls confuse alsamixer | ||
| 3634 | * So call somewhat different.. | ||
| 3635 | */ | ||
| 3636 | /* .name = "Capture Source", */ | ||
| 3637 | .name = "Input Source", | ||
| 3638 | .count = 2, | ||
| 3639 | .info = ad198x_mux_enum_info, | ||
| 3640 | .get = ad198x_mux_enum_get, | ||
| 3641 | .put = ad198x_mux_enum_put, | ||
| 3642 | }, | ||
| 3643 | { } /* end */ | ||
| 3644 | }; | ||
| 3645 | |||
| 3646 | static struct hda_input_mux ad1884a_mobile_capture_source = { | ||
| 3647 | .num_items = 2, | ||
| 3648 | .items = { | ||
| 3649 | { "Mic", 0x1 }, /* port-C */ | ||
| 3650 | { "Mix", 0x3 }, | ||
| 3651 | }, | ||
| 3652 | }; | ||
| 3653 | |||
| 3654 | static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | ||
| 3655 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
| 3656 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 3657 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
| 3658 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
| 3659 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
| 3660 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
| 3661 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
| 3662 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
| 3663 | HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT), | ||
| 3664 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3665 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3666 | { | ||
| 3667 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 3668 | .name = "Capture Source", | ||
| 3669 | .info = ad198x_mux_enum_info, | ||
| 3670 | .get = ad198x_mux_enum_get, | ||
| 3671 | .put = ad198x_mux_enum_put, | ||
| 3672 | }, | ||
| 3673 | { } /* end */ | ||
| 3674 | }; | ||
| 3675 | |||
| 3676 | /* mute internal speaker if HP is plugged */ | ||
| 3677 | static void ad1884a_hp_automute(struct hda_codec *codec) | ||
| 3678 | { | ||
| 3679 | unsigned int present; | ||
| 3680 | |||
| 3681 | present = snd_hda_codec_read(codec, 0x11, 0, | ||
| 3682 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
| 3683 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
| 3684 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
| 3685 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
| 3686 | present ? 0x00 : 0x02); | ||
| 3687 | } | ||
| 3688 | |||
| 3689 | #define AD1884A_HP_EVENT 0x37 | ||
| 3690 | |||
| 3691 | /* unsolicited event for HP jack sensing */ | ||
| 3692 | static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
| 3693 | { | ||
| 3694 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
| 3695 | return; | ||
| 3696 | ad1884a_hp_automute(codec); | ||
| 3697 | } | ||
| 3698 | |||
| 3699 | /* initialize jack-sensing, too */ | ||
| 3700 | static int ad1884a_hp_init(struct hda_codec *codec) | ||
| 3701 | { | ||
| 3702 | ad198x_init(codec); | ||
| 3703 | ad1884a_hp_automute(codec); | ||
| 3704 | return 0; | ||
| 3705 | } | ||
| 3706 | |||
| 3707 | /* additional verbs for laptop model */ | ||
| 3708 | static struct hda_verb ad1884a_laptop_verbs[] = { | ||
| 3709 | /* Port-A (HP) pin - always unmuted */ | ||
| 3710 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 3711 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
| 3712 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
| 3713 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
| 3714 | /* Port-F pin */ | ||
| 3715 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 3716 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
| 3717 | /* analog mix */ | ||
| 3718 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
| 3719 | /* unsolicited event for pin-sense */ | ||
| 3720 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
| 3721 | { } /* end */ | ||
| 3722 | }; | ||
| 3723 | |||
| 3724 | /* | ||
| 3725 | * Thinkpad X300 | ||
| 3726 | * 0x11 - HP | ||
| 3727 | * 0x12 - speaker | ||
| 3728 | * 0x14 - mic-in | ||
| 3729 | * 0x17 - built-in mic | ||
| 3730 | */ | ||
| 3731 | |||
| 3732 | static struct hda_verb ad1984a_thinkpad_verbs[] = { | ||
| 3733 | /* HP unmute */ | ||
| 3734 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 3735 | /* analog mix */ | ||
| 3736 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
| 3737 | /* turn on EAPD */ | ||
| 3738 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
| 3739 | /* unsolicited event for pin-sense */ | ||
| 3740 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
| 3741 | /* internal mic - dmic */ | ||
| 3742 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
| 3743 | /* set magic COEFs for dmic */ | ||
| 3744 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
| 3745 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
| 3746 | { } /* end */ | ||
| 3747 | }; | ||
| 3748 | |||
| 3749 | static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { | ||
| 3750 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
| 3751 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 3752 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
| 3753 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
| 3754 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
| 3755 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
| 3756 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
| 3757 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
| 3758 | HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), | ||
| 3759 | HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT), | ||
| 3760 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3761 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
| 3762 | { | ||
| 3763 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 3764 | .name = "Capture Source", | ||
| 3765 | .info = ad198x_mux_enum_info, | ||
| 3766 | .get = ad198x_mux_enum_get, | ||
| 3767 | .put = ad198x_mux_enum_put, | ||
| 3768 | }, | ||
| 3769 | { } /* end */ | ||
| 3770 | }; | ||
| 3771 | |||
| 3772 | static struct hda_input_mux ad1984a_thinkpad_capture_source = { | ||
| 3773 | .num_items = 3, | ||
| 3774 | .items = { | ||
| 3775 | { "Mic", 0x0 }, | ||
| 3776 | { "Internal Mic", 0x5 }, | ||
| 3777 | { "Mix", 0x3 }, | ||
| 3778 | }, | ||
| 3779 | }; | ||
| 3780 | |||
| 3781 | /* mute internal speaker if HP is plugged */ | ||
| 3782 | static void ad1984a_thinkpad_automute(struct hda_codec *codec) | ||
| 3783 | { | ||
| 3784 | unsigned int present; | ||
| 3785 | |||
| 3786 | present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
| 3787 | & AC_PINSENSE_PRESENCE; | ||
| 3788 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | ||
| 3789 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
| 3790 | } | ||
| 3791 | |||
| 3792 | /* unsolicited event for HP jack sensing */ | ||
| 3793 | static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, | ||
| 3794 | unsigned int res) | ||
| 3795 | { | ||
| 3796 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
| 3797 | return; | ||
| 3798 | ad1984a_thinkpad_automute(codec); | ||
| 3799 | } | ||
| 3800 | |||
| 3801 | /* initialize jack-sensing, too */ | ||
| 3802 | static int ad1984a_thinkpad_init(struct hda_codec *codec) | ||
| 3803 | { | ||
| 3804 | ad198x_init(codec); | ||
| 3805 | ad1984a_thinkpad_automute(codec); | ||
| 3806 | return 0; | ||
| 3807 | } | ||
| 3808 | |||
| 3809 | /* | ||
| 3810 | */ | ||
| 3811 | |||
| 3812 | enum { | ||
| 3813 | AD1884A_DESKTOP, | ||
| 3814 | AD1884A_LAPTOP, | ||
| 3815 | AD1884A_MOBILE, | ||
| 3816 | AD1884A_THINKPAD, | ||
| 3817 | AD1884A_MODELS | ||
| 3818 | }; | ||
| 3819 | |||
| 3820 | static const char *ad1884a_models[AD1884A_MODELS] = { | ||
| 3821 | [AD1884A_DESKTOP] = "desktop", | ||
| 3822 | [AD1884A_LAPTOP] = "laptop", | ||
| 3823 | [AD1884A_MOBILE] = "mobile", | ||
| 3824 | [AD1884A_THINKPAD] = "thinkpad", | ||
| 3825 | }; | ||
| 3826 | |||
| 3827 | static struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||
| 3828 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | ||
| 3829 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | ||
| 3830 | {} | ||
| 3831 | }; | ||
| 3832 | |||
| 3833 | static int patch_ad1884a(struct hda_codec *codec) | ||
| 3834 | { | ||
| 3835 | struct ad198x_spec *spec; | ||
| 3836 | int board_config; | ||
| 3837 | |||
| 3838 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
| 3839 | if (spec == NULL) | ||
| 3840 | return -ENOMEM; | ||
| 3841 | |||
| 3842 | mutex_init(&spec->amp_mutex); | ||
| 3843 | codec->spec = spec; | ||
| 3844 | |||
| 3845 | spec->multiout.max_channels = 2; | ||
| 3846 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); | ||
| 3847 | spec->multiout.dac_nids = ad1884a_dac_nids; | ||
| 3848 | spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; | ||
| 3849 | spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); | ||
| 3850 | spec->adc_nids = ad1884a_adc_nids; | ||
| 3851 | spec->capsrc_nids = ad1884a_capsrc_nids; | ||
| 3852 | spec->input_mux = &ad1884a_capture_source; | ||
| 3853 | spec->num_mixers = 1; | ||
| 3854 | spec->mixers[0] = ad1884a_base_mixers; | ||
| 3855 | spec->num_init_verbs = 1; | ||
| 3856 | spec->init_verbs[0] = ad1884a_init_verbs; | ||
| 3857 | spec->spdif_route = 0; | ||
| 3858 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 3859 | spec->loopback.amplist = ad1884a_loopbacks; | ||
| 3860 | #endif | ||
| 3861 | codec->patch_ops = ad198x_patch_ops; | ||
| 3862 | |||
| 3863 | /* override some parameters */ | ||
| 3864 | board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, | ||
| 3865 | ad1884a_models, | ||
| 3866 | ad1884a_cfg_tbl); | ||
| 3867 | switch (board_config) { | ||
| 3868 | case AD1884A_LAPTOP: | ||
| 3869 | spec->mixers[0] = ad1884a_laptop_mixers; | ||
| 3870 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | ||
| 3871 | spec->multiout.dig_out_nid = 0; | ||
| 3872 | spec->input_mux = &ad1884a_laptop_capture_source; | ||
| 3873 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||
| 3874 | codec->patch_ops.init = ad1884a_hp_init; | ||
| 3875 | break; | ||
| 3876 | case AD1884A_MOBILE: | ||
| 3877 | spec->mixers[0] = ad1884a_mobile_mixers; | ||
| 3878 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | ||
| 3879 | spec->multiout.dig_out_nid = 0; | ||
| 3880 | spec->input_mux = &ad1884a_mobile_capture_source; | ||
| 3881 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||
| 3882 | codec->patch_ops.init = ad1884a_hp_init; | ||
| 3883 | break; | ||
| 3884 | case AD1884A_THINKPAD: | ||
| 3885 | spec->mixers[0] = ad1984a_thinkpad_mixers; | ||
| 3886 | spec->init_verbs[spec->num_init_verbs++] = | ||
| 3887 | ad1984a_thinkpad_verbs; | ||
| 3888 | spec->multiout.dig_out_nid = 0; | ||
| 3889 | spec->input_mux = &ad1984a_thinkpad_capture_source; | ||
| 3890 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; | ||
| 3891 | codec->patch_ops.init = ad1984a_thinkpad_init; | ||
| 3892 | break; | ||
| 3893 | } | ||
| 3894 | |||
| 3895 | return 0; | ||
| 3896 | } | ||
| 3897 | |||
| 3898 | |||
| 3899 | /* | ||
| 3359 | * AD1882 | 3900 | * AD1882 |
| 3360 | * | 3901 | * |
| 3361 | * port-A - front hp-out | 3902 | * port-A - front hp-out |
| @@ -3654,13 +4195,19 @@ static int patch_ad1882(struct hda_codec *codec) | |||
| 3654 | * patch entries | 4195 | * patch entries |
| 3655 | */ | 4196 | */ |
| 3656 | struct hda_codec_preset snd_hda_preset_analog[] = { | 4197 | struct hda_codec_preset snd_hda_preset_analog[] = { |
| 4198 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, | ||
| 3657 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, | 4199 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, |
| 4200 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, | ||
| 3658 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, | 4201 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, |
| 4202 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, | ||
| 4203 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, | ||
| 3659 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | 4204 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, |
| 3660 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | 4205 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, |
| 3661 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, | 4206 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, |
| 3662 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 4207 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
| 3663 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, | 4208 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, |
| 3664 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, | 4209 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, |
| 4210 | { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 }, | ||
| 4211 | { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, | ||
| 3665 | {} /* terminator */ | 4212 | {} /* terminator */ |
| 3666 | }; | 4213 | }; |
