aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorDavid Henningsson <david.henningsson@canonical.com>2012-01-02 06:40:17 -0500
committerTakashi Iwai <tiwai@suse.de>2012-01-08 03:57:37 -0500
commit5660ffd06935e564404412997a703279e325fa64 (patch)
treef986afa20a08327d6eefc5e335ec5e337a8d2453 /sound
parent78e2a928e377d5124932d4399c6c581908b027a0 (diff)
ALSA: HDA: Add support for Cirrus Logic 4213
The CS4213 chip is similar to the CS4210, but it does not have SPDIF capabilities. Also, it has fewer pins, and the vendor specific nid is different. With this patch, we have working inputs and outputs (and automute/autoswitch). However, we don't know anything about the vendor specific processing coefficients, so we don't read or write to that node in this patch. BugLink: https://bugs.launchpad.net/bugs/910792 Tested-by: Hsin-Yi Chen <hychen@canonical.com> Signed-off-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_cirrus.c105
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
152static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) 156static 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
1568static void cs421x_pinmux_init(struct hda_codec *codec) 1572static 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*/
1889static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) 1894static 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
1908static struct hda_codec_ops cs4210_patch_ops = { 1916static 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
1919static int patch_cs421x(struct hda_codec *codec) 1927static 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
1981static 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)
1977static const struct hda_codec_preset snd_hda_preset_cirrus[] = { 2010static 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
1984MODULE_ALIAS("snd-hda-codec-id:10134206"); 2018MODULE_ALIAS("snd-hda-codec-id:10134206");
1985MODULE_ALIAS("snd-hda-codec-id:10134207"); 2019MODULE_ALIAS("snd-hda-codec-id:10134207");
1986MODULE_ALIAS("snd-hda-codec-id:10134210"); 2020MODULE_ALIAS("snd-hda-codec-id:10134210");
2021MODULE_ALIAS("snd-hda-codec-id:10134213");
1987 2022
1988MODULE_LICENSE("GPL"); 2023MODULE_LICENSE("GPL");
1989MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); 2024MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");