diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-11-17 09:31:34 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:20:17 -0500 |
commit | fd66e0d0591dd12eb0bea1e9f3aa194bb93cebbd (patch) | |
tree | 010f8f3a7d1db8061616d0228c48bfe129ddabb7 | |
parent | 9398441edaf0dc64eca828e3ce7a0326c8640d4c (diff) |
[ALSA] hda-codec - Add AD1988 support
Modules: HDA Codec driver
Add AD1988 codec support to hda-codec driver.
Still experimental, and no BIOS configuration parser is implemented yet.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/patch_analog.c | 785 |
1 files changed, 785 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1f371fe6b92f..25116a883ca6 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -41,6 +41,7 @@ struct ad198x_spec { | |||
41 | * max_channels, dacs must be set | 41 | * max_channels, dacs must be set |
42 | * dig_out_nid and hp_nid are optional | 42 | * dig_out_nid and hp_nid are optional |
43 | */ | 43 | */ |
44 | unsigned int cur_eapd; | ||
44 | 45 | ||
45 | /* capture */ | 46 | /* capture */ |
46 | unsigned int num_adc_nids; | 47 | unsigned int num_adc_nids; |
@@ -857,11 +858,795 @@ static int patch_ad1981(struct hda_codec *codec) | |||
857 | 858 | ||
858 | 859 | ||
859 | /* | 860 | /* |
861 | * AD1988 | ||
862 | * | ||
863 | * Output pins and routes | ||
864 | * | ||
865 | * Pin Mix Sel DAC | ||
866 | * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06 | ||
867 | * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06 | ||
868 | * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a | ||
869 | * port-D 0x12 (mute/hp) <- 0x29 <- 04 | ||
870 | * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a | ||
871 | * port-F 0x16 (mute) <- 0x2a <- 06 | ||
872 | * port-G 0x24 (mute) <- 0x27 <- 05 | ||
873 | * port-H 0x25 (mute) <- 0x28 <- 0a | ||
874 | * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06 | ||
875 | * | ||
876 | * | ||
877 | * Input pins and routes | ||
878 | * | ||
879 | * pin boost mix input # / adc input # | ||
880 | * port-A 0x11 -> 0x38 -> mix 2, ADC 0 | ||
881 | * port-B 0x14 -> 0x39 -> mix 0, ADC 1 | ||
882 | * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2 | ||
883 | * port-D 0x12 -> 0x3d -> mix 3, ADC 8 | ||
884 | * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4 | ||
885 | * port-F 0x16 -> 0x3b -> mix 5, ADC 3 | ||
886 | * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6 | ||
887 | * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7 | ||
888 | * | ||
889 | * | ||
890 | * DAC assignment | ||
891 | * front DAC - 04 | ||
892 | * surr DAC - 06 | ||
893 | * CLFE DAC - 05 | ||
894 | * side DAC - 0a | ||
895 | * opt DAC - 03 | ||
896 | * | ||
897 | * Inputs of Analog Mix (0x20) | ||
898 | * 0:Port-B (front mic) | ||
899 | * 1:Port-C/G/H (line-in) | ||
900 | * 2:Port-A | ||
901 | * 3:Port-D (line-in/2) | ||
902 | * 4:Port-E/G/H (mic-in) | ||
903 | * 5:Port-F (mic2-in) | ||
904 | * 6:CD | ||
905 | * 7:Beep | ||
906 | * | ||
907 | * ADC selection | ||
908 | * 0:Port-A | ||
909 | * 1:Port-B (front mic-in) | ||
910 | * 2:Port-C (line-in) | ||
911 | * 3:Port-F (mic2-in) | ||
912 | * 4:Port-E (mic-in) | ||
913 | * 5:CD | ||
914 | * 6:Port-G | ||
915 | * 7:Port-H | ||
916 | * 8:Port-D (line-in/2) | ||
917 | * 9:Mix | ||
918 | * | ||
919 | * Proposed pin assignments by the datasheet | ||
920 | * | ||
921 | * 6-stack | ||
922 | * Port-A front headphone | ||
923 | * B front mic-in | ||
924 | * C rear line-in | ||
925 | * D rear front-out | ||
926 | * E rear mic-in | ||
927 | * F rear surround | ||
928 | * G rear CLFE | ||
929 | * H rear side | ||
930 | * | ||
931 | * 3-stack | ||
932 | * Port-A front headphone | ||
933 | * B front mic | ||
934 | * C rear line-in/surround | ||
935 | * D rear front-out | ||
936 | * E rear mic-in/CLFE | ||
937 | * | ||
938 | * laptop | ||
939 | * Port-A headphone | ||
940 | * B mic-in | ||
941 | * C docking station | ||
942 | * D internal speaker (with EAPD) | ||
943 | * E/F quad mic array | ||
944 | */ | ||
945 | |||
946 | |||
947 | /* models */ | ||
948 | enum { | ||
949 | AD1988_6STACK, | ||
950 | AD1988_6STACK_DIG, | ||
951 | AD1988_3STACK, | ||
952 | AD1988_3STACK_DIG, | ||
953 | AD1988_LAPTOP, | ||
954 | AD1988_LAPTOP_DIG, | ||
955 | AD1988_MODEL_LAST, | ||
956 | }; | ||
957 | |||
958 | |||
959 | /* | ||
960 | * mixers | ||
961 | */ | ||
962 | |||
963 | static hda_nid_t ad1988_dac_nids[4] = { | ||
964 | 0x04, 0x06, 0x05, 0x0a | ||
965 | }; | ||
966 | |||
967 | static hda_nid_t ad1988_adc_nids[3] = { | ||
968 | 0x08, 0x09, 0x0f | ||
969 | }; | ||
970 | |||
971 | #define AD1988_SPDIF_OUT 0x02 | ||
972 | #define AD1988_SPDIF_IN 0x07 | ||
973 | |||
974 | static struct hda_input_mux ad1988_6stack_capture_source = { | ||
975 | .num_items = 5, | ||
976 | .items = { | ||
977 | { "Front Mic", 0x0 }, | ||
978 | { "Line", 0x1 }, | ||
979 | { "Mic", 0x4 }, | ||
980 | { "CD", 0x5 }, | ||
981 | { "Mix", 0x9 }, | ||
982 | }, | ||
983 | }; | ||
984 | |||
985 | static struct hda_input_mux ad1988_laptop_capture_source = { | ||
986 | .num_items = 3, | ||
987 | .items = { | ||
988 | { "Mic/Line", 0x0 }, | ||
989 | { "CD", 0x5 }, | ||
990 | { "Mix", 0x9 }, | ||
991 | }, | ||
992 | }; | ||
993 | |||
994 | /* | ||
995 | */ | ||
996 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | ||
997 | struct snd_ctl_elem_info *uinfo) | ||
998 | { | ||
999 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1000 | struct ad198x_spec *spec = codec->spec; | ||
1001 | return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, | ||
1002 | spec->num_channel_mode); | ||
1003 | } | ||
1004 | |||
1005 | static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, | ||
1006 | struct snd_ctl_elem_value *ucontrol) | ||
1007 | { | ||
1008 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1009 | struct ad198x_spec *spec = codec->spec; | ||
1010 | return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, | ||
1011 | spec->num_channel_mode, spec->multiout.max_channels); | ||
1012 | } | ||
1013 | |||
1014 | static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | ||
1015 | struct snd_ctl_elem_value *ucontrol) | ||
1016 | { | ||
1017 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1018 | struct ad198x_spec *spec = codec->spec; | ||
1019 | return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | ||
1020 | spec->num_channel_mode, &spec->multiout.max_channels); | ||
1021 | } | ||
1022 | |||
1023 | /* | ||
1024 | * EAPD control | ||
1025 | */ | ||
1026 | static int ad1988_eapd_info(struct snd_kcontrol *kcontrol, | ||
1027 | struct snd_ctl_elem_info *uinfo) | ||
1028 | { | ||
1029 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1030 | uinfo->count = 1; | ||
1031 | uinfo->value.integer.min = 0; | ||
1032 | uinfo->value.integer.max = 1; | ||
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | static int ad1988_eapd_get(struct snd_kcontrol *kcontrol, | ||
1037 | struct snd_ctl_elem_value *ucontrol) | ||
1038 | { | ||
1039 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1040 | struct ad198x_spec *spec = codec->spec; | ||
1041 | ucontrol->value.enumerated.item[0] = ! spec->cur_eapd; | ||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | static int ad1988_eapd_put(struct snd_kcontrol *kcontrol, | ||
1046 | struct snd_ctl_elem_value *ucontrol) | ||
1047 | { | ||
1048 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1049 | struct ad198x_spec *spec = codec->spec; | ||
1050 | unsigned int eapd; | ||
1051 | eapd = ! ucontrol->value.enumerated.item[0]; | ||
1052 | if (eapd == spec->cur_eapd && ! codec->in_resume) | ||
1053 | return 0; | ||
1054 | spec->cur_eapd = eapd; | ||
1055 | snd_hda_codec_write(codec, 0x12 /* port-D */, | ||
1056 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
1057 | eapd ? 0x02 : 0x00); | ||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | /* 6-stack mode */ | ||
1062 | static struct snd_kcontrol_new ad1988_6stack_mixers[] = { | ||
1063 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
1064 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1065 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
1066 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
1067 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
1068 | |||
1069 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
1070 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | ||
1071 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | ||
1072 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | ||
1073 | HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), | ||
1074 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
1075 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
1076 | |||
1077 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
1078 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
1079 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
1080 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
1081 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
1082 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
1083 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
1084 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
1085 | |||
1086 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||
1087 | HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||
1088 | |||
1089 | HDA_CODEC_VOLUME("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
1090 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
1091 | |||
1092 | HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), | ||
1093 | HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), | ||
1094 | |||
1095 | { } /* end */ | ||
1096 | }; | ||
1097 | |||
1098 | /* 3-stack mode */ | ||
1099 | static struct snd_kcontrol_new ad1988_3stack_mixers[] = { | ||
1100 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
1101 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1102 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
1103 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
1104 | |||
1105 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
1106 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | ||
1107 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | ||
1108 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | ||
1109 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
1110 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
1111 | |||
1112 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
1113 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
1114 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
1115 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
1116 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
1117 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
1118 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
1119 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
1120 | |||
1121 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||
1122 | HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||
1123 | |||
1124 | HDA_CODEC_VOLUME("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
1125 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
1126 | |||
1127 | HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), | ||
1128 | HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), | ||
1129 | { | ||
1130 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1131 | .name = "Channel Mode", | ||
1132 | .info = ad198x_ch_mode_info, | ||
1133 | .get = ad198x_ch_mode_get, | ||
1134 | .put = ad198x_ch_mode_put, | ||
1135 | }, | ||
1136 | |||
1137 | { } /* end */ | ||
1138 | }; | ||
1139 | |||
1140 | /* laptop mode */ | ||
1141 | static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | ||
1142 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
1143 | HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), | ||
1144 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
1145 | |||
1146 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
1147 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
1148 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
1149 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
1150 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
1151 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
1152 | |||
1153 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||
1154 | HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||
1155 | |||
1156 | HDA_CODEC_VOLUME("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
1157 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
1158 | |||
1159 | HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT), | ||
1160 | |||
1161 | { | ||
1162 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1163 | .name = "External Amplifier", | ||
1164 | .info = ad1988_eapd_info, | ||
1165 | .get = ad1988_eapd_get, | ||
1166 | .put = ad1988_eapd_put, | ||
1167 | }, | ||
1168 | |||
1169 | { } /* end */ | ||
1170 | }; | ||
1171 | |||
1172 | /* capture */ | ||
1173 | static struct snd_kcontrol_new ad1988_capture_mixers[] = { | ||
1174 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1175 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
1176 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
1177 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
1178 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
1179 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
1180 | { | ||
1181 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1182 | /* The multiple "Capture Source" controls confuse alsamixer | ||
1183 | * So call somewhat different.. | ||
1184 | * FIXME: the controls appear in the "playback" view! | ||
1185 | */ | ||
1186 | /* .name = "Capture Source", */ | ||
1187 | .name = "Input Source", | ||
1188 | .count = 3, | ||
1189 | .info = ad198x_mux_enum_info, | ||
1190 | .get = ad198x_mux_enum_get, | ||
1191 | .put = ad198x_mux_enum_put, | ||
1192 | }, | ||
1193 | { } /* end */ | ||
1194 | }; | ||
1195 | |||
1196 | static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, | ||
1197 | struct snd_ctl_elem_info *uinfo) | ||
1198 | { | ||
1199 | static char *texts[] = { | ||
1200 | "PCM", "ADC1", "ADC2", "ADC3" | ||
1201 | }; | ||
1202 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1203 | uinfo->count = 1; | ||
1204 | uinfo->value.enumerated.items = 4; | ||
1205 | if (uinfo->value.enumerated.item >= 4) | ||
1206 | uinfo->value.enumerated.item = 3; | ||
1207 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, | ||
1212 | struct snd_ctl_elem_value *ucontrol) | ||
1213 | { | ||
1214 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1215 | unsigned int sel; | ||
1216 | |||
1217 | sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1218 | if (sel > 0) { | ||
1219 | sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1220 | if (sel <= 3) | ||
1221 | sel++; | ||
1222 | else | ||
1223 | sel = 0; | ||
1224 | } | ||
1225 | ucontrol->value.enumerated.item[0] = sel; | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | ||
1230 | struct snd_ctl_elem_value *ucontrol) | ||
1231 | { | ||
1232 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1233 | unsigned int sel; | ||
1234 | int change; | ||
1235 | |||
1236 | sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1237 | if (! ucontrol->value.enumerated.item[0]) { | ||
1238 | change = sel != 0; | ||
1239 | if (change) | ||
1240 | snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 0); | ||
1241 | } else { | ||
1242 | change = sel == 0; | ||
1243 | if (change) | ||
1244 | snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 1); | ||
1245 | sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1; | ||
1246 | change |= sel == ucontrol->value.enumerated.item[0]; | ||
1247 | if (change) | ||
1248 | snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, | ||
1249 | ucontrol->value.enumerated.item[0] - 1); | ||
1250 | } | ||
1251 | return change; | ||
1252 | } | ||
1253 | |||
1254 | static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | ||
1255 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
1256 | { | ||
1257 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1258 | .name = "IEC958 Playback Source", | ||
1259 | .info = ad1988_spdif_playback_source_info, | ||
1260 | .get = ad1988_spdif_playback_source_get, | ||
1261 | .put = ad1988_spdif_playback_source_put, | ||
1262 | }, | ||
1263 | { } /* end */ | ||
1264 | }; | ||
1265 | |||
1266 | static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { | ||
1267 | HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), | ||
1268 | { } /* end */ | ||
1269 | }; | ||
1270 | |||
1271 | |||
1272 | /* | ||
1273 | * initialization verbs | ||
1274 | */ | ||
1275 | |||
1276 | /* | ||
1277 | * for 6-stack (+dig) | ||
1278 | */ | ||
1279 | static struct hda_verb ad1988_6stack_init_verbs[] = { | ||
1280 | /* Front, Surround, CLFE, side DAC; mute as default */ | ||
1281 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1282 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1283 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1284 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1285 | /* Port-A front headphon path */ | ||
1286 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ | ||
1287 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1288 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1289 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1290 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1291 | /* Port-D line-out path */ | ||
1292 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1293 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1294 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1295 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1296 | /* Port-F surround path */ | ||
1297 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1298 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1299 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1300 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1301 | /* Port-G CLFE path */ | ||
1302 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1303 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1304 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1305 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1306 | /* Port-H side path */ | ||
1307 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1308 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1309 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1310 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1311 | /* Mono out path */ | ||
1312 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
1313 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1314 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1315 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1316 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
1317 | /* Port-B front mic-in path */ | ||
1318 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1319 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1320 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1321 | /* Port-C line-in path */ | ||
1322 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1323 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1324 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1325 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1326 | /* Port-E mic-in path */ | ||
1327 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1328 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1329 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1330 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1331 | |||
1332 | { } | ||
1333 | }; | ||
1334 | |||
1335 | static struct hda_verb ad1988_capture_init_verbs[] = { | ||
1336 | /* mute analog mix */ | ||
1337 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1338 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1339 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
1340 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
1341 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
1342 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
1343 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
1344 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
1345 | /* select ADCs - front-mic */ | ||
1346 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1347 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1348 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1349 | /* ADCs; muted */ | ||
1350 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1351 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1352 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1353 | |||
1354 | { } | ||
1355 | }; | ||
1356 | |||
1357 | static struct hda_verb ad1988_spdif_init_verbs[] = { | ||
1358 | /* SPDIF out sel */ | ||
1359 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
1360 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ | ||
1361 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1362 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1363 | /* SPDIF out pin */ | ||
1364 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
1365 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ | ||
1366 | |||
1367 | { } | ||
1368 | }; | ||
1369 | |||
1370 | /* | ||
1371 | * verbs for 3stack (+dig) | ||
1372 | */ | ||
1373 | static struct hda_verb ad1988_3stack_ch2_init[] = { | ||
1374 | /* set port-C to line-in */ | ||
1375 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
1376 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
1377 | /* set port-E to mic-in */ | ||
1378 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
1379 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1380 | { } /* end */ | ||
1381 | }; | ||
1382 | |||
1383 | static struct hda_verb ad1988_3stack_ch6_init[] = { | ||
1384 | /* set port-C to surround out */ | ||
1385 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1386 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1387 | /* set port-E to CLFE out */ | ||
1388 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1389 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1390 | { } /* end */ | ||
1391 | }; | ||
1392 | |||
1393 | static struct hda_channel_mode ad1988_3stack_modes[2] = { | ||
1394 | { 2, ad1988_3stack_ch2_init }, | ||
1395 | { 6, ad1988_3stack_ch6_init }, | ||
1396 | }; | ||
1397 | |||
1398 | static struct hda_verb ad1988_3stack_init_verbs[] = { | ||
1399 | /* Front, Surround, CLFE, side DAC; mute as default */ | ||
1400 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1401 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1402 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1403 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1404 | /* Port-A front headphon path */ | ||
1405 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ | ||
1406 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1407 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1408 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1409 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1410 | /* Port-D line-out path */ | ||
1411 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1412 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1413 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1414 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1415 | /* Mono out path */ | ||
1416 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
1417 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1418 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1419 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1420 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
1421 | /* Port-B front mic-in path */ | ||
1422 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1423 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1424 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1425 | /* Port-C line-in/surround path */ | ||
1426 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1427 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1428 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1429 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1430 | /* Port-E mic-in/CLFE path */ | ||
1431 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1432 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1433 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1434 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1435 | /* mute analog mix */ | ||
1436 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1437 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1438 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
1439 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
1440 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
1441 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
1442 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
1443 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
1444 | /* select ADCs - front-mic */ | ||
1445 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1446 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1447 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1448 | /* ADCs; muted */ | ||
1449 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1450 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1451 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1452 | { } | ||
1453 | }; | ||
1454 | |||
1455 | /* | ||
1456 | * verbs for laptop mode (+dig) | ||
1457 | */ | ||
1458 | static struct hda_verb ad1988_laptop_hp_on[] = { | ||
1459 | /* unmute port-A and mute port-D */ | ||
1460 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1461 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
1462 | { } /* end */ | ||
1463 | }; | ||
1464 | static struct hda_verb ad1988_laptop_hp_off[] = { | ||
1465 | /* mute port-A and unmute port-D */ | ||
1466 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
1467 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
1468 | { } /* end */ | ||
1469 | }; | ||
1470 | |||
1471 | #define AD1988_HP_EVENT 0x01 | ||
1472 | |||
1473 | static struct hda_verb ad1988_laptop_init_verbs[] = { | ||
1474 | /* Front, Surround, CLFE, side DAC; mute as default */ | ||
1475 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1476 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1477 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1478 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1479 | /* Port-A front headphon path */ | ||
1480 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ | ||
1481 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1482 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1483 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1484 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1485 | /* unsolicited event for pin-sense */ | ||
1486 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, | ||
1487 | /* Port-D line-out path + EAPD */ | ||
1488 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1489 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1490 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1491 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1492 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ | ||
1493 | /* Mono out path */ | ||
1494 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
1495 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1496 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1497 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1498 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
1499 | /* Port-B mic-in path */ | ||
1500 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1501 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1502 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1503 | /* Port-C docking station - try to output */ | ||
1504 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1505 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1506 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1507 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1508 | /* mute analog mix */ | ||
1509 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1510 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1511 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
1512 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
1513 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
1514 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
1515 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
1516 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
1517 | /* select ADCs - mic */ | ||
1518 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1519 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1520 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1521 | /* ADCs; muted */ | ||
1522 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1523 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1524 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1525 | { } | ||
1526 | }; | ||
1527 | |||
1528 | static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | ||
1529 | { | ||
1530 | if ((res >> 26) != AD1988_HP_EVENT) | ||
1531 | return; | ||
1532 | if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31)) | ||
1533 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); | ||
1534 | else | ||
1535 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | ||
1536 | } | ||
1537 | |||
1538 | |||
1539 | /* | ||
1540 | */ | ||
1541 | |||
1542 | static struct hda_board_config ad1988_cfg_tbl[] = { | ||
1543 | { .modelname = "6stack", .config = AD1988_6STACK }, | ||
1544 | { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG }, | ||
1545 | { .modelname = "3stack", .config = AD1988_3STACK }, | ||
1546 | { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG }, | ||
1547 | { .modelname = "laptop", .config = AD1988_LAPTOP }, | ||
1548 | { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG }, | ||
1549 | {} | ||
1550 | }; | ||
1551 | |||
1552 | static int patch_ad1988(struct hda_codec *codec) | ||
1553 | { | ||
1554 | struct ad198x_spec *spec; | ||
1555 | int board_config; | ||
1556 | |||
1557 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1558 | if (spec == NULL) | ||
1559 | return -ENOMEM; | ||
1560 | |||
1561 | init_MUTEX(&spec->amp_mutex); | ||
1562 | codec->spec = spec; | ||
1563 | |||
1564 | board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl); | ||
1565 | if (board_config < 0 || board_config >= AD1988_MODEL_LAST) { | ||
1566 | printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); | ||
1567 | board_config = AD1988_6STACK; | ||
1568 | } | ||
1569 | |||
1570 | switch (board_config) { | ||
1571 | case AD1988_6STACK: | ||
1572 | case AD1988_6STACK_DIG: | ||
1573 | spec->multiout.max_channels = 8; | ||
1574 | spec->multiout.num_dacs = 4; | ||
1575 | spec->multiout.dac_nids = ad1988_dac_nids; | ||
1576 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
1577 | spec->adc_nids = ad1988_adc_nids; | ||
1578 | spec->input_mux = &ad1988_6stack_capture_source; | ||
1579 | spec->num_mixers = 1; | ||
1580 | spec->mixers[0] = ad1988_6stack_mixers; | ||
1581 | spec->num_init_verbs = 1; | ||
1582 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | ||
1583 | if (board_config == AD1988_6STACK_DIG) { | ||
1584 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
1585 | spec->dig_in_nid = AD1988_SPDIF_IN; | ||
1586 | } | ||
1587 | break; | ||
1588 | case AD1988_3STACK: | ||
1589 | case AD1988_3STACK_DIG: | ||
1590 | spec->multiout.max_channels = 6; | ||
1591 | spec->multiout.num_dacs = 3; | ||
1592 | spec->multiout.dac_nids = ad1988_dac_nids; | ||
1593 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
1594 | spec->adc_nids = ad1988_adc_nids; | ||
1595 | spec->input_mux = &ad1988_6stack_capture_source; | ||
1596 | spec->channel_mode = ad1988_3stack_modes; | ||
1597 | spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); | ||
1598 | spec->num_mixers = 1; | ||
1599 | spec->mixers[0] = ad1988_3stack_mixers; | ||
1600 | spec->num_init_verbs = 1; | ||
1601 | spec->init_verbs[0] = ad1988_3stack_init_verbs; | ||
1602 | if (board_config == AD1988_3STACK_DIG) | ||
1603 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
1604 | break; | ||
1605 | case AD1988_LAPTOP: | ||
1606 | case AD1988_LAPTOP_DIG: | ||
1607 | spec->multiout.max_channels = 2; | ||
1608 | spec->multiout.num_dacs = 1; | ||
1609 | spec->multiout.dac_nids = ad1988_dac_nids; | ||
1610 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
1611 | spec->adc_nids = ad1988_adc_nids; | ||
1612 | spec->input_mux = &ad1988_laptop_capture_source; | ||
1613 | spec->num_mixers = 1; | ||
1614 | spec->mixers[0] = ad1988_laptop_mixers; | ||
1615 | spec->num_init_verbs = 1; | ||
1616 | spec->init_verbs[0] = ad1988_laptop_init_verbs; | ||
1617 | if (board_config == AD1988_LAPTOP_DIG) | ||
1618 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
1619 | break; | ||
1620 | } | ||
1621 | |||
1622 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; | ||
1623 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; | ||
1624 | if (spec->multiout.dig_out_nid) { | ||
1625 | spec->mixers[spec->num_mixers++] = ad1988_spdif_out_mixers; | ||
1626 | spec->init_verbs[spec->num_init_verbs++] = ad1988_spdif_init_verbs; | ||
1627 | } | ||
1628 | if (spec->dig_in_nid) | ||
1629 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | ||
1630 | |||
1631 | codec->patch_ops = ad198x_patch_ops; | ||
1632 | switch (board_config) { | ||
1633 | case AD1988_LAPTOP: | ||
1634 | case AD1988_LAPTOP_DIG: | ||
1635 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | ||
1636 | break; | ||
1637 | } | ||
1638 | |||
1639 | return 0; | ||
1640 | } | ||
1641 | |||
1642 | |||
1643 | /* | ||
860 | * patch entries | 1644 | * patch entries |
861 | */ | 1645 | */ |
862 | struct hda_codec_preset snd_hda_preset_analog[] = { | 1646 | struct hda_codec_preset snd_hda_preset_analog[] = { |
863 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | 1647 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, |
864 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | 1648 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, |
865 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 1649 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
1650 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, | ||
866 | {} /* terminator */ | 1651 | {} /* terminator */ |
867 | }; | 1652 | }; |