aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLydia Wang <lydiawang@viatech.com.cn>2009-10-10 07:07:52 -0400
committerTakashi Iwai <tiwai@suse.de>2009-10-11 11:56:53 -0400
commit1564b2878f5cf160f60af99d4dbca1dd7809ee8a (patch)
tree2224b34919c247b6bfacce32a81a0953036fc0c4
parentcdc1784d49258198df600fbc1d37c07d7eee5ed6 (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.c177
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
212struct via_spec { 212struct 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
394static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
395
393static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, 396static 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
664static 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
679static 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}
716static 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
729static 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
739static 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
767static 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
813static 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 */
661static struct snd_kcontrol_new vt1708_capture_mixer[] = { 826static 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