diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 105 |
1 files changed, 70 insertions, 35 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index ea660429713d..036056c42c13 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -138,7 +138,7 @@ enum { | |||
138 | */ | 138 | */ |
139 | #define CS4210_DAC_NID 0x02 | 139 | #define CS4210_DAC_NID 0x02 |
140 | #define CS4210_ADC_NID 0x03 | 140 | #define CS4210_ADC_NID 0x03 |
141 | #define CS421X_VENDOR_NID 0x0B | 141 | #define CS4210_VENDOR_NID 0x0B |
142 | #define CS421X_DMIC_PIN_NID 0x09 /* Port E */ | 142 | #define CS421X_DMIC_PIN_NID 0x09 /* Port E */ |
143 | #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ | 143 | #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ |
144 | 144 | ||
@@ -149,6 +149,10 @@ enum { | |||
149 | 149 | ||
150 | #define SPDIF_EVENT 0x04 | 150 | #define SPDIF_EVENT 0x04 |
151 | 151 | ||
152 | /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */ | ||
153 | #define CS4213_VENDOR_NID 0x09 | ||
154 | |||
155 | |||
152 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) | 156 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) |
153 | { | 157 | { |
154 | struct cs_spec *spec = codec->spec; | 158 | struct cs_spec *spec = codec->spec; |
@@ -923,8 +927,8 @@ static void cs_automute(struct hda_codec *codec) | |||
923 | /* mute speakers if spdif or hp jack is plugged in */ | 927 | /* mute speakers if spdif or hp jack is plugged in */ |
924 | for (i = 0; i < cfg->speaker_outs; i++) { | 928 | for (i = 0; i < cfg->speaker_outs; i++) { |
925 | int pin_ctl = hp_present ? 0 : PIN_OUT; | 929 | int pin_ctl = hp_present ? 0 : PIN_OUT; |
926 | /* detect on spdif is specific to CS421x */ | 930 | /* detect on spdif is specific to CS4210 */ |
927 | if (spdif_present && (spec->vendor_nid == CS421X_VENDOR_NID)) | 931 | if (spdif_present && (spec->vendor_nid == CS4210_VENDOR_NID)) |
928 | pin_ctl = 0; | 932 | pin_ctl = 0; |
929 | 933 | ||
930 | nid = cfg->speaker_pins[i]; | 934 | nid = cfg->speaker_pins[i]; |
@@ -938,8 +942,8 @@ static void cs_automute(struct hda_codec *codec) | |||
938 | AC_VERB_SET_GPIO_DATA, gpio); | 942 | AC_VERB_SET_GPIO_DATA, gpio); |
939 | } | 943 | } |
940 | 944 | ||
941 | /* specific to CS421x */ | 945 | /* specific to CS4210 */ |
942 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | 946 | if (spec->vendor_nid == CS4210_VENDOR_NID) { |
943 | /* mute HPs if spdif jack (SENSE_B) is present */ | 947 | /* mute HPs if spdif jack (SENSE_B) is present */ |
944 | for (i = 0; i < cfg->hp_outs; i++) { | 948 | for (i = 0; i < cfg->hp_outs; i++) { |
945 | nid = cfg->hp_pins[i]; | 949 | nid = cfg->hp_pins[i]; |
@@ -976,7 +980,12 @@ static void cs_automic(struct hda_codec *codec) | |||
976 | present = snd_hda_jack_detect(codec, nid); | 980 | present = snd_hda_jack_detect(codec, nid); |
977 | 981 | ||
978 | /* specific to CS421x, single ADC */ | 982 | /* specific to CS421x, single ADC */ |
979 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | 983 | if (spec->vendor_nid == CS420X_VENDOR_NID) { |
984 | if (present) | ||
985 | change_cur_input(codec, spec->automic_idx, 0); | ||
986 | else | ||
987 | change_cur_input(codec, !spec->automic_idx, 0); | ||
988 | } else { | ||
980 | if (present) { | 989 | if (present) { |
981 | spec->last_input = spec->cur_input; | 990 | spec->last_input = spec->cur_input; |
982 | spec->cur_input = spec->automic_idx; | 991 | spec->cur_input = spec->automic_idx; |
@@ -984,11 +993,6 @@ static void cs_automic(struct hda_codec *codec) | |||
984 | spec->cur_input = spec->last_input; | 993 | spec->cur_input = spec->last_input; |
985 | } | 994 | } |
986 | cs_update_input_select(codec); | 995 | 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 | } | 996 | } |
993 | } | 997 | } |
994 | 998 | ||
@@ -1070,15 +1074,8 @@ static void init_input(struct hda_codec *codec) | |||
1070 | if (spec->mic_detect && spec->automic_idx == i) | 1074 | if (spec->mic_detect && spec->automic_idx == i) |
1071 | snd_hda_jack_detect_enable(codec, pin, MIC_EVENT); | 1075 | snd_hda_jack_detect_enable(codec, pin, MIC_EVENT); |
1072 | } | 1076 | } |
1073 | /* specific to CS421x */ | 1077 | /* CS420x has multiple ADC, CS421x has single ADC */ |
1074 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | 1078 | if (spec->vendor_nid == CS420X_VENDOR_NID) { |
1075 | if (spec->mic_detect) | ||
1076 | cs_automic(codec); | ||
1077 | else { | ||
1078 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | ||
1079 | cs_update_input_select(codec); | ||
1080 | } | ||
1081 | } else { | ||
1082 | change_cur_input(codec, spec->cur_input, 1); | 1079 | change_cur_input(codec, spec->cur_input, 1); |
1083 | if (spec->mic_detect) | 1080 | if (spec->mic_detect) |
1084 | cs_automic(codec); | 1081 | cs_automic(codec); |
@@ -1092,6 +1089,13 @@ static void init_input(struct hda_codec *codec) | |||
1092 | * selected in IDX_SPDIF_CTL. | 1089 | * selected in IDX_SPDIF_CTL. |
1093 | */ | 1090 | */ |
1094 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | 1091 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); |
1092 | } else { | ||
1093 | if (spec->mic_detect) | ||
1094 | cs_automic(codec); | ||
1095 | else { | ||
1096 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | ||
1097 | cs_update_input_select(codec); | ||
1098 | } | ||
1095 | } | 1099 | } |
1096 | } | 1100 | } |
1097 | 1101 | ||
@@ -1565,7 +1569,7 @@ static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { | |||
1565 | .tlv = { .p = cs421x_speaker_boost_db_scale }, | 1569 | .tlv = { .p = cs421x_speaker_boost_db_scale }, |
1566 | }; | 1570 | }; |
1567 | 1571 | ||
1568 | static void cs421x_pinmux_init(struct hda_codec *codec) | 1572 | static void cs4210_pinmux_init(struct hda_codec *codec) |
1569 | { | 1573 | { |
1570 | struct cs_spec *spec = codec->spec; | 1574 | struct cs_spec *spec = codec->spec; |
1571 | unsigned int def_conf, coef; | 1575 | unsigned int def_conf, coef; |
@@ -1620,10 +1624,11 @@ static int cs421x_init(struct hda_codec *codec) | |||
1620 | { | 1624 | { |
1621 | struct cs_spec *spec = codec->spec; | 1625 | struct cs_spec *spec = codec->spec; |
1622 | 1626 | ||
1623 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs); | 1627 | if (spec->vendor_nid == CS4210_VENDOR_NID) { |
1624 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); | 1628 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs); |
1625 | 1629 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); | |
1626 | cs421x_pinmux_init(codec); | 1630 | cs4210_pinmux_init(codec); |
1631 | } | ||
1627 | 1632 | ||
1628 | if (spec->gpio_mask) { | 1633 | if (spec->gpio_mask) { |
1629 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, | 1634 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, |
@@ -1791,7 +1796,7 @@ static int build_cs421x_output(struct hda_codec *codec) | |||
1791 | if (err < 0) | 1796 | if (err < 0) |
1792 | return err; | 1797 | return err; |
1793 | 1798 | ||
1794 | if (cfg->speaker_outs) { | 1799 | if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) { |
1795 | err = snd_hda_ctl_add(codec, 0, | 1800 | err = snd_hda_ctl_add(codec, 0, |
1796 | snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); | 1801 | snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); |
1797 | if (err < 0) | 1802 | if (err < 0) |
@@ -1888,6 +1893,7 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) | |||
1888 | */ | 1893 | */ |
1889 | static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) | 1894 | static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) |
1890 | { | 1895 | { |
1896 | struct cs_spec *spec = codec->spec; | ||
1891 | unsigned int coef; | 1897 | unsigned int coef; |
1892 | 1898 | ||
1893 | snd_hda_shutup_pins(codec); | 1899 | snd_hda_shutup_pins(codec); |
@@ -1897,15 +1903,17 @@ static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) | |||
1897 | snd_hda_codec_write(codec, CS4210_ADC_NID, 0, | 1903 | snd_hda_codec_write(codec, CS4210_ADC_NID, 0, |
1898 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | 1904 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); |
1899 | 1905 | ||
1900 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); | 1906 | if (spec->vendor_nid == CS4210_VENDOR_NID) { |
1901 | coef |= 0x0004; /* PDREF */ | 1907 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); |
1902 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | 1908 | coef |= 0x0004; /* PDREF */ |
1909 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | ||
1910 | } | ||
1903 | 1911 | ||
1904 | return 0; | 1912 | return 0; |
1905 | } | 1913 | } |
1906 | #endif | 1914 | #endif |
1907 | 1915 | ||
1908 | static struct hda_codec_ops cs4210_patch_ops = { | 1916 | static struct hda_codec_ops cs421x_patch_ops = { |
1909 | .build_controls = cs421x_build_controls, | 1917 | .build_controls = cs421x_build_controls, |
1910 | .build_pcms = cs_build_pcms, | 1918 | .build_pcms = cs_build_pcms, |
1911 | .init = cs421x_init, | 1919 | .init = cs421x_init, |
@@ -1916,7 +1924,7 @@ static struct hda_codec_ops cs4210_patch_ops = { | |||
1916 | #endif | 1924 | #endif |
1917 | }; | 1925 | }; |
1918 | 1926 | ||
1919 | static int patch_cs421x(struct hda_codec *codec) | 1927 | static int patch_cs4210(struct hda_codec *codec) |
1920 | { | 1928 | { |
1921 | struct cs_spec *spec; | 1929 | struct cs_spec *spec; |
1922 | int err; | 1930 | int err; |
@@ -1926,7 +1934,7 @@ static int patch_cs421x(struct hda_codec *codec) | |||
1926 | return -ENOMEM; | 1934 | return -ENOMEM; |
1927 | codec->spec = spec; | 1935 | codec->spec = spec; |
1928 | 1936 | ||
1929 | spec->vendor_nid = CS421X_VENDOR_NID; | 1937 | spec->vendor_nid = CS4210_VENDOR_NID; |
1930 | 1938 | ||
1931 | spec->board_config = | 1939 | spec->board_config = |
1932 | snd_hda_check_board_config(codec, CS421X_MODELS, | 1940 | snd_hda_check_board_config(codec, CS421X_MODELS, |
@@ -1954,14 +1962,39 @@ static int patch_cs421x(struct hda_codec *codec) | |||
1954 | is auto-parsed. If GPIO or SENSE_B is forced, DMIC input | 1962 | is auto-parsed. If GPIO or SENSE_B is forced, DMIC input |
1955 | is disabled. | 1963 | is disabled. |
1956 | */ | 1964 | */ |
1957 | cs421x_pinmux_init(codec); | 1965 | cs4210_pinmux_init(codec); |
1958 | 1966 | ||
1959 | err = cs421x_parse_auto_config(codec); | 1967 | err = cs421x_parse_auto_config(codec); |
1960 | if (err < 0) | 1968 | if (err < 0) |
1961 | goto error; | 1969 | goto error; |
1962 | 1970 | ||
1963 | codec->patch_ops = cs4210_patch_ops; | 1971 | codec->patch_ops = cs421x_patch_ops; |
1972 | |||
1973 | return 0; | ||
1974 | |||
1975 | error: | ||
1976 | kfree(codec->spec); | ||
1977 | codec->spec = NULL; | ||
1978 | return err; | ||
1979 | } | ||
1980 | |||
1981 | static int patch_cs4213(struct hda_codec *codec) | ||
1982 | { | ||
1983 | struct cs_spec *spec; | ||
1984 | int err; | ||
1985 | |||
1986 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1987 | if (!spec) | ||
1988 | return -ENOMEM; | ||
1989 | codec->spec = spec; | ||
1990 | |||
1991 | spec->vendor_nid = CS4213_VENDOR_NID; | ||
1992 | |||
1993 | err = cs421x_parse_auto_config(codec); | ||
1994 | if (err < 0) | ||
1995 | goto error; | ||
1964 | 1996 | ||
1997 | codec->patch_ops = cs421x_patch_ops; | ||
1965 | return 0; | 1998 | return 0; |
1966 | 1999 | ||
1967 | error: | 2000 | error: |
@@ -1977,13 +2010,15 @@ static int patch_cs421x(struct hda_codec *codec) | |||
1977 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { | 2010 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { |
1978 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, | 2011 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, |
1979 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, | 2012 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, |
1980 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x }, | 2013 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 }, |
2014 | { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 }, | ||
1981 | {} /* terminator */ | 2015 | {} /* terminator */ |
1982 | }; | 2016 | }; |
1983 | 2017 | ||
1984 | MODULE_ALIAS("snd-hda-codec-id:10134206"); | 2018 | MODULE_ALIAS("snd-hda-codec-id:10134206"); |
1985 | MODULE_ALIAS("snd-hda-codec-id:10134207"); | 2019 | MODULE_ALIAS("snd-hda-codec-id:10134207"); |
1986 | MODULE_ALIAS("snd-hda-codec-id:10134210"); | 2020 | MODULE_ALIAS("snd-hda-codec-id:10134210"); |
2021 | MODULE_ALIAS("snd-hda-codec-id:10134213"); | ||
1987 | 2022 | ||
1988 | MODULE_LICENSE("GPL"); | 2023 | MODULE_LICENSE("GPL"); |
1989 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); | 2024 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); |