[alsa-devel] [PATCH] hda: Advanced power management for codecs.

Takashi Iwai tiwai at suse.de
Mon Jan 7 18:10:38 CET 2008


At Mon, 07 Jan 2008 11:44:08 -0500,
Matthew Ranostay wrote:
> 
> [1  <text/plain; ISO-8859-1 (7bit)>]
> 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.

Thanks.  This is an interesting patch.

> ---
> Signed-off-by: Matthew Ranostay <mranostay at embeddedalley.com>
> [2 stac92hd7xxx_power_save.patch <text/plain (7bit)>]
> 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;

This stuff should go rather to snd_hda_mixer_amp_switch_put().  It's
not specific to STAC codecs.

The #ifdef doesn't suffice, BTW.  The power-saving is a dynamic switch
(via module parameter and/or sysfs), so you need to check whether
power-saving mode is active nor not.  Also, these calls should be
within the snd_hda_power_up/down() block.


> @@ -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);

Is this verb available on every STAC codec?  I took a look at some
specs but they don't show this verb at all.


Takashi


More information about the Alsa-devel mailing list