diff options
author | Nickolas Lloyd <ultrageek.lloyd@gmail.com> | 2009-05-15 09:33:30 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-05-15 09:34:10 -0400 |
commit | 2fc998907947f92b1b9113faad531d7f5a857987 (patch) | |
tree | 53a008070b21204e8f4bab7bd1c273cebc6e6290 /sound | |
parent | 7442f9dadb8626bd9e7e01445560499560b99f5d (diff) |
ALSA: hda - add controls to toggle DC bias on mic ports
This patch adds a mixer control for the STAC92XX boards to control the
DC bias of mic ports, allowing recording from both powered and
non-powered sources. It replaces the "Mic Output Switch" with "Mic Jack
Mode" to switch between Mic, Line In, and Line Out.
Signed-off-by: Nickolas Lloyd <ultrageek.lloyd@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 111 |
1 files changed, 107 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ecf53f755a09..02950980778e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -634,6 +634,96 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, | |||
634 | return 0; | 634 | return 0; |
635 | } | 635 | } |
636 | 636 | ||
637 | static unsigned int stac92xx_vref_set(struct hda_codec *codec, | ||
638 | hda_nid_t nid, unsigned int new_vref) | ||
639 | { | ||
640 | unsigned int error; | ||
641 | unsigned int pincfg; | ||
642 | pincfg = snd_hda_codec_read(codec, nid, 0, | ||
643 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
644 | |||
645 | pincfg &= 0xff; | ||
646 | pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); | ||
647 | pincfg |= new_vref; | ||
648 | |||
649 | if (new_vref == AC_PINCTL_VREF_HIZ) | ||
650 | pincfg |= AC_PINCTL_OUT_EN; | ||
651 | else | ||
652 | pincfg |= AC_PINCTL_IN_EN; | ||
653 | |||
654 | error = snd_hda_codec_write_cache(codec, nid, 0, | ||
655 | AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg); | ||
656 | if (error < 0) | ||
657 | return error; | ||
658 | else | ||
659 | return 1; | ||
660 | } | ||
661 | |||
662 | static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) | ||
663 | { | ||
664 | unsigned int vref; | ||
665 | vref = snd_hda_codec_read(codec, nid, 0, | ||
666 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
667 | vref &= AC_PINCTL_VREFEN; | ||
668 | return vref; | ||
669 | } | ||
670 | |||
671 | static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, | ||
672 | struct snd_ctl_elem_value *ucontrol) | ||
673 | { | ||
674 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
675 | unsigned int new_vref; | ||
676 | unsigned int error; | ||
677 | |||
678 | if (ucontrol->value.enumerated.item[0] == 0) | ||
679 | new_vref = AC_PINCTL_VREF_80; | ||
680 | else if (ucontrol->value.enumerated.item[0] == 1) | ||
681 | new_vref = AC_PINCTL_VREF_GRD; | ||
682 | else | ||
683 | new_vref = AC_PINCTL_VREF_HIZ; | ||
684 | |||
685 | if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { | ||
686 | error = stac92xx_vref_set(codec, | ||
687 | kcontrol->private_value, new_vref); | ||
688 | return error; | ||
689 | } | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, | ||
695 | struct snd_ctl_elem_value *ucontrol) | ||
696 | { | ||
697 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
698 | unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); | ||
699 | if (vref == AC_PINCTL_VREF_80) | ||
700 | ucontrol->value.enumerated.item[0] = 0; | ||
701 | else if (vref == AC_PINCTL_VREF_GRD) | ||
702 | ucontrol->value.enumerated.item[0] = 1; | ||
703 | else if (vref == AC_PINCTL_VREF_HIZ) | ||
704 | ucontrol->value.enumerated.item[0] = 2; | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, | ||
710 | struct snd_ctl_elem_info *uinfo) | ||
711 | { | ||
712 | static char *texts[] = { | ||
713 | "Mic In", "Line In", "Line Out" | ||
714 | }; | ||
715 | |||
716 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
717 | uinfo->value.enumerated.items = 3; | ||
718 | uinfo->count = 1; | ||
719 | if (uinfo->value.enumerated.item >= 3) | ||
720 | uinfo->value.enumerated.item = 2; | ||
721 | strcpy(uinfo->value.enumerated.name, | ||
722 | texts[uinfo->value.enumerated.item]); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
637 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 727 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
638 | { | 728 | { |
639 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 729 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -995,6 +1085,17 @@ static struct hda_verb stac9205_core_init[] = { | |||
995 | .private_value = verb_read | (verb_write << 16), \ | 1085 | .private_value = verb_read | (verb_write << 16), \ |
996 | } | 1086 | } |
997 | 1087 | ||
1088 | #define DC_BIAS(xname, idx, nid) \ | ||
1089 | { \ | ||
1090 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1091 | .name = xname, \ | ||
1092 | .index = idx, \ | ||
1093 | .info = stac92xx_dc_bias_info, \ | ||
1094 | .get = stac92xx_dc_bias_get, \ | ||
1095 | .put = stac92xx_dc_bias_put, \ | ||
1096 | .private_value = nid, \ | ||
1097 | } | ||
1098 | |||
998 | static struct snd_kcontrol_new stac9200_mixer[] = { | 1099 | static struct snd_kcontrol_new stac9200_mixer[] = { |
999 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | 1100 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
1000 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | 1101 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
@@ -2702,7 +2803,8 @@ enum { | |||
2702 | STAC_CTL_WIDGET_AMP_VOL, | 2803 | STAC_CTL_WIDGET_AMP_VOL, |
2703 | STAC_CTL_WIDGET_HP_SWITCH, | 2804 | STAC_CTL_WIDGET_HP_SWITCH, |
2704 | STAC_CTL_WIDGET_IO_SWITCH, | 2805 | STAC_CTL_WIDGET_IO_SWITCH, |
2705 | STAC_CTL_WIDGET_CLFE_SWITCH | 2806 | STAC_CTL_WIDGET_CLFE_SWITCH, |
2807 | STAC_CTL_WIDGET_DC_BIAS | ||
2706 | }; | 2808 | }; |
2707 | 2809 | ||
2708 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 2810 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
@@ -2714,6 +2816,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { | |||
2714 | STAC_CODEC_HP_SWITCH(NULL), | 2816 | STAC_CODEC_HP_SWITCH(NULL), |
2715 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2817 | STAC_CODEC_IO_SWITCH(NULL, 0), |
2716 | STAC_CODEC_CLFE_SWITCH(NULL, 0), | 2818 | STAC_CODEC_CLFE_SWITCH(NULL, 0), |
2819 | DC_BIAS(NULL, 0, 0), | ||
2717 | }; | 2820 | }; |
2718 | 2821 | ||
2719 | /* add dynamic controls */ | 2822 | /* add dynamic controls */ |
@@ -3165,9 +3268,9 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
3165 | } | 3268 | } |
3166 | 3269 | ||
3167 | if (spec->mic_switch) { | 3270 | if (spec->mic_switch) { |
3168 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, | 3271 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, |
3169 | "Mic as Output Switch", | 3272 | "Mic Jack Mode", |
3170 | (spec->mic_switch << 8) | 1); | 3273 | spec->mic_switch); |
3171 | if (err < 0) | 3274 | if (err < 0) |
3172 | return err; | 3275 | return err; |
3173 | } | 3276 | } |