Commit 2fc998907947f92b1b9113faad531d7f5a857987
Committed by
Takashi Iwai
1 parent
7442f9dadb
Exists in
master
and in
20 other branches
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>
Showing 1 changed file with 107 additions and 4 deletions Side-by-side Diff
sound/pci/hda/patch_sigmatel.c
... | ... | @@ -634,6 +634,96 @@ |
634 | 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 | 727 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
638 | 728 | { |
639 | 729 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
... | ... | @@ -995,6 +1085,17 @@ |
995 | 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 | 1099 | static struct snd_kcontrol_new stac9200_mixer[] = { |
999 | 1100 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
1000 | 1101 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
... | ... | @@ -2702,7 +2803,8 @@ |
2702 | 2803 | STAC_CTL_WIDGET_AMP_VOL, |
2703 | 2804 | STAC_CTL_WIDGET_HP_SWITCH, |
2704 | 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 | 2810 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
... | ... | @@ -2714,6 +2816,7 @@ |
2714 | 2816 | STAC_CODEC_HP_SWITCH(NULL), |
2715 | 2817 | STAC_CODEC_IO_SWITCH(NULL, 0), |
2716 | 2818 | STAC_CODEC_CLFE_SWITCH(NULL, 0), |
2819 | + DC_BIAS(NULL, 0, 0), | |
2717 | 2820 | }; |
2718 | 2821 | |
2719 | 2822 | /* add dynamic controls */ |
... | ... | @@ -3165,9 +3268,9 @@ |
3165 | 3268 | } |
3166 | 3269 | |
3167 | 3270 | if (spec->mic_switch) { |
3168 | - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, | |
3169 | - "Mic as Output Switch", | |
3170 | - (spec->mic_switch << 8) | 1); | |
3271 | + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, | |
3272 | + "Mic Jack Mode", | |
3273 | + spec->mic_switch); | |
3171 | 3274 | if (err < 0) |
3172 | 3275 | return err; |
3173 | 3276 | } |