summaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/patch_sigmatel.c219
1 files changed, 140 insertions, 79 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index a915f404f654..48f4a36c4813 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -670,62 +670,6 @@ static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
return vref;
}
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int new_vref;
- unsigned int error;
-
- if (ucontrol->value.enumerated.item[0] == 0)
- new_vref = AC_PINCTL_VREF_80;
- else if (ucontrol->value.enumerated.item[0] == 1)
- new_vref = AC_PINCTL_VREF_GRD;
- else
- new_vref = AC_PINCTL_VREF_HIZ;
-
- if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) {
- error = stac92xx_vref_set(codec,
- kcontrol->private_value, new_vref);
- return error;
- }
-
- return 0;
-}
-
-static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value);
- if (vref == AC_PINCTL_VREF_80)
- ucontrol->value.enumerated.item[0] = 0;
- else if (vref == AC_PINCTL_VREF_GRD)
- ucontrol->value.enumerated.item[0] = 1;
- else if (vref == AC_PINCTL_VREF_HIZ)
- ucontrol->value.enumerated.item[0] = 2;
-
- return 0;
-}
-
-static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- static char *texts[] = {
- "Mic In", "Line In", "Line Out"
- };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = 3;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= 3)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
-}
-
static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -2652,7 +2596,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
return 0;
}
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
+ hda_nid_t nid)
{
unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
@@ -2706,15 +2651,108 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
return 1;
}
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
+static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int i;
+ static char *texts[] = {
+ "Mic In", "Line In", "Line Out"
+ };
+
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t nid = kcontrol->private_value;
+
+ if (nid == spec->mic_switch || nid == spec->line_switch)
+ i = 3;
+ else
+ i = 2;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = i;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= i)
+ uinfo->value.enumerated.item = i-1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value;
+ unsigned int vref = stac92xx_vref_get(codec, nid);
+
+ if (vref == stac92xx_get_default_vref(codec, nid))
+ ucontrol->value.enumerated.item[0] = 0;
+ else if (vref == AC_PINCTL_VREF_GRD)
+ ucontrol->value.enumerated.item[0] = 1;
+ else if (vref == AC_PINCTL_VREF_HIZ)
+ ucontrol->value.enumerated.item[0] = 2;
+
+ return 0;
+}
+
+static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int new_vref = 0;
+ unsigned int error;
+ hda_nid_t nid = kcontrol->private_value;
+
+ if (ucontrol->value.enumerated.item[0] == 0)
+ new_vref = stac92xx_get_default_vref(codec, nid);
+ else if (ucontrol->value.enumerated.item[0] == 1)
+ new_vref = AC_PINCTL_VREF_GRD;
+ else if (ucontrol->value.enumerated.item[0] == 2)
+ new_vref = AC_PINCTL_VREF_HIZ;
+ else
+ return 0;
+
+ if (new_vref != stac92xx_vref_get(codec, nid)) {
+ error = stac92xx_vref_set(codec, nid, new_vref);
+ return error;
+ }
+
+ return 0;
+}
+
+static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[2];
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (kcontrol->private_value == spec->line_switch)
+ texts[0] = "Line In";
+ else
+ texts[0] = "Mic In";
+ texts[1] = "Line Out";
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = 2;
+ uinfo->count = 1;
+
+ if (uinfo->value.enumerated.item >= 2)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- int io_idx = kcontrol-> private_value & 0xff;
+ hda_nid_t nid = kcontrol->private_value;
+ int io_idx = (nid == spec->mic_switch) ? 1 : 0;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
+ ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
return 0;
}
@@ -2722,9 +2760,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = kcontrol->private_value >> 8;
- int io_idx = kcontrol-> private_value & 0xff;
- unsigned short val = !!ucontrol->value.integer.value[0];
+ hda_nid_t nid = kcontrol->private_value;
+ int io_idx = (nid == spec->mic_switch) ? 1 : 0;
+ unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -2733,7 +2771,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
else {
unsigned int pinctl = AC_PINCTL_IN_EN;
if (io_idx) /* set VREF for mic */
- pinctl |= stac92xx_get_vref(codec, nid);
+ pinctl |= stac92xx_get_default_vref(codec, nid);
stac92xx_auto_set_pinctl(codec, nid, pinctl);
}
@@ -2891,6 +2929,34 @@ static struct snd_kcontrol_new stac_input_src_temp = {
.put = stac92xx_mux_enum_put,
};
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
+ hda_nid_t nid, int idx)
+{
+ int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ int control = 0;
+ struct sigmatel_spec *spec = codec->spec;
+ char name[22];
+
+ if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+ if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+ && nid == spec->line_switch)
+ control = STAC_CTL_WIDGET_IO_SWITCH;
+ else if (snd_hda_query_pin_caps(codec, nid)
+ & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
+ control = STAC_CTL_WIDGET_DC_BIAS;
+ else if (nid == spec->mic_switch)
+ control = STAC_CTL_WIDGET_IO_SWITCH;
+ }
+
+ if (control) {
+ strcpy(name, auto_pin_cfg_labels[idx]);
+ return stac92xx_add_control(codec->spec, control,
+ strcat(name, " Jack Mode"), nid);
+ }
+
+ return 0;
+}
+
static int stac92xx_add_input_source(struct sigmatel_spec *spec)
{
struct snd_kcontrol_new *knew;
@@ -3253,7 +3319,9 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t nid;
int err;
+ int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
spec->multiout.dac_nids,
@@ -3270,20 +3338,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
return err;
}
- if (spec->line_switch) {
- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
- "Line In as Output Switch",
- spec->line_switch << 8);
- if (err < 0)
- return err;
- }
-
- if (spec->mic_switch) {
- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS,
- "Mic Jack Mode",
- spec->mic_switch);
- if (err < 0)
- return err;
+ for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
+ nid = cfg->input_pins[idx];
+ if (nid) {
+ err = stac92xx_add_jack_mode_control(codec, nid, idx);
+ if (err < 0)
+ return err;
+ }
}
return 0;
@@ -4193,7 +4254,7 @@ static int stac92xx_init(struct hda_codec *codec)
unsigned int pinctl, conf;
if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
/* for mic pins, force to initialize */
- pinctl = stac92xx_get_vref(codec, nid);
+ pinctl = stac92xx_get_default_vref(codec, nid);
pinctl |= AC_PINCTL_IN_EN;
stac92xx_auto_set_pinctl(codec, nid, pinctl);
} else {