Added support for advanced power management features in new IDT codecs.
Inactive ADCs and DACs are changed to D3 mode when not in playback or
capture, also inactive line-out/headphone ports are disabled when jack
detect does not sense a connection.
---
Signed-off-by: Matthew Ranostay <mranostay@xxxxxxxxxxxxxxxxx>
diff -r 5b03c0176aa5 pci/hda/patch_sigmatel.c
--- a/pci/hda/patch_sigmatel.c Mon Jan 07 13:33:45 2008 +0100
+++ b/pci/hda/patch_sigmatel.c Mon Jan 07 11:22:56 2008 -0500
@@ -160,6 +160,7 @@ struct sigmatel_spec {
/* i/o switches */
unsigned int io_switch[2];
+ unsigned int io_state[2];
unsigned int clfe_swap;
unsigned int aloopback;
@@ -438,6 +439,52 @@ static int stac92xx_aloopback_put(struct
kcontrol->private_value >> 16, dac_mode);
return 1;
+}
+
+static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+ int i;
+
+ for (i = 0; i < spec->multiout.num_dacs; i++) {
+ if (spec->multiout.dac_nids[i] == nid)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int stac92xx_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ int idx = (kcontrol->private_value >> 19) & 0xf;
+ int chs = (kcontrol->private_value >> 16) & 0x3;
+ long *valp = ucontrol->value.integer.value;
+ unsigned int wid_caps, val, change;
+
+ change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ if (!is_in_dac_nids(spec, nid))
+ nid = spec->adc_nids[idx];
+
+ val = *valp++;
+ wid_caps = get_wcaps(codec, nid);
+ if (wid_caps & AC_WCAP_POWER) {
+ if (chs == 3)
+ val |= *valp;
+ else { /* Center/LFE mixers workaround */
+ spec->io_state[--chs] = val;
+ val |= spec->io_state[chs ? 0 : 1];
+ }
+
+ /* set to power state D3 mode if DAC/ADC isn't being used */
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+ val ? 0: AC_PWRST_D3);
+ }
+#endif
+ return change;
}
static struct hda_verb stac9200_core_init[] = {
@@ -622,6 +669,20 @@ static struct hda_verb stac9205_core_ini
.private_value = verb_read | (verb_write << 16), \
}
+#define STAC_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xcidx, \
+ .info = snd_hda_mixer_amp_switch_info, \
+ .get = snd_hda_mixer_amp_switch_get, \
+ .put = stac92xx_mixer_amp_switch_put, \
+ .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, xindex, direction), \
+ }
+
+#define STAC_CODEC_MUTE(xname, nid, xindex, direction) \
+ STAC_CODEC_MUTE_IDX(xname, 0, nid, xindex, direction)
+
static struct snd_kcontrol_new stac9200_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
@@ -640,10 +701,10 @@ static struct snd_kcontrol_new stac92hd7
HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x14, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x1, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x1, HDA_OUTPUT),
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
@@ -670,10 +731,10 @@ static struct snd_kcontrol_new stac92hd7
HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x14, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x1, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x1, HDA_OUTPUT),
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
@@ -700,10 +761,10 @@ static struct snd_kcontrol_new stac92hd7
HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x14, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x1, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x1, HDA_OUTPUT),
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
@@ -730,12 +791,12 @@ static struct snd_kcontrol_new stac92hd7
HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x19, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x1, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x1, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x1, HDA_OUTPUT),
HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
@@ -751,12 +812,12 @@ static struct snd_kcontrol_new stac92hd7
HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x19, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x1, HDA_OUTPUT),
+ STAC_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x1, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x1, HDA_OUTPUT),
{ } /* end */
};
@@ -857,7 +918,7 @@ static int stac92xx_build_controls(struc
if (err < 0)
return err;
}
- return 0;
+ return 0;
}
static unsigned int ref9200_pin_configs[8] = {
@@ -1962,7 +2023,7 @@ enum {
static struct snd_kcontrol_new stac92xx_control_templates[] = {
HDA_CODEC_VOLUME(NULL, 0, 0, 0),
- HDA_CODEC_MUTE(NULL, 0, 0, 0),
+ STAC_CODEC_MUTE(NULL, 0, 0, 0),
STAC_CODEC_IO_SWITCH(NULL, 0),
STAC_CODEC_CLFE_SWITCH(NULL, 0),
};
@@ -2059,19 +2120,6 @@ static int stac92xx_add_dyn_out_pins(str
return 0;
}
-
-static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
-{
- int i;
-
- for (i = 0; i < spec->multiout.num_dacs; i++) {
- if (spec->multiout.dac_nids[i] == nid)
- return 1;
- }
-
- return 0;
-}
-
/*
* Fill in the dac_nids table from the parsed pin configuration
* This function only works when every pin in line_out_pins[]
@@ -2806,6 +2854,7 @@ static void stac92xx_hp_detect(struct hd
struct sigmatel_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i, presence;
+ unsigned char pwr_state = 0;
presence = 0;
for (i = 0; i < cfg->hp_outs; i++) {
@@ -2816,12 +2865,16 @@ static void stac92xx_hp_detect(struct hd
if (presence) {
/* disable lineouts, enable hp */
- for (i = 0; i < cfg->line_outs; i++)
+ for (i = 0; i < cfg->line_outs; i++) {
stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
AC_PINCTL_OUT_EN);
- for (i = 0; i < cfg->speaker_outs; i++)
+ pwr_state |= 1 << (cfg->line_out_pins[i] - 0xa);
+ }
+ for (i = 0; i < cfg->speaker_outs; i++) {
stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
AC_PINCTL_OUT_EN);
+ pwr_state |= 1 << (cfg->speaker_pins[i] - 0xa);
+ }
} else {
/* enable lineouts, disable hp */
for (i = 0; i < cfg->line_outs; i++)
@@ -2830,7 +2883,12 @@ static void stac92xx_hp_detect(struct hd
for (i = 0; i < cfg->speaker_outs; i++)
stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
AC_PINCTL_OUT_EN);
- }
+ for (i = 0; i < cfg->hp_outs; i++)
+ pwr_state |= 1 << (cfg->hp_pins[i] - 0xa);
+ }
+
+ /* power down unused ports */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, pwr_state);
}
static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel