diff options
author | Lydia Wang <lydiawang@viatech.com.cn> | 2009-10-10 07:07:52 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-10-11 11:56:53 -0400 |
commit | 1564b2878f5cf160f60af99d4dbca1dd7809ee8a (patch) | |
tree | 2224b34919c247b6bfacce32a81a0953036fc0c4 | |
parent | cdc1784d49258198df600fbc1d37c07d7eee5ed6 (diff) |
ALSA: HDA VIA: Add smart5.1 function.
Smart 5.1 is for 3-jacks model, to reuse input pins as outputs.
While off, they act as "line out" / "line in" / "mic in".
While on, they acts as "line out" / "back left/right" / "center/lfe".
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 | 177 |
1 files changed, 173 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e3bd5261986e..26ee1c3a4d16 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -211,7 +211,7 @@ static struct snd_kcontrol_new vt1708_control_templates[] = { | |||
211 | 211 | ||
212 | struct via_spec { | 212 | struct via_spec { |
213 | /* codec parameterization */ | 213 | /* codec parameterization */ |
214 | struct snd_kcontrol_new *mixers[3]; | 214 | struct snd_kcontrol_new *mixers[4]; |
215 | unsigned int num_mixers; | 215 | unsigned int num_mixers; |
216 | 216 | ||
217 | struct hda_verb *init_verbs[5]; | 217 | struct hda_verb *init_verbs[5]; |
@@ -253,6 +253,7 @@ struct via_spec { | |||
253 | const struct hda_input_mux *hp_mux; | 253 | const struct hda_input_mux *hp_mux; |
254 | unsigned int hp_independent_mode; | 254 | unsigned int hp_independent_mode; |
255 | unsigned int hp_independent_mode_index; | 255 | unsigned int hp_independent_mode_index; |
256 | unsigned int smart51_enabled; | ||
256 | 257 | ||
257 | enum VIA_HDA_CODEC codec_type; | 258 | enum VIA_HDA_CODEC codec_type; |
258 | 259 | ||
@@ -390,6 +391,8 @@ static void via_auto_init_analog_input(struct hda_codec *codec) | |||
390 | } | 391 | } |
391 | } | 392 | } |
392 | 393 | ||
394 | static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); | ||
395 | |||
393 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, | 396 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, |
394 | unsigned int *affected_parm) | 397 | unsigned int *affected_parm) |
395 | { | 398 | { |
@@ -400,9 +403,10 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, | |||
400 | & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ | 403 | & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ |
401 | unsigned present = snd_hda_codec_read(codec, nid, 0, | 404 | unsigned present = snd_hda_codec_read(codec, nid, 0, |
402 | AC_VERB_GET_PIN_SENSE, 0) >> 31; | 405 | AC_VERB_GET_PIN_SENSE, 0) >> 31; |
403 | 406 | struct via_spec *spec = codec->spec; | |
404 | if ((no_presence || present) && get_defcfg_connect(def_conf) | 407 | if ((spec->smart51_enabled && is_smart51_pins(spec, nid)) |
405 | != AC_JACK_PORT_NONE) { | 408 | || ((no_presence || present) |
409 | && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { | ||
406 | *affected_parm = AC_PWRST_D0; /* if it's connected */ | 410 | *affected_parm = AC_PWRST_D0; /* if it's connected */ |
407 | parm = AC_PWRST_D0; | 411 | parm = AC_PWRST_D0; |
408 | } else | 412 | } else |
@@ -657,6 +661,167 @@ static struct snd_kcontrol_new via_hp_mixer[] = { | |||
657 | { } /* end */ | 661 | { } /* end */ |
658 | }; | 662 | }; |
659 | 663 | ||
664 | static void notify_aa_path_ctls(struct hda_codec *codec) | ||
665 | { | ||
666 | int i; | ||
667 | struct snd_ctl_elem_id id; | ||
668 | const char *labels[] = {"Mic", "Front Mic", "Line"}; | ||
669 | |||
670 | memset(&id, 0, sizeof(id)); | ||
671 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
672 | for (i = 0; i < ARRAY_SIZE(labels); i++) { | ||
673 | sprintf(id.name, "%s Playback Volume", labels[i]); | ||
674 | snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
675 | &id); | ||
676 | } | ||
677 | } | ||
678 | |||
679 | static void mute_aa_path(struct hda_codec *codec, int mute) | ||
680 | { | ||
681 | struct via_spec *spec = codec->spec; | ||
682 | hda_nid_t nid_mixer; | ||
683 | int start_idx; | ||
684 | int end_idx; | ||
685 | int i; | ||
686 | /* get nid of MW0 and start & end index */ | ||
687 | switch (spec->codec_type) { | ||
688 | case VT1708: | ||
689 | nid_mixer = 0x17; | ||
690 | start_idx = 2; | ||
691 | end_idx = 4; | ||
692 | break; | ||
693 | case VT1709_10CH: | ||
694 | case VT1709_6CH: | ||
695 | nid_mixer = 0x18; | ||
696 | start_idx = 2; | ||
697 | end_idx = 4; | ||
698 | break; | ||
699 | case VT1708B_8CH: | ||
700 | case VT1708B_4CH: | ||
701 | case VT1708S: | ||
702 | nid_mixer = 0x16; | ||
703 | start_idx = 2; | ||
704 | end_idx = 4; | ||
705 | break; | ||
706 | default: | ||
707 | return; | ||
708 | } | ||
709 | /* check AA path's mute status */ | ||
710 | for (i = start_idx; i <= end_idx; i++) { | ||
711 | int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; | ||
712 | snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i, | ||
713 | HDA_AMP_MUTE, val); | ||
714 | } | ||
715 | } | ||
716 | static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) | ||
717 | { | ||
718 | int res = 0; | ||
719 | int index; | ||
720 | for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) { | ||
721 | if (pin == spec->autocfg.input_pins[index]) { | ||
722 | res = 1; | ||
723 | break; | ||
724 | } | ||
725 | } | ||
726 | return res; | ||
727 | } | ||
728 | |||
729 | static int via_smart51_info(struct snd_kcontrol *kcontrol, | ||
730 | struct snd_ctl_elem_info *uinfo) | ||
731 | { | ||
732 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
733 | uinfo->count = 1; | ||
734 | uinfo->value.integer.min = 0; | ||
735 | uinfo->value.integer.max = 1; | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int via_smart51_get(struct snd_kcontrol *kcontrol, | ||
740 | struct snd_ctl_elem_value *ucontrol) | ||
741 | { | ||
742 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
743 | struct via_spec *spec = codec->spec; | ||
744 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
745 | int on = 1; | ||
746 | int i; | ||
747 | |||
748 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
749 | hda_nid_t nid = spec->autocfg.input_pins[index[i]]; | ||
750 | if (nid) { | ||
751 | int ctl = | ||
752 | snd_hda_codec_read(codec, nid, 0, | ||
753 | AC_VERB_GET_PIN_WIDGET_CONTROL, | ||
754 | 0); | ||
755 | if (i == AUTO_PIN_FRONT_MIC | ||
756 | && spec->hp_independent_mode) | ||
757 | continue; /* ignore FMic for independent HP */ | ||
758 | if (ctl & AC_PINCTL_IN_EN | ||
759 | && !(ctl & AC_PINCTL_OUT_EN)) | ||
760 | on = 0; | ||
761 | } | ||
762 | } | ||
763 | *ucontrol->value.integer.value = on; | ||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | static int via_smart51_put(struct snd_kcontrol *kcontrol, | ||
768 | struct snd_ctl_elem_value *ucontrol) | ||
769 | { | ||
770 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
771 | struct via_spec *spec = codec->spec; | ||
772 | int out_in = *ucontrol->value.integer.value | ||
773 | ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; | ||
774 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
775 | int i; | ||
776 | |||
777 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
778 | hda_nid_t nid = spec->autocfg.input_pins[index[i]]; | ||
779 | if (i == AUTO_PIN_FRONT_MIC | ||
780 | && spec->hp_independent_mode) | ||
781 | continue; /* don't retask FMic for independent HP */ | ||
782 | if (nid) { | ||
783 | unsigned int parm = snd_hda_codec_read( | ||
784 | codec, nid, 0, | ||
785 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
786 | parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); | ||
787 | parm |= out_in; | ||
788 | snd_hda_codec_write(codec, nid, 0, | ||
789 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
790 | parm); | ||
791 | if (out_in == AC_PINCTL_OUT_EN) { | ||
792 | mute_aa_path(codec, 1); | ||
793 | notify_aa_path_ctls(codec); | ||
794 | } | ||
795 | } | ||
796 | if (i == AUTO_PIN_FRONT_MIC) { | ||
797 | if (spec->codec_type == VT1708S) { | ||
798 | /* input = index 1 (AOW3) */ | ||
799 | snd_hda_codec_write( | ||
800 | codec, nid, 0, | ||
801 | AC_VERB_SET_CONNECT_SEL, 1); | ||
802 | snd_hda_codec_amp_stereo( | ||
803 | codec, nid, HDA_OUTPUT, | ||
804 | 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); | ||
805 | } | ||
806 | } | ||
807 | } | ||
808 | spec->smart51_enabled = *ucontrol->value.integer.value; | ||
809 | set_jack_power_state(codec); | ||
810 | return 1; | ||
811 | } | ||
812 | |||
813 | static struct snd_kcontrol_new via_smart51_mixer[] = { | ||
814 | { | ||
815 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
816 | .name = "Smart 5.1", | ||
817 | .count = 1, | ||
818 | .info = via_smart51_info, | ||
819 | .get = via_smart51_get, | ||
820 | .put = via_smart51_put, | ||
821 | }, | ||
822 | {} /* end */ | ||
823 | }; | ||
824 | |||
660 | /* capture mixer elements */ | 825 | /* capture mixer elements */ |
661 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | 826 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { |
662 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | 827 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), |
@@ -1587,6 +1752,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
1587 | if (spec->hp_mux) | 1752 | if (spec->hp_mux) |
1588 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 1753 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
1589 | 1754 | ||
1755 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
1590 | return 1; | 1756 | return 1; |
1591 | } | 1757 | } |
1592 | 1758 | ||
@@ -2087,6 +2253,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
2087 | if (spec->hp_mux) | 2253 | if (spec->hp_mux) |
2088 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 2254 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
2089 | 2255 | ||
2256 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
2090 | return 1; | 2257 | return 1; |
2091 | } | 2258 | } |
2092 | 2259 | ||
@@ -2649,6 +2816,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | |||
2649 | if (spec->hp_mux) | 2816 | if (spec->hp_mux) |
2650 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 2817 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
2651 | 2818 | ||
2819 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
2652 | return 1; | 2820 | return 1; |
2653 | } | 2821 | } |
2654 | 2822 | ||
@@ -3142,6 +3310,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | |||
3142 | if (spec->hp_mux) | 3310 | if (spec->hp_mux) |
3143 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3311 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
3144 | 3312 | ||
3313 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
3145 | return 1; | 3314 | return 1; |
3146 | } | 3315 | } |
3147 | 3316 | ||