aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/patch_analog.c299
1 files changed, 255 insertions, 44 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 5a3821ae93a8..b2479268778d 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -310,7 +310,7 @@ static int ad198x_resume(struct hda_codec *codec)
310 struct ad198x_spec *spec = codec->spec; 310 struct ad198x_spec *spec = codec->spec;
311 int i; 311 int i;
312 312
313 ad198x_init(codec); 313 codec->patch_ops.init(codec);
314 for (i = 0; i < spec->num_mixers; i++) 314 for (i = 0; i < spec->num_mixers; i++)
315 snd_hda_resume_ctls(codec, spec->mixers[i]); 315 snd_hda_resume_ctls(codec, spec->mixers[i]);
316 if (spec->multiout.dig_out_nid) 316 if (spec->multiout.dig_out_nid)
@@ -333,6 +333,53 @@ static struct hda_codec_ops ad198x_patch_ops = {
333 333
334 334
335/* 335/*
336 * EAPD control
337 * the private value = nid | (invert << 8)
338 */
339static int ad198x_eapd_info(struct snd_kcontrol *kcontrol,
340 struct snd_ctl_elem_info *uinfo)
341{
342 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
343 uinfo->count = 1;
344 uinfo->value.integer.min = 0;
345 uinfo->value.integer.max = 1;
346 return 0;
347}
348
349static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
350 struct snd_ctl_elem_value *ucontrol)
351{
352 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
353 struct ad198x_spec *spec = codec->spec;
354 int invert = (kcontrol->private_value >> 8) & 1;
355 if (invert)
356 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
357 else
358 ucontrol->value.integer.value[0] = spec->cur_eapd;
359 return 0;
360}
361
362static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
363 struct snd_ctl_elem_value *ucontrol)
364{
365 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
366 struct ad198x_spec *spec = codec->spec;
367 int invert = (kcontrol->private_value >> 8) & 1;
368 hda_nid_t nid = kcontrol->private_value & 0xff;
369 unsigned int eapd;
370 eapd = ucontrol->value.integer.value[0];
371 if (invert)
372 eapd = !eapd;
373 if (eapd == spec->cur_eapd && ! codec->in_resume)
374 return 0;
375 spec->cur_eapd = eapd;
376 snd_hda_codec_write(codec, nid,
377 0, AC_VERB_SET_EAPD_BTLENABLE,
378 eapd ? 0x02 : 0x00);
379 return 1;
380}
381
382/*
336 * AD1986A specific 383 * AD1986A specific
337 */ 384 */
338 385
@@ -346,6 +393,7 @@ static hda_nid_t ad1986a_dac_nids[3] = {
346 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC 393 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
347}; 394};
348static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; 395static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
396static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
349 397
350static struct hda_input_mux ad1986a_capture_source = { 398static struct hda_input_mux ad1986a_capture_source = {
351 .num_items = 7, 399 .num_items = 7,
@@ -577,6 +625,7 @@ static int patch_ad1986a(struct hda_codec *codec)
577 625
578static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; 626static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
579static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; 627static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
628static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
580 629
581static struct hda_input_mux ad1983_capture_source = { 630static struct hda_input_mux ad1983_capture_source = {
582 .num_items = 4, 631 .num_items = 4,
@@ -719,7 +768,7 @@ static int patch_ad1983(struct hda_codec *codec)
719 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; 768 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
720 spec->num_adc_nids = 1; 769 spec->num_adc_nids = 1;
721 spec->adc_nids = ad1983_adc_nids; 770 spec->adc_nids = ad1983_adc_nids;
722 spec->capsrc_nids = ad1983_adc_nids; 771 spec->capsrc_nids = ad1983_capsrc_nids;
723 spec->input_mux = &ad1983_capture_source; 772 spec->input_mux = &ad1983_capture_source;
724 spec->num_mixers = 1; 773 spec->num_mixers = 1;
725 spec->mixers[0] = ad1983_mixers; 774 spec->mixers[0] = ad1983_mixers;
@@ -743,6 +792,7 @@ static int patch_ad1983(struct hda_codec *codec)
743 792
744static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; 793static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
745static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; 794static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
795static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
746 796
747/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ 797/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
748static struct hda_input_mux ad1981_capture_source = { 798static struct hda_input_mux ad1981_capture_source = {
@@ -848,9 +898,192 @@ static struct hda_verb ad1981_init_verbs[] = {
848 { } /* end */ 898 { } /* end */
849}; 899};
850 900
901/*
902 * Patch for HP nx6320
903 *
904 * nx6320 uses EAPD in the reserve way - EAPD-on means the internal
905 * speaker output enabled _and_ mute-LED off.
906 */
907
908#define AD1981_HP_EVENT 0x37
909#define AD1981_MIC_EVENT 0x38
910
911static struct hda_verb ad1981_hp_init_verbs[] = {
912 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
913 /* pin sensing on HP and Mic jacks */
914 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
915 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
916 {}
917};
918
919/* turn on/off EAPD (+ mute HP) as a master switch */
920static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
921 struct snd_ctl_elem_value *ucontrol)
922{
923 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
924 struct ad198x_spec *spec = codec->spec;
925
926 if (! ad198x_eapd_put(kcontrol, ucontrol))
927 return 0;
928
929 /* toggle HP mute appropriately */
930 snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0,
931 0x80, spec->cur_eapd ? 0 : 0x80);
932 snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0,
933 0x80, spec->cur_eapd ? 0 : 0x80);
934 return 1;
935}
936
937/* bind volumes of both NID 0x05 and 0x06 */
938static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol,
939 struct snd_ctl_elem_value *ucontrol)
940{
941 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
942 long *valp = ucontrol->value.integer.value;
943 int change;
944
945 change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
946 0x7f, valp[0] & 0x7f);
947 change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
948 0x7f, valp[1] & 0x7f);
949 snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0,
950 0x7f, valp[0] & 0x7f);
951 snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0,
952 0x7f, valp[1] & 0x7f);
953 return change;
954}
955
956/* mute internal speaker if HP is plugged */
957static void ad1981_hp_automute(struct hda_codec *codec)
958{
959 unsigned int present;
960
961 present = snd_hda_codec_read(codec, 0x06, 0,
962 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
963 snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
964 0x80, present ? 0x80 : 0);
965 snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
966 0x80, present ? 0x80 : 0);
967}
968
969/* toggle input of built-in and mic jack appropriately */
970static void ad1981_hp_automic(struct hda_codec *codec)
971{
972 static struct hda_verb mic_jack_on[] = {
973 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
974 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
975 {}
976 };
977 static struct hda_verb mic_jack_off[] = {
978 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
979 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
980 {}
981 };
982 unsigned int present;
983
984 present = snd_hda_codec_read(codec, 0x08, 0,
985 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
986 if (present)
987 snd_hda_sequence_write(codec, mic_jack_on);
988 else
989 snd_hda_sequence_write(codec, mic_jack_off);
990}
991
992/* unsolicited event for HP jack sensing */
993static void ad1981_hp_unsol_event(struct hda_codec *codec,
994 unsigned int res)
995{
996 res >>= 26;
997 switch (res) {
998 case AD1981_HP_EVENT:
999 ad1981_hp_automute(codec);
1000 break;
1001 case AD1981_MIC_EVENT:
1002 ad1981_hp_automic(codec);
1003 break;
1004 }
1005}
1006
1007static struct hda_input_mux ad1981_hp_capture_source = {
1008 .num_items = 3,
1009 .items = {
1010 { "Mic", 0x0 },
1011 { "Docking-Station", 0x1 },
1012 { "Mix", 0x2 },
1013 },
1014};
1015
1016static struct snd_kcontrol_new ad1981_hp_mixers[] = {
1017 {
1018 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1019 .name = "Master Playback Volume",
1020 .info = snd_hda_mixer_amp_volume_info,
1021 .get = snd_hda_mixer_amp_volume_get,
1022 .put = ad1981_hp_master_vol_put,
1023 .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1024 },
1025 {
1026 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1027 .name = "Master Playback Switch",
1028 .info = ad198x_eapd_info,
1029 .get = ad198x_eapd_get,
1030 .put = ad1981_hp_master_sw_put,
1031 .private_value = 0x05,
1032 },
1033 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1034 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1035#if 0
1036 /* FIXME: analog mic/line loopback doesn't work with my tests...
1037 * (although recording is OK)
1038 */
1039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1040 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1041 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1042 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1043 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1044 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1045 /* FIXME: does this laptop have analog CD connection? */
1046 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1047 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1048#endif
1049 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1050 HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
1051 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1052 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1053 {
1054 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1055 .name = "Capture Source",
1056 .info = ad198x_mux_enum_info,
1057 .get = ad198x_mux_enum_get,
1058 .put = ad198x_mux_enum_put,
1059 },
1060 { } /* end */
1061};
1062
1063/* initialize jack-sensing, too */
1064static int ad1981_hp_init(struct hda_codec *codec)
1065{
1066 ad198x_init(codec);
1067 ad1981_hp_automute(codec);
1068 ad1981_hp_automic(codec);
1069 return 0;
1070}
1071
1072/* models */
1073enum { AD1981_BASIC, AD1981_HP };
1074
1075static struct hda_board_config ad1981_cfg_tbl[] = {
1076 { .modelname = "hp", .config = AD1981_HP },
1077 { .pci_subvendor = 0x103c, .pci_subdevice = 0x30aa,
1078 .config = AD1981_HP },
1079 { .modelname = "basic", .config = AD1981_BASIC },
1080 {}
1081};
1082
851static int patch_ad1981(struct hda_codec *codec) 1083static int patch_ad1981(struct hda_codec *codec)
852{ 1084{
853 struct ad198x_spec *spec; 1085 struct ad198x_spec *spec;
1086 int board_config;
854 1087
855 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 1088 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
856 if (spec == NULL) 1089 if (spec == NULL)
@@ -865,7 +1098,7 @@ static int patch_ad1981(struct hda_codec *codec)
865 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; 1098 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
866 spec->num_adc_nids = 1; 1099 spec->num_adc_nids = 1;
867 spec->adc_nids = ad1981_adc_nids; 1100 spec->adc_nids = ad1981_adc_nids;
868 spec->capsrc_nids = ad1981_adc_nids; 1101 spec->capsrc_nids = ad1981_capsrc_nids;
869 spec->input_mux = &ad1981_capture_source; 1102 spec->input_mux = &ad1981_capture_source;
870 spec->num_mixers = 1; 1103 spec->num_mixers = 1;
871 spec->mixers[0] = ad1981_mixers; 1104 spec->mixers[0] = ad1981_mixers;
@@ -875,6 +1108,21 @@ static int patch_ad1981(struct hda_codec *codec)
875 1108
876 codec->patch_ops = ad198x_patch_ops; 1109 codec->patch_ops = ad198x_patch_ops;
877 1110
1111 /* override some parameters */
1112 board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl);
1113 switch (board_config) {
1114 case AD1981_HP:
1115 spec->mixers[0] = ad1981_hp_mixers;
1116 spec->num_init_verbs = 2;
1117 spec->init_verbs[1] = ad1981_hp_init_verbs;
1118 spec->multiout.dig_out_nid = 0;
1119 spec->input_mux = &ad1981_hp_capture_source;
1120
1121 codec->patch_ops.init = ad1981_hp_init;
1122 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1123 break;
1124 }
1125
878 return 0; 1126 return 0;
879} 1127}
880 1128
@@ -1062,44 +1310,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
1062 spec->num_channel_mode, &spec->multiout.max_channels); 1310 spec->num_channel_mode, &spec->multiout.max_channels);
1063} 1311}
1064 1312
1065/*
1066 * EAPD control
1067 */
1068static int ad1988_eapd_info(struct snd_kcontrol *kcontrol,
1069 struct snd_ctl_elem_info *uinfo)
1070{
1071 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1072 uinfo->count = 1;
1073 uinfo->value.integer.min = 0;
1074 uinfo->value.integer.max = 1;
1075 return 0;
1076}
1077
1078static int ad1988_eapd_get(struct snd_kcontrol *kcontrol,
1079 struct snd_ctl_elem_value *ucontrol)
1080{
1081 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1082 struct ad198x_spec *spec = codec->spec;
1083 ucontrol->value.enumerated.item[0] = ! spec->cur_eapd;
1084 return 0;
1085}
1086
1087static int ad1988_eapd_put(struct snd_kcontrol *kcontrol,
1088 struct snd_ctl_elem_value *ucontrol)
1089{
1090 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1091 struct ad198x_spec *spec = codec->spec;
1092 unsigned int eapd;
1093 eapd = ! ucontrol->value.enumerated.item[0];
1094 if (eapd == spec->cur_eapd && ! codec->in_resume)
1095 return 0;
1096 spec->cur_eapd = eapd;
1097 snd_hda_codec_write(codec, 0x12 /* port-D */,
1098 0, AC_VERB_SET_EAPD_BTLENABLE,
1099 eapd ? 0x02 : 0x00);
1100 return 0;
1101}
1102
1103/* 6-stack mode */ 1313/* 6-stack mode */
1104static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { 1314static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
1105 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), 1315 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
@@ -1222,9 +1432,10 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
1222 { 1432 {
1223 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1433 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1224 .name = "External Amplifier", 1434 .name = "External Amplifier",
1225 .info = ad1988_eapd_info, 1435 .info = ad198x_eapd_info,
1226 .get = ad1988_eapd_get, 1436 .get = ad198x_eapd_get,
1227 .put = ad1988_eapd_put, 1437 .put = ad198x_eapd_put,
1438 .private_value = 0x12 | (1 << 8), /* port-D, inversed */
1228 }, 1439 },
1229 1440
1230 { } /* end */ 1441 { } /* end */