diff options
-rw-r--r-- | sound/pci/hda/patch_via.c | 554 |
1 files changed, 545 insertions, 9 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 1c87231fa7e5..c78385340694 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -86,6 +86,7 @@ enum VIA_HDA_CODEC { | |||
86 | VT1708S, | 86 | VT1708S, |
87 | VT1708BCE, | 87 | VT1708BCE, |
88 | VT1702, | 88 | VT1702, |
89 | VT1718S, | ||
89 | CODEC_TYPES, | 90 | CODEC_TYPES, |
90 | }; | 91 | }; |
91 | 92 | ||
@@ -175,6 +176,9 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | |||
175 | else if ((dev_id & 0xfff) == 0x398 | 176 | else if ((dev_id & 0xfff) == 0x398 |
176 | && (dev_id >> 12) < 8) | 177 | && (dev_id >> 12) < 8) |
177 | codec_type = VT1702; | 178 | codec_type = VT1702; |
179 | else if ((dev_id & 0xfff) == 0x428 | ||
180 | && (dev_id >> 12) < 8) | ||
181 | codec_type = VT1718S; | ||
178 | else | 182 | else |
179 | codec_type = UNKNOWN; | 183 | codec_type = UNKNOWN; |
180 | return codec_type; | 184 | return codec_type; |
@@ -284,6 +288,11 @@ static hda_nid_t vt1702_adc_nids[3] = { | |||
284 | 0x12, 0x20, 0x1F | 288 | 0x12, 0x20, 0x1F |
285 | }; | 289 | }; |
286 | 290 | ||
291 | static hda_nid_t vt1718S_adc_nids[2] = { | ||
292 | /* ADC1-2 */ | ||
293 | 0x10, 0x11 | ||
294 | }; | ||
295 | |||
287 | /* add dynamic controls */ | 296 | /* add dynamic controls */ |
288 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 297 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
289 | unsigned long val) | 298 | unsigned long val) |
@@ -512,6 +521,67 @@ static void set_jack_power_state(struct hda_codec *codec) | |||
512 | snd_hda_codec_write(codec, 0x27, 0, | 521 | snd_hda_codec_write(codec, 0x27, 0, |
513 | AC_VERB_SET_POWER_STATE, parm); | 522 | AC_VERB_SET_POWER_STATE, parm); |
514 | } | 523 | } |
524 | } else if (spec->codec_type == VT1718S) { | ||
525 | /* MUX6 (1eh) = stereo mixer */ | ||
526 | imux_is_smixer = snd_hda_codec_read( | ||
527 | codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; | ||
528 | /* inputs */ | ||
529 | /* PW 5/6/7 (29h/2ah/2bh) */ | ||
530 | parm = AC_PWRST_D3; | ||
531 | set_pin_power_state(codec, 0x29, &parm); | ||
532 | set_pin_power_state(codec, 0x2a, &parm); | ||
533 | set_pin_power_state(codec, 0x2b, &parm); | ||
534 | if (imux_is_smixer) | ||
535 | parm = AC_PWRST_D0; | ||
536 | /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ | ||
537 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, | ||
538 | parm); | ||
539 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, | ||
540 | parm); | ||
541 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, | ||
542 | parm); | ||
543 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, | ||
544 | parm); | ||
545 | |||
546 | /* outputs */ | ||
547 | /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ | ||
548 | parm = AC_PWRST_D3; | ||
549 | set_pin_power_state(codec, 0x27, &parm); | ||
550 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, | ||
551 | parm); | ||
552 | snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, | ||
553 | parm); | ||
554 | |||
555 | /* PW2 (26h), AOW2 (ah) */ | ||
556 | parm = AC_PWRST_D3; | ||
557 | set_pin_power_state(codec, 0x26, &parm); | ||
558 | snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, | ||
559 | parm); | ||
560 | |||
561 | /* PW0/1 (24h/25h) */ | ||
562 | parm = AC_PWRST_D3; | ||
563 | set_pin_power_state(codec, 0x24, &parm); | ||
564 | set_pin_power_state(codec, 0x25, &parm); | ||
565 | if (!spec->hp_independent_mode) /* check for redirected HP */ | ||
566 | set_pin_power_state(codec, 0x28, &parm); | ||
567 | snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, | ||
568 | parm); | ||
569 | snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, | ||
570 | parm); | ||
571 | /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ | ||
572 | snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, | ||
573 | imux_is_smixer ? AC_PWRST_D0 : parm); | ||
574 | if (spec->hp_independent_mode) { | ||
575 | /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ | ||
576 | parm = AC_PWRST_D3; | ||
577 | set_pin_power_state(codec, 0x28, &parm); | ||
578 | snd_hda_codec_write(codec, 0x1b, 0, | ||
579 | AC_VERB_SET_POWER_STATE, parm); | ||
580 | snd_hda_codec_write(codec, 0x34, 0, | ||
581 | AC_VERB_SET_POWER_STATE, parm); | ||
582 | snd_hda_codec_write(codec, 0xc, 0, | ||
583 | AC_VERB_SET_POWER_STATE, parm); | ||
584 | } | ||
515 | } | 585 | } |
516 | } | 586 | } |
517 | 587 | ||
@@ -572,11 +642,21 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
572 | { | 642 | { |
573 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 643 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
574 | struct via_spec *spec = codec->spec; | 644 | struct via_spec *spec = codec->spec; |
575 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | 645 | hda_nid_t nid; |
576 | unsigned int pinsel = snd_hda_codec_read(codec, nid, 0, | 646 | unsigned int pinsel; |
577 | AC_VERB_GET_CONNECT_SEL, | ||
578 | 0x00); | ||
579 | 647 | ||
648 | switch (spec->codec_type) { | ||
649 | case VT1718S: | ||
650 | nid = 0x34; | ||
651 | break; | ||
652 | default: | ||
653 | nid = spec->autocfg.hp_pins[0]; | ||
654 | break; | ||
655 | } | ||
656 | /* use !! to translate conn sel 2 for VT1718S */ | ||
657 | pinsel = !!snd_hda_codec_read(codec, nid, 0, | ||
658 | AC_VERB_GET_CONNECT_SEL, | ||
659 | 0x00); | ||
580 | ucontrol->value.enumerated.item[0] = pinsel; | 660 | ucontrol->value.enumerated.item[0] = pinsel; |
581 | 661 | ||
582 | return 0; | 662 | return 0; |
@@ -635,6 +715,16 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
635 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel | 715 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel |
636 | ? 1 : 0; | 716 | ? 1 : 0; |
637 | 717 | ||
718 | switch (spec->codec_type) { | ||
719 | case VT1718S: | ||
720 | nid = 0x34; | ||
721 | pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ | ||
722 | spec->multiout.num_dacs = 4; | ||
723 | break; | ||
724 | default: | ||
725 | nid = spec->autocfg.hp_pins[0]; | ||
726 | break; | ||
727 | } | ||
638 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); | 728 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); |
639 | 729 | ||
640 | if (spec->multiout.hp_nid && spec->multiout.hp_nid | 730 | if (spec->multiout.hp_nid && spec->multiout.hp_nid |
@@ -645,7 +735,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
645 | update_side_mute_status(codec); | 735 | update_side_mute_status(codec); |
646 | /* update HP volume/swtich active state */ | 736 | /* update HP volume/swtich active state */ |
647 | if (spec->codec_type == VT1708S | 737 | if (spec->codec_type == VT1708S |
648 | || spec->codec_type == VT1702) { | 738 | || spec->codec_type == VT1702 |
739 | || spec->codec_type == VT1718S) { | ||
649 | activate_ctl(codec, "Headphone Playback Volume", | 740 | activate_ctl(codec, "Headphone Playback Volume", |
650 | spec->hp_independent_mode); | 741 | spec->hp_independent_mode); |
651 | activate_ctl(codec, "Headphone Playback Switch", | 742 | activate_ctl(codec, "Headphone Playback Switch", |
@@ -758,7 +849,8 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol, | |||
758 | AC_VERB_GET_PIN_WIDGET_CONTROL, | 849 | AC_VERB_GET_PIN_WIDGET_CONTROL, |
759 | 0); | 850 | 0); |
760 | if (i == AUTO_PIN_FRONT_MIC | 851 | if (i == AUTO_PIN_FRONT_MIC |
761 | && spec->hp_independent_mode) | 852 | && spec->hp_independent_mode |
853 | && spec->codec_type != VT1718S) | ||
762 | continue; /* ignore FMic for independent HP */ | 854 | continue; /* ignore FMic for independent HP */ |
763 | if (ctl & AC_PINCTL_IN_EN | 855 | if (ctl & AC_PINCTL_IN_EN |
764 | && !(ctl & AC_PINCTL_OUT_EN)) | 856 | && !(ctl & AC_PINCTL_OUT_EN)) |
@@ -782,7 +874,8 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, | |||
782 | for (i = 0; i < ARRAY_SIZE(index); i++) { | 874 | for (i = 0; i < ARRAY_SIZE(index); i++) { |
783 | hda_nid_t nid = spec->autocfg.input_pins[index[i]]; | 875 | hda_nid_t nid = spec->autocfg.input_pins[index[i]]; |
784 | if (i == AUTO_PIN_FRONT_MIC | 876 | if (i == AUTO_PIN_FRONT_MIC |
785 | && spec->hp_independent_mode) | 877 | && spec->hp_independent_mode |
878 | && spec->codec_type != VT1718S) | ||
786 | continue; /* don't retask FMic for independent HP */ | 879 | continue; /* don't retask FMic for independent HP */ |
787 | if (nid) { | 880 | if (nid) { |
788 | unsigned int parm = snd_hda_codec_read( | 881 | unsigned int parm = snd_hda_codec_read( |
@@ -797,6 +890,10 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, | |||
797 | mute_aa_path(codec, 1); | 890 | mute_aa_path(codec, 1); |
798 | notify_aa_path_ctls(codec); | 891 | notify_aa_path_ctls(codec); |
799 | } | 892 | } |
893 | if (spec->codec_type == VT1718S) | ||
894 | snd_hda_codec_amp_stereo( | ||
895 | codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
896 | HDA_AMP_UNMUTE); | ||
800 | } | 897 | } |
801 | if (i == AUTO_PIN_FRONT_MIC) { | 898 | if (i == AUTO_PIN_FRONT_MIC) { |
802 | if (spec->codec_type == VT1708S) { | 899 | if (spec->codec_type == VT1708S) { |
@@ -871,6 +968,11 @@ static int is_aa_path_mute(struct hda_codec *codec) | |||
871 | start_idx = 1; | 968 | start_idx = 1; |
872 | end_idx = 3; | 969 | end_idx = 3; |
873 | break; | 970 | break; |
971 | case VT1718S: | ||
972 | nid_mixer = 0x21; | ||
973 | start_idx = 1; | ||
974 | end_idx = 3; | ||
975 | break; | ||
874 | default: | 976 | default: |
875 | return 0; | 977 | return 0; |
876 | } | 978 | } |
@@ -920,6 +1022,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) | |||
920 | parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */ | 1022 | parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */ |
921 | break; | 1023 | break; |
922 | case VT1708S: | 1024 | case VT1708S: |
1025 | case VT1718S: | ||
923 | verb = 0xf73; | 1026 | verb = 0xf73; |
924 | parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ | 1027 | parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ |
925 | break; | 1028 | break; |
@@ -1026,8 +1129,8 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, | |||
1026 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, | 1129 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, |
1027 | 0, format); | 1130 | 0, format); |
1028 | 1131 | ||
1029 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | 1132 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] |
1030 | !spec->hp_independent_mode) | 1133 | && !spec->hp_independent_mode) |
1031 | /* headphone out will just decode front left/right (stereo) */ | 1134 | /* headphone out will just decode front left/right (stereo) */ |
1032 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, | 1135 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, |
1033 | 0, format); | 1136 | 0, format); |
@@ -3821,6 +3924,435 @@ static int patch_vt1702(struct hda_codec *codec) | |||
3821 | return 0; | 3924 | return 0; |
3822 | } | 3925 | } |
3823 | 3926 | ||
3927 | /* Patch for VT1718S */ | ||
3928 | |||
3929 | /* capture mixer elements */ | ||
3930 | static struct snd_kcontrol_new vt1718S_capture_mixer[] = { | ||
3931 | HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), | ||
3932 | HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), | ||
3933 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), | ||
3934 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), | ||
3935 | HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), | ||
3936 | HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, | ||
3937 | HDA_INPUT), | ||
3938 | { | ||
3939 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3940 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3941 | * So call somewhat different.. | ||
3942 | */ | ||
3943 | .name = "Input Source", | ||
3944 | .count = 2, | ||
3945 | .info = via_mux_enum_info, | ||
3946 | .get = via_mux_enum_get, | ||
3947 | .put = via_mux_enum_put, | ||
3948 | }, | ||
3949 | { } /* end */ | ||
3950 | }; | ||
3951 | |||
3952 | static struct hda_verb vt1718S_volume_init_verbs[] = { | ||
3953 | /* | ||
3954 | * Unmute ADC0-1 and set the default input to mic-in | ||
3955 | */ | ||
3956 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3957 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3958 | |||
3959 | |||
3960 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
3961 | * mixer widget | ||
3962 | */ | ||
3963 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
3964 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3965 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3966 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3967 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3968 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
3969 | |||
3970 | /* Setup default input of Front HP to MW9 */ | ||
3971 | {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3972 | /* PW9 PW10 Output enable */ | ||
3973 | {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
3974 | {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
3975 | /* PW11 Input enable */ | ||
3976 | {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN}, | ||
3977 | /* Enable Boost Volume backdoor */ | ||
3978 | {0x1, 0xf88, 0x8}, | ||
3979 | /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */ | ||
3980 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3981 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3982 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3983 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3984 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3985 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3986 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3987 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3988 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3989 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3990 | /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */ | ||
3991 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
3992 | {0x35, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3993 | /* Unmute MW4's index 0 */ | ||
3994 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3995 | { } | ||
3996 | }; | ||
3997 | |||
3998 | |||
3999 | static struct hda_verb vt1718S_uniwill_init_verbs[] = { | ||
4000 | {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4001 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
4002 | {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4003 | {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4004 | {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4005 | {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4006 | {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4007 | {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4008 | {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4009 | { } | ||
4010 | }; | ||
4011 | |||
4012 | static struct hda_pcm_stream vt1718S_pcm_analog_playback = { | ||
4013 | .substreams = 2, | ||
4014 | .channels_min = 2, | ||
4015 | .channels_max = 10, | ||
4016 | .nid = 0x8, /* NID to query formats and rates */ | ||
4017 | .ops = { | ||
4018 | .open = via_playback_pcm_open, | ||
4019 | .prepare = via_playback_multi_pcm_prepare, | ||
4020 | .cleanup = via_playback_multi_pcm_cleanup, | ||
4021 | .close = via_pcm_open_close, | ||
4022 | }, | ||
4023 | }; | ||
4024 | |||
4025 | static struct hda_pcm_stream vt1718S_pcm_analog_capture = { | ||
4026 | .substreams = 2, | ||
4027 | .channels_min = 2, | ||
4028 | .channels_max = 2, | ||
4029 | .nid = 0x10, /* NID to query formats and rates */ | ||
4030 | .ops = { | ||
4031 | .open = via_pcm_open_close, | ||
4032 | .prepare = via_capture_pcm_prepare, | ||
4033 | .cleanup = via_capture_pcm_cleanup, | ||
4034 | .close = via_pcm_open_close, | ||
4035 | }, | ||
4036 | }; | ||
4037 | |||
4038 | static struct hda_pcm_stream vt1718S_pcm_digital_playback = { | ||
4039 | .substreams = 2, | ||
4040 | .channels_min = 2, | ||
4041 | .channels_max = 2, | ||
4042 | .rates = SNDRV_PCM_RATE_48000, | ||
4043 | /* NID is set in via_build_pcms */ | ||
4044 | .ops = { | ||
4045 | .open = via_dig_playback_pcm_open, | ||
4046 | .close = via_dig_playback_pcm_close, | ||
4047 | .prepare = via_dig_playback_pcm_prepare, | ||
4048 | .cleanup = via_dig_playback_pcm_cleanup | ||
4049 | }, | ||
4050 | }; | ||
4051 | |||
4052 | static struct hda_pcm_stream vt1718S_pcm_digital_capture = { | ||
4053 | .substreams = 1, | ||
4054 | .channels_min = 2, | ||
4055 | .channels_max = 2, | ||
4056 | }; | ||
4057 | |||
4058 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
4059 | static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, | ||
4060 | const struct auto_pin_cfg *cfg) | ||
4061 | { | ||
4062 | int i; | ||
4063 | hda_nid_t nid; | ||
4064 | |||
4065 | spec->multiout.num_dacs = cfg->line_outs; | ||
4066 | |||
4067 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
4068 | |||
4069 | for (i = 0; i < 4; i++) { | ||
4070 | nid = cfg->line_out_pins[i]; | ||
4071 | if (nid) { | ||
4072 | /* config dac list */ | ||
4073 | switch (i) { | ||
4074 | case AUTO_SEQ_FRONT: | ||
4075 | spec->multiout.dac_nids[i] = 0x8; | ||
4076 | break; | ||
4077 | case AUTO_SEQ_CENLFE: | ||
4078 | spec->multiout.dac_nids[i] = 0xa; | ||
4079 | break; | ||
4080 | case AUTO_SEQ_SURROUND: | ||
4081 | spec->multiout.dac_nids[i] = 0x9; | ||
4082 | break; | ||
4083 | case AUTO_SEQ_SIDE: | ||
4084 | spec->multiout.dac_nids[i] = 0xb; | ||
4085 | break; | ||
4086 | } | ||
4087 | } | ||
4088 | } | ||
4089 | |||
4090 | return 0; | ||
4091 | } | ||
4092 | |||
4093 | /* add playback controls from the parsed DAC table */ | ||
4094 | static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, | ||
4095 | const struct auto_pin_cfg *cfg) | ||
4096 | { | ||
4097 | char name[32]; | ||
4098 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
4099 | hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; | ||
4100 | hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; | ||
4101 | hda_nid_t nid, nid_vol, nid_mute = 0; | ||
4102 | int i, err; | ||
4103 | |||
4104 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
4105 | nid = cfg->line_out_pins[i]; | ||
4106 | |||
4107 | if (!nid) | ||
4108 | continue; | ||
4109 | nid_vol = nid_vols[i]; | ||
4110 | nid_mute = nid_mutes[i]; | ||
4111 | |||
4112 | if (i == AUTO_SEQ_CENLFE) { | ||
4113 | /* Center/LFE */ | ||
4114 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4115 | "Center Playback Volume", | ||
4116 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
4117 | HDA_OUTPUT)); | ||
4118 | if (err < 0) | ||
4119 | return err; | ||
4120 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4121 | "LFE Playback Volume", | ||
4122 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
4123 | HDA_OUTPUT)); | ||
4124 | if (err < 0) | ||
4125 | return err; | ||
4126 | err = via_add_control( | ||
4127 | spec, VIA_CTL_WIDGET_MUTE, | ||
4128 | "Center Playback Switch", | ||
4129 | HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, | ||
4130 | HDA_OUTPUT)); | ||
4131 | if (err < 0) | ||
4132 | return err; | ||
4133 | err = via_add_control( | ||
4134 | spec, VIA_CTL_WIDGET_MUTE, | ||
4135 | "LFE Playback Switch", | ||
4136 | HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, | ||
4137 | HDA_OUTPUT)); | ||
4138 | if (err < 0) | ||
4139 | return err; | ||
4140 | } else if (i == AUTO_SEQ_FRONT) { | ||
4141 | /* Front */ | ||
4142 | sprintf(name, "%s Playback Volume", chname[i]); | ||
4143 | err = via_add_control( | ||
4144 | spec, VIA_CTL_WIDGET_VOL, name, | ||
4145 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
4146 | if (err < 0) | ||
4147 | return err; | ||
4148 | sprintf(name, "%s Playback Switch", chname[i]); | ||
4149 | err = via_add_control( | ||
4150 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
4151 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
4152 | HDA_OUTPUT)); | ||
4153 | if (err < 0) | ||
4154 | return err; | ||
4155 | } else { | ||
4156 | sprintf(name, "%s Playback Volume", chname[i]); | ||
4157 | err = via_add_control( | ||
4158 | spec, VIA_CTL_WIDGET_VOL, name, | ||
4159 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
4160 | if (err < 0) | ||
4161 | return err; | ||
4162 | sprintf(name, "%s Playback Switch", chname[i]); | ||
4163 | err = via_add_control( | ||
4164 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
4165 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
4166 | HDA_OUTPUT)); | ||
4167 | if (err < 0) | ||
4168 | return err; | ||
4169 | } | ||
4170 | } | ||
4171 | return 0; | ||
4172 | } | ||
4173 | |||
4174 | static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
4175 | { | ||
4176 | int err; | ||
4177 | |||
4178 | if (!pin) | ||
4179 | return 0; | ||
4180 | |||
4181 | spec->multiout.hp_nid = 0xc; /* AOW4 */ | ||
4182 | spec->hp_independent_mode_index = 1; | ||
4183 | |||
4184 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4185 | "Headphone Playback Volume", | ||
4186 | HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT)); | ||
4187 | if (err < 0) | ||
4188 | return err; | ||
4189 | |||
4190 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
4191 | "Headphone Playback Switch", | ||
4192 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
4193 | if (err < 0) | ||
4194 | return err; | ||
4195 | |||
4196 | create_hp_imux(spec); | ||
4197 | return 0; | ||
4198 | } | ||
4199 | |||
4200 | /* create playback/capture controls for input pins */ | ||
4201 | static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec, | ||
4202 | const struct auto_pin_cfg *cfg) | ||
4203 | { | ||
4204 | static char *labels[] = { | ||
4205 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
4206 | }; | ||
4207 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
4208 | int i, err, idx = 0; | ||
4209 | |||
4210 | /* for internal loopback recording select */ | ||
4211 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
4212 | imux->items[imux->num_items].index = 5; | ||
4213 | imux->num_items++; | ||
4214 | |||
4215 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
4216 | if (!cfg->input_pins[i]) | ||
4217 | continue; | ||
4218 | |||
4219 | switch (cfg->input_pins[i]) { | ||
4220 | case 0x2b: /* Mic */ | ||
4221 | idx = 1; | ||
4222 | break; | ||
4223 | |||
4224 | case 0x2a: /* Line In */ | ||
4225 | idx = 2; | ||
4226 | break; | ||
4227 | |||
4228 | case 0x29: /* Front Mic */ | ||
4229 | idx = 3; | ||
4230 | break; | ||
4231 | |||
4232 | case 0x2c: /* CD */ | ||
4233 | idx = 0; | ||
4234 | break; | ||
4235 | } | ||
4236 | err = via_new_analog_input(spec, labels[i], idx, 0x21); | ||
4237 | if (err < 0) | ||
4238 | return err; | ||
4239 | imux->items[imux->num_items].label = labels[i]; | ||
4240 | imux->items[imux->num_items].index = idx; | ||
4241 | imux->num_items++; | ||
4242 | } | ||
4243 | return 0; | ||
4244 | } | ||
4245 | |||
4246 | static int vt1718S_parse_auto_config(struct hda_codec *codec) | ||
4247 | { | ||
4248 | struct via_spec *spec = codec->spec; | ||
4249 | int err; | ||
4250 | |||
4251 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
4252 | |||
4253 | if (err < 0) | ||
4254 | return err; | ||
4255 | err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg); | ||
4256 | if (err < 0) | ||
4257 | return err; | ||
4258 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
4259 | return 0; /* can't find valid BIOS pin config */ | ||
4260 | |||
4261 | err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
4262 | if (err < 0) | ||
4263 | return err; | ||
4264 | err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
4265 | if (err < 0) | ||
4266 | return err; | ||
4267 | err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
4268 | if (err < 0) | ||
4269 | return err; | ||
4270 | |||
4271 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
4272 | |||
4273 | fill_dig_outs(codec); | ||
4274 | |||
4275 | if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428) | ||
4276 | spec->dig_in_nid = 0x13; | ||
4277 | |||
4278 | if (spec->kctls.list) | ||
4279 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
4280 | |||
4281 | spec->input_mux = &spec->private_imux[0]; | ||
4282 | |||
4283 | if (spec->hp_mux) | ||
4284 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
4285 | |||
4286 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
4287 | |||
4288 | return 1; | ||
4289 | } | ||
4290 | |||
4291 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4292 | static struct hda_amp_list vt1718S_loopbacks[] = { | ||
4293 | { 0x21, HDA_INPUT, 1 }, | ||
4294 | { 0x21, HDA_INPUT, 2 }, | ||
4295 | { 0x21, HDA_INPUT, 3 }, | ||
4296 | { 0x21, HDA_INPUT, 4 }, | ||
4297 | { } /* end */ | ||
4298 | }; | ||
4299 | #endif | ||
4300 | |||
4301 | static int patch_vt1718S(struct hda_codec *codec) | ||
4302 | { | ||
4303 | struct via_spec *spec; | ||
4304 | int err; | ||
4305 | |||
4306 | /* create a codec specific record */ | ||
4307 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
4308 | if (spec == NULL) | ||
4309 | return -ENOMEM; | ||
4310 | |||
4311 | codec->spec = spec; | ||
4312 | |||
4313 | /* automatic parse from the BIOS config */ | ||
4314 | err = vt1718S_parse_auto_config(codec); | ||
4315 | if (err < 0) { | ||
4316 | via_free(codec); | ||
4317 | return err; | ||
4318 | } else if (!err) { | ||
4319 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
4320 | "from BIOS. Using genenic mode...\n"); | ||
4321 | } | ||
4322 | |||
4323 | spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs; | ||
4324 | spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs; | ||
4325 | |||
4326 | spec->stream_name_analog = "VT1718S Analog"; | ||
4327 | spec->stream_analog_playback = &vt1718S_pcm_analog_playback; | ||
4328 | spec->stream_analog_capture = &vt1718S_pcm_analog_capture; | ||
4329 | |||
4330 | spec->stream_name_digital = "VT1718S Digital"; | ||
4331 | spec->stream_digital_playback = &vt1718S_pcm_digital_playback; | ||
4332 | if (codec->vendor_id == 0x11060428) | ||
4333 | spec->stream_digital_capture = &vt1718S_pcm_digital_capture; | ||
4334 | |||
4335 | if (!spec->adc_nids && spec->input_mux) { | ||
4336 | spec->adc_nids = vt1718S_adc_nids; | ||
4337 | spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids); | ||
4338 | get_mux_nids(codec); | ||
4339 | override_mic_boost(codec, 0x1a, 0, 3, 40); | ||
4340 | override_mic_boost(codec, 0x1e, 0, 3, 40); | ||
4341 | spec->mixers[spec->num_mixers] = vt1718S_capture_mixer; | ||
4342 | spec->num_mixers++; | ||
4343 | } | ||
4344 | |||
4345 | codec->patch_ops = via_patch_ops; | ||
4346 | |||
4347 | codec->patch_ops.init = via_auto_init; | ||
4348 | codec->patch_ops.unsol_event = via_unsol_event, | ||
4349 | |||
4350 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4351 | spec->loopback.amplist = vt1718S_loopbacks; | ||
4352 | #endif | ||
4353 | |||
4354 | return 0; | ||
4355 | } | ||
3824 | /* | 4356 | /* |
3825 | * patch entries | 4357 | * patch entries |
3826 | */ | 4358 | */ |
@@ -3893,6 +4425,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { | |||
3893 | .patch = patch_vt1702}, | 4425 | .patch = patch_vt1702}, |
3894 | { .id = 0x11067398, .name = "VT1702", | 4426 | { .id = 0x11067398, .name = "VT1702", |
3895 | .patch = patch_vt1702}, | 4427 | .patch = patch_vt1702}, |
4428 | { .id = 0x11060428, .name = "VT1718S", | ||
4429 | .patch = patch_vt1718S}, | ||
4430 | { .id = 0x11064428, .name = "VT1718S", | ||
4431 | .patch = patch_vt1718S}, | ||
3896 | {} /* terminator */ | 4432 | {} /* terminator */ |
3897 | }; | 4433 | }; |
3898 | 4434 | ||