aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_via.c
diff options
context:
space:
mode:
authorLydia Wang <lydiawang@viatech.com.cn>2009-10-10 07:08:43 -0400
committerTakashi Iwai <tiwai@suse.de>2009-10-11 11:58:59 -0400
commit25eaba2f8a6877ba6f58197c4723c2433a316e09 (patch)
treec5a68bbd3f91dac351b366a3811563608e879650 /sound/pci/hda/patch_via.c
parentf3db423df84570c9950754a5771ad26f0111235f (diff)
ALSA: HDA VIA: Add VT2002P 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.c665
1 files changed, 660 insertions, 5 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 2977004677ec..a94cc91c18ff 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -88,6 +88,7 @@ enum VIA_HDA_CODEC {
88 VT1702, 88 VT1702,
89 VT1718S, 89 VT1718S,
90 VT1716S, 90 VT1716S,
91 VT2002P,
91 CODEC_TYPES, 92 CODEC_TYPES,
92}; 93};
93 94
@@ -184,6 +185,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
184 codec_type = VT1716S; 185 codec_type = VT1716S;
185 else if (dev_id == 0x0441 || dev_id == 0x4441) 186 else if (dev_id == 0x0441 || dev_id == 0x4441)
186 codec_type = VT1718S; 187 codec_type = VT1718S;
188 else if (dev_id == 0x0438 || dev_id == 0x4438)
189 codec_type = VT2002P;
187 else 190 else
188 codec_type = UNKNOWN; 191 codec_type = UNKNOWN;
189 return codec_type; 192 return codec_type;
@@ -193,11 +196,14 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
193#define VIA_GPIO_EVENT 0x02 196#define VIA_GPIO_EVENT 0x02
194#define VIA_JACK_EVENT 0x04 197#define VIA_JACK_EVENT 0x04
195#define VIA_MONO_EVENT 0x08 198#define VIA_MONO_EVENT 0x08
199#define VIA_SPEAKER_EVENT 0x10
200#define VIA_BIND_HP_EVENT 0x20
196 201
197enum { 202enum {
198 VIA_CTL_WIDGET_VOL, 203 VIA_CTL_WIDGET_VOL,
199 VIA_CTL_WIDGET_MUTE, 204 VIA_CTL_WIDGET_MUTE,
200 VIA_CTL_WIDGET_ANALOG_MUTE, 205 VIA_CTL_WIDGET_ANALOG_MUTE,
206 VIA_CTL_WIDGET_BIND_PIN_MUTE,
201}; 207};
202 208
203enum { 209enum {
@@ -235,6 +241,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
235 flush_scheduled_work(); 241 flush_scheduled_work();
236} 242}
237 243
244
238static int analog_input_switch_put(struct snd_kcontrol *kcontrol, 245static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
239 struct snd_ctl_elem_value *ucontrol) 246 struct snd_ctl_elem_value *ucontrol)
240{ 247{
@@ -262,13 +269,108 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
262 .put = analog_input_switch_put, \ 269 .put = analog_input_switch_put, \
263 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } 270 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
264 271
272static void via_hp_bind_automute(struct hda_codec *codec);
273
274static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
275 struct snd_ctl_elem_value *ucontrol)
276{
277 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
278 struct via_spec *spec = codec->spec;
279 int i;
280 int change = 0;
281
282 long *valp = ucontrol->value.integer.value;
283 int lmute, rmute;
284 if (strstr(kcontrol->id.name, "Switch") == NULL) {
285 snd_printd("Invalid control!\n");
286 return change;
287 }
288 change = snd_hda_mixer_amp_switch_put(kcontrol,
289 ucontrol);
290 /* Get mute value */
291 lmute = *valp ? 0 : HDA_AMP_MUTE;
292 valp++;
293 rmute = *valp ? 0 : HDA_AMP_MUTE;
294
295 /* Set hp pins */
296 if (!spec->hp_independent_mode) {
297 for (i = 0; i < spec->autocfg.hp_outs; i++) {
298 snd_hda_codec_amp_update(
299 codec, spec->autocfg.hp_pins[i],
300 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
301 lmute);
302 snd_hda_codec_amp_update(
303 codec, spec->autocfg.hp_pins[i],
304 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
305 rmute);
306 }
307 }
308
309 if (!lmute && !rmute) {
310 /* Line Outs */
311 for (i = 0; i < spec->autocfg.line_outs; i++)
312 snd_hda_codec_amp_stereo(
313 codec, spec->autocfg.line_out_pins[i],
314 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
315 /* Speakers */
316 for (i = 0; i < spec->autocfg.speaker_outs; i++)
317 snd_hda_codec_amp_stereo(
318 codec, spec->autocfg.speaker_pins[i],
319 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
320 /* unmute */
321 via_hp_bind_automute(codec);
322
323 } else {
324 if (lmute) {
325 /* Mute all left channels */
326 for (i = 1; i < spec->autocfg.line_outs; i++)
327 snd_hda_codec_amp_update(
328 codec,
329 spec->autocfg.line_out_pins[i],
330 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
331 lmute);
332 for (i = 0; i < spec->autocfg.speaker_outs; i++)
333 snd_hda_codec_amp_update(
334 codec,
335 spec->autocfg.speaker_pins[i],
336 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
337 lmute);
338 }
339 if (rmute) {
340 /* mute all right channels */
341 for (i = 1; i < spec->autocfg.line_outs; i++)
342 snd_hda_codec_amp_update(
343 codec,
344 spec->autocfg.line_out_pins[i],
345 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
346 rmute);
347 for (i = 0; i < spec->autocfg.speaker_outs; i++)
348 snd_hda_codec_amp_update(
349 codec,
350 spec->autocfg.speaker_pins[i],
351 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
352 rmute);
353 }
354 }
355 return change;
356}
357
358#define BIND_PIN_MUTE \
359 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
360 .name = NULL, \
361 .index = 0, \
362 .info = snd_hda_mixer_amp_switch_info, \
363 .get = snd_hda_mixer_amp_switch_get, \
364 .put = bind_pin_switch_put, \
365 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
366
265static struct snd_kcontrol_new vt1708_control_templates[] = { 367static struct snd_kcontrol_new vt1708_control_templates[] = {
266 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 368 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
267 HDA_CODEC_MUTE(NULL, 0, 0, 0), 369 HDA_CODEC_MUTE(NULL, 0, 0, 0),
268 ANALOG_INPUT_MUTE, 370 ANALOG_INPUT_MUTE,
371 BIND_PIN_MUTE,
269}; 372};
270 373
271
272static hda_nid_t vt1708_adc_nids[2] = { 374static hda_nid_t vt1708_adc_nids[2] = {
273 /* ADC1-2 */ 375 /* ADC1-2 */
274 0x15, 0x27 376 0x15, 0x27
@@ -304,6 +406,11 @@ static hda_nid_t vt1716S_adc_nids[2] = {
304 0x13, 0x14 406 0x13, 0x14
305}; 407};
306 408
409static hda_nid_t vt2002P_adc_nids[2] = {
410 /* ADC1-2 */
411 0x10, 0x11
412};
413
307/* add dynamic controls */ 414/* add dynamic controls */
308static int via_add_control(struct via_spec *spec, int type, const char *name, 415static int via_add_control(struct via_spec *spec, int type, const char *name,
309 unsigned long val) 416 unsigned long val)
@@ -386,10 +493,13 @@ static void via_auto_init_hp_out(struct hda_codec *codec)
386{ 493{
387 struct via_spec *spec = codec->spec; 494 struct via_spec *spec = codec->spec;
388 hda_nid_t pin; 495 hda_nid_t pin;
496 int i;
389 497
390 pin = spec->autocfg.hp_pins[0]; 498 for (i = 0; i < spec->autocfg.hp_outs; i++) {
391 if (pin) /* connect to front */ 499 pin = spec->autocfg.hp_pins[i];
392 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); 500 if (pin) /* connect to front */
501 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
502 }
393} 503}
394 504
395static void via_auto_init_analog_input(struct hda_codec *codec) 505static void via_auto_init_analog_input(struct hda_codec *codec)
@@ -693,6 +803,107 @@ static void set_jack_power_state(struct hda_codec *codec)
693 imux_is_smixer ? AC_PWRST_D0 : parm); 803 imux_is_smixer ? AC_PWRST_D0 : parm);
694 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, 804 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
695 mono_out ? AC_PWRST_D0 : parm); 805 mono_out ? AC_PWRST_D0 : parm);
806 } else if (spec->codec_type == VT2002P) {
807 unsigned int present;
808 /* MUX9 (1eh) = stereo mixer */
809 imux_is_smixer = snd_hda_codec_read(
810 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
811 /* inputs */
812 /* PW 5/6/7 (29h/2ah/2bh) */
813 parm = AC_PWRST_D3;
814 set_pin_power_state(codec, 0x29, &parm);
815 set_pin_power_state(codec, 0x2a, &parm);
816 set_pin_power_state(codec, 0x2b, &parm);
817 if (imux_is_smixer)
818 parm = AC_PWRST_D0;
819 /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
820 snd_hda_codec_write(codec, 0x1e, 0,
821 AC_VERB_SET_POWER_STATE, parm);
822 snd_hda_codec_write(codec, 0x1f, 0,
823 AC_VERB_SET_POWER_STATE, parm);
824 snd_hda_codec_write(codec, 0x10, 0,
825 AC_VERB_SET_POWER_STATE, parm);
826 snd_hda_codec_write(codec, 0x11, 0,
827 AC_VERB_SET_POWER_STATE, parm);
828
829 /* outputs */
830 /* AOW0 (8h)*/
831 snd_hda_codec_write(codec, 0x8, 0,
832 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
833
834 /* PW4 (26h), MW4 (1ch), MUX4(37h) */
835 parm = AC_PWRST_D3;
836 set_pin_power_state(codec, 0x26, &parm);
837 snd_hda_codec_write(codec, 0x1c, 0,
838 AC_VERB_SET_POWER_STATE, parm);
839 snd_hda_codec_write(codec, 0x37,
840 0, AC_VERB_SET_POWER_STATE, parm);
841
842 /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
843 parm = AC_PWRST_D3;
844 set_pin_power_state(codec, 0x25, &parm);
845 snd_hda_codec_write(codec, 0x19, 0,
846 AC_VERB_SET_POWER_STATE, parm);
847 snd_hda_codec_write(codec, 0x35, 0,
848 AC_VERB_SET_POWER_STATE, parm);
849 if (spec->hp_independent_mode) {
850 snd_hda_codec_write(codec, 0x9, 0,
851 AC_VERB_SET_POWER_STATE, parm);
852 }
853
854 /* Class-D */
855 /* PW0 (24h), MW0(18h), MUX0(34h) */
856 present = snd_hda_codec_read(
857 codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
858 parm = AC_PWRST_D3;
859 set_pin_power_state(codec, 0x24, &parm);
860 if (present) {
861 snd_hda_codec_write(
862 codec, 0x18, 0,
863 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
864 snd_hda_codec_write(
865 codec, 0x34, 0,
866 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
867 } else {
868 snd_hda_codec_write(
869 codec, 0x18, 0,
870 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
871 snd_hda_codec_write(
872 codec, 0x34, 0,
873 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
874 }
875
876 /* Mono Out */
877 /* PW15 (31h), MW8(17h), MUX8(3bh) */
878 present = snd_hda_codec_read(
879 codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
880 parm = AC_PWRST_D3;
881 set_pin_power_state(codec, 0x31, &parm);
882 if (present) {
883 snd_hda_codec_write(
884 codec, 0x17, 0,
885 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
886 snd_hda_codec_write(
887 codec, 0x3b, 0,
888 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
889 } else {
890 snd_hda_codec_write(
891 codec, 0x17, 0,
892 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
893 snd_hda_codec_write(
894 codec, 0x3b, 0,
895 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
896 }
897
898 /* MW9 (21h) */
899 if (imux_is_smixer || !is_aa_path_mute(codec))
900 snd_hda_codec_write(
901 codec, 0x21, 0,
902 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
903 else
904 snd_hda_codec_write(
905 codec, 0x21, 0,
906 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
696 } 907 }
697} 908}
698 909
@@ -760,6 +971,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
760 case VT1718S: 971 case VT1718S:
761 nid = 0x34; 972 nid = 0x34;
762 break; 973 break;
974 case VT2002P:
975 nid = 0x35;
976 break;
763 default: 977 default:
764 nid = spec->autocfg.hp_pins[0]; 978 nid = spec->autocfg.hp_pins[0];
765 break; 979 break;
@@ -832,6 +1046,9 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
832 pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ 1046 pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
833 spec->multiout.num_dacs = 4; 1047 spec->multiout.num_dacs = 4;
834 break; 1048 break;
1049 case VT2002P:
1050 nid = 0x35;
1051 break;
835 default: 1052 default:
836 nid = spec->autocfg.hp_pins[0]; 1053 nid = spec->autocfg.hp_pins[0];
837 break; 1054 break;
@@ -848,7 +1065,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
848 if (spec->codec_type == VT1708S 1065 if (spec->codec_type == VT1708S
849 || spec->codec_type == VT1702 1066 || spec->codec_type == VT1702
850 || spec->codec_type == VT1718S 1067 || spec->codec_type == VT1718S
851 || spec->codec_type == VT1716S) { 1068 || spec->codec_type == VT1716S
1069 || spec->codec_type == VT2002P) {
852 activate_ctl(codec, "Headphone Playback Volume", 1070 activate_ctl(codec, "Headphone Playback Volume",
853 spec->hp_independent_mode); 1071 spec->hp_independent_mode);
854 activate_ctl(codec, "Headphone Playback Switch", 1072 activate_ctl(codec, "Headphone Playback Switch",
@@ -1088,6 +1306,11 @@ static int is_aa_path_mute(struct hda_codec *codec)
1088 start_idx = 1; 1306 start_idx = 1;
1089 end_idx = 3; 1307 end_idx = 3;
1090 break; 1308 break;
1309 case VT2002P:
1310 nid_mixer = 0x21;
1311 start_idx = 0;
1312 end_idx = 2;
1313 break;
1091 default: 1314 default:
1092 return 0; 1315 return 0;
1093 } 1316 }
@@ -1146,6 +1369,10 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
1146 verb = 0xf73; 1369 verb = 0xf73;
1147 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ 1370 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
1148 break; 1371 break;
1372 case VT2002P:
1373 verb = 0xf93;
1374 parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
1375 break;
1149 default: 1376 default:
1150 return; /* other codecs are not supported */ 1377 return; /* other codecs are not supported */
1151 } 1378 }
@@ -1645,6 +1872,66 @@ static void via_gpio_control(struct hda_codec *codec)
1645 } 1872 }
1646} 1873}
1647 1874
1875/* mute Internal-Speaker if HP is plugged */
1876static void via_speaker_automute(struct hda_codec *codec)
1877{
1878 unsigned int hp_present;
1879 struct via_spec *spec = codec->spec;
1880
1881 if (spec->codec_type != VT2002P)
1882 return;
1883
1884 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1885 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1886
1887 if (!spec->hp_independent_mode) {
1888 struct snd_ctl_elem_id id;
1889 snd_hda_codec_amp_stereo(
1890 codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
1891 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
1892 /* notify change */
1893 memset(&id, 0, sizeof(id));
1894 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1895 strcpy(id.name, "Speaker Playback Switch");
1896 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1897 &id);
1898 }
1899}
1900
1901/* mute line-out and internal speaker if HP is plugged */
1902static void via_hp_bind_automute(struct hda_codec *codec)
1903{
1904 unsigned int hp_present, present = 0;
1905 struct via_spec *spec = codec->spec;
1906 int i;
1907
1908 if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
1909 return;
1910
1911 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1912 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1913
1914 present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0,
1915 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1916
1917 if (!spec->hp_independent_mode) {
1918 /* Mute Line-Outs */
1919 for (i = 0; i < spec->autocfg.line_outs; i++)
1920 snd_hda_codec_amp_stereo(
1921 codec, spec->autocfg.line_out_pins[i],
1922 HDA_OUTPUT, 0,
1923 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
1924 if (hp_present)
1925 present = hp_present;
1926 }
1927 /* Speakers */
1928 for (i = 0; i < spec->autocfg.speaker_outs; i++)
1929 snd_hda_codec_amp_stereo(
1930 codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
1931 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1932}
1933
1934
1648/* unsolicited event for jack sensing */ 1935/* unsolicited event for jack sensing */
1649static void via_unsol_event(struct hda_codec *codec, 1936static void via_unsol_event(struct hda_codec *codec,
1650 unsigned int res) 1937 unsigned int res)
@@ -1658,6 +1945,10 @@ static void via_unsol_event(struct hda_codec *codec,
1658 set_jack_power_state(codec); 1945 set_jack_power_state(codec);
1659 if (res & VIA_MONO_EVENT) 1946 if (res & VIA_MONO_EVENT)
1660 via_mono_automute(codec); 1947 via_mono_automute(codec);
1948 if (res & VIA_SPEAKER_EVENT)
1949 via_speaker_automute(codec);
1950 if (res & VIA_BIND_HP_EVENT)
1951 via_hp_bind_automute(codec);
1661} 1952}
1662 1953
1663static int via_init(struct hda_codec *codec) 1954static int via_init(struct hda_codec *codec)
@@ -2067,10 +2358,19 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
2067/* init callback for auto-configuration model -- overriding the default init */ 2358/* init callback for auto-configuration model -- overriding the default init */
2068static int via_auto_init(struct hda_codec *codec) 2359static int via_auto_init(struct hda_codec *codec)
2069{ 2360{
2361 struct via_spec *spec = codec->spec;
2362
2070 via_init(codec); 2363 via_init(codec);
2071 via_auto_init_multi_out(codec); 2364 via_auto_init_multi_out(codec);
2072 via_auto_init_hp_out(codec); 2365 via_auto_init_hp_out(codec);
2073 via_auto_init_analog_input(codec); 2366 via_auto_init_analog_input(codec);
2367 if (spec->codec_type == VT2002P) {
2368 via_hp_bind_automute(codec);
2369 } else {
2370 via_hp_automute(codec);
2371 via_speaker_automute(codec);
2372 }
2373
2074 return 0; 2374 return 0;
2075} 2375}
2076 2376
@@ -5001,6 +5301,359 @@ static int patch_vt1716S(struct hda_codec *codec)
5001 5301
5002 return 0; 5302 return 0;
5003} 5303}
5304
5305/* for vt2002P */
5306
5307/* capture mixer elements */
5308static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
5309 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5310 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5311 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5312 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5313 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5314 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
5315 HDA_INPUT),
5316 {
5317 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5318 /* The multiple "Capture Source" controls confuse alsamixer
5319 * So call somewhat different..
5320 */
5321 /* .name = "Capture Source", */
5322 .name = "Input Source",
5323 .count = 2,
5324 .info = via_mux_enum_info,
5325 .get = via_mux_enum_get,
5326 .put = via_mux_enum_put,
5327 },
5328 { } /* end */
5329};
5330
5331static struct hda_verb vt2002P_volume_init_verbs[] = {
5332 /*
5333 * Unmute ADC0-1 and set the default input to mic-in
5334 */
5335 {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5336 {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5337
5338
5339 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5340 * mixer widget
5341 */
5342 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5343 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5344 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5345 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5346 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5347 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5348
5349 /* MUX Indices: Mic = 0 */
5350 {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5351 {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5352
5353 /* PW9 Output enable */
5354 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5355
5356 /* Enable Boost Volume backdoor */
5357 {0x1, 0xfb9, 0x24},
5358
5359 /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5360 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5361 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5362 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5363 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5364 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5365 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5366 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5367 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5368
5369 /* set MUX0/1/4/8 = 0 (AOW0) */
5370 {0x34, AC_VERB_SET_CONNECT_SEL, 0},
5371 {0x35, AC_VERB_SET_CONNECT_SEL, 0},
5372 {0x37, AC_VERB_SET_CONNECT_SEL, 0},
5373 {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
5374
5375 /* set PW0 index=0 (MW0) */
5376 {0x24, AC_VERB_SET_CONNECT_SEL, 0},
5377
5378 /* Enable AOW0 to MW9 */
5379 {0x1, 0xfb8, 0x88},
5380 { }
5381};
5382
5383
5384static struct hda_verb vt2002P_uniwill_init_verbs[] = {
5385 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
5386 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5387 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
5388 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5389 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5390 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5391 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5392 { }
5393};
5394
5395static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
5396 .substreams = 2,
5397 .channels_min = 2,
5398 .channels_max = 2,
5399 .nid = 0x8, /* NID to query formats and rates */
5400 .ops = {
5401 .open = via_playback_pcm_open,
5402 .prepare = via_playback_multi_pcm_prepare,
5403 .cleanup = via_playback_multi_pcm_cleanup,
5404 .close = via_pcm_open_close,
5405 },
5406};
5407
5408static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
5409 .substreams = 2,
5410 .channels_min = 2,
5411 .channels_max = 2,
5412 .nid = 0x10, /* NID to query formats and rates */
5413 .ops = {
5414 .open = via_pcm_open_close,
5415 .prepare = via_capture_pcm_prepare,
5416 .cleanup = via_capture_pcm_cleanup,
5417 .close = via_pcm_open_close,
5418 },
5419};
5420
5421static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
5422 .substreams = 1,
5423 .channels_min = 2,
5424 .channels_max = 2,
5425 .rates = SNDRV_PCM_RATE_48000,
5426 /* NID is set in via_build_pcms */
5427 .ops = {
5428 .open = via_dig_playback_pcm_open,
5429 .close = via_dig_playback_pcm_close,
5430 .prepare = via_dig_playback_pcm_prepare,
5431 .cleanup = via_dig_playback_pcm_cleanup
5432 },
5433};
5434
5435/* fill in the dac_nids table from the parsed pin configuration */
5436static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
5437 const struct auto_pin_cfg *cfg)
5438{
5439 spec->multiout.num_dacs = 1;
5440 spec->multiout.dac_nids = spec->private_dac_nids;
5441 if (cfg->line_out_pins[0])
5442 spec->multiout.dac_nids[0] = 0x8;
5443 return 0;
5444}
5445
5446/* add playback controls from the parsed DAC table */
5447static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
5448 const struct auto_pin_cfg *cfg)
5449{
5450 int err;
5451
5452 if (!cfg->line_out_pins[0])
5453 return -1;
5454
5455
5456 /* Line-Out: PortE */
5457 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5458 "Master Front Playback Volume",
5459 HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5460 if (err < 0)
5461 return err;
5462 err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
5463 "Master Front Playback Switch",
5464 HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
5465 if (err < 0)
5466 return err;
5467
5468 return 0;
5469}
5470
5471static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5472{
5473 int err;
5474
5475 if (!pin)
5476 return 0;
5477
5478 spec->multiout.hp_nid = 0x9;
5479 spec->hp_independent_mode_index = 1;
5480
5481 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5482 "Headphone Playback Volume",
5483 HDA_COMPOSE_AMP_VAL(
5484 spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
5485 if (err < 0)
5486 return err;
5487
5488 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5489 "Headphone Playback Switch",
5490 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5491 if (err < 0)
5492 return err;
5493
5494 create_hp_imux(spec);
5495 return 0;
5496}
5497
5498/* create playback/capture controls for input pins */
5499static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
5500 const struct auto_pin_cfg *cfg)
5501{
5502 static char *labels[] = {
5503 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5504 };
5505 struct hda_input_mux *imux = &spec->private_imux[0];
5506 int i, err, idx = 0;
5507
5508 for (i = 0; i < AUTO_PIN_LAST; i++) {
5509 if (!cfg->input_pins[i])
5510 continue;
5511
5512 switch (cfg->input_pins[i]) {
5513 case 0x2b: /* Mic */
5514 idx = 0;
5515 break;
5516
5517 case 0x2a: /* Line In */
5518 idx = 1;
5519 break;
5520
5521 case 0x29: /* Front Mic */
5522 idx = 2;
5523 break;
5524 }
5525 err = via_new_analog_input(spec, labels[i], idx, 0x21);
5526 if (err < 0)
5527 return err;
5528 imux->items[imux->num_items].label = labels[i];
5529 imux->items[imux->num_items].index = idx;
5530 imux->num_items++;
5531 }
5532
5533 /* build volume/mute control of loopback */
5534 err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
5535 if (err < 0)
5536 return err;
5537
5538 /* for internal loopback recording select */
5539 imux->items[imux->num_items].label = "Stereo Mixer";
5540 imux->items[imux->num_items].index = 3;
5541 imux->num_items++;
5542
5543 /* for digital mic select */
5544 imux->items[imux->num_items].label = "Digital Mic";
5545 imux->items[imux->num_items].index = 4;
5546 imux->num_items++;
5547
5548 return 0;
5549}
5550
5551static int vt2002P_parse_auto_config(struct hda_codec *codec)
5552{
5553 struct via_spec *spec = codec->spec;
5554 int err;
5555
5556
5557 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5558 if (err < 0)
5559 return err;
5560
5561 err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
5562 if (err < 0)
5563 return err;
5564
5565 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5566 return 0; /* can't find valid BIOS pin config */
5567
5568 err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
5569 if (err < 0)
5570 return err;
5571 err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5572 if (err < 0)
5573 return err;
5574 err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
5575 if (err < 0)
5576 return err;
5577
5578 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5579
5580 fill_dig_outs(codec);
5581
5582 if (spec->kctls.list)
5583 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5584
5585 spec->input_mux = &spec->private_imux[0];
5586
5587 if (spec->hp_mux)
5588 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5589
5590 return 1;
5591}
5592
5593#ifdef CONFIG_SND_HDA_POWER_SAVE
5594static struct hda_amp_list vt2002P_loopbacks[] = {
5595 { 0x21, HDA_INPUT, 0 },
5596 { 0x21, HDA_INPUT, 1 },
5597 { 0x21, HDA_INPUT, 2 },
5598 { } /* end */
5599};
5600#endif
5601
5602
5603/* patch for vt2002P */
5604static int patch_vt2002P(struct hda_codec *codec)
5605{
5606 struct via_spec *spec;
5607 int err;
5608
5609 /* create a codec specific record */
5610 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5611 if (spec == NULL)
5612 return -ENOMEM;
5613
5614 codec->spec = spec;
5615
5616 /* automatic parse from the BIOS config */
5617 err = vt2002P_parse_auto_config(codec);
5618 if (err < 0) {
5619 via_free(codec);
5620 return err;
5621 } else if (!err) {
5622 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5623 "from BIOS. Using genenic mode...\n");
5624 }
5625
5626 spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs;
5627 spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
5628
5629 spec->stream_name_analog = "VT2002P Analog";
5630 spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
5631 spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
5632
5633 spec->stream_name_digital = "VT2002P Digital";
5634 spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
5635
5636 if (!spec->adc_nids && spec->input_mux) {
5637 spec->adc_nids = vt2002P_adc_nids;
5638 spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
5639 get_mux_nids(codec);
5640 override_mic_boost(codec, 0x2b, 0, 3, 40);
5641 override_mic_boost(codec, 0x29, 0, 3, 40);
5642 spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
5643 spec->num_mixers++;
5644 }
5645
5646 codec->patch_ops = via_patch_ops;
5647
5648 codec->patch_ops.init = via_auto_init;
5649 codec->patch_ops.unsol_event = via_unsol_event,
5650
5651#ifdef CONFIG_SND_HDA_POWER_SAVE
5652 spec->loopback.amplist = vt2002P_loopbacks;
5653#endif
5654
5655 return 0;
5656}
5004/* 5657/*
5005 * patch entries 5658 * patch entries
5006 */ 5659 */
@@ -5085,6 +5738,8 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
5085 .patch = patch_vt1716S}, 5738 .patch = patch_vt1716S},
5086 { .id = 0x1106a721, .name = "VT1716S", 5739 { .id = 0x1106a721, .name = "VT1716S",
5087 .patch = patch_vt1716S}, 5740 .patch = patch_vt1716S},
5741 { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
5742 { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
5088 {} /* terminator */ 5743 {} /* terminator */
5089}; 5744};
5090 5745