diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 743 |
1 files changed, 709 insertions, 34 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 7f93739b1e33..47d6ffc9b5b5 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <sound/core.h> | 25 | #include <sound/core.h> |
26 | #include "hda_codec.h" | 26 | #include "hda_codec.h" |
27 | #include "hda_local.h" | 27 | #include "hda_local.h" |
28 | #include <sound/tlv.h> | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | */ | 31 | */ |
@@ -61,9 +62,15 @@ struct cs_spec { | |||
61 | 62 | ||
62 | unsigned int hp_detect:1; | 63 | unsigned int hp_detect:1; |
63 | unsigned int mic_detect:1; | 64 | unsigned int mic_detect:1; |
65 | /* CS421x */ | ||
66 | unsigned int spdif_detect:1; | ||
67 | unsigned int sense_b:1; | ||
68 | hda_nid_t vendor_nid; | ||
69 | struct hda_input_mux input_mux; | ||
70 | unsigned int last_input; | ||
64 | }; | 71 | }; |
65 | 72 | ||
66 | /* available models */ | 73 | /* available models with CS420x */ |
67 | enum { | 74 | enum { |
68 | CS420X_MBP53, | 75 | CS420X_MBP53, |
69 | CS420X_MBP55, | 76 | CS420X_MBP55, |
@@ -72,6 +79,12 @@ enum { | |||
72 | CS420X_MODELS | 79 | CS420X_MODELS |
73 | }; | 80 | }; |
74 | 81 | ||
82 | /* CS421x boards */ | ||
83 | enum { | ||
84 | CS421X_CDB4210, | ||
85 | CS421X_MODELS | ||
86 | }; | ||
87 | |||
75 | /* Vendor-specific processing widget */ | 88 | /* Vendor-specific processing widget */ |
76 | #define CS420X_VENDOR_NID 0x11 | 89 | #define CS420X_VENDOR_NID 0x11 |
77 | #define CS_DIG_OUT1_PIN_NID 0x10 | 90 | #define CS_DIG_OUT1_PIN_NID 0x10 |
@@ -111,21 +124,42 @@ enum { | |||
111 | /* 0x0009 - 0x0014 -> 12 test regs */ | 124 | /* 0x0009 - 0x0014 -> 12 test regs */ |
112 | /* 0x0015 - visibility reg */ | 125 | /* 0x0015 - visibility reg */ |
113 | 126 | ||
127 | /* | ||
128 | * Cirrus Logic CS4210 | ||
129 | * | ||
130 | * 1 DAC => HP(sense) / Speakers, | ||
131 | * 1 ADC <= LineIn(sense) / MicIn / DMicIn, | ||
132 | * 1 SPDIF OUT => SPDIF Trasmitter(sense) | ||
133 | */ | ||
134 | #define CS4210_DAC_NID 0x02 | ||
135 | #define CS4210_ADC_NID 0x03 | ||
136 | #define CS421X_VENDOR_NID 0x0B | ||
137 | #define CS421X_DMIC_PIN_NID 0x09 /* Port E */ | ||
138 | #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ | ||
139 | |||
140 | #define CS421X_IDX_DEV_CFG 0x01 | ||
141 | #define CS421X_IDX_ADC_CFG 0x02 | ||
142 | #define CS421X_IDX_DAC_CFG 0x03 | ||
143 | #define CS421X_IDX_SPK_CTL 0x04 | ||
144 | |||
145 | #define SPDIF_EVENT 0x04 | ||
114 | 146 | ||
115 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) | 147 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) |
116 | { | 148 | { |
117 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | 149 | struct cs_spec *spec = codec->spec; |
150 | snd_hda_codec_write(codec, spec->vendor_nid, 0, | ||
118 | AC_VERB_SET_COEF_INDEX, idx); | 151 | AC_VERB_SET_COEF_INDEX, idx); |
119 | return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0, | 152 | return snd_hda_codec_read(codec, spec->vendor_nid, 0, |
120 | AC_VERB_GET_PROC_COEF, 0); | 153 | AC_VERB_GET_PROC_COEF, 0); |
121 | } | 154 | } |
122 | 155 | ||
123 | static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, | 156 | static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, |
124 | unsigned int coef) | 157 | unsigned int coef) |
125 | { | 158 | { |
126 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | 159 | struct cs_spec *spec = codec->spec; |
160 | snd_hda_codec_write(codec, spec->vendor_nid, 0, | ||
127 | AC_VERB_SET_COEF_INDEX, idx); | 161 | AC_VERB_SET_COEF_INDEX, idx); |
128 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | 162 | snd_hda_codec_write(codec, spec->vendor_nid, 0, |
129 | AC_VERB_SET_PROC_COEF, coef); | 163 | AC_VERB_SET_PROC_COEF, coef); |
130 | } | 164 | } |
131 | 165 | ||
@@ -347,15 +381,12 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, | |||
347 | nid = codec->start_nid; | 381 | nid = codec->start_nid; |
348 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 382 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
349 | unsigned int type; | 383 | unsigned int type; |
350 | int idx; | ||
351 | type = get_wcaps_type(get_wcaps(codec, nid)); | 384 | type = get_wcaps_type(get_wcaps(codec, nid)); |
352 | if (type != AC_WID_AUD_IN) | 385 | if (type != AC_WID_AUD_IN) |
353 | continue; | 386 | continue; |
354 | idx = snd_hda_get_conn_index(codec, nid, pin, 0); | 387 | *idxp = snd_hda_get_conn_index(codec, nid, pin, false); |
355 | if (idx >= 0) { | 388 | if (*idxp >= 0) |
356 | *idxp = idx; | ||
357 | return nid; | 389 | return nid; |
358 | } | ||
359 | } | 390 | } |
360 | return 0; | 391 | return 0; |
361 | } | 392 | } |
@@ -835,6 +866,8 @@ static int build_digital_input(struct hda_codec *codec) | |||
835 | 866 | ||
836 | /* | 867 | /* |
837 | * auto-mute and auto-mic switching | 868 | * auto-mute and auto-mic switching |
869 | * CS421x auto-output redirecting | ||
870 | * HP/SPK/SPDIF | ||
838 | */ | 871 | */ |
839 | 872 | ||
840 | static void cs_automute(struct hda_codec *codec) | 873 | static void cs_automute(struct hda_codec *codec) |
@@ -842,9 +875,25 @@ static void cs_automute(struct hda_codec *codec) | |||
842 | struct cs_spec *spec = codec->spec; | 875 | struct cs_spec *spec = codec->spec; |
843 | struct auto_pin_cfg *cfg = &spec->autocfg; | 876 | struct auto_pin_cfg *cfg = &spec->autocfg; |
844 | unsigned int hp_present; | 877 | unsigned int hp_present; |
878 | unsigned int spdif_present; | ||
845 | hda_nid_t nid; | 879 | hda_nid_t nid; |
846 | int i; | 880 | int i; |
847 | 881 | ||
882 | spdif_present = 0; | ||
883 | if (cfg->dig_outs) { | ||
884 | nid = cfg->dig_out_pins[0]; | ||
885 | if (is_jack_detectable(codec, nid)) { | ||
886 | /* | ||
887 | TODO: SPDIF output redirect when SENSE_B is enabled. | ||
888 | Shared (SENSE_A) jack (e.g HP/mini-TOSLINK) | ||
889 | assumed. | ||
890 | */ | ||
891 | if (snd_hda_jack_detect(codec, nid) | ||
892 | /* && spec->sense_b */) | ||
893 | spdif_present = 1; | ||
894 | } | ||
895 | } | ||
896 | |||
848 | hp_present = 0; | 897 | hp_present = 0; |
849 | for (i = 0; i < cfg->hp_outs; i++) { | 898 | for (i = 0; i < cfg->hp_outs; i++) { |
850 | nid = cfg->hp_pins[i]; | 899 | nid = cfg->hp_pins[i]; |
@@ -854,11 +903,19 @@ static void cs_automute(struct hda_codec *codec) | |||
854 | if (hp_present) | 903 | if (hp_present) |
855 | break; | 904 | break; |
856 | } | 905 | } |
906 | |||
907 | /* mute speakers if spdif or hp jack is plugged in */ | ||
857 | for (i = 0; i < cfg->speaker_outs; i++) { | 908 | for (i = 0; i < cfg->speaker_outs; i++) { |
858 | nid = cfg->speaker_pins[i]; | 909 | nid = cfg->speaker_pins[i]; |
859 | snd_hda_codec_write(codec, nid, 0, | 910 | snd_hda_codec_write(codec, nid, 0, |
860 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 911 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
861 | hp_present ? 0 : PIN_OUT); | 912 | hp_present ? 0 : PIN_OUT); |
913 | /* detect on spdif is specific to CS421x */ | ||
914 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | ||
915 | snd_hda_codec_write(codec, nid, 0, | ||
916 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
917 | spdif_present ? 0 : PIN_OUT); | ||
918 | } | ||
862 | } | 919 | } |
863 | if (spec->board_config == CS420X_MBP53 || | 920 | if (spec->board_config == CS420X_MBP53 || |
864 | spec->board_config == CS420X_MBP55 || | 921 | spec->board_config == CS420X_MBP55 || |
@@ -867,21 +924,62 @@ static void cs_automute(struct hda_codec *codec) | |||
867 | snd_hda_codec_write(codec, 0x01, 0, | 924 | snd_hda_codec_write(codec, 0x01, 0, |
868 | AC_VERB_SET_GPIO_DATA, gpio); | 925 | AC_VERB_SET_GPIO_DATA, gpio); |
869 | } | 926 | } |
927 | |||
928 | /* specific to CS421x */ | ||
929 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | ||
930 | /* mute HPs if spdif jack (SENSE_B) is present */ | ||
931 | for (i = 0; i < cfg->hp_outs; i++) { | ||
932 | nid = cfg->hp_pins[i]; | ||
933 | snd_hda_codec_write(codec, nid, 0, | ||
934 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
935 | (spdif_present && spec->sense_b) ? 0 : PIN_HP); | ||
936 | } | ||
937 | |||
938 | /* SPDIF TX on/off */ | ||
939 | if (cfg->dig_outs) { | ||
940 | nid = cfg->dig_out_pins[0]; | ||
941 | snd_hda_codec_write(codec, nid, 0, | ||
942 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
943 | spdif_present ? PIN_OUT : 0); | ||
944 | |||
945 | } | ||
946 | /* Update board GPIOs if neccessary ... */ | ||
947 | } | ||
870 | } | 948 | } |
871 | 949 | ||
950 | /* | ||
951 | * Auto-input redirect for CS421x | ||
952 | * Switch max 3 inputs of a single ADC (nid 3) | ||
953 | */ | ||
954 | |||
872 | static void cs_automic(struct hda_codec *codec) | 955 | static void cs_automic(struct hda_codec *codec) |
873 | { | 956 | { |
874 | struct cs_spec *spec = codec->spec; | 957 | struct cs_spec *spec = codec->spec; |
875 | struct auto_pin_cfg *cfg = &spec->autocfg; | 958 | struct auto_pin_cfg *cfg = &spec->autocfg; |
876 | hda_nid_t nid; | 959 | hda_nid_t nid; |
877 | unsigned int present; | 960 | unsigned int present; |
878 | 961 | ||
879 | nid = cfg->inputs[spec->automic_idx].pin; | 962 | nid = cfg->inputs[spec->automic_idx].pin; |
880 | present = snd_hda_jack_detect(codec, nid); | 963 | present = snd_hda_jack_detect(codec, nid); |
881 | if (present) | 964 | |
882 | change_cur_input(codec, spec->automic_idx, 0); | 965 | /* specific to CS421x, single ADC */ |
883 | else | 966 | if (spec->vendor_nid == CS421X_VENDOR_NID) { |
884 | change_cur_input(codec, !spec->automic_idx, 0); | 967 | if (present) { |
968 | spec->last_input = spec->cur_input; | ||
969 | spec->cur_input = spec->automic_idx; | ||
970 | } else { | ||
971 | spec->cur_input = spec->last_input; | ||
972 | } | ||
973 | |||
974 | snd_hda_codec_write_cache(codec, spec->cur_adc, 0, | ||
975 | AC_VERB_SET_CONNECT_SEL, | ||
976 | spec->adc_idx[spec->cur_input]); | ||
977 | } else { | ||
978 | if (present) | ||
979 | change_cur_input(codec, spec->automic_idx, 0); | ||
980 | else | ||
981 | change_cur_input(codec, !spec->automic_idx, 0); | ||
982 | } | ||
885 | } | 983 | } |
886 | 984 | ||
887 | /* | 985 | /* |
@@ -911,23 +1009,28 @@ static void init_output(struct hda_codec *codec) | |||
911 | for (i = 0; i < cfg->line_outs; i++) | 1009 | for (i = 0; i < cfg->line_outs; i++) |
912 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | 1010 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, |
913 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 1011 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); |
1012 | /* HP */ | ||
914 | for (i = 0; i < cfg->hp_outs; i++) { | 1013 | for (i = 0; i < cfg->hp_outs; i++) { |
915 | hda_nid_t nid = cfg->hp_pins[i]; | 1014 | hda_nid_t nid = cfg->hp_pins[i]; |
916 | snd_hda_codec_write(codec, nid, 0, | 1015 | snd_hda_codec_write(codec, nid, 0, |
917 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | 1016 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); |
918 | if (!cfg->speaker_outs) | 1017 | if (!cfg->speaker_outs) |
919 | continue; | 1018 | continue; |
920 | if (is_jack_detectable(codec, nid)) { | 1019 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { |
921 | snd_hda_codec_write(codec, nid, 0, | 1020 | snd_hda_codec_write(codec, nid, 0, |
922 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1021 | AC_VERB_SET_UNSOLICITED_ENABLE, |
923 | AC_USRSP_EN | HP_EVENT); | 1022 | AC_USRSP_EN | HP_EVENT); |
924 | spec->hp_detect = 1; | 1023 | spec->hp_detect = 1; |
925 | } | 1024 | } |
926 | } | 1025 | } |
1026 | |||
1027 | /* Speaker */ | ||
927 | for (i = 0; i < cfg->speaker_outs; i++) | 1028 | for (i = 0; i < cfg->speaker_outs; i++) |
928 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | 1029 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, |
929 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 1030 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); |
930 | if (spec->hp_detect) | 1031 | |
1032 | /* SPDIF is enabled on presence detect for CS421x */ | ||
1033 | if (spec->hp_detect || spec->spdif_detect) | ||
931 | cs_automute(codec); | 1034 | cs_automute(codec); |
932 | } | 1035 | } |
933 | 1036 | ||
@@ -961,19 +1064,31 @@ static void init_input(struct hda_codec *codec) | |||
961 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1064 | AC_VERB_SET_UNSOLICITED_ENABLE, |
962 | AC_USRSP_EN | MIC_EVENT); | 1065 | AC_USRSP_EN | MIC_EVENT); |
963 | } | 1066 | } |
964 | change_cur_input(codec, spec->cur_input, 1); | 1067 | /* specific to CS421x */ |
965 | if (spec->mic_detect) | 1068 | if (spec->vendor_nid == CS421X_VENDOR_NID) { |
966 | cs_automic(codec); | 1069 | if (spec->mic_detect) |
967 | 1070 | cs_automic(codec); | |
968 | coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ | 1071 | else { |
969 | if (is_active_pin(codec, CS_DMIC2_PIN_NID)) | 1072 | spec->cur_adc = spec->adc_nid[spec->cur_input]; |
970 | coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ | 1073 | snd_hda_codec_write(codec, spec->cur_adc, 0, |
971 | if (is_active_pin(codec, CS_DMIC1_PIN_NID)) | 1074 | AC_VERB_SET_CONNECT_SEL, |
972 | coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 | 1075 | spec->adc_idx[spec->cur_input]); |
973 | * No effect if SPDIF_OUT2 is selected in | 1076 | } |
974 | * IDX_SPDIF_CTL. | 1077 | } else { |
975 | */ | 1078 | change_cur_input(codec, spec->cur_input, 1); |
976 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | 1079 | if (spec->mic_detect) |
1080 | cs_automic(codec); | ||
1081 | |||
1082 | coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ | ||
1083 | if (is_active_pin(codec, CS_DMIC2_PIN_NID)) | ||
1084 | coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */ | ||
1085 | if (is_active_pin(codec, CS_DMIC1_PIN_NID)) | ||
1086 | coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off | ||
1087 | * No effect if SPDIF_OUT2 is | ||
1088 | * selected in IDX_SPDIF_CTL. | ||
1089 | */ | ||
1090 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | ||
1091 | } | ||
977 | } | 1092 | } |
978 | 1093 | ||
979 | static const struct hda_verb cs_coef_init_verbs[] = { | 1094 | static const struct hda_verb cs_coef_init_verbs[] = { |
@@ -1221,16 +1336,16 @@ static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { | |||
1221 | [CS420X_IMAC27] = imac27_pincfgs, | 1336 | [CS420X_IMAC27] = imac27_pincfgs, |
1222 | }; | 1337 | }; |
1223 | 1338 | ||
1224 | static void fix_pincfg(struct hda_codec *codec, int model) | 1339 | static void fix_pincfg(struct hda_codec *codec, int model, |
1340 | const struct cs_pincfg **pin_configs) | ||
1225 | { | 1341 | { |
1226 | const struct cs_pincfg *cfg = cs_pincfgs[model]; | 1342 | const struct cs_pincfg *cfg = pin_configs[model]; |
1227 | if (!cfg) | 1343 | if (!cfg) |
1228 | return; | 1344 | return; |
1229 | for (; cfg->nid; cfg++) | 1345 | for (; cfg->nid; cfg++) |
1230 | snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); | 1346 | snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); |
1231 | } | 1347 | } |
1232 | 1348 | ||
1233 | |||
1234 | static int patch_cs420x(struct hda_codec *codec) | 1349 | static int patch_cs420x(struct hda_codec *codec) |
1235 | { | 1350 | { |
1236 | struct cs_spec *spec; | 1351 | struct cs_spec *spec; |
@@ -1241,11 +1356,13 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1241 | return -ENOMEM; | 1356 | return -ENOMEM; |
1242 | codec->spec = spec; | 1357 | codec->spec = spec; |
1243 | 1358 | ||
1359 | spec->vendor_nid = CS420X_VENDOR_NID; | ||
1360 | |||
1244 | spec->board_config = | 1361 | spec->board_config = |
1245 | snd_hda_check_board_config(codec, CS420X_MODELS, | 1362 | snd_hda_check_board_config(codec, CS420X_MODELS, |
1246 | cs420x_models, cs420x_cfg_tbl); | 1363 | cs420x_models, cs420x_cfg_tbl); |
1247 | if (spec->board_config >= 0) | 1364 | if (spec->board_config >= 0) |
1248 | fix_pincfg(codec, spec->board_config); | 1365 | fix_pincfg(codec, spec->board_config, cs_pincfgs); |
1249 | 1366 | ||
1250 | switch (spec->board_config) { | 1367 | switch (spec->board_config) { |
1251 | case CS420X_IMAC27: | 1368 | case CS420X_IMAC27: |
@@ -1272,6 +1389,562 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1272 | return err; | 1389 | return err; |
1273 | } | 1390 | } |
1274 | 1391 | ||
1392 | /* | ||
1393 | * Cirrus Logic CS4210 | ||
1394 | * | ||
1395 | * 1 DAC => HP(sense) / Speakers, | ||
1396 | * 1 ADC <= LineIn(sense) / MicIn / DMicIn, | ||
1397 | * 1 SPDIF OUT => SPDIF Trasmitter(sense) | ||
1398 | */ | ||
1399 | |||
1400 | /* CS4210 board names */ | ||
1401 | static const char *cs421x_models[CS421X_MODELS] = { | ||
1402 | [CS421X_CDB4210] = "cdb4210", | ||
1403 | }; | ||
1404 | |||
1405 | static const struct snd_pci_quirk cs421x_cfg_tbl[] = { | ||
1406 | /* Test Intel board + CDB2410 */ | ||
1407 | SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), | ||
1408 | {} /* terminator */ | ||
1409 | }; | ||
1410 | |||
1411 | /* CS4210 board pinconfigs */ | ||
1412 | /* Default CS4210 (CDB4210)*/ | ||
1413 | static const struct cs_pincfg cdb4210_pincfgs[] = { | ||
1414 | { 0x05, 0x0321401f }, | ||
1415 | { 0x06, 0x90170010 }, | ||
1416 | { 0x07, 0x03813031 }, | ||
1417 | { 0x08, 0xb7a70037 }, | ||
1418 | { 0x09, 0xb7a6003e }, | ||
1419 | { 0x0a, 0x034510f0 }, | ||
1420 | {} /* terminator */ | ||
1421 | }; | ||
1422 | |||
1423 | static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = { | ||
1424 | [CS421X_CDB4210] = cdb4210_pincfgs, | ||
1425 | }; | ||
1426 | |||
1427 | static const struct hda_verb cs421x_coef_init_verbs[] = { | ||
1428 | {0x0B, AC_VERB_SET_PROC_STATE, 1}, | ||
1429 | {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, | ||
1430 | /* | ||
1431 | Disable Coefficient Index Auto-Increment(DAI)=1, | ||
1432 | PDREF=0 | ||
1433 | */ | ||
1434 | {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, | ||
1435 | |||
1436 | {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, | ||
1437 | /* ADC SZCMode = Digital Soft Ramp */ | ||
1438 | {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 }, | ||
1439 | |||
1440 | {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG}, | ||
1441 | {0x0B, AC_VERB_SET_PROC_COEF, | ||
1442 | (0x0002 /* DAC SZCMode = Digital Soft Ramp */ | ||
1443 | | 0x0004 /* Mute DAC on FIFO error */ | ||
1444 | | 0x0008 /* Enable DAC High Pass Filter */ | ||
1445 | )}, | ||
1446 | {} /* terminator */ | ||
1447 | }; | ||
1448 | |||
1449 | /* Errata: CS4210 rev A1 Silicon | ||
1450 | * | ||
1451 | * http://www.cirrus.com/en/pubs/errata/ | ||
1452 | * | ||
1453 | * Description: | ||
1454 | * 1. Performance degredation is present in the ADC. | ||
1455 | * 2. Speaker output is not completely muted upon HP detect. | ||
1456 | * 3. Noise is present when clipping occurs on the amplified | ||
1457 | * speaker outputs. | ||
1458 | * | ||
1459 | * Workaround: | ||
1460 | * The following verb sequence written to the registers during | ||
1461 | * initialization will correct the issues listed above. | ||
1462 | */ | ||
1463 | |||
1464 | static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = { | ||
1465 | {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ | ||
1466 | |||
1467 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006}, | ||
1468 | {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */ | ||
1469 | |||
1470 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A}, | ||
1471 | {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */ | ||
1472 | |||
1473 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011}, | ||
1474 | {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */ | ||
1475 | |||
1476 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A}, | ||
1477 | {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */ | ||
1478 | |||
1479 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B}, | ||
1480 | {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */ | ||
1481 | |||
1482 | {} /* terminator */ | ||
1483 | }; | ||
1484 | |||
1485 | /* Speaker Amp Gain is controlled by the vendor widget's coef 4 */ | ||
1486 | static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0); | ||
1487 | |||
1488 | static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol, | ||
1489 | struct snd_ctl_elem_info *uinfo) | ||
1490 | { | ||
1491 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1492 | uinfo->count = 1; | ||
1493 | uinfo->value.integer.min = 0; | ||
1494 | uinfo->value.integer.max = 3; | ||
1495 | return 0; | ||
1496 | } | ||
1497 | |||
1498 | static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol, | ||
1499 | struct snd_ctl_elem_value *ucontrol) | ||
1500 | { | ||
1501 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1502 | |||
1503 | ucontrol->value.integer.value[0] = | ||
1504 | cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003; | ||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, | ||
1509 | struct snd_ctl_elem_value *ucontrol) | ||
1510 | { | ||
1511 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1512 | |||
1513 | unsigned int vol = ucontrol->value.integer.value[0]; | ||
1514 | unsigned int coef = | ||
1515 | cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL); | ||
1516 | unsigned int original_coef = coef; | ||
1517 | |||
1518 | coef &= ~0x0003; | ||
1519 | coef |= (vol & 0x0003); | ||
1520 | if (original_coef == coef) | ||
1521 | return 0; | ||
1522 | else { | ||
1523 | cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); | ||
1524 | return 1; | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { | ||
1529 | |||
1530 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1531 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1532 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1533 | .name = "Speaker Boost Playback Volume", | ||
1534 | .info = cs421x_boost_vol_info, | ||
1535 | .get = cs421x_boost_vol_get, | ||
1536 | .put = cs421x_boost_vol_put, | ||
1537 | .tlv = { .p = cs421x_speaker_boost_db_scale }, | ||
1538 | }; | ||
1539 | |||
1540 | static void cs421x_pinmux_init(struct hda_codec *codec) | ||
1541 | { | ||
1542 | struct cs_spec *spec = codec->spec; | ||
1543 | unsigned int def_conf, coef; | ||
1544 | |||
1545 | /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */ | ||
1546 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); | ||
1547 | |||
1548 | if (spec->gpio_mask) | ||
1549 | coef |= 0x0008; /* B1,B2 are GPIOs */ | ||
1550 | else | ||
1551 | coef &= ~0x0008; | ||
1552 | |||
1553 | if (spec->sense_b) | ||
1554 | coef |= 0x0010; /* B2 is SENSE_B, not inverted */ | ||
1555 | else | ||
1556 | coef &= ~0x0010; | ||
1557 | |||
1558 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | ||
1559 | |||
1560 | if ((spec->gpio_mask || spec->sense_b) && | ||
1561 | is_active_pin(codec, CS421X_DMIC_PIN_NID)) { | ||
1562 | |||
1563 | /* | ||
1564 | GPIO or SENSE_B forced - disconnect the DMIC pin. | ||
1565 | */ | ||
1566 | def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); | ||
1567 | def_conf &= ~AC_DEFCFG_PORT_CONN; | ||
1568 | def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); | ||
1569 | snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf); | ||
1570 | } | ||
1571 | } | ||
1572 | |||
1573 | static void init_cs421x_digital(struct hda_codec *codec) | ||
1574 | { | ||
1575 | struct cs_spec *spec = codec->spec; | ||
1576 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
1577 | int i; | ||
1578 | |||
1579 | |||
1580 | for (i = 0; i < cfg->dig_outs; i++) { | ||
1581 | hda_nid_t nid = cfg->dig_out_pins[i]; | ||
1582 | if (!cfg->speaker_outs) | ||
1583 | continue; | ||
1584 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { | ||
1585 | |||
1586 | snd_hda_codec_write(codec, nid, 0, | ||
1587 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1588 | AC_USRSP_EN | SPDIF_EVENT); | ||
1589 | spec->spdif_detect = 1; | ||
1590 | } | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | static int cs421x_init(struct hda_codec *codec) | ||
1595 | { | ||
1596 | struct cs_spec *spec = codec->spec; | ||
1597 | |||
1598 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs); | ||
1599 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); | ||
1600 | |||
1601 | cs421x_pinmux_init(codec); | ||
1602 | |||
1603 | if (spec->gpio_mask) { | ||
1604 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, | ||
1605 | spec->gpio_mask); | ||
1606 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, | ||
1607 | spec->gpio_dir); | ||
1608 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
1609 | spec->gpio_data); | ||
1610 | } | ||
1611 | |||
1612 | init_output(codec); | ||
1613 | init_input(codec); | ||
1614 | init_cs421x_digital(codec); | ||
1615 | |||
1616 | return 0; | ||
1617 | } | ||
1618 | |||
1619 | /* | ||
1620 | * CS4210 Input MUX (1 ADC) | ||
1621 | */ | ||
1622 | static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
1623 | struct snd_ctl_elem_info *uinfo) | ||
1624 | { | ||
1625 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1626 | struct cs_spec *spec = codec->spec; | ||
1627 | |||
1628 | return snd_hda_input_mux_info(&spec->input_mux, uinfo); | ||
1629 | } | ||
1630 | |||
1631 | static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
1632 | struct snd_ctl_elem_value *ucontrol) | ||
1633 | { | ||
1634 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1635 | struct cs_spec *spec = codec->spec; | ||
1636 | |||
1637 | ucontrol->value.enumerated.item[0] = spec->cur_input; | ||
1638 | return 0; | ||
1639 | } | ||
1640 | |||
1641 | static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
1642 | struct snd_ctl_elem_value *ucontrol) | ||
1643 | { | ||
1644 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1645 | struct cs_spec *spec = codec->spec; | ||
1646 | |||
1647 | return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, | ||
1648 | spec->adc_nid[0], &spec->cur_input); | ||
1649 | |||
1650 | } | ||
1651 | |||
1652 | static struct snd_kcontrol_new cs421x_capture_source = { | ||
1653 | |||
1654 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1655 | .name = "Capture Source", | ||
1656 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
1657 | .info = cs421x_mux_enum_info, | ||
1658 | .get = cs421x_mux_enum_get, | ||
1659 | .put = cs421x_mux_enum_put, | ||
1660 | }; | ||
1661 | |||
1662 | static int cs421x_add_input_volume_control(struct hda_codec *codec, int item) | ||
1663 | { | ||
1664 | struct cs_spec *spec = codec->spec; | ||
1665 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
1666 | const struct hda_input_mux *imux = &spec->input_mux; | ||
1667 | hda_nid_t pin = cfg->inputs[item].pin; | ||
1668 | struct snd_kcontrol *kctl; | ||
1669 | u32 caps; | ||
1670 | |||
1671 | if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) | ||
1672 | return 0; | ||
1673 | |||
1674 | caps = query_amp_caps(codec, pin, HDA_INPUT); | ||
1675 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1676 | if (caps <= 1) | ||
1677 | return 0; | ||
1678 | |||
1679 | return add_volume(codec, imux->items[item].label, 0, | ||
1680 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); | ||
1681 | } | ||
1682 | |||
1683 | /* add a (input-boost) volume control to the given input pin */ | ||
1684 | static int build_cs421x_input(struct hda_codec *codec) | ||
1685 | { | ||
1686 | struct cs_spec *spec = codec->spec; | ||
1687 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
1688 | struct hda_input_mux *imux = &spec->input_mux; | ||
1689 | int i, err, type_idx; | ||
1690 | const char *label; | ||
1691 | |||
1692 | if (!spec->num_inputs) | ||
1693 | return 0; | ||
1694 | |||
1695 | /* make bind-capture */ | ||
1696 | spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); | ||
1697 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); | ||
1698 | for (i = 0; i < 2; i++) { | ||
1699 | struct snd_kcontrol *kctl; | ||
1700 | int n; | ||
1701 | if (!spec->capture_bind[i]) | ||
1702 | return -ENOMEM; | ||
1703 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); | ||
1704 | if (!kctl) | ||
1705 | return -ENOMEM; | ||
1706 | kctl->private_value = (long)spec->capture_bind[i]; | ||
1707 | err = snd_hda_ctl_add(codec, 0, kctl); | ||
1708 | if (err < 0) | ||
1709 | return err; | ||
1710 | for (n = 0; n < AUTO_PIN_LAST; n++) { | ||
1711 | if (!spec->adc_nid[n]) | ||
1712 | continue; | ||
1713 | err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); | ||
1714 | if (err < 0) | ||
1715 | return err; | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1719 | /* Add Input MUX Items + Capture Volume/Switch */ | ||
1720 | for (i = 0; i < spec->num_inputs; i++) { | ||
1721 | label = hda_get_autocfg_input_label(codec, cfg, i); | ||
1722 | snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx); | ||
1723 | |||
1724 | err = cs421x_add_input_volume_control(codec, i); | ||
1725 | if (err < 0) | ||
1726 | return err; | ||
1727 | } | ||
1728 | |||
1729 | /* | ||
1730 | Add 'Capture Source' Switch if | ||
1731 | * 2 inputs and no mic detec | ||
1732 | * 3 inputs | ||
1733 | */ | ||
1734 | if ((spec->num_inputs == 2 && !spec->mic_detect) || | ||
1735 | (spec->num_inputs == 3)) { | ||
1736 | |||
1737 | err = snd_hda_ctl_add(codec, spec->adc_nid[0], | ||
1738 | snd_ctl_new1(&cs421x_capture_source, codec)); | ||
1739 | if (err < 0) | ||
1740 | return err; | ||
1741 | } | ||
1742 | |||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | /* Single DAC (Mute/Gain) */ | ||
1747 | static int build_cs421x_output(struct hda_codec *codec) | ||
1748 | { | ||
1749 | hda_nid_t dac = CS4210_DAC_NID; | ||
1750 | struct cs_spec *spec = codec->spec; | ||
1751 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
1752 | struct snd_kcontrol *kctl; | ||
1753 | int err; | ||
1754 | char *name = "HP/Speakers"; | ||
1755 | |||
1756 | fix_volume_caps(codec, dac); | ||
1757 | if (!spec->vmaster_sw) { | ||
1758 | err = add_vmaster(codec, dac); | ||
1759 | if (err < 0) | ||
1760 | return err; | ||
1761 | } | ||
1762 | |||
1763 | err = add_mute(codec, name, 0, | ||
1764 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | ||
1765 | if (err < 0) | ||
1766 | return err; | ||
1767 | err = snd_ctl_add_slave(spec->vmaster_sw, kctl); | ||
1768 | if (err < 0) | ||
1769 | return err; | ||
1770 | |||
1771 | err = add_volume(codec, name, 0, | ||
1772 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | ||
1773 | if (err < 0) | ||
1774 | return err; | ||
1775 | err = snd_ctl_add_slave(spec->vmaster_vol, kctl); | ||
1776 | if (err < 0) | ||
1777 | return err; | ||
1778 | |||
1779 | if (cfg->speaker_outs) { | ||
1780 | err = snd_hda_ctl_add(codec, 0, | ||
1781 | snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); | ||
1782 | if (err < 0) | ||
1783 | return err; | ||
1784 | } | ||
1785 | return err; | ||
1786 | } | ||
1787 | |||
1788 | static int cs421x_build_controls(struct hda_codec *codec) | ||
1789 | { | ||
1790 | int err; | ||
1791 | |||
1792 | err = build_cs421x_output(codec); | ||
1793 | if (err < 0) | ||
1794 | return err; | ||
1795 | err = build_cs421x_input(codec); | ||
1796 | if (err < 0) | ||
1797 | return err; | ||
1798 | err = build_digital_output(codec); | ||
1799 | if (err < 0) | ||
1800 | return err; | ||
1801 | return cs421x_init(codec); | ||
1802 | } | ||
1803 | |||
1804 | static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) | ||
1805 | { | ||
1806 | switch ((res >> 26) & 0x3f) { | ||
1807 | case HP_EVENT: | ||
1808 | case SPDIF_EVENT: | ||
1809 | cs_automute(codec); | ||
1810 | break; | ||
1811 | |||
1812 | case MIC_EVENT: | ||
1813 | cs_automic(codec); | ||
1814 | break; | ||
1815 | } | ||
1816 | } | ||
1817 | |||
1818 | static int parse_cs421x_input(struct hda_codec *codec) | ||
1819 | { | ||
1820 | struct cs_spec *spec = codec->spec; | ||
1821 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
1822 | int i; | ||
1823 | |||
1824 | for (i = 0; i < cfg->num_inputs; i++) { | ||
1825 | hda_nid_t pin = cfg->inputs[i].pin; | ||
1826 | spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); | ||
1827 | spec->cur_input = spec->last_input = i; | ||
1828 | spec->num_inputs++; | ||
1829 | |||
1830 | /* check whether the automatic mic switch is available */ | ||
1831 | if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) { | ||
1832 | spec->mic_detect = 1; | ||
1833 | spec->automic_idx = i; | ||
1834 | } | ||
1835 | } | ||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | static int cs421x_parse_auto_config(struct hda_codec *codec) | ||
1840 | { | ||
1841 | struct cs_spec *spec = codec->spec; | ||
1842 | int err; | ||
1843 | |||
1844 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
1845 | if (err < 0) | ||
1846 | return err; | ||
1847 | err = parse_output(codec); | ||
1848 | if (err < 0) | ||
1849 | return err; | ||
1850 | err = parse_cs421x_input(codec); | ||
1851 | if (err < 0) | ||
1852 | return err; | ||
1853 | err = parse_digital_output(codec); | ||
1854 | if (err < 0) | ||
1855 | return err; | ||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1859 | #ifdef CONFIG_PM | ||
1860 | /* | ||
1861 | Manage PDREF, when transitioning to D3hot | ||
1862 | (DAC,ADC) -> D3, PDREF=1, AFG->D3 | ||
1863 | */ | ||
1864 | static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) | ||
1865 | { | ||
1866 | unsigned int coef; | ||
1867 | |||
1868 | snd_hda_shutup_pins(codec); | ||
1869 | |||
1870 | snd_hda_codec_write(codec, CS4210_DAC_NID, 0, | ||
1871 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
1872 | snd_hda_codec_write(codec, CS4210_ADC_NID, 0, | ||
1873 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
1874 | |||
1875 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); | ||
1876 | coef |= 0x0004; /* PDREF */ | ||
1877 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | ||
1878 | |||
1879 | return 0; | ||
1880 | } | ||
1881 | #endif | ||
1882 | |||
1883 | static struct hda_codec_ops cs4210_patch_ops = { | ||
1884 | .build_controls = cs421x_build_controls, | ||
1885 | .build_pcms = cs_build_pcms, | ||
1886 | .init = cs421x_init, | ||
1887 | .free = cs_free, | ||
1888 | .unsol_event = cs421x_unsol_event, | ||
1889 | #ifdef CONFIG_PM | ||
1890 | .suspend = cs421x_suspend, | ||
1891 | #endif | ||
1892 | }; | ||
1893 | |||
1894 | static int patch_cs421x(struct hda_codec *codec) | ||
1895 | { | ||
1896 | struct cs_spec *spec; | ||
1897 | int err; | ||
1898 | |||
1899 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1900 | if (!spec) | ||
1901 | return -ENOMEM; | ||
1902 | codec->spec = spec; | ||
1903 | |||
1904 | spec->vendor_nid = CS421X_VENDOR_NID; | ||
1905 | |||
1906 | spec->board_config = | ||
1907 | snd_hda_check_board_config(codec, CS421X_MODELS, | ||
1908 | cs421x_models, cs421x_cfg_tbl); | ||
1909 | if (spec->board_config >= 0) | ||
1910 | fix_pincfg(codec, spec->board_config, cs421x_pincfgs); | ||
1911 | /* | ||
1912 | Setup GPIO/SENSE for each board (if used) | ||
1913 | */ | ||
1914 | switch (spec->board_config) { | ||
1915 | case CS421X_CDB4210: | ||
1916 | snd_printd("CS4210 board: %s\n", | ||
1917 | cs421x_models[spec->board_config]); | ||
1918 | /* spec->gpio_mask = 3; | ||
1919 | spec->gpio_dir = 3; | ||
1920 | spec->gpio_data = 3; | ||
1921 | */ | ||
1922 | spec->sense_b = 1; | ||
1923 | |||
1924 | break; | ||
1925 | } | ||
1926 | |||
1927 | /* | ||
1928 | Update the GPIO/DMIC/SENSE_B pinmux before the configuration | ||
1929 | is auto-parsed. If GPIO or SENSE_B is forced, DMIC input | ||
1930 | is disabled. | ||
1931 | */ | ||
1932 | cs421x_pinmux_init(codec); | ||
1933 | |||
1934 | err = cs421x_parse_auto_config(codec); | ||
1935 | if (err < 0) | ||
1936 | goto error; | ||
1937 | |||
1938 | codec->patch_ops = cs4210_patch_ops; | ||
1939 | |||
1940 | return 0; | ||
1941 | |||
1942 | error: | ||
1943 | kfree(codec->spec); | ||
1944 | codec->spec = NULL; | ||
1945 | return err; | ||
1946 | } | ||
1947 | |||
1275 | 1948 | ||
1276 | /* | 1949 | /* |
1277 | * patch entries | 1950 | * patch entries |
@@ -1279,11 +1952,13 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1279 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { | 1952 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { |
1280 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, | 1953 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, |
1281 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, | 1954 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, |
1955 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x }, | ||
1282 | {} /* terminator */ | 1956 | {} /* terminator */ |
1283 | }; | 1957 | }; |
1284 | 1958 | ||
1285 | MODULE_ALIAS("snd-hda-codec-id:10134206"); | 1959 | MODULE_ALIAS("snd-hda-codec-id:10134206"); |
1286 | MODULE_ALIAS("snd-hda-codec-id:10134207"); | 1960 | MODULE_ALIAS("snd-hda-codec-id:10134207"); |
1961 | MODULE_ALIAS("snd-hda-codec-id:10134210"); | ||
1287 | 1962 | ||
1288 | MODULE_LICENSE("GPL"); | 1963 | MODULE_LICENSE("GPL"); |
1289 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); | 1964 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); |