aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_analog.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r--sound/pci/hda/patch_analog.c581
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
32struct ad198x_spec { 33struct 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
223static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 230static 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
621static struct hda_input_mux ad1986a_automic_capture_source = {
622 .num_items = 2,
623 .items = {
624 { "Mic", 0x0 },
625 { "Mix", 0x5 },
626 },
627};
628
614static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { 629static 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 */
658static 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
669static 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
677static 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
646static void ad1986a_update_hp(struct hda_codec *codec) 686static 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
887static 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 */
848static struct hda_verb ad1986a_ultra_init[] = { 897static 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
2145static 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 */
2250static 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 */
3135static struct hda_input_mux ad1984_thinkpad_capture_source = { 3210static 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
3451static 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
3460static 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
3471static 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 */
3525static 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
3580static 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
3600static 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
3610static 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
3646static 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
3654static 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 */
3677static 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 */
3692static 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 */
3700static 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 */
3708static 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
3732static 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
3749static 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
3772static 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 */
3782static 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 */
3793static 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 */
3802static 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
3812enum {
3813 AD1884A_DESKTOP,
3814 AD1884A_LAPTOP,
3815 AD1884A_MOBILE,
3816 AD1884A_THINKPAD,
3817 AD1884A_MODELS
3818};
3819
3820static const char *ad1884a_models[AD1884A_MODELS] = {
3821 [AD1884A_DESKTOP] = "desktop",
3822 [AD1884A_LAPTOP] = "laptop",
3823 [AD1884A_MOBILE] = "mobile",
3824 [AD1884A_THINKPAD] = "thinkpad",
3825};
3826
3827static 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
3833static 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 */
3656struct hda_codec_preset snd_hda_preset_analog[] = { 4197struct 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};