diff options
author | Lydia Wang <lydiawang@viatech.com.cn> | 2009-10-10 07:08:46 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-10-11 11:59:06 -0400 |
commit | ab6734e7ea32e9f9cbe0f55eeddf4aa629ed1c3d (patch) | |
tree | 47b0ff23a2ce43784df122cd03a7ba30819d1942 /sound/pci/hda/patch_via.c | |
parent | 25eaba2f8a6877ba6f58197c4723c2433a316e09 (diff) |
ALSA: HDA VIA: Add VT1812 support.
Signed-off-by: Lydia Wang <lydiawang@viatech.com.cn>
Signed-off-by: Logan Li <loganli@viatech.com.cn>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r-- | sound/pci/hda/patch_via.c | 494 |
1 files changed, 491 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index a94cc91c18ff..b3c5e8a78154 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -89,6 +89,7 @@ enum VIA_HDA_CODEC { | |||
89 | VT1718S, | 89 | VT1718S, |
90 | VT1716S, | 90 | VT1716S, |
91 | VT2002P, | 91 | VT2002P, |
92 | VT1812, | ||
92 | CODEC_TYPES, | 93 | CODEC_TYPES, |
93 | }; | 94 | }; |
94 | 95 | ||
@@ -187,6 +188,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | |||
187 | codec_type = VT1718S; | 188 | codec_type = VT1718S; |
188 | else if (dev_id == 0x0438 || dev_id == 0x4438) | 189 | else if (dev_id == 0x0438 || dev_id == 0x4438) |
189 | codec_type = VT2002P; | 190 | codec_type = VT2002P; |
191 | else if (dev_id == 0x0448) | ||
192 | codec_type = VT1812; | ||
190 | else | 193 | else |
191 | codec_type = UNKNOWN; | 194 | codec_type = UNKNOWN; |
192 | return codec_type; | 195 | return codec_type; |
@@ -411,6 +414,12 @@ static hda_nid_t vt2002P_adc_nids[2] = { | |||
411 | 0x10, 0x11 | 414 | 0x10, 0x11 |
412 | }; | 415 | }; |
413 | 416 | ||
417 | static hda_nid_t vt1812_adc_nids[2] = { | ||
418 | /* ADC1-2 */ | ||
419 | 0x10, 0x11 | ||
420 | }; | ||
421 | |||
422 | |||
414 | /* add dynamic controls */ | 423 | /* add dynamic controls */ |
415 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 424 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
416 | unsigned long val) | 425 | unsigned long val) |
@@ -904,6 +913,120 @@ static void set_jack_power_state(struct hda_codec *codec) | |||
904 | snd_hda_codec_write( | 913 | snd_hda_codec_write( |
905 | codec, 0x21, 0, | 914 | codec, 0x21, 0, |
906 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | 915 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); |
916 | } else if (spec->codec_type == VT1812) { | ||
917 | unsigned int present; | ||
918 | /* MUX10 (1eh) = stereo mixer */ | ||
919 | imux_is_smixer = snd_hda_codec_read( | ||
920 | codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; | ||
921 | /* inputs */ | ||
922 | /* PW 5/6/7 (29h/2ah/2bh) */ | ||
923 | parm = AC_PWRST_D3; | ||
924 | set_pin_power_state(codec, 0x29, &parm); | ||
925 | set_pin_power_state(codec, 0x2a, &parm); | ||
926 | set_pin_power_state(codec, 0x2b, &parm); | ||
927 | if (imux_is_smixer) | ||
928 | parm = AC_PWRST_D0; | ||
929 | /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ | ||
930 | snd_hda_codec_write(codec, 0x1e, 0, | ||
931 | AC_VERB_SET_POWER_STATE, parm); | ||
932 | snd_hda_codec_write(codec, 0x1f, 0, | ||
933 | AC_VERB_SET_POWER_STATE, parm); | ||
934 | snd_hda_codec_write(codec, 0x10, 0, | ||
935 | AC_VERB_SET_POWER_STATE, parm); | ||
936 | snd_hda_codec_write(codec, 0x11, 0, | ||
937 | AC_VERB_SET_POWER_STATE, parm); | ||
938 | |||
939 | /* outputs */ | ||
940 | /* AOW0 (8h)*/ | ||
941 | snd_hda_codec_write(codec, 0x8, 0, | ||
942 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
943 | |||
944 | /* PW4 (28h), MW4 (18h), MUX4(38h) */ | ||
945 | parm = AC_PWRST_D3; | ||
946 | set_pin_power_state(codec, 0x28, &parm); | ||
947 | snd_hda_codec_write(codec, 0x18, 0, | ||
948 | AC_VERB_SET_POWER_STATE, parm); | ||
949 | snd_hda_codec_write(codec, 0x38, 0, | ||
950 | AC_VERB_SET_POWER_STATE, parm); | ||
951 | |||
952 | /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ | ||
953 | parm = AC_PWRST_D3; | ||
954 | set_pin_power_state(codec, 0x25, &parm); | ||
955 | snd_hda_codec_write(codec, 0x15, 0, | ||
956 | AC_VERB_SET_POWER_STATE, parm); | ||
957 | snd_hda_codec_write(codec, 0x35, 0, | ||
958 | AC_VERB_SET_POWER_STATE, parm); | ||
959 | if (spec->hp_independent_mode) { | ||
960 | snd_hda_codec_write(codec, 0x9, 0, | ||
961 | AC_VERB_SET_POWER_STATE, parm); | ||
962 | } | ||
963 | |||
964 | /* Internal Speaker */ | ||
965 | /* PW0 (24h), MW0(14h), MUX0(34h) */ | ||
966 | present = snd_hda_codec_read( | ||
967 | codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
968 | parm = AC_PWRST_D3; | ||
969 | set_pin_power_state(codec, 0x24, &parm); | ||
970 | if (present) { | ||
971 | snd_hda_codec_write(codec, 0x14, 0, | ||
972 | AC_VERB_SET_POWER_STATE, | ||
973 | AC_PWRST_D3); | ||
974 | snd_hda_codec_write(codec, 0x34, 0, | ||
975 | AC_VERB_SET_POWER_STATE, | ||
976 | AC_PWRST_D3); | ||
977 | } else { | ||
978 | snd_hda_codec_write(codec, 0x14, 0, | ||
979 | AC_VERB_SET_POWER_STATE, | ||
980 | AC_PWRST_D0); | ||
981 | snd_hda_codec_write(codec, 0x34, 0, | ||
982 | AC_VERB_SET_POWER_STATE, | ||
983 | AC_PWRST_D0); | ||
984 | } | ||
985 | /* Mono Out */ | ||
986 | /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ | ||
987 | present = snd_hda_codec_read( | ||
988 | codec, 0x28, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
989 | parm = AC_PWRST_D3; | ||
990 | set_pin_power_state(codec, 0x31, &parm); | ||
991 | if (present) { | ||
992 | snd_hda_codec_write(codec, 0x1c, 0, | ||
993 | AC_VERB_SET_POWER_STATE, | ||
994 | AC_PWRST_D3); | ||
995 | snd_hda_codec_write(codec, 0x3c, 0, | ||
996 | AC_VERB_SET_POWER_STATE, | ||
997 | AC_PWRST_D3); | ||
998 | snd_hda_codec_write(codec, 0x3e, 0, | ||
999 | AC_VERB_SET_POWER_STATE, | ||
1000 | AC_PWRST_D3); | ||
1001 | } else { | ||
1002 | snd_hda_codec_write(codec, 0x1c, 0, | ||
1003 | AC_VERB_SET_POWER_STATE, | ||
1004 | AC_PWRST_D0); | ||
1005 | snd_hda_codec_write(codec, 0x3c, 0, | ||
1006 | AC_VERB_SET_POWER_STATE, | ||
1007 | AC_PWRST_D0); | ||
1008 | snd_hda_codec_write(codec, 0x3e, 0, | ||
1009 | AC_VERB_SET_POWER_STATE, | ||
1010 | AC_PWRST_D0); | ||
1011 | } | ||
1012 | |||
1013 | /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ | ||
1014 | parm = AC_PWRST_D3; | ||
1015 | set_pin_power_state(codec, 0x33, &parm); | ||
1016 | snd_hda_codec_write(codec, 0x1d, 0, | ||
1017 | AC_VERB_SET_POWER_STATE, parm); | ||
1018 | snd_hda_codec_write(codec, 0x3d, 0, | ||
1019 | AC_VERB_SET_POWER_STATE, parm); | ||
1020 | |||
1021 | /* MW9 (21h) */ | ||
1022 | if (imux_is_smixer || !is_aa_path_mute(codec)) | ||
1023 | snd_hda_codec_write( | ||
1024 | codec, 0x21, 0, | ||
1025 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
1026 | else | ||
1027 | snd_hda_codec_write( | ||
1028 | codec, 0x21, 0, | ||
1029 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
907 | } | 1030 | } |
908 | } | 1031 | } |
909 | 1032 | ||
@@ -974,6 +1097,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
974 | case VT2002P: | 1097 | case VT2002P: |
975 | nid = 0x35; | 1098 | nid = 0x35; |
976 | break; | 1099 | break; |
1100 | case VT1812: | ||
1101 | nid = 0x3d; | ||
1102 | break; | ||
977 | default: | 1103 | default: |
978 | nid = spec->autocfg.hp_pins[0]; | 1104 | nid = spec->autocfg.hp_pins[0]; |
979 | break; | 1105 | break; |
@@ -1049,6 +1175,9 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
1049 | case VT2002P: | 1175 | case VT2002P: |
1050 | nid = 0x35; | 1176 | nid = 0x35; |
1051 | break; | 1177 | break; |
1178 | case VT1812: | ||
1179 | nid = 0x3d; | ||
1180 | break; | ||
1052 | default: | 1181 | default: |
1053 | nid = spec->autocfg.hp_pins[0]; | 1182 | nid = spec->autocfg.hp_pins[0]; |
1054 | break; | 1183 | break; |
@@ -1066,7 +1195,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
1066 | || spec->codec_type == VT1702 | 1195 | || spec->codec_type == VT1702 |
1067 | || spec->codec_type == VT1718S | 1196 | || spec->codec_type == VT1718S |
1068 | || spec->codec_type == VT1716S | 1197 | || spec->codec_type == VT1716S |
1069 | || spec->codec_type == VT2002P) { | 1198 | || spec->codec_type == VT2002P |
1199 | || spec->codec_type == VT1812) { | ||
1070 | activate_ctl(codec, "Headphone Playback Volume", | 1200 | activate_ctl(codec, "Headphone Playback Volume", |
1071 | spec->hp_independent_mode); | 1201 | spec->hp_independent_mode); |
1072 | activate_ctl(codec, "Headphone Playback Switch", | 1202 | activate_ctl(codec, "Headphone Playback Switch", |
@@ -1307,6 +1437,7 @@ static int is_aa_path_mute(struct hda_codec *codec) | |||
1307 | end_idx = 3; | 1437 | end_idx = 3; |
1308 | break; | 1438 | break; |
1309 | case VT2002P: | 1439 | case VT2002P: |
1440 | case VT1812: | ||
1310 | nid_mixer = 0x21; | 1441 | nid_mixer = 0x21; |
1311 | start_idx = 0; | 1442 | start_idx = 0; |
1312 | end_idx = 2; | 1443 | end_idx = 2; |
@@ -1370,6 +1501,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) | |||
1370 | parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ | 1501 | parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ |
1371 | break; | 1502 | break; |
1372 | case VT2002P: | 1503 | case VT2002P: |
1504 | case VT1812: | ||
1373 | verb = 0xf93; | 1505 | verb = 0xf93; |
1374 | parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ | 1506 | parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ |
1375 | break; | 1507 | break; |
@@ -1878,7 +2010,7 @@ static void via_speaker_automute(struct hda_codec *codec) | |||
1878 | unsigned int hp_present; | 2010 | unsigned int hp_present; |
1879 | struct via_spec *spec = codec->spec; | 2011 | struct via_spec *spec = codec->spec; |
1880 | 2012 | ||
1881 | if (spec->codec_type != VT2002P) | 2013 | if (spec->codec_type != VT2002P && spec->codec_type != VT1812) |
1882 | return; | 2014 | return; |
1883 | 2015 | ||
1884 | hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, | 2016 | hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, |
@@ -2364,7 +2496,7 @@ static int via_auto_init(struct hda_codec *codec) | |||
2364 | via_auto_init_multi_out(codec); | 2496 | via_auto_init_multi_out(codec); |
2365 | via_auto_init_hp_out(codec); | 2497 | via_auto_init_hp_out(codec); |
2366 | via_auto_init_analog_input(codec); | 2498 | via_auto_init_analog_input(codec); |
2367 | if (spec->codec_type == VT2002P) { | 2499 | if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { |
2368 | via_hp_bind_automute(codec); | 2500 | via_hp_bind_automute(codec); |
2369 | } else { | 2501 | } else { |
2370 | via_hp_automute(codec); | 2502 | via_hp_automute(codec); |
@@ -5654,6 +5786,361 @@ static int patch_vt2002P(struct hda_codec *codec) | |||
5654 | 5786 | ||
5655 | return 0; | 5787 | return 0; |
5656 | } | 5788 | } |
5789 | |||
5790 | /* for vt1812 */ | ||
5791 | |||
5792 | /* capture mixer elements */ | ||
5793 | static struct snd_kcontrol_new vt1812_capture_mixer[] = { | ||
5794 | HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), | ||
5795 | HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), | ||
5796 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), | ||
5797 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), | ||
5798 | HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), | ||
5799 | HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0, | ||
5800 | HDA_INPUT), | ||
5801 | { | ||
5802 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5803 | /* The multiple "Capture Source" controls confuse alsamixer | ||
5804 | * So call somewhat different.. | ||
5805 | */ | ||
5806 | .name = "Input Source", | ||
5807 | .count = 2, | ||
5808 | .info = via_mux_enum_info, | ||
5809 | .get = via_mux_enum_get, | ||
5810 | .put = via_mux_enum_put, | ||
5811 | }, | ||
5812 | { } /* end */ | ||
5813 | }; | ||
5814 | |||
5815 | static struct hda_verb vt1812_volume_init_verbs[] = { | ||
5816 | /* | ||
5817 | * Unmute ADC0-1 and set the default input to mic-in | ||
5818 | */ | ||
5819 | {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5820 | {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5821 | |||
5822 | |||
5823 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
5824 | * mixer widget | ||
5825 | */ | ||
5826 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
5827 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5828 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5829 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5830 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5831 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5832 | |||
5833 | /* MUX Indices: Mic = 0 */ | ||
5834 | {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5835 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5836 | |||
5837 | /* PW9 Output enable */ | ||
5838 | {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
5839 | |||
5840 | /* Enable Boost Volume backdoor */ | ||
5841 | {0x1, 0xfb9, 0x24}, | ||
5842 | |||
5843 | /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ | ||
5844 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5845 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5846 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5847 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5848 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5849 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5850 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5851 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5852 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5853 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5854 | |||
5855 | /* set MUX0/1/4/13/15 = 0 (AOW0) */ | ||
5856 | {0x34, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5857 | {0x35, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5858 | {0x38, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5859 | {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5860 | {0x3d, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5861 | |||
5862 | /* Enable AOW0 to MW9 */ | ||
5863 | {0x1, 0xfb8, 0xa8}, | ||
5864 | { } | ||
5865 | }; | ||
5866 | |||
5867 | |||
5868 | static struct hda_verb vt1812_uniwill_init_verbs[] = { | ||
5869 | {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5870 | AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, | ||
5871 | {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, | ||
5872 | {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5873 | AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, | ||
5874 | {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5875 | {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5876 | {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5877 | { } | ||
5878 | }; | ||
5879 | |||
5880 | static struct hda_pcm_stream vt1812_pcm_analog_playback = { | ||
5881 | .substreams = 2, | ||
5882 | .channels_min = 2, | ||
5883 | .channels_max = 2, | ||
5884 | .nid = 0x8, /* NID to query formats and rates */ | ||
5885 | .ops = { | ||
5886 | .open = via_playback_pcm_open, | ||
5887 | .prepare = via_playback_multi_pcm_prepare, | ||
5888 | .cleanup = via_playback_multi_pcm_cleanup, | ||
5889 | .close = via_pcm_open_close, | ||
5890 | }, | ||
5891 | }; | ||
5892 | |||
5893 | static struct hda_pcm_stream vt1812_pcm_analog_capture = { | ||
5894 | .substreams = 2, | ||
5895 | .channels_min = 2, | ||
5896 | .channels_max = 2, | ||
5897 | .nid = 0x10, /* NID to query formats and rates */ | ||
5898 | .ops = { | ||
5899 | .open = via_pcm_open_close, | ||
5900 | .prepare = via_capture_pcm_prepare, | ||
5901 | .cleanup = via_capture_pcm_cleanup, | ||
5902 | .close = via_pcm_open_close, | ||
5903 | }, | ||
5904 | }; | ||
5905 | |||
5906 | static struct hda_pcm_stream vt1812_pcm_digital_playback = { | ||
5907 | .substreams = 1, | ||
5908 | .channels_min = 2, | ||
5909 | .channels_max = 2, | ||
5910 | .rates = SNDRV_PCM_RATE_48000, | ||
5911 | /* NID is set in via_build_pcms */ | ||
5912 | .ops = { | ||
5913 | .open = via_dig_playback_pcm_open, | ||
5914 | .close = via_dig_playback_pcm_close, | ||
5915 | .prepare = via_dig_playback_pcm_prepare, | ||
5916 | .cleanup = via_dig_playback_pcm_cleanup | ||
5917 | }, | ||
5918 | }; | ||
5919 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
5920 | static int vt1812_auto_fill_dac_nids(struct via_spec *spec, | ||
5921 | const struct auto_pin_cfg *cfg) | ||
5922 | { | ||
5923 | spec->multiout.num_dacs = 1; | ||
5924 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
5925 | if (cfg->line_out_pins[0]) | ||
5926 | spec->multiout.dac_nids[0] = 0x8; | ||
5927 | return 0; | ||
5928 | } | ||
5929 | |||
5930 | |||
5931 | /* add playback controls from the parsed DAC table */ | ||
5932 | static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec, | ||
5933 | const struct auto_pin_cfg *cfg) | ||
5934 | { | ||
5935 | int err; | ||
5936 | |||
5937 | if (!cfg->line_out_pins[0]) | ||
5938 | return -1; | ||
5939 | |||
5940 | /* Line-Out: PortE */ | ||
5941 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5942 | "Master Front Playback Volume", | ||
5943 | HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); | ||
5944 | if (err < 0) | ||
5945 | return err; | ||
5946 | err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, | ||
5947 | "Master Front Playback Switch", | ||
5948 | HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT)); | ||
5949 | if (err < 0) | ||
5950 | return err; | ||
5951 | |||
5952 | return 0; | ||
5953 | } | ||
5954 | |||
5955 | static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
5956 | { | ||
5957 | int err; | ||
5958 | |||
5959 | if (!pin) | ||
5960 | return 0; | ||
5961 | |||
5962 | spec->multiout.hp_nid = 0x9; | ||
5963 | spec->hp_independent_mode_index = 1; | ||
5964 | |||
5965 | |||
5966 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5967 | "Headphone Playback Volume", | ||
5968 | HDA_COMPOSE_AMP_VAL( | ||
5969 | spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); | ||
5970 | if (err < 0) | ||
5971 | return err; | ||
5972 | |||
5973 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
5974 | "Headphone Playback Switch", | ||
5975 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
5976 | if (err < 0) | ||
5977 | return err; | ||
5978 | |||
5979 | create_hp_imux(spec); | ||
5980 | return 0; | ||
5981 | } | ||
5982 | |||
5983 | /* create playback/capture controls for input pins */ | ||
5984 | static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, | ||
5985 | const struct auto_pin_cfg *cfg) | ||
5986 | { | ||
5987 | static char *labels[] = { | ||
5988 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
5989 | }; | ||
5990 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
5991 | int i, err, idx = 0; | ||
5992 | |||
5993 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
5994 | if (!cfg->input_pins[i]) | ||
5995 | continue; | ||
5996 | |||
5997 | switch (cfg->input_pins[i]) { | ||
5998 | case 0x2b: /* Mic */ | ||
5999 | idx = 0; | ||
6000 | break; | ||
6001 | |||
6002 | case 0x2a: /* Line In */ | ||
6003 | idx = 1; | ||
6004 | break; | ||
6005 | |||
6006 | case 0x29: /* Front Mic */ | ||
6007 | idx = 2; | ||
6008 | break; | ||
6009 | } | ||
6010 | err = via_new_analog_input(spec, labels[i], idx, 0x21); | ||
6011 | if (err < 0) | ||
6012 | return err; | ||
6013 | imux->items[imux->num_items].label = labels[i]; | ||
6014 | imux->items[imux->num_items].index = idx; | ||
6015 | imux->num_items++; | ||
6016 | } | ||
6017 | /* build volume/mute control of loopback */ | ||
6018 | err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21); | ||
6019 | if (err < 0) | ||
6020 | return err; | ||
6021 | |||
6022 | /* for internal loopback recording select */ | ||
6023 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
6024 | imux->items[imux->num_items].index = 5; | ||
6025 | imux->num_items++; | ||
6026 | |||
6027 | /* for digital mic select */ | ||
6028 | imux->items[imux->num_items].label = "Digital Mic"; | ||
6029 | imux->items[imux->num_items].index = 6; | ||
6030 | imux->num_items++; | ||
6031 | |||
6032 | return 0; | ||
6033 | } | ||
6034 | |||
6035 | static int vt1812_parse_auto_config(struct hda_codec *codec) | ||
6036 | { | ||
6037 | struct via_spec *spec = codec->spec; | ||
6038 | int err; | ||
6039 | |||
6040 | |||
6041 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
6042 | if (err < 0) | ||
6043 | return err; | ||
6044 | fill_dig_outs(codec); | ||
6045 | err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg); | ||
6046 | if (err < 0) | ||
6047 | return err; | ||
6048 | |||
6049 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs) | ||
6050 | return 0; /* can't find valid BIOS pin config */ | ||
6051 | |||
6052 | err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
6053 | if (err < 0) | ||
6054 | return err; | ||
6055 | err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
6056 | if (err < 0) | ||
6057 | return err; | ||
6058 | err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
6059 | if (err < 0) | ||
6060 | return err; | ||
6061 | |||
6062 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
6063 | |||
6064 | fill_dig_outs(codec); | ||
6065 | |||
6066 | if (spec->kctls.list) | ||
6067 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
6068 | |||
6069 | spec->input_mux = &spec->private_imux[0]; | ||
6070 | |||
6071 | if (spec->hp_mux) | ||
6072 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
6073 | |||
6074 | return 1; | ||
6075 | } | ||
6076 | |||
6077 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
6078 | static struct hda_amp_list vt1812_loopbacks[] = { | ||
6079 | { 0x21, HDA_INPUT, 0 }, | ||
6080 | { 0x21, HDA_INPUT, 1 }, | ||
6081 | { 0x21, HDA_INPUT, 2 }, | ||
6082 | { } /* end */ | ||
6083 | }; | ||
6084 | #endif | ||
6085 | |||
6086 | |||
6087 | /* patch for vt1812 */ | ||
6088 | static int patch_vt1812(struct hda_codec *codec) | ||
6089 | { | ||
6090 | struct via_spec *spec; | ||
6091 | int err; | ||
6092 | |||
6093 | /* create a codec specific record */ | ||
6094 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
6095 | if (spec == NULL) | ||
6096 | return -ENOMEM; | ||
6097 | |||
6098 | codec->spec = spec; | ||
6099 | |||
6100 | /* automatic parse from the BIOS config */ | ||
6101 | err = vt1812_parse_auto_config(codec); | ||
6102 | if (err < 0) { | ||
6103 | via_free(codec); | ||
6104 | return err; | ||
6105 | } else if (!err) { | ||
6106 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
6107 | "from BIOS. Using genenic mode...\n"); | ||
6108 | } | ||
6109 | |||
6110 | |||
6111 | spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs; | ||
6112 | spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs; | ||
6113 | |||
6114 | spec->stream_name_analog = "VT1812 Analog"; | ||
6115 | spec->stream_analog_playback = &vt1812_pcm_analog_playback; | ||
6116 | spec->stream_analog_capture = &vt1812_pcm_analog_capture; | ||
6117 | |||
6118 | spec->stream_name_digital = "VT1812 Digital"; | ||
6119 | spec->stream_digital_playback = &vt1812_pcm_digital_playback; | ||
6120 | |||
6121 | |||
6122 | if (!spec->adc_nids && spec->input_mux) { | ||
6123 | spec->adc_nids = vt1812_adc_nids; | ||
6124 | spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids); | ||
6125 | get_mux_nids(codec); | ||
6126 | override_mic_boost(codec, 0x2b, 0, 3, 40); | ||
6127 | override_mic_boost(codec, 0x29, 0, 3, 40); | ||
6128 | spec->mixers[spec->num_mixers] = vt1812_capture_mixer; | ||
6129 | spec->num_mixers++; | ||
6130 | } | ||
6131 | |||
6132 | codec->patch_ops = via_patch_ops; | ||
6133 | |||
6134 | codec->patch_ops.init = via_auto_init; | ||
6135 | codec->patch_ops.unsol_event = via_unsol_event, | ||
6136 | |||
6137 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
6138 | spec->loopback.amplist = vt1812_loopbacks; | ||
6139 | #endif | ||
6140 | |||
6141 | return 0; | ||
6142 | } | ||
6143 | |||
5657 | /* | 6144 | /* |
5658 | * patch entries | 6145 | * patch entries |
5659 | */ | 6146 | */ |
@@ -5740,6 +6227,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = { | |||
5740 | .patch = patch_vt1716S}, | 6227 | .patch = patch_vt1716S}, |
5741 | { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, | 6228 | { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, |
5742 | { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, | 6229 | { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, |
6230 | { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, | ||
5743 | {} /* terminator */ | 6231 | {} /* terminator */ |
5744 | }; | 6232 | }; |
5745 | 6233 | ||