diff options
author | Lydia Wang <lydiawang@viatech.com.cn> | 2012-12-10 05:28:11 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-12-10 05:45:24 -0500 |
commit | 43737e0ae97ea87285686ffd07e30c82d897beb5 (patch) | |
tree | 90c05d541c9aea63eb069e2829433480adf8ba36 | |
parent | 97768a8e658605a905ba0d908d1b23b475170bed (diff) |
ALSA: HDA: VIA Add support for codec VT1705CF.
Add support for new codec VT1705CF.
When power on/off Audio output converter of VT1705CF, the stream tag
will be cleared. But driver caches the value. So when power on Audio
output converter, the update_conv_power_state() will restore the saved
stream tag of it.
Signed-off-by: Lydia Wang <lydiawang@viatech.com.cn>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-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 | ||