aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-01-22 09:31:33 -0500
committerTakashi Iwai <tiwai@suse.de>2013-01-22 10:41:56 -0500
commit272f3ea317762e55740326c01af64052a5fbb819 (patch)
treed0f13a9efe5a2402a1afab5ac85c9b48ef0a8633 /sound/pci
parentdc870f38e9faf7dd89355aae2252126688a1a372 (diff)
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output mux source: the digital audio out widget may take the sources from multiple connections, where 0x01 indicates it's a PCM while others point ADCs. It's obviously invalid in the HD-audio spec POV, but it's somehow convincing, too. And, to make things more complex, AD1988A and AD1882 have deeper connection routes that aren't expressed correctly. In this patch, the SPDIF mux control is implemented in two ways: - For easier one like AD1981, AD1983, AD1884 and AD1984, where the SPDIF audio out widget takes just two or three sources, we can simply implement via the normal input_mux and connection verb calls. - For the complex routes like AD1988A (but not AD1988B) or AD1882, we prepare "faked" paths represented statically, and switch the paths using these static ones, instead of parsing the routes from the widget tree. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/patch_analog.c266
1 files changed, 261 insertions, 5 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index a186b3da20b7..5d8328a64207 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -35,6 +35,10 @@
35struct ad198x_spec { 35struct ad198x_spec {
36 struct hda_gen_spec gen; 36 struct hda_gen_spec gen;
37 37
38 /* for auto parser */
39 int smux_paths[4];
40 unsigned int cur_smux;
41
38 const struct snd_kcontrol_new *mixers[6]; 42 const struct snd_kcontrol_new *mixers[6];
39 int num_mixers; 43 int num_mixers;
40 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ 44 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
@@ -1519,13 +1523,94 @@ static const char * const ad1983_models[AD1983_MODELS] = {
1519 [AD1983_BASIC] = "basic", 1523 [AD1983_BASIC] = "basic",
1520}; 1524};
1521 1525
1526/*
1527 * SPDIF mux control for AD1983 auto-parser
1528 */
1529static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
1530 struct snd_ctl_elem_info *uinfo)
1531{
1532 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1533 struct ad198x_spec *spec = codec->spec;
1534 static const char * const texts2[] = { "PCM", "ADC" };
1535 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
1536 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1537 int num_conns = snd_hda_get_num_conns(codec, dig_out);
1538
1539 if (num_conns == 2)
1540 return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
1541 else if (num_conns == 3)
1542 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
1543 else
1544 return -EINVAL;
1545}
1546
1547static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
1548 struct snd_ctl_elem_value *ucontrol)
1549{
1550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1551 struct ad198x_spec *spec = codec->spec;
1552
1553 ucontrol->value.enumerated.item[0] = spec->cur_smux;
1554 return 0;
1555}
1556
1557static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
1558 struct snd_ctl_elem_value *ucontrol)
1559{
1560 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1561 struct ad198x_spec *spec = codec->spec;
1562 unsigned int val = ucontrol->value.enumerated.item[0];
1563 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1564 int num_conns = snd_hda_get_num_conns(codec, dig_out);
1565
1566 if (val >= num_conns)
1567 return -EINVAL;
1568 if (spec->cur_smux == val)
1569 return 0;
1570 spec->cur_smux = val;
1571 snd_hda_codec_write_cache(codec, dig_out, 0,
1572 AC_VERB_SET_CONNECT_SEL, val);
1573 return 1;
1574}
1575
1576static struct snd_kcontrol_new ad1983_auto_smux_mixer = {
1577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1578 .name = "IEC958 Playback Source",
1579 .info = ad1983_auto_smux_enum_info,
1580 .get = ad1983_auto_smux_enum_get,
1581 .put = ad1983_auto_smux_enum_put,
1582};
1583
1584static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
1585{
1586 struct ad198x_spec *spec = codec->spec;
1587 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1588 int num_conns;
1589
1590 if (!dig_out)
1591 return 0;
1592 num_conns = snd_hda_get_num_conns(codec, dig_out);
1593 if (num_conns != 2 && num_conns != 3)
1594 return 0;
1595 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
1596 return -ENOMEM;
1597 return 0;
1598}
1599
1522static int ad1983_parse_auto_config(struct hda_codec *codec) 1600static int ad1983_parse_auto_config(struct hda_codec *codec)
1523{ 1601{
1524 struct ad198x_spec *spec = codec->spec; 1602 struct ad198x_spec *spec = codec->spec;
1603 int err;
1525 1604
1526 spec->beep_dev_nid = 0x10; 1605 spec->beep_dev_nid = 0x10;
1527 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); 1606 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1528 return ad198x_parse_auto_config(codec); 1607 err = ad198x_parse_auto_config(codec);
1608 if (err < 0)
1609 return err;
1610 err = ad1983_add_spdif_mux_ctl(codec);
1611 if (err < 0)
1612 return err;
1613 return 0;
1529} 1614}
1530 1615
1531static int patch_ad1983(struct hda_codec *codec) 1616static int patch_ad1983(struct hda_codec *codec)
@@ -1950,11 +2035,18 @@ static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
1950static int ad1981_parse_auto_config(struct hda_codec *codec) 2035static int ad1981_parse_auto_config(struct hda_codec *codec)
1951{ 2036{
1952 struct ad198x_spec *spec = codec->spec; 2037 struct ad198x_spec *spec = codec->spec;
2038 int err;
1953 2039
1954 spec->gen.mixer_nid = 0x0e; 2040 spec->gen.mixer_nid = 0x0e;
1955 spec->beep_dev_nid = 0x10; 2041 spec->beep_dev_nid = 0x10;
1956 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); 2042 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
1957 return ad198x_parse_auto_config(codec); 2043 err = ad198x_parse_auto_config(codec);
2044 if (err < 0)
2045 return err;
2046 err = ad1983_add_spdif_mux_ctl(codec);
2047 if (err < 0)
2048 return err;
2049 return 0;
1958} 2050}
1959 2051
1960static int patch_ad1981(struct hda_codec *codec) 2052static int patch_ad1981(struct hda_codec *codec)
@@ -2820,17 +2912,167 @@ static const struct hda_amp_list ad1988_loopbacks[] = {
2820}; 2912};
2821#endif 2913#endif
2822 2914
2915static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
2916 struct snd_ctl_elem_info *uinfo)
2917{
2918 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2919 static const char * const texts[] = {
2920 "PCM", "ADC1", "ADC2", "ADC3",
2921 };
2922 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
2923 if (num_conns > 4)
2924 num_conns = 4;
2925 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
2926}
2927
2928static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
2929 struct snd_ctl_elem_value *ucontrol)
2930{
2931 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2932 struct ad198x_spec *spec = codec->spec;
2933
2934 ucontrol->value.enumerated.item[0] = spec->cur_smux;
2935 return 0;
2936}
2937
2938static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
2939 struct snd_ctl_elem_value *ucontrol)
2940{
2941 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2942 struct ad198x_spec *spec = codec->spec;
2943 unsigned int val = ucontrol->value.enumerated.item[0];
2944 struct nid_path *path;
2945 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
2946
2947 if (val >= num_conns)
2948 return -EINVAL;
2949 if (spec->cur_smux == val)
2950 return 0;
2951
2952 mutex_lock(&codec->control_mutex);
2953 codec->cached_write = 1;
2954 path = snd_hda_get_path_from_idx(codec,
2955 spec->smux_paths[spec->cur_smux]);
2956 if (path)
2957 snd_hda_activate_path(codec, path, false, true);
2958 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
2959 if (path)
2960 snd_hda_activate_path(codec, path, true, true);
2961 spec->cur_smux = val;
2962 codec->cached_write = 0;
2963 mutex_unlock(&codec->control_mutex);
2964 snd_hda_codec_flush_cache(codec); /* flush the updates */
2965 return 1;
2966}
2967
2968static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
2969 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2970 .name = "IEC958 Playback Source",
2971 .info = ad1988_auto_smux_enum_info,
2972 .get = ad1988_auto_smux_enum_get,
2973 .put = ad1988_auto_smux_enum_put,
2974};
2975
2976static int ad1988_auto_init(struct hda_codec *codec)
2977{
2978 struct ad198x_spec *spec = codec->spec;
2979 int i, err;
2980
2981 err = snd_hda_gen_init(codec);
2982 if (err < 0)
2983 return err;
2984 if (!spec->gen.autocfg.dig_outs)
2985 return 0;
2986
2987 for (i = 0; i < 4; i++) {
2988 struct nid_path *path;
2989 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
2990 if (path)
2991 snd_hda_activate_path(codec, path, path->active, false);
2992 }
2993
2994 return 0;
2995}
2996
2997static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
2998{
2999 struct ad198x_spec *spec = codec->spec;
3000 int i, num_conns;
3001 /* we create four static faked paths, since AD codecs have odd
3002 * widget connections regarding the SPDIF out source
3003 */
3004 static struct nid_path fake_paths[4] = {
3005 {
3006 .depth = 3,
3007 .path = { 0x02, 0x1d, 0x1b },
3008 .idx = { 0, 0, 0 },
3009 .multi = { 0, 0, 0 },
3010 },
3011 {
3012 .depth = 4,
3013 .path = { 0x08, 0x0b, 0x1d, 0x1b },
3014 .idx = { 0, 0, 1, 0 },
3015 .multi = { 0, 1, 0, 0 },
3016 },
3017 {
3018 .depth = 4,
3019 .path = { 0x09, 0x0b, 0x1d, 0x1b },
3020 .idx = { 0, 1, 1, 0 },
3021 .multi = { 0, 1, 0, 0 },
3022 },
3023 {
3024 .depth = 4,
3025 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
3026 .idx = { 0, 2, 1, 0 },
3027 .multi = { 0, 1, 0, 0 },
3028 },
3029 };
3030
3031 /* SPDIF source mux appears to be present only on AD1988A */
3032 if (!spec->gen.autocfg.dig_outs ||
3033 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
3034 return 0;
3035
3036 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
3037 if (num_conns != 3 && num_conns != 4)
3038 return 0;
3039
3040 for (i = 0; i < num_conns; i++) {
3041 struct nid_path *path = snd_array_new(&spec->gen.paths);
3042 if (!path)
3043 return -ENOMEM;
3044 *path = fake_paths[i];
3045 if (!i)
3046 path->active = 1;
3047 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
3048 }
3049
3050 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
3051 return -ENOMEM;
3052
3053 codec->patch_ops.init = ad1988_auto_init;
3054
3055 return 0;
3056}
3057
2823/* 3058/*
2824 */ 3059 */
2825 3060
2826static int ad1988_parse_auto_config(struct hda_codec *codec) 3061static int ad1988_parse_auto_config(struct hda_codec *codec)
2827{ 3062{
2828 struct ad198x_spec *spec = codec->spec; 3063 struct ad198x_spec *spec = codec->spec;
3064 int err;
2829 3065
2830 spec->gen.mixer_nid = 0x20; 3066 spec->gen.mixer_nid = 0x20;
2831 spec->beep_dev_nid = 0x10; 3067 spec->beep_dev_nid = 0x10;
2832 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); 3068 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
2833 return ad198x_parse_auto_config(codec); 3069 err = ad198x_parse_auto_config(codec);
3070 if (err < 0)
3071 return err;
3072 err = ad1988_add_spdif_mux_ctl(codec);
3073 if (err < 0)
3074 return err;
3075 return 0;
2834} 3076}
2835 3077
2836/* 3078/*
@@ -3174,11 +3416,18 @@ static const char * const ad1884_models[AD1884_MODELS] = {
3174static int ad1884_parse_auto_config(struct hda_codec *codec) 3416static int ad1884_parse_auto_config(struct hda_codec *codec)
3175{ 3417{
3176 struct ad198x_spec *spec = codec->spec; 3418 struct ad198x_spec *spec = codec->spec;
3419 int err;
3177 3420
3178 spec->gen.mixer_nid = 0x20; 3421 spec->gen.mixer_nid = 0x20;
3179 spec->beep_dev_nid = 0x10; 3422 spec->beep_dev_nid = 0x10;
3180 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); 3423 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3181 return ad198x_parse_auto_config(codec); 3424 err = ad198x_parse_auto_config(codec);
3425 if (err < 0)
3426 return err;
3427 err = ad1983_add_spdif_mux_ctl(codec);
3428 if (err < 0)
3429 return err;
3430 return 0;
3182} 3431}
3183 3432
3184static int patch_ad1884_auto(struct hda_codec *codec) 3433static int patch_ad1884_auto(struct hda_codec *codec)
@@ -4635,11 +4884,18 @@ static const char * const ad1882_models[AD1986A_MODELS] = {
4635static int ad1882_parse_auto_config(struct hda_codec *codec) 4884static int ad1882_parse_auto_config(struct hda_codec *codec)
4636{ 4885{
4637 struct ad198x_spec *spec = codec->spec; 4886 struct ad198x_spec *spec = codec->spec;
4887 int err;
4638 4888
4639 spec->gen.mixer_nid = 0x20; 4889 spec->gen.mixer_nid = 0x20;
4640 spec->beep_dev_nid = 0x10; 4890 spec->beep_dev_nid = 0x10;
4641 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); 4891 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4642 return ad198x_parse_auto_config(codec); 4892 err = ad198x_parse_auto_config(codec);
4893 if (err < 0)
4894 return err;
4895 err = ad1988_add_spdif_mux_ctl(codec);
4896 if (err < 0)
4897 return err;
4898 return 0;
4643} 4899}
4644 4900
4645static int patch_ad1882(struct hda_codec *codec) 4901static int patch_ad1882(struct hda_codec *codec)