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@embeddedalley.com
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)