diff options
author | Lydia Wang <lydiawang@viatech.com.cn> | 2009-10-10 07:08:41 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-10-11 11:58:51 -0400 |
commit | f3db423df84570c9950754a5771ad26f0111235f (patch) | |
tree | b7aa721c748d26b97aae03f652114268c3809a25 | |
parent | bb3c6bfc3f7a5416d85c5dbc312e2d47fc672eef (diff) |
ALSA: HDA VIA: Add VT1716S 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>
-rw-r--r-- | sound/pci/hda/patch_via.c | 648 |
1 files changed, 644 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2e7e72c83a52..2977004677ec 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -87,12 +87,13 @@ enum VIA_HDA_CODEC { | |||
87 | VT1708BCE, | 87 | VT1708BCE, |
88 | VT1702, | 88 | VT1702, |
89 | VT1718S, | 89 | VT1718S, |
90 | VT1716S, | ||
90 | CODEC_TYPES, | 91 | CODEC_TYPES, |
91 | }; | 92 | }; |
92 | 93 | ||
93 | struct via_spec { | 94 | struct via_spec { |
94 | /* codec parameterization */ | 95 | /* codec parameterization */ |
95 | struct snd_kcontrol_new *mixers[4]; | 96 | struct snd_kcontrol_new *mixers[6]; |
96 | unsigned int num_mixers; | 97 | unsigned int num_mixers; |
97 | 98 | ||
98 | struct hda_verb *init_verbs[5]; | 99 | struct hda_verb *init_verbs[5]; |
@@ -135,7 +136,7 @@ struct via_spec { | |||
135 | unsigned int hp_independent_mode; | 136 | unsigned int hp_independent_mode; |
136 | unsigned int hp_independent_mode_index; | 137 | unsigned int hp_independent_mode_index; |
137 | unsigned int smart51_enabled; | 138 | unsigned int smart51_enabled; |
138 | 139 | unsigned int dmic_enabled; | |
139 | enum VIA_HDA_CODEC codec_type; | 140 | enum VIA_HDA_CODEC codec_type; |
140 | 141 | ||
141 | /* work to check hp jack state */ | 142 | /* work to check hp jack state */ |
@@ -179,6 +180,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | |||
179 | else if ((dev_id & 0xfff) == 0x428 | 180 | else if ((dev_id & 0xfff) == 0x428 |
180 | && (dev_id >> 12) < 8) | 181 | && (dev_id >> 12) < 8) |
181 | codec_type = VT1718S; | 182 | codec_type = VT1718S; |
183 | else if (dev_id == 0x0433 || dev_id == 0xa721) | ||
184 | codec_type = VT1716S; | ||
182 | else if (dev_id == 0x0441 || dev_id == 0x4441) | 185 | else if (dev_id == 0x0441 || dev_id == 0x4441) |
183 | codec_type = VT1718S; | 186 | codec_type = VT1718S; |
184 | else | 187 | else |
@@ -189,6 +192,7 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | |||
189 | #define VIA_HP_EVENT 0x01 | 192 | #define VIA_HP_EVENT 0x01 |
190 | #define VIA_GPIO_EVENT 0x02 | 193 | #define VIA_GPIO_EVENT 0x02 |
191 | #define VIA_JACK_EVENT 0x04 | 194 | #define VIA_JACK_EVENT 0x04 |
195 | #define VIA_MONO_EVENT 0x08 | ||
192 | 196 | ||
193 | enum { | 197 | enum { |
194 | VIA_CTL_WIDGET_VOL, | 198 | VIA_CTL_WIDGET_VOL, |
@@ -295,6 +299,11 @@ static hda_nid_t vt1718S_adc_nids[2] = { | |||
295 | 0x10, 0x11 | 299 | 0x10, 0x11 |
296 | }; | 300 | }; |
297 | 301 | ||
302 | static hda_nid_t vt1716S_adc_nids[2] = { | ||
303 | /* ADC1-2 */ | ||
304 | 0x13, 0x14 | ||
305 | }; | ||
306 | |||
298 | /* add dynamic controls */ | 307 | /* add dynamic controls */ |
299 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 308 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
300 | unsigned long val) | 309 | unsigned long val) |
@@ -584,6 +593,106 @@ static void set_jack_power_state(struct hda_codec *codec) | |||
584 | snd_hda_codec_write(codec, 0xc, 0, | 593 | snd_hda_codec_write(codec, 0xc, 0, |
585 | AC_VERB_SET_POWER_STATE, parm); | 594 | AC_VERB_SET_POWER_STATE, parm); |
586 | } | 595 | } |
596 | } else if (spec->codec_type == VT1716S) { | ||
597 | unsigned int mono_out, present; | ||
598 | /* SW0 (17h) = stereo mixer */ | ||
599 | imux_is_smixer = snd_hda_codec_read( | ||
600 | codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; | ||
601 | /* inputs */ | ||
602 | /* PW 1/2/5 (1ah/1bh/1eh) */ | ||
603 | parm = AC_PWRST_D3; | ||
604 | set_pin_power_state(codec, 0x1a, &parm); | ||
605 | set_pin_power_state(codec, 0x1b, &parm); | ||
606 | set_pin_power_state(codec, 0x1e, &parm); | ||
607 | if (imux_is_smixer) | ||
608 | parm = AC_PWRST_D0; | ||
609 | /* SW0 (17h), AIW0(13h) */ | ||
610 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, | ||
611 | parm); | ||
612 | snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, | ||
613 | parm); | ||
614 | |||
615 | parm = AC_PWRST_D3; | ||
616 | set_pin_power_state(codec, 0x1e, &parm); | ||
617 | /* PW11 (22h) */ | ||
618 | if (spec->dmic_enabled) | ||
619 | set_pin_power_state(codec, 0x22, &parm); | ||
620 | else | ||
621 | snd_hda_codec_write( | ||
622 | codec, 0x22, 0, | ||
623 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
624 | |||
625 | /* SW2(26h), AIW1(14h) */ | ||
626 | snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, | ||
627 | parm); | ||
628 | snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, | ||
629 | parm); | ||
630 | |||
631 | /* outputs */ | ||
632 | /* PW0 (19h), SW1 (18h), AOW1 (11h) */ | ||
633 | parm = AC_PWRST_D3; | ||
634 | set_pin_power_state(codec, 0x19, &parm); | ||
635 | /* Smart 5.1 PW2(1bh) */ | ||
636 | if (spec->smart51_enabled) | ||
637 | set_pin_power_state(codec, 0x1b, &parm); | ||
638 | snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, | ||
639 | parm); | ||
640 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, | ||
641 | parm); | ||
642 | |||
643 | /* PW7 (23h), SW3 (27h), AOW3 (25h) */ | ||
644 | parm = AC_PWRST_D3; | ||
645 | set_pin_power_state(codec, 0x23, &parm); | ||
646 | /* Smart 5.1 PW1(1ah) */ | ||
647 | if (spec->smart51_enabled) | ||
648 | set_pin_power_state(codec, 0x1a, &parm); | ||
649 | snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, | ||
650 | parm); | ||
651 | |||
652 | /* Smart 5.1 PW5(1eh) */ | ||
653 | if (spec->smart51_enabled) | ||
654 | set_pin_power_state(codec, 0x1e, &parm); | ||
655 | snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, | ||
656 | parm); | ||
657 | |||
658 | /* Mono out */ | ||
659 | /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ | ||
660 | present = snd_hda_codec_read( | ||
661 | codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
662 | if (present) | ||
663 | mono_out = 0; | ||
664 | else { | ||
665 | present = snd_hda_codec_read( | ||
666 | codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
667 | & 0x80000000; | ||
668 | if (!spec->hp_independent_mode && present) | ||
669 | mono_out = 0; | ||
670 | else | ||
671 | mono_out = 1; | ||
672 | } | ||
673 | parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; | ||
674 | snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, | ||
675 | parm); | ||
676 | snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, | ||
677 | parm); | ||
678 | snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, | ||
679 | parm); | ||
680 | |||
681 | /* PW 3/4 (1ch/1dh) */ | ||
682 | parm = AC_PWRST_D3; | ||
683 | set_pin_power_state(codec, 0x1c, &parm); | ||
684 | set_pin_power_state(codec, 0x1d, &parm); | ||
685 | /* HP Independent Mode, power on AOW3 */ | ||
686 | if (spec->hp_independent_mode) | ||
687 | snd_hda_codec_write(codec, 0x25, 0, | ||
688 | AC_VERB_SET_POWER_STATE, parm); | ||
689 | |||
690 | /* force to D0 for internal Speaker */ | ||
691 | /* MW0 (16h), AOW0 (10h) */ | ||
692 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, | ||
693 | imux_is_smixer ? AC_PWRST_D0 : parm); | ||
694 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, | ||
695 | mono_out ? AC_PWRST_D0 : parm); | ||
587 | } | 696 | } |
588 | } | 697 | } |
589 | 698 | ||
@@ -738,7 +847,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
738 | /* update HP volume/swtich active state */ | 847 | /* update HP volume/swtich active state */ |
739 | if (spec->codec_type == VT1708S | 848 | if (spec->codec_type == VT1708S |
740 | || spec->codec_type == VT1702 | 849 | || spec->codec_type == VT1702 |
741 | || spec->codec_type == VT1718S) { | 850 | || spec->codec_type == VT1718S |
851 | || spec->codec_type == VT1716S) { | ||
742 | activate_ctl(codec, "Headphone Playback Volume", | 852 | activate_ctl(codec, "Headphone Playback Volume", |
743 | spec->hp_independent_mode); | 853 | spec->hp_independent_mode); |
744 | activate_ctl(codec, "Headphone Playback Switch", | 854 | activate_ctl(codec, "Headphone Playback Switch", |
@@ -797,6 +907,7 @@ static void mute_aa_path(struct hda_codec *codec, int mute) | |||
797 | case VT1708B_8CH: | 907 | case VT1708B_8CH: |
798 | case VT1708B_4CH: | 908 | case VT1708B_4CH: |
799 | case VT1708S: | 909 | case VT1708S: |
910 | case VT1716S: | ||
800 | nid_mixer = 0x16; | 911 | nid_mixer = 0x16; |
801 | start_idx = 2; | 912 | start_idx = 2; |
802 | end_idx = 4; | 913 | end_idx = 4; |
@@ -898,7 +1009,8 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, | |||
898 | HDA_AMP_UNMUTE); | 1009 | HDA_AMP_UNMUTE); |
899 | } | 1010 | } |
900 | if (i == AUTO_PIN_FRONT_MIC) { | 1011 | if (i == AUTO_PIN_FRONT_MIC) { |
901 | if (spec->codec_type == VT1708S) { | 1012 | if (spec->codec_type == VT1708S |
1013 | || spec->codec_type == VT1716S) { | ||
902 | /* input = index 1 (AOW3) */ | 1014 | /* input = index 1 (AOW3) */ |
903 | snd_hda_codec_write( | 1015 | snd_hda_codec_write( |
904 | codec, nid, 0, | 1016 | codec, nid, 0, |
@@ -961,6 +1073,7 @@ static int is_aa_path_mute(struct hda_codec *codec) | |||
961 | case VT1708B_8CH: | 1073 | case VT1708B_8CH: |
962 | case VT1708B_4CH: | 1074 | case VT1708B_4CH: |
963 | case VT1708S: | 1075 | case VT1708S: |
1076 | case VT1716S: | ||
964 | nid_mixer = 0x16; | 1077 | nid_mixer = 0x16; |
965 | start_idx = 2; | 1078 | start_idx = 2; |
966 | end_idx = 4; | 1079 | end_idx = 4; |
@@ -1025,6 +1138,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) | |||
1025 | break; | 1138 | break; |
1026 | case VT1708S: | 1139 | case VT1708S: |
1027 | case VT1718S: | 1140 | case VT1718S: |
1141 | case VT1716S: | ||
1028 | verb = 0xf73; | 1142 | verb = 0xf73; |
1029 | parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ | 1143 | parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ |
1030 | break; | 1144 | break; |
@@ -1453,6 +1567,36 @@ static void via_hp_automute(struct hda_codec *codec) | |||
1453 | } | 1567 | } |
1454 | } | 1568 | } |
1455 | 1569 | ||
1570 | /* mute mono out if HP or Line out is plugged */ | ||
1571 | static void via_mono_automute(struct hda_codec *codec) | ||
1572 | { | ||
1573 | unsigned int hp_present, lineout_present; | ||
1574 | struct via_spec *spec = codec->spec; | ||
1575 | |||
1576 | if (spec->codec_type != VT1716S) | ||
1577 | return; | ||
1578 | |||
1579 | lineout_present = snd_hda_codec_read( | ||
1580 | codec, spec->autocfg.line_out_pins[0], 0, | ||
1581 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1582 | |||
1583 | /* Mute Mono Out if Line Out is plugged */ | ||
1584 | if (lineout_present) { | ||
1585 | snd_hda_codec_amp_stereo( | ||
1586 | codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
1587 | return; | ||
1588 | } | ||
1589 | |||
1590 | hp_present = snd_hda_codec_read( | ||
1591 | codec, spec->autocfg.hp_pins[0], 0, | ||
1592 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1593 | |||
1594 | if (!spec->hp_independent_mode) | ||
1595 | snd_hda_codec_amp_stereo( | ||
1596 | codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
1597 | hp_present ? HDA_AMP_MUTE : 0); | ||
1598 | } | ||
1599 | |||
1456 | static void via_gpio_control(struct hda_codec *codec) | 1600 | static void via_gpio_control(struct hda_codec *codec) |
1457 | { | 1601 | { |
1458 | unsigned int gpio_data; | 1602 | unsigned int gpio_data; |
@@ -1512,6 +1656,8 @@ static void via_unsol_event(struct hda_codec *codec, | |||
1512 | via_gpio_control(codec); | 1656 | via_gpio_control(codec); |
1513 | if (res & VIA_JACK_EVENT) | 1657 | if (res & VIA_JACK_EVENT) |
1514 | set_jack_power_state(codec); | 1658 | set_jack_power_state(codec); |
1659 | if (res & VIA_MONO_EVENT) | ||
1660 | via_mono_automute(codec); | ||
1515 | } | 1661 | } |
1516 | 1662 | ||
1517 | static int via_init(struct hda_codec *codec) | 1663 | static int via_init(struct hda_codec *codec) |
@@ -4365,6 +4511,496 @@ static int patch_vt1718S(struct hda_codec *codec) | |||
4365 | 4511 | ||
4366 | return 0; | 4512 | return 0; |
4367 | } | 4513 | } |
4514 | |||
4515 | /* Patch for VT1716S */ | ||
4516 | |||
4517 | static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol, | ||
4518 | struct snd_ctl_elem_info *uinfo) | ||
4519 | { | ||
4520 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
4521 | uinfo->count = 1; | ||
4522 | uinfo->value.integer.min = 0; | ||
4523 | uinfo->value.integer.max = 1; | ||
4524 | return 0; | ||
4525 | } | ||
4526 | |||
4527 | static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, | ||
4528 | struct snd_ctl_elem_value *ucontrol) | ||
4529 | { | ||
4530 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4531 | int index = 0; | ||
4532 | |||
4533 | index = snd_hda_codec_read(codec, 0x26, 0, | ||
4534 | AC_VERB_GET_CONNECT_SEL, 0); | ||
4535 | if (index != -1) | ||
4536 | *ucontrol->value.integer.value = index; | ||
4537 | |||
4538 | return 0; | ||
4539 | } | ||
4540 | |||
4541 | static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, | ||
4542 | struct snd_ctl_elem_value *ucontrol) | ||
4543 | { | ||
4544 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4545 | struct via_spec *spec = codec->spec; | ||
4546 | int index = *ucontrol->value.integer.value; | ||
4547 | |||
4548 | snd_hda_codec_write(codec, 0x26, 0, | ||
4549 | AC_VERB_SET_CONNECT_SEL, index); | ||
4550 | spec->dmic_enabled = index; | ||
4551 | set_jack_power_state(codec); | ||
4552 | |||
4553 | return 1; | ||
4554 | } | ||
4555 | |||
4556 | /* capture mixer elements */ | ||
4557 | static struct snd_kcontrol_new vt1716S_capture_mixer[] = { | ||
4558 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), | ||
4559 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), | ||
4560 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), | ||
4561 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), | ||
4562 | HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), | ||
4563 | HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, | ||
4564 | HDA_INPUT), | ||
4565 | { | ||
4566 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4567 | .name = "Input Source", | ||
4568 | .count = 1, | ||
4569 | .info = via_mux_enum_info, | ||
4570 | .get = via_mux_enum_get, | ||
4571 | .put = via_mux_enum_put, | ||
4572 | }, | ||
4573 | { } /* end */ | ||
4574 | }; | ||
4575 | |||
4576 | static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { | ||
4577 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), | ||
4578 | { | ||
4579 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4580 | .name = "Digital Mic Capture Switch", | ||
4581 | .count = 1, | ||
4582 | .info = vt1716s_dmic_info, | ||
4583 | .get = vt1716s_dmic_get, | ||
4584 | .put = vt1716s_dmic_put, | ||
4585 | }, | ||
4586 | {} /* end */ | ||
4587 | }; | ||
4588 | |||
4589 | |||
4590 | /* mono-out mixer elements */ | ||
4591 | static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { | ||
4592 | HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), | ||
4593 | { } /* end */ | ||
4594 | }; | ||
4595 | |||
4596 | static struct hda_verb vt1716S_volume_init_verbs[] = { | ||
4597 | /* | ||
4598 | * Unmute ADC0-1 and set the default input to mic-in | ||
4599 | */ | ||
4600 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4601 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4602 | |||
4603 | |||
4604 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
4605 | * mixer widget | ||
4606 | */ | ||
4607 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
4608 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4609 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4610 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4611 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4612 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4613 | |||
4614 | /* MUX Indices: Stereo Mixer = 5 */ | ||
4615 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x5}, | ||
4616 | |||
4617 | /* Setup default input of PW4 to MW0 */ | ||
4618 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4619 | |||
4620 | /* Setup default input of SW1 as MW0 */ | ||
4621 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4622 | |||
4623 | /* Setup default input of SW4 as AOW0 */ | ||
4624 | {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4625 | |||
4626 | /* PW9 PW10 Output enable */ | ||
4627 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
4628 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
4629 | |||
4630 | /* Unmute SW1, PW12 */ | ||
4631 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4632 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4633 | /* PW12 Output enable */ | ||
4634 | {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
4635 | /* Enable Boost Volume backdoor */ | ||
4636 | {0x1, 0xf8a, 0x80}, | ||
4637 | /* don't bybass mixer */ | ||
4638 | {0x1, 0xf88, 0xc0}, | ||
4639 | /* Enable mono output */ | ||
4640 | {0x1, 0xf90, 0x08}, | ||
4641 | { } | ||
4642 | }; | ||
4643 | |||
4644 | |||
4645 | static struct hda_verb vt1716S_uniwill_init_verbs[] = { | ||
4646 | {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4647 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
4648 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4649 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4650 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4651 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4652 | AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT}, | ||
4653 | {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4654 | {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4655 | { } | ||
4656 | }; | ||
4657 | |||
4658 | static struct hda_pcm_stream vt1716S_pcm_analog_playback = { | ||
4659 | .substreams = 2, | ||
4660 | .channels_min = 2, | ||
4661 | .channels_max = 6, | ||
4662 | .nid = 0x10, /* NID to query formats and rates */ | ||
4663 | .ops = { | ||
4664 | .open = via_playback_pcm_open, | ||
4665 | .prepare = via_playback_multi_pcm_prepare, | ||
4666 | .cleanup = via_playback_multi_pcm_cleanup, | ||
4667 | .close = via_pcm_open_close, | ||
4668 | }, | ||
4669 | }; | ||
4670 | |||
4671 | static struct hda_pcm_stream vt1716S_pcm_analog_capture = { | ||
4672 | .substreams = 2, | ||
4673 | .channels_min = 2, | ||
4674 | .channels_max = 2, | ||
4675 | .nid = 0x13, /* NID to query formats and rates */ | ||
4676 | .ops = { | ||
4677 | .open = via_pcm_open_close, | ||
4678 | .prepare = via_capture_pcm_prepare, | ||
4679 | .cleanup = via_capture_pcm_cleanup, | ||
4680 | .close = via_pcm_open_close, | ||
4681 | }, | ||
4682 | }; | ||
4683 | |||
4684 | static struct hda_pcm_stream vt1716S_pcm_digital_playback = { | ||
4685 | .substreams = 2, | ||
4686 | .channels_min = 2, | ||
4687 | .channels_max = 2, | ||
4688 | .rates = SNDRV_PCM_RATE_48000, | ||
4689 | /* NID is set in via_build_pcms */ | ||
4690 | .ops = { | ||
4691 | .open = via_dig_playback_pcm_open, | ||
4692 | .close = via_dig_playback_pcm_close, | ||
4693 | .prepare = via_dig_playback_pcm_prepare, | ||
4694 | .cleanup = via_dig_playback_pcm_cleanup | ||
4695 | }, | ||
4696 | }; | ||
4697 | |||
4698 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
4699 | static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, | ||
4700 | const struct auto_pin_cfg *cfg) | ||
4701 | { int i; | ||
4702 | hda_nid_t nid; | ||
4703 | |||
4704 | spec->multiout.num_dacs = cfg->line_outs; | ||
4705 | |||
4706 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
4707 | |||
4708 | for (i = 0; i < 3; i++) { | ||
4709 | nid = cfg->line_out_pins[i]; | ||
4710 | if (nid) { | ||
4711 | /* config dac list */ | ||
4712 | switch (i) { | ||
4713 | case AUTO_SEQ_FRONT: | ||
4714 | spec->multiout.dac_nids[i] = 0x10; | ||
4715 | break; | ||
4716 | case AUTO_SEQ_CENLFE: | ||
4717 | spec->multiout.dac_nids[i] = 0x25; | ||
4718 | break; | ||
4719 | case AUTO_SEQ_SURROUND: | ||
4720 | spec->multiout.dac_nids[i] = 0x11; | ||
4721 | break; | ||
4722 | } | ||
4723 | } | ||
4724 | } | ||
4725 | |||
4726 | return 0; | ||
4727 | } | ||
4728 | |||
4729 | /* add playback controls from the parsed DAC table */ | ||
4730 | static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, | ||
4731 | const struct auto_pin_cfg *cfg) | ||
4732 | { | ||
4733 | char name[32]; | ||
4734 | static const char *chname[3] = { "Front", "Surround", "C/LFE" }; | ||
4735 | hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; | ||
4736 | hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; | ||
4737 | hda_nid_t nid, nid_vol, nid_mute; | ||
4738 | int i, err; | ||
4739 | |||
4740 | for (i = 0; i <= AUTO_SEQ_CENLFE; i++) { | ||
4741 | nid = cfg->line_out_pins[i]; | ||
4742 | |||
4743 | if (!nid) | ||
4744 | continue; | ||
4745 | |||
4746 | nid_vol = nid_vols[i]; | ||
4747 | nid_mute = nid_mutes[i]; | ||
4748 | |||
4749 | if (i == AUTO_SEQ_CENLFE) { | ||
4750 | err = via_add_control( | ||
4751 | spec, VIA_CTL_WIDGET_VOL, | ||
4752 | "Center Playback Volume", | ||
4753 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | ||
4754 | if (err < 0) | ||
4755 | return err; | ||
4756 | err = via_add_control( | ||
4757 | spec, VIA_CTL_WIDGET_VOL, | ||
4758 | "LFE Playback Volume", | ||
4759 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | ||
4760 | if (err < 0) | ||
4761 | return err; | ||
4762 | err = via_add_control( | ||
4763 | spec, VIA_CTL_WIDGET_MUTE, | ||
4764 | "Center Playback Switch", | ||
4765 | HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, | ||
4766 | HDA_OUTPUT)); | ||
4767 | if (err < 0) | ||
4768 | return err; | ||
4769 | err = via_add_control( | ||
4770 | spec, VIA_CTL_WIDGET_MUTE, | ||
4771 | "LFE Playback Switch", | ||
4772 | HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, | ||
4773 | HDA_OUTPUT)); | ||
4774 | if (err < 0) | ||
4775 | return err; | ||
4776 | } else if (i == AUTO_SEQ_FRONT) { | ||
4777 | |||
4778 | err = via_add_control( | ||
4779 | spec, VIA_CTL_WIDGET_VOL, | ||
4780 | "Master Front Playback Volume", | ||
4781 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); | ||
4782 | if (err < 0) | ||
4783 | return err; | ||
4784 | err = via_add_control( | ||
4785 | spec, VIA_CTL_WIDGET_MUTE, | ||
4786 | "Master Front Playback Switch", | ||
4787 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); | ||
4788 | if (err < 0) | ||
4789 | return err; | ||
4790 | |||
4791 | sprintf(name, "%s Playback Volume", chname[i]); | ||
4792 | err = via_add_control( | ||
4793 | spec, VIA_CTL_WIDGET_VOL, name, | ||
4794 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
4795 | if (err < 0) | ||
4796 | return err; | ||
4797 | sprintf(name, "%s Playback Switch", chname[i]); | ||
4798 | err = via_add_control( | ||
4799 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
4800 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
4801 | HDA_OUTPUT)); | ||
4802 | if (err < 0) | ||
4803 | return err; | ||
4804 | } else { | ||
4805 | sprintf(name, "%s Playback Volume", chname[i]); | ||
4806 | err = via_add_control( | ||
4807 | spec, VIA_CTL_WIDGET_VOL, name, | ||
4808 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
4809 | if (err < 0) | ||
4810 | return err; | ||
4811 | sprintf(name, "%s Playback Switch", chname[i]); | ||
4812 | err = via_add_control( | ||
4813 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
4814 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
4815 | HDA_OUTPUT)); | ||
4816 | if (err < 0) | ||
4817 | return err; | ||
4818 | } | ||
4819 | } | ||
4820 | return 0; | ||
4821 | } | ||
4822 | |||
4823 | static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
4824 | { | ||
4825 | int err; | ||
4826 | |||
4827 | if (!pin) | ||
4828 | return 0; | ||
4829 | |||
4830 | spec->multiout.hp_nid = 0x25; /* AOW3 */ | ||
4831 | spec->hp_independent_mode_index = 1; | ||
4832 | |||
4833 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4834 | "Headphone Playback Volume", | ||
4835 | HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); | ||
4836 | if (err < 0) | ||
4837 | return err; | ||
4838 | |||
4839 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
4840 | "Headphone Playback Switch", | ||
4841 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
4842 | if (err < 0) | ||
4843 | return err; | ||
4844 | |||
4845 | create_hp_imux(spec); | ||
4846 | return 0; | ||
4847 | } | ||
4848 | |||
4849 | /* create playback/capture controls for input pins */ | ||
4850 | static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec, | ||
4851 | const struct auto_pin_cfg *cfg) | ||
4852 | { | ||
4853 | static char *labels[] = { | ||
4854 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
4855 | }; | ||
4856 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
4857 | int i, err, idx = 0; | ||
4858 | |||
4859 | /* for internal loopback recording select */ | ||
4860 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
4861 | imux->items[imux->num_items].index = 5; | ||
4862 | imux->num_items++; | ||
4863 | |||
4864 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
4865 | if (!cfg->input_pins[i]) | ||
4866 | continue; | ||
4867 | |||
4868 | switch (cfg->input_pins[i]) { | ||
4869 | case 0x1a: /* Mic */ | ||
4870 | idx = 2; | ||
4871 | break; | ||
4872 | |||
4873 | case 0x1b: /* Line In */ | ||
4874 | idx = 3; | ||
4875 | break; | ||
4876 | |||
4877 | case 0x1e: /* Front Mic */ | ||
4878 | idx = 4; | ||
4879 | break; | ||
4880 | |||
4881 | case 0x1f: /* CD */ | ||
4882 | idx = 1; | ||
4883 | break; | ||
4884 | } | ||
4885 | err = via_new_analog_input(spec, labels[i], idx, 0x16); | ||
4886 | if (err < 0) | ||
4887 | return err; | ||
4888 | imux->items[imux->num_items].label = labels[i]; | ||
4889 | imux->items[imux->num_items].index = idx-1; | ||
4890 | imux->num_items++; | ||
4891 | } | ||
4892 | return 0; | ||
4893 | } | ||
4894 | |||
4895 | static int vt1716S_parse_auto_config(struct hda_codec *codec) | ||
4896 | { | ||
4897 | struct via_spec *spec = codec->spec; | ||
4898 | int err; | ||
4899 | |||
4900 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
4901 | if (err < 0) | ||
4902 | return err; | ||
4903 | err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg); | ||
4904 | if (err < 0) | ||
4905 | return err; | ||
4906 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
4907 | return 0; /* can't find valid BIOS pin config */ | ||
4908 | |||
4909 | err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
4910 | if (err < 0) | ||
4911 | return err; | ||
4912 | err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
4913 | if (err < 0) | ||
4914 | return err; | ||
4915 | err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
4916 | if (err < 0) | ||
4917 | return err; | ||
4918 | |||
4919 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
4920 | |||
4921 | fill_dig_outs(codec); | ||
4922 | |||
4923 | if (spec->kctls.list) | ||
4924 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
4925 | |||
4926 | spec->input_mux = &spec->private_imux[0]; | ||
4927 | |||
4928 | if (spec->hp_mux) | ||
4929 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
4930 | |||
4931 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
4932 | |||
4933 | return 1; | ||
4934 | } | ||
4935 | |||
4936 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4937 | static struct hda_amp_list vt1716S_loopbacks[] = { | ||
4938 | { 0x16, HDA_INPUT, 1 }, | ||
4939 | { 0x16, HDA_INPUT, 2 }, | ||
4940 | { 0x16, HDA_INPUT, 3 }, | ||
4941 | { 0x16, HDA_INPUT, 4 }, | ||
4942 | { } /* end */ | ||
4943 | }; | ||
4944 | #endif | ||
4945 | |||
4946 | static int patch_vt1716S(struct hda_codec *codec) | ||
4947 | { | ||
4948 | struct via_spec *spec; | ||
4949 | int err; | ||
4950 | |||
4951 | /* create a codec specific record */ | ||
4952 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
4953 | if (spec == NULL) | ||
4954 | return -ENOMEM; | ||
4955 | |||
4956 | codec->spec = spec; | ||
4957 | |||
4958 | /* automatic parse from the BIOS config */ | ||
4959 | err = vt1716S_parse_auto_config(codec); | ||
4960 | if (err < 0) { | ||
4961 | via_free(codec); | ||
4962 | return err; | ||
4963 | } else if (!err) { | ||
4964 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
4965 | "from BIOS. Using genenic mode...\n"); | ||
4966 | } | ||
4967 | |||
4968 | spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs; | ||
4969 | spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs; | ||
4970 | |||
4971 | spec->stream_name_analog = "VT1716S Analog"; | ||
4972 | spec->stream_analog_playback = &vt1716S_pcm_analog_playback; | ||
4973 | spec->stream_analog_capture = &vt1716S_pcm_analog_capture; | ||
4974 | |||
4975 | spec->stream_name_digital = "VT1716S Digital"; | ||
4976 | spec->stream_digital_playback = &vt1716S_pcm_digital_playback; | ||
4977 | |||
4978 | if (!spec->adc_nids && spec->input_mux) { | ||
4979 | spec->adc_nids = vt1716S_adc_nids; | ||
4980 | spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids); | ||
4981 | get_mux_nids(codec); | ||
4982 | override_mic_boost(codec, 0x1a, 0, 3, 40); | ||
4983 | override_mic_boost(codec, 0x1e, 0, 3, 40); | ||
4984 | spec->mixers[spec->num_mixers] = vt1716S_capture_mixer; | ||
4985 | spec->num_mixers++; | ||
4986 | } | ||
4987 | |||
4988 | spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; | ||
4989 | spec->num_mixers++; | ||
4990 | |||
4991 | spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; | ||
4992 | |||
4993 | codec->patch_ops = via_patch_ops; | ||
4994 | |||
4995 | codec->patch_ops.init = via_auto_init; | ||
4996 | codec->patch_ops.unsol_event = via_unsol_event, | ||
4997 | |||
4998 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4999 | spec->loopback.amplist = vt1716S_loopbacks; | ||
5000 | #endif | ||
5001 | |||
5002 | return 0; | ||
5003 | } | ||
4368 | /* | 5004 | /* |
4369 | * patch entries | 5005 | * patch entries |
4370 | */ | 5006 | */ |
@@ -4445,6 +5081,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { | |||
4445 | .patch = patch_vt1718S}, | 5081 | .patch = patch_vt1718S}, |
4446 | { .id = 0x11064441, .name = "VT1828S", | 5082 | { .id = 0x11064441, .name = "VT1828S", |
4447 | .patch = patch_vt1718S}, | 5083 | .patch = patch_vt1718S}, |
5084 | { .id = 0x11060433, .name = "VT1716S", | ||
5085 | .patch = patch_vt1716S}, | ||
5086 | { .id = 0x1106a721, .name = "VT1716S", | ||
5087 | .patch = patch_vt1716S}, | ||
4448 | {} /* terminator */ | 5088 | {} /* terminator */ |
4449 | }; | 5089 | }; |
4450 | 5090 | ||