diff options
-rw-r--r-- | sound/pci/hda/patch_analog.c | 266 |
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 @@ | |||
35 | struct ad198x_spec { | 35 | struct 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 | */ | ||
1529 | static 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 | |||
1547 | static 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 | |||
1557 | static 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 | |||
1576 | static 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 | |||
1584 | static 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 | |||
1522 | static int ad1983_parse_auto_config(struct hda_codec *codec) | 1600 | static 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 | ||
1531 | static int patch_ad1983(struct hda_codec *codec) | 1616 | static int patch_ad1983(struct hda_codec *codec) |
@@ -1950,11 +2035,18 @@ static const struct snd_pci_quirk ad1981_cfg_tbl[] = { | |||
1950 | static int ad1981_parse_auto_config(struct hda_codec *codec) | 2035 | static 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 | ||
1960 | static int patch_ad1981(struct hda_codec *codec) | 2052 | static 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 | ||
2915 | static 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 | |||
2928 | static 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 | |||
2938 | static 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 | |||
2968 | static 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 | |||
2976 | static 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 | |||
2997 | static 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 | ||
2826 | static int ad1988_parse_auto_config(struct hda_codec *codec) | 3061 | static 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] = { | |||
3174 | static int ad1884_parse_auto_config(struct hda_codec *codec) | 3416 | static 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 | ||
3184 | static int patch_ad1884_auto(struct hda_codec *codec) | 3433 | static int patch_ad1884_auto(struct hda_codec *codec) |
@@ -4635,11 +4884,18 @@ static const char * const ad1882_models[AD1986A_MODELS] = { | |||
4635 | static int ad1882_parse_auto_config(struct hda_codec *codec) | 4884 | static 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 | ||
4645 | static int patch_ad1882(struct hda_codec *codec) | 4901 | static int patch_ad1882(struct hda_codec *codec) |