diff options
| -rw-r--r-- | sound/pci/hda/patch_via.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index dd8cd6af5d66..08ca407fd167 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
| @@ -76,6 +76,7 @@ enum VIA_HDA_CODEC { | |||
| 76 | VT2002P, | 76 | VT2002P, |
| 77 | VT1812, | 77 | VT1812, |
| 78 | VT1802, | 78 | VT1802, |
| 79 | VT1705CF, | ||
| 79 | CODEC_TYPES, | 80 | CODEC_TYPES, |
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| @@ -220,6 +221,7 @@ struct via_spec { | |||
| 220 | int vt1708_hp_present; | 221 | int vt1708_hp_present; |
| 221 | 222 | ||
| 222 | void (*set_widgets_power_state)(struct hda_codec *codec); | 223 | void (*set_widgets_power_state)(struct hda_codec *codec); |
| 224 | unsigned int dac_stream_tag[4]; | ||
| 223 | 225 | ||
| 224 | struct hda_loopback_check loopback; | 226 | struct hda_loopback_check loopback; |
| 225 | int num_loopbacks; | 227 | int num_loopbacks; |
| @@ -296,6 +298,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | |||
| 296 | codec_type = VT1708S; | 298 | codec_type = VT1708S; |
| 297 | else if ((dev_id & 0xfff) == 0x446) | 299 | else if ((dev_id & 0xfff) == 0x446) |
| 298 | codec_type = VT1802; | 300 | codec_type = VT1802; |
| 301 | else if (dev_id == 0x4760) | ||
| 302 | codec_type = VT1705CF; | ||
| 299 | else | 303 | else |
| 300 | codec_type = UNKNOWN; | 304 | codec_type = UNKNOWN; |
| 301 | return codec_type; | 305 | return codec_type; |
| @@ -711,6 +715,28 @@ static void update_power_state(struct hda_codec *codec, hda_nid_t nid, | |||
| 711 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); | 715 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); |
| 712 | } | 716 | } |
| 713 | 717 | ||
| 718 | static void update_conv_power_state(struct hda_codec *codec, hda_nid_t nid, | ||
| 719 | unsigned int parm, unsigned int index) | ||
| 720 | { | ||
| 721 | struct via_spec *spec = codec->spec; | ||
| 722 | unsigned int format; | ||
| 723 | if (snd_hda_codec_read(codec, nid, 0, | ||
| 724 | AC_VERB_GET_POWER_STATE, 0) == parm) | ||
| 725 | return; | ||
| 726 | format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
| 727 | if (format && (spec->dac_stream_tag[index] != format)) | ||
| 728 | spec->dac_stream_tag[index] = format; | ||
| 729 | |||
| 730 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); | ||
| 731 | if (parm == AC_PWRST_D0) { | ||
| 732 | format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
| 733 | if (!format && (spec->dac_stream_tag[index] != format)) | ||
| 734 | snd_hda_codec_write(codec, nid, 0, | ||
| 735 | AC_VERB_SET_CHANNEL_STREAMID, | ||
| 736 | spec->dac_stream_tag[index]); | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 714 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, | 740 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, |
| 715 | unsigned int *affected_parm) | 741 | unsigned int *affected_parm) |
| 716 | { | 742 | { |
| @@ -1085,6 +1111,10 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) | |||
| 1085 | verb = 0xf93; | 1111 | verb = 0xf93; |
| 1086 | parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ | 1112 | parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ |
| 1087 | break; | 1113 | break; |
| 1114 | case VT1705CF: | ||
| 1115 | verb = 0xf82; | ||
| 1116 | parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ | ||
| 1117 | break; | ||
| 1088 | default: | 1118 | default: |
| 1089 | return; /* other codecs are not supported */ | 1119 | return; /* other codecs are not supported */ |
| 1090 | } | 1120 | } |
| @@ -3817,6 +3847,125 @@ static int patch_vt1812(struct hda_codec *codec) | |||
| 3817 | return 0; | 3847 | return 0; |
| 3818 | } | 3848 | } |
| 3819 | 3849 | ||
| 3850 | /* patch for vt3476 */ | ||
| 3851 | |||
| 3852 | static const struct hda_verb vt3476_init_verbs[] = { | ||
| 3853 | /* Enable DMic 8/16/32K */ | ||
| 3854 | {0x1, 0xF7B, 0x30}, | ||
| 3855 | /* Enable Boost Volume backdoor */ | ||
| 3856 | {0x1, 0xFB9, 0x20}, | ||
| 3857 | /* Enable AOW-MW9 path */ | ||
| 3858 | {0x1, 0xFB8, 0x10}, | ||
| 3859 | { } | ||
| 3860 | }; | ||
| 3861 | |||
| 3862 | static void set_widgets_power_state_vt3476(struct hda_codec *codec) | ||
| 3863 | { | ||
| 3864 | struct via_spec *spec = codec->spec; | ||
| 3865 | int imux_is_smixer; | ||
| 3866 | unsigned int parm, parm2; | ||
| 3867 | /* MUX10 (1eh) = stereo mixer */ | ||
| 3868 | imux_is_smixer = | ||
| 3869 | snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 4; | ||
| 3870 | /* inputs */ | ||
| 3871 | /* PW 5/6/7 (29h/2ah/2bh) */ | ||
| 3872 | parm = AC_PWRST_D3; | ||
| 3873 | set_pin_power_state(codec, 0x29, &parm); | ||
| 3874 | set_pin_power_state(codec, 0x2a, &parm); | ||
| 3875 | set_pin_power_state(codec, 0x2b, &parm); | ||
| 3876 | if (imux_is_smixer) | ||
| 3877 | parm = AC_PWRST_D0; | ||
| 3878 | /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ | ||
| 3879 | update_power_state(codec, 0x1e, parm); | ||
| 3880 | update_power_state(codec, 0x1f, parm); | ||
| 3881 | update_power_state(codec, 0x10, parm); | ||
| 3882 | update_power_state(codec, 0x11, parm); | ||
| 3883 | |||
| 3884 | /* outputs */ | ||
| 3885 | /* PW3 (27h), MW3(37h), AOW3 (bh) */ | ||
| 3886 | if (spec->codec_type == VT1705CF) { | ||
| 3887 | parm = AC_PWRST_D3; | ||
| 3888 | update_power_state(codec, 0x27, parm); | ||
| 3889 | update_power_state(codec, 0x37, parm); | ||
| 3890 | } else { | ||
| 3891 | parm = AC_PWRST_D3; | ||
| 3892 | set_pin_power_state(codec, 0x27, &parm); | ||
| 3893 | update_power_state(codec, 0x37, parm); | ||
| 3894 | } | ||
| 3895 | |||
| 3896 | /* PW2 (26h), MW2(36h), AOW2 (ah) */ | ||
| 3897 | parm = AC_PWRST_D3; | ||
| 3898 | set_pin_power_state(codec, 0x26, &parm); | ||
| 3899 | update_power_state(codec, 0x36, parm); | ||
| 3900 | if (spec->smart51_enabled) { | ||
| 3901 | /* PW7(2bh), MW7(3bh), MUX7(1Bh) */ | ||
| 3902 | set_pin_power_state(codec, 0x2b, &parm); | ||
| 3903 | update_power_state(codec, 0x3b, parm); | ||
| 3904 | update_power_state(codec, 0x1b, parm); | ||
| 3905 | } | ||
| 3906 | update_conv_power_state(codec, 0xa, parm, 2); | ||
| 3907 | |||
| 3908 | /* PW1 (25h), MW1(35h), AOW1 (9h) */ | ||
| 3909 | parm = AC_PWRST_D3; | ||
| 3910 | set_pin_power_state(codec, 0x25, &parm); | ||
| 3911 | update_power_state(codec, 0x35, parm); | ||
| 3912 | if (spec->smart51_enabled) { | ||
| 3913 | /* PW6(2ah), MW6(3ah), MUX6(1ah) */ | ||
| 3914 | set_pin_power_state(codec, 0x2a, &parm); | ||
| 3915 | update_power_state(codec, 0x3a, parm); | ||
| 3916 | update_power_state(codec, 0x1a, parm); | ||
| 3917 | } | ||
| 3918 | update_conv_power_state(codec, 0x9, parm, 1); | ||
| 3919 | |||
| 3920 | /* PW4 (28h), MW4 (38h), MUX4(18h), AOW3(bh)/AOW0(8h) */ | ||
| 3921 | parm = AC_PWRST_D3; | ||
| 3922 | set_pin_power_state(codec, 0x28, &parm); | ||
| 3923 | update_power_state(codec, 0x38, parm); | ||
| 3924 | update_power_state(codec, 0x18, parm); | ||
| 3925 | if (spec->hp_independent_mode) | ||
| 3926 | update_conv_power_state(codec, 0xb, parm, 3); | ||
| 3927 | parm2 = parm; /* for pin 0x0b */ | ||
| 3928 | |||
| 3929 | /* PW0 (24h), MW0(34h), MW9(3fh), AOW0 (8h) */ | ||
| 3930 | parm = AC_PWRST_D3; | ||
| 3931 | set_pin_power_state(codec, 0x24, &parm); | ||
| 3932 | update_power_state(codec, 0x34, parm); | ||
| 3933 | if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3) | ||
| 3934 | parm = parm2; | ||
| 3935 | update_conv_power_state(codec, 0x8, parm, 0); | ||
| 3936 | /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ | ||
| 3937 | update_power_state(codec, 0x3f, imux_is_smixer ? AC_PWRST_D0 : parm); | ||
| 3938 | } | ||
| 3939 | |||
| 3940 | static int patch_vt3476(struct hda_codec *codec) | ||
| 3941 | { | ||
| 3942 | struct via_spec *spec; | ||
| 3943 | int err; | ||
| 3944 | |||
| 3945 | /* create a codec specific record */ | ||
| 3946 | spec = via_new_spec(codec); | ||
| 3947 | if (spec == NULL) | ||
| 3948 | return -ENOMEM; | ||
| 3949 | |||
| 3950 | spec->aa_mix_nid = 0x3f; | ||
| 3951 | add_secret_dac_path(codec); | ||
| 3952 | |||
| 3953 | /* automatic parse from the BIOS config */ | ||
| 3954 | err = via_parse_auto_config(codec); | ||
| 3955 | if (err < 0) { | ||
| 3956 | via_free(codec); | ||
| 3957 | return err; | ||
| 3958 | } | ||
| 3959 | |||
| 3960 | spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs; | ||
| 3961 | |||
| 3962 | codec->patch_ops = via_patch_ops; | ||
| 3963 | |||
| 3964 | spec->set_widgets_power_state = set_widgets_power_state_vt3476; | ||
| 3965 | |||
| 3966 | return 0; | ||
| 3967 | } | ||
| 3968 | |||
| 3820 | /* | 3969 | /* |
| 3821 | * patch entries | 3970 | * patch entries |
| 3822 | */ | 3971 | */ |
| @@ -3910,6 +4059,8 @@ static const struct hda_codec_preset snd_hda_preset_via[] = { | |||
| 3910 | .patch = patch_vt2002P}, | 4059 | .patch = patch_vt2002P}, |
| 3911 | { .id = 0x11068446, .name = "VT1802", | 4060 | { .id = 0x11068446, .name = "VT1802", |
| 3912 | .patch = patch_vt2002P}, | 4061 | .patch = patch_vt2002P}, |
| 4062 | { .id = 0x11064760, .name = "VT1705CF", | ||
| 4063 | .patch = patch_vt3476}, | ||
| 3913 | {} /* terminator */ | 4064 | {} /* terminator */ |
| 3914 | }; | 4065 | }; |
| 3915 | 4066 | ||
