diff options
Diffstat (limited to 'sound/pci/hda/patch_cirrus.c')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 187 |
1 files changed, 118 insertions, 69 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 70a7abda7e2..0e99357e822 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <sound/core.h> | 26 | #include <sound/core.h> |
27 | #include "hda_codec.h" | 27 | #include "hda_codec.h" |
28 | #include "hda_local.h" | 28 | #include "hda_local.h" |
29 | #include "hda_jack.h" | ||
29 | #include <sound/tlv.h> | 30 | #include <sound/tlv.h> |
30 | 31 | ||
31 | /* | 32 | /* |
@@ -78,6 +79,7 @@ enum { | |||
78 | CS420X_MBP53, | 79 | CS420X_MBP53, |
79 | CS420X_MBP55, | 80 | CS420X_MBP55, |
80 | CS420X_IMAC27, | 81 | CS420X_IMAC27, |
82 | CS420X_IMAC27_122, | ||
81 | CS420X_APPLE, | 83 | CS420X_APPLE, |
82 | CS420X_AUTO, | 84 | CS420X_AUTO, |
83 | CS420X_MODELS | 85 | CS420X_MODELS |
@@ -137,7 +139,7 @@ enum { | |||
137 | */ | 139 | */ |
138 | #define CS4210_DAC_NID 0x02 | 140 | #define CS4210_DAC_NID 0x02 |
139 | #define CS4210_ADC_NID 0x03 | 141 | #define CS4210_ADC_NID 0x03 |
140 | #define CS421X_VENDOR_NID 0x0B | 142 | #define CS4210_VENDOR_NID 0x0B |
141 | #define CS421X_DMIC_PIN_NID 0x09 /* Port E */ | 143 | #define CS421X_DMIC_PIN_NID 0x09 /* Port E */ |
142 | #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ | 144 | #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ |
143 | 145 | ||
@@ -148,6 +150,10 @@ enum { | |||
148 | 150 | ||
149 | #define SPDIF_EVENT 0x04 | 151 | #define SPDIF_EVENT 0x04 |
150 | 152 | ||
153 | /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */ | ||
154 | #define CS4213_VENDOR_NID 0x09 | ||
155 | |||
156 | |||
151 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) | 157 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) |
152 | { | 158 | { |
153 | struct cs_spec *spec = codec->spec; | 159 | struct cs_spec *spec = codec->spec; |
@@ -721,8 +727,9 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, | |||
721 | if (uinfo->value.enumerated.item >= spec->num_inputs) | 727 | if (uinfo->value.enumerated.item >= spec->num_inputs) |
722 | uinfo->value.enumerated.item = spec->num_inputs - 1; | 728 | uinfo->value.enumerated.item = spec->num_inputs - 1; |
723 | idx = spec->input_idx[uinfo->value.enumerated.item]; | 729 | idx = spec->input_idx[uinfo->value.enumerated.item]; |
724 | strcpy(uinfo->value.enumerated.name, | 730 | snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, cfg, |
725 | hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1)); | 731 | uinfo->value.enumerated.name, |
732 | sizeof(uinfo->value.enumerated.name), NULL); | ||
726 | return 0; | 733 | return 0; |
727 | } | 734 | } |
728 | 735 | ||
@@ -920,16 +927,14 @@ static void cs_automute(struct hda_codec *codec) | |||
920 | 927 | ||
921 | /* mute speakers if spdif or hp jack is plugged in */ | 928 | /* mute speakers if spdif or hp jack is plugged in */ |
922 | for (i = 0; i < cfg->speaker_outs; i++) { | 929 | for (i = 0; i < cfg->speaker_outs; i++) { |
930 | int pin_ctl = hp_present ? 0 : PIN_OUT; | ||
931 | /* detect on spdif is specific to CS4210 */ | ||
932 | if (spdif_present && (spec->vendor_nid == CS4210_VENDOR_NID)) | ||
933 | pin_ctl = 0; | ||
934 | |||
923 | nid = cfg->speaker_pins[i]; | 935 | nid = cfg->speaker_pins[i]; |
924 | snd_hda_codec_write(codec, nid, 0, | 936 | snd_hda_codec_write(codec, nid, 0, |
925 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 937 | AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl); |
926 | hp_present ? 0 : PIN_OUT); | ||
927 | /* detect on spdif is specific to CS421x */ | ||
928 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | ||
929 | snd_hda_codec_write(codec, nid, 0, | ||
930 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
931 | spdif_present ? 0 : PIN_OUT); | ||
932 | } | ||
933 | } | 938 | } |
934 | if (spec->gpio_eapd_hp) { | 939 | if (spec->gpio_eapd_hp) { |
935 | unsigned int gpio = hp_present ? | 940 | unsigned int gpio = hp_present ? |
@@ -938,8 +943,8 @@ static void cs_automute(struct hda_codec *codec) | |||
938 | AC_VERB_SET_GPIO_DATA, gpio); | 943 | AC_VERB_SET_GPIO_DATA, gpio); |
939 | } | 944 | } |
940 | 945 | ||
941 | /* specific to CS421x */ | 946 | /* specific to CS4210 */ |
942 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | 947 | if (spec->vendor_nid == CS4210_VENDOR_NID) { |
943 | /* mute HPs if spdif jack (SENSE_B) is present */ | 948 | /* mute HPs if spdif jack (SENSE_B) is present */ |
944 | for (i = 0; i < cfg->hp_outs; i++) { | 949 | for (i = 0; i < cfg->hp_outs; i++) { |
945 | nid = cfg->hp_pins[i]; | 950 | nid = cfg->hp_pins[i]; |
@@ -976,7 +981,12 @@ static void cs_automic(struct hda_codec *codec) | |||
976 | present = snd_hda_jack_detect(codec, nid); | 981 | present = snd_hda_jack_detect(codec, nid); |
977 | 982 | ||
978 | /* specific to CS421x, single ADC */ | 983 | /* specific to CS421x, single ADC */ |
979 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | 984 | if (spec->vendor_nid == CS420X_VENDOR_NID) { |
985 | if (present) | ||
986 | change_cur_input(codec, spec->automic_idx, 0); | ||
987 | else | ||
988 | change_cur_input(codec, !spec->automic_idx, 0); | ||
989 | } else { | ||
980 | if (present) { | 990 | if (present) { |
981 | spec->last_input = spec->cur_input; | 991 | spec->last_input = spec->cur_input; |
982 | spec->cur_input = spec->automic_idx; | 992 | spec->cur_input = spec->automic_idx; |
@@ -984,11 +994,6 @@ static void cs_automic(struct hda_codec *codec) | |||
984 | spec->cur_input = spec->last_input; | 994 | spec->cur_input = spec->last_input; |
985 | } | 995 | } |
986 | cs_update_input_select(codec); | 996 | cs_update_input_select(codec); |
987 | } else { | ||
988 | if (present) | ||
989 | change_cur_input(codec, spec->automic_idx, 0); | ||
990 | else | ||
991 | change_cur_input(codec, !spec->automic_idx, 0); | ||
992 | } | 997 | } |
993 | } | 998 | } |
994 | 999 | ||
@@ -1027,9 +1032,7 @@ static void init_output(struct hda_codec *codec) | |||
1027 | if (!cfg->speaker_outs) | 1032 | if (!cfg->speaker_outs) |
1028 | continue; | 1033 | continue; |
1029 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { | 1034 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { |
1030 | snd_hda_codec_write(codec, nid, 0, | 1035 | snd_hda_jack_detect_enable(codec, nid, HP_EVENT); |
1031 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1032 | AC_USRSP_EN | HP_EVENT); | ||
1033 | spec->hp_detect = 1; | 1036 | spec->hp_detect = 1; |
1034 | } | 1037 | } |
1035 | } | 1038 | } |
@@ -1070,19 +1073,10 @@ static void init_input(struct hda_codec *codec) | |||
1070 | AC_VERB_SET_AMP_GAIN_MUTE, | 1073 | AC_VERB_SET_AMP_GAIN_MUTE, |
1071 | AMP_IN_MUTE(spec->adc_idx[i])); | 1074 | AMP_IN_MUTE(spec->adc_idx[i])); |
1072 | if (spec->mic_detect && spec->automic_idx == i) | 1075 | if (spec->mic_detect && spec->automic_idx == i) |
1073 | snd_hda_codec_write(codec, pin, 0, | 1076 | snd_hda_jack_detect_enable(codec, pin, MIC_EVENT); |
1074 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1075 | AC_USRSP_EN | MIC_EVENT); | ||
1076 | } | 1077 | } |
1077 | /* specific to CS421x */ | 1078 | /* CS420x has multiple ADC, CS421x has single ADC */ |
1078 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | 1079 | if (spec->vendor_nid == CS420X_VENDOR_NID) { |
1079 | if (spec->mic_detect) | ||
1080 | cs_automic(codec); | ||
1081 | else { | ||
1082 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | ||
1083 | cs_update_input_select(codec); | ||
1084 | } | ||
1085 | } else { | ||
1086 | change_cur_input(codec, spec->cur_input, 1); | 1080 | change_cur_input(codec, spec->cur_input, 1); |
1087 | if (spec->mic_detect) | 1081 | if (spec->mic_detect) |
1088 | cs_automic(codec); | 1082 | cs_automic(codec); |
@@ -1096,6 +1090,13 @@ static void init_input(struct hda_codec *codec) | |||
1096 | * selected in IDX_SPDIF_CTL. | 1090 | * selected in IDX_SPDIF_CTL. |
1097 | */ | 1091 | */ |
1098 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | 1092 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); |
1093 | } else { | ||
1094 | if (spec->mic_detect) | ||
1095 | cs_automic(codec); | ||
1096 | else { | ||
1097 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | ||
1098 | cs_update_input_select(codec); | ||
1099 | } | ||
1099 | } | 1100 | } |
1100 | } | 1101 | } |
1101 | 1102 | ||
@@ -1200,11 +1201,14 @@ static int cs_init(struct hda_codec *codec) | |||
1200 | init_output(codec); | 1201 | init_output(codec); |
1201 | init_input(codec); | 1202 | init_input(codec); |
1202 | init_digital(codec); | 1203 | init_digital(codec); |
1204 | snd_hda_jack_report_sync(codec); | ||
1205 | |||
1203 | return 0; | 1206 | return 0; |
1204 | } | 1207 | } |
1205 | 1208 | ||
1206 | static int cs_build_controls(struct hda_codec *codec) | 1209 | static int cs_build_controls(struct hda_codec *codec) |
1207 | { | 1210 | { |
1211 | struct cs_spec *spec = codec->spec; | ||
1208 | int err; | 1212 | int err; |
1209 | 1213 | ||
1210 | err = build_output(codec); | 1214 | err = build_output(codec); |
@@ -1219,7 +1223,15 @@ static int cs_build_controls(struct hda_codec *codec) | |||
1219 | err = build_digital_input(codec); | 1223 | err = build_digital_input(codec); |
1220 | if (err < 0) | 1224 | if (err < 0) |
1221 | return err; | 1225 | return err; |
1222 | return cs_init(codec); | 1226 | err = cs_init(codec); |
1227 | if (err < 0) | ||
1228 | return err; | ||
1229 | |||
1230 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); | ||
1231 | if (err < 0) | ||
1232 | return err; | ||
1233 | |||
1234 | return 0; | ||
1223 | } | 1235 | } |
1224 | 1236 | ||
1225 | static void cs_free(struct hda_codec *codec) | 1237 | static void cs_free(struct hda_codec *codec) |
@@ -1232,7 +1244,7 @@ static void cs_free(struct hda_codec *codec) | |||
1232 | 1244 | ||
1233 | static void cs_unsol_event(struct hda_codec *codec, unsigned int res) | 1245 | static void cs_unsol_event(struct hda_codec *codec, unsigned int res) |
1234 | { | 1246 | { |
1235 | switch ((res >> 26) & 0x7f) { | 1247 | switch (snd_hda_jack_get_action(codec, res >> 26)) { |
1236 | case HP_EVENT: | 1248 | case HP_EVENT: |
1237 | cs_automute(codec); | 1249 | cs_automute(codec); |
1238 | break; | 1250 | break; |
@@ -1240,6 +1252,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res) | |||
1240 | cs_automic(codec); | 1252 | cs_automic(codec); |
1241 | break; | 1253 | break; |
1242 | } | 1254 | } |
1255 | snd_hda_jack_report_sync(codec); | ||
1243 | } | 1256 | } |
1244 | 1257 | ||
1245 | static const struct hda_codec_ops cs_patch_ops = { | 1258 | static const struct hda_codec_ops cs_patch_ops = { |
@@ -1278,6 +1291,7 @@ static const char * const cs420x_models[CS420X_MODELS] = { | |||
1278 | [CS420X_MBP53] = "mbp53", | 1291 | [CS420X_MBP53] = "mbp53", |
1279 | [CS420X_MBP55] = "mbp55", | 1292 | [CS420X_MBP55] = "mbp55", |
1280 | [CS420X_IMAC27] = "imac27", | 1293 | [CS420X_IMAC27] = "imac27", |
1294 | [CS420X_IMAC27_122] = "imac27_122", | ||
1281 | [CS420X_APPLE] = "apple", | 1295 | [CS420X_APPLE] = "apple", |
1282 | [CS420X_AUTO] = "auto", | 1296 | [CS420X_AUTO] = "auto", |
1283 | }; | 1297 | }; |
@@ -1294,6 +1308,7 @@ static const struct snd_pci_quirk cs420x_cfg_tbl[] = { | |||
1294 | }; | 1308 | }; |
1295 | 1309 | ||
1296 | static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = { | 1310 | static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = { |
1311 | SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), | ||
1297 | SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), | 1312 | SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), |
1298 | {} /* terminator */ | 1313 | {} /* terminator */ |
1299 | }; | 1314 | }; |
@@ -1393,6 +1408,12 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1393 | spec->gpio_mask = spec->gpio_dir = | 1408 | spec->gpio_mask = spec->gpio_dir = |
1394 | spec->gpio_eapd_hp | spec->gpio_eapd_speaker; | 1409 | spec->gpio_eapd_hp | spec->gpio_eapd_speaker; |
1395 | break; | 1410 | break; |
1411 | case CS420X_IMAC27_122: | ||
1412 | spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ | ||
1413 | spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ | ||
1414 | spec->gpio_mask = spec->gpio_dir = | ||
1415 | spec->gpio_eapd_hp | spec->gpio_eapd_speaker; | ||
1416 | break; | ||
1396 | } | 1417 | } |
1397 | 1418 | ||
1398 | err = cs_parse_auto_config(codec); | 1419 | err = cs_parse_auto_config(codec); |
@@ -1557,7 +1578,7 @@ static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { | |||
1557 | .tlv = { .p = cs421x_speaker_boost_db_scale }, | 1578 | .tlv = { .p = cs421x_speaker_boost_db_scale }, |
1558 | }; | 1579 | }; |
1559 | 1580 | ||
1560 | static void cs421x_pinmux_init(struct hda_codec *codec) | 1581 | static void cs4210_pinmux_init(struct hda_codec *codec) |
1561 | { | 1582 | { |
1562 | struct cs_spec *spec = codec->spec; | 1583 | struct cs_spec *spec = codec->spec; |
1563 | unsigned int def_conf, coef; | 1584 | unsigned int def_conf, coef; |
@@ -1602,10 +1623,7 @@ static void init_cs421x_digital(struct hda_codec *codec) | |||
1602 | if (!cfg->speaker_outs) | 1623 | if (!cfg->speaker_outs) |
1603 | continue; | 1624 | continue; |
1604 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { | 1625 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { |
1605 | 1626 | snd_hda_jack_detect_enable(codec, nid, SPDIF_EVENT); | |
1606 | snd_hda_codec_write(codec, nid, 0, | ||
1607 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1608 | AC_USRSP_EN | SPDIF_EVENT); | ||
1609 | spec->spdif_detect = 1; | 1627 | spec->spdif_detect = 1; |
1610 | } | 1628 | } |
1611 | } | 1629 | } |
@@ -1615,10 +1633,11 @@ static int cs421x_init(struct hda_codec *codec) | |||
1615 | { | 1633 | { |
1616 | struct cs_spec *spec = codec->spec; | 1634 | struct cs_spec *spec = codec->spec; |
1617 | 1635 | ||
1618 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs); | 1636 | if (spec->vendor_nid == CS4210_VENDOR_NID) { |
1619 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); | 1637 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs); |
1620 | 1638 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); | |
1621 | cs421x_pinmux_init(codec); | 1639 | cs4210_pinmux_init(codec); |
1640 | } | ||
1622 | 1641 | ||
1623 | if (spec->gpio_mask) { | 1642 | if (spec->gpio_mask) { |
1624 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, | 1643 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, |
@@ -1632,6 +1651,7 @@ static int cs421x_init(struct hda_codec *codec) | |||
1632 | init_output(codec); | 1651 | init_output(codec); |
1633 | init_input(codec); | 1652 | init_input(codec); |
1634 | init_cs421x_digital(codec); | 1653 | init_cs421x_digital(codec); |
1654 | snd_hda_jack_report_sync(codec); | ||
1635 | 1655 | ||
1636 | return 0; | 1656 | return 0; |
1637 | } | 1657 | } |
@@ -1771,32 +1791,21 @@ static int build_cs421x_output(struct hda_codec *codec) | |||
1771 | struct auto_pin_cfg *cfg = &spec->autocfg; | 1791 | struct auto_pin_cfg *cfg = &spec->autocfg; |
1772 | struct snd_kcontrol *kctl; | 1792 | struct snd_kcontrol *kctl; |
1773 | int err; | 1793 | int err; |
1774 | char *name = "HP/Speakers"; | 1794 | char *name = "Master"; |
1775 | 1795 | ||
1776 | fix_volume_caps(codec, dac); | 1796 | fix_volume_caps(codec, dac); |
1777 | if (!spec->vmaster_sw) { | ||
1778 | err = add_vmaster(codec, dac); | ||
1779 | if (err < 0) | ||
1780 | return err; | ||
1781 | } | ||
1782 | 1797 | ||
1783 | err = add_mute(codec, name, 0, | 1798 | err = add_mute(codec, name, 0, |
1784 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | 1799 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); |
1785 | if (err < 0) | 1800 | if (err < 0) |
1786 | return err; | 1801 | return err; |
1787 | err = snd_ctl_add_slave(spec->vmaster_sw, kctl); | ||
1788 | if (err < 0) | ||
1789 | return err; | ||
1790 | 1802 | ||
1791 | err = add_volume(codec, name, 0, | 1803 | err = add_volume(codec, name, 0, |
1792 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | 1804 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); |
1793 | if (err < 0) | 1805 | if (err < 0) |
1794 | return err; | 1806 | return err; |
1795 | err = snd_ctl_add_slave(spec->vmaster_vol, kctl); | ||
1796 | if (err < 0) | ||
1797 | return err; | ||
1798 | 1807 | ||
1799 | if (cfg->speaker_outs) { | 1808 | if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) { |
1800 | err = snd_hda_ctl_add(codec, 0, | 1809 | err = snd_hda_ctl_add(codec, 0, |
1801 | snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); | 1810 | snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); |
1802 | if (err < 0) | 1811 | if (err < 0) |
@@ -1807,6 +1816,7 @@ static int build_cs421x_output(struct hda_codec *codec) | |||
1807 | 1816 | ||
1808 | static int cs421x_build_controls(struct hda_codec *codec) | 1817 | static int cs421x_build_controls(struct hda_codec *codec) |
1809 | { | 1818 | { |
1819 | struct cs_spec *spec = codec->spec; | ||
1810 | int err; | 1820 | int err; |
1811 | 1821 | ||
1812 | err = build_cs421x_output(codec); | 1822 | err = build_cs421x_output(codec); |
@@ -1818,12 +1828,20 @@ static int cs421x_build_controls(struct hda_codec *codec) | |||
1818 | err = build_digital_output(codec); | 1828 | err = build_digital_output(codec); |
1819 | if (err < 0) | 1829 | if (err < 0) |
1820 | return err; | 1830 | return err; |
1821 | return cs421x_init(codec); | 1831 | err = cs421x_init(codec); |
1832 | if (err < 0) | ||
1833 | return err; | ||
1834 | |||
1835 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); | ||
1836 | if (err < 0) | ||
1837 | return err; | ||
1838 | |||
1839 | return 0; | ||
1822 | } | 1840 | } |
1823 | 1841 | ||
1824 | static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) | 1842 | static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) |
1825 | { | 1843 | { |
1826 | switch ((res >> 26) & 0x3f) { | 1844 | switch (snd_hda_jack_get_action(codec, res >> 26)) { |
1827 | case HP_EVENT: | 1845 | case HP_EVENT: |
1828 | case SPDIF_EVENT: | 1846 | case SPDIF_EVENT: |
1829 | cs_automute(codec); | 1847 | cs_automute(codec); |
@@ -1833,6 +1851,7 @@ static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) | |||
1833 | cs_automic(codec); | 1851 | cs_automic(codec); |
1834 | break; | 1852 | break; |
1835 | } | 1853 | } |
1854 | snd_hda_jack_report_sync(codec); | ||
1836 | } | 1855 | } |
1837 | 1856 | ||
1838 | static int parse_cs421x_input(struct hda_codec *codec) | 1857 | static int parse_cs421x_input(struct hda_codec *codec) |
@@ -1883,6 +1902,7 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) | |||
1883 | */ | 1902 | */ |
1884 | static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) | 1903 | static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) |
1885 | { | 1904 | { |
1905 | struct cs_spec *spec = codec->spec; | ||
1886 | unsigned int coef; | 1906 | unsigned int coef; |
1887 | 1907 | ||
1888 | snd_hda_shutup_pins(codec); | 1908 | snd_hda_shutup_pins(codec); |
@@ -1892,15 +1912,17 @@ static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) | |||
1892 | snd_hda_codec_write(codec, CS4210_ADC_NID, 0, | 1912 | snd_hda_codec_write(codec, CS4210_ADC_NID, 0, |
1893 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | 1913 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); |
1894 | 1914 | ||
1895 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); | 1915 | if (spec->vendor_nid == CS4210_VENDOR_NID) { |
1896 | coef |= 0x0004; /* PDREF */ | 1916 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); |
1897 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | 1917 | coef |= 0x0004; /* PDREF */ |
1918 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | ||
1919 | } | ||
1898 | 1920 | ||
1899 | return 0; | 1921 | return 0; |
1900 | } | 1922 | } |
1901 | #endif | 1923 | #endif |
1902 | 1924 | ||
1903 | static struct hda_codec_ops cs4210_patch_ops = { | 1925 | static struct hda_codec_ops cs421x_patch_ops = { |
1904 | .build_controls = cs421x_build_controls, | 1926 | .build_controls = cs421x_build_controls, |
1905 | .build_pcms = cs_build_pcms, | 1927 | .build_pcms = cs_build_pcms, |
1906 | .init = cs421x_init, | 1928 | .init = cs421x_init, |
@@ -1911,7 +1933,7 @@ static struct hda_codec_ops cs4210_patch_ops = { | |||
1911 | #endif | 1933 | #endif |
1912 | }; | 1934 | }; |
1913 | 1935 | ||
1914 | static int patch_cs421x(struct hda_codec *codec) | 1936 | static int patch_cs4210(struct hda_codec *codec) |
1915 | { | 1937 | { |
1916 | struct cs_spec *spec; | 1938 | struct cs_spec *spec; |
1917 | int err; | 1939 | int err; |
@@ -1921,7 +1943,7 @@ static int patch_cs421x(struct hda_codec *codec) | |||
1921 | return -ENOMEM; | 1943 | return -ENOMEM; |
1922 | codec->spec = spec; | 1944 | codec->spec = spec; |
1923 | 1945 | ||
1924 | spec->vendor_nid = CS421X_VENDOR_NID; | 1946 | spec->vendor_nid = CS4210_VENDOR_NID; |
1925 | 1947 | ||
1926 | spec->board_config = | 1948 | spec->board_config = |
1927 | snd_hda_check_board_config(codec, CS421X_MODELS, | 1949 | snd_hda_check_board_config(codec, CS421X_MODELS, |
@@ -1949,14 +1971,39 @@ static int patch_cs421x(struct hda_codec *codec) | |||
1949 | is auto-parsed. If GPIO or SENSE_B is forced, DMIC input | 1971 | is auto-parsed. If GPIO or SENSE_B is forced, DMIC input |
1950 | is disabled. | 1972 | is disabled. |
1951 | */ | 1973 | */ |
1952 | cs421x_pinmux_init(codec); | 1974 | cs4210_pinmux_init(codec); |
1953 | 1975 | ||
1954 | err = cs421x_parse_auto_config(codec); | 1976 | err = cs421x_parse_auto_config(codec); |
1955 | if (err < 0) | 1977 | if (err < 0) |
1956 | goto error; | 1978 | goto error; |
1957 | 1979 | ||
1958 | codec->patch_ops = cs4210_patch_ops; | 1980 | codec->patch_ops = cs421x_patch_ops; |
1981 | |||
1982 | return 0; | ||
1983 | |||
1984 | error: | ||
1985 | kfree(codec->spec); | ||
1986 | codec->spec = NULL; | ||
1987 | return err; | ||
1988 | } | ||
1989 | |||
1990 | static int patch_cs4213(struct hda_codec *codec) | ||
1991 | { | ||
1992 | struct cs_spec *spec; | ||
1993 | int err; | ||
1994 | |||
1995 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1996 | if (!spec) | ||
1997 | return -ENOMEM; | ||
1998 | codec->spec = spec; | ||
1999 | |||
2000 | spec->vendor_nid = CS4213_VENDOR_NID; | ||
2001 | |||
2002 | err = cs421x_parse_auto_config(codec); | ||
2003 | if (err < 0) | ||
2004 | goto error; | ||
1959 | 2005 | ||
2006 | codec->patch_ops = cs421x_patch_ops; | ||
1960 | return 0; | 2007 | return 0; |
1961 | 2008 | ||
1962 | error: | 2009 | error: |
@@ -1972,13 +2019,15 @@ static int patch_cs421x(struct hda_codec *codec) | |||
1972 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { | 2019 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { |
1973 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, | 2020 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, |
1974 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, | 2021 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, |
1975 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x }, | 2022 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 }, |
2023 | { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 }, | ||
1976 | {} /* terminator */ | 2024 | {} /* terminator */ |
1977 | }; | 2025 | }; |
1978 | 2026 | ||
1979 | MODULE_ALIAS("snd-hda-codec-id:10134206"); | 2027 | MODULE_ALIAS("snd-hda-codec-id:10134206"); |
1980 | MODULE_ALIAS("snd-hda-codec-id:10134207"); | 2028 | MODULE_ALIAS("snd-hda-codec-id:10134207"); |
1981 | MODULE_ALIAS("snd-hda-codec-id:10134210"); | 2029 | MODULE_ALIAS("snd-hda-codec-id:10134210"); |
2030 | MODULE_ALIAS("snd-hda-codec-id:10134213"); | ||
1982 | 2031 | ||
1983 | MODULE_LICENSE("GPL"); | 2032 | MODULE_LICENSE("GPL"); |
1984 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); | 2033 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); |