Commit 2fc998907947f92b1b9113faad531d7f5a857987

Authored by Nickolas Lloyd
Committed by Takashi Iwai
1 parent 7442f9dadb

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 }