[alsa-devel] [PATCH] hda_codec: Added power management for ADC/DAC's

Takashi Iwai tiwai at suse.de
Sat Jan 19 10:49:20 CET 2008


At Fri, 18 Jan 2008 17:15:52 -0500,
Matthew Ranostay wrote:
> 
> Added power management support to muted DACs and ADCs. They are set into D3 state when both channels are muted, and D0 when unmuted. We specify the ADC in the HDA_CODEC_MUTE_IDX instead of the ADC mux, so that we can easily know which node to power manage, and we use the connection list to get the needed mux node.
> 
> Signed-off-by: Matthew Ranostay <mranostay at embeddedalley.com>

Hmm, I'm afraid this could break the codes for other codecs.
IIRC, some codecs use the audio-input widget itself as the input mux.

Besides, I'd like to keep this power-saving feature as an option,
preferably dynamically activated.  In that way, we can check easily
whether any problem lies on the power-saving feature or not.

I feel it can be better put after the merge window of 2.6.25, in order
to avoid a bug report flood :)  But, let's keep discussing.


Thanks,

Takashi

> ---
> diff -r 1cb5fe1b2443 pci/hda/hda_codec.c
> --- a/pci/hda/hda_codec.c	Thu Jan 17 17:44:49 2008 +0100
> +++ b/pci/hda/hda_codec.c	Fri Jan 18 11:16:36 2008 -0500
> @@ -1091,11 +1091,19 @@ int snd_hda_mixer_amp_switch_get(struct 
>  {
>  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
>  	hda_nid_t nid = get_amp_nid(kcontrol);
> +	hda_nid_t conn_list[1];
>  	int chs = get_amp_channels(kcontrol);
>  	int dir = get_amp_direction(kcontrol);
>  	int idx = get_amp_index(kcontrol);
> +	int wcaps = get_wcaps(codec, nid);
> +	int wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
>  	long *valp = ucontrol->value.integer.value;
>  
> +	/* if pin is a adc get the mux connection */
> +	if (wtype == AC_WID_AUD_IN) {
> +		snd_hda_get_connections(codec, nid, conn_list, 1);
> +		nid = conn_list[0];
> +	}
>  	if (chs & 1)
>  		*valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) &
>  			   HDA_AMP_MUTE) ? 0 : 1;
> @@ -1109,24 +1117,52 @@ int snd_hda_mixer_amp_switch_put(struct 
>  				 struct snd_ctl_elem_value *ucontrol)
>  {
>  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
> +	hda_nid_t ctl_nid = get_amp_nid(kcontrol);
>  	hda_nid_t nid = get_amp_nid(kcontrol);
> +	hda_nid_t conn_list[1];
>  	int chs = get_amp_channels(kcontrol);
>  	int dir = get_amp_direction(kcontrol);
>  	int idx = get_amp_index(kcontrol);
> +	int wcaps = get_wcaps(codec, nid);
> +	int wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
>  	long *valp = ucontrol->value.integer.value;
> -	int change = 0;
> +	int change = 0, val = 0;
>  
>  	snd_hda_power_up(codec);
> +	/* if pin is a adc get the mux connection */
> +	if (wtype == AC_WID_AUD_IN) {
> +		snd_hda_get_connections(codec, nid, conn_list, 1);
> +		nid = conn_list[0];
> +	}
>  	if (chs & 1) {
>  		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
>  						  HDA_AMP_MUTE,
>  						  *valp ? 0 : HDA_AMP_MUTE);
> +		val = !*valp;
>  		valp++;
>  	}
> -	if (chs & 2)
> +	if (chs & 2) {
>  		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
>  						   HDA_AMP_MUTE,
>  						   *valp ? 0 : HDA_AMP_MUTE);
> +		val &= !*valp;
> +	}
> +
> +	/* check for power management support */
> +	if ((wcaps & AC_WCAP_POWER) && (wcaps != AC_WID_AUD_MIX)) {
> +		if ((chs != 3) && (wcaps & AC_WCAP_STEREO)) {
> +			struct hda_amp_info *info;
> +			info = get_alloc_amp_hash(codec,
> +						HDA_HASH_KEY(nid, dir, idx));
> +			/* get the other channel value */
> +			val &= !(get_vol_mute(codec, info, nid,
> +					~chs & 3, dir, idx) & HDA_AMP_MUTE);
> +		}
> +		/* power down adc/dac if both channels are muted */
> +		snd_hda_codec_write(codec, ctl_nid, 0, AC_VERB_SET_POWER_STATE,
> +							val ? AC_PWRST_D3 : 0);
> +	}
> +
>  #ifdef CONFIG_SND_HDA_POWER_SAVE
>  	if (codec->patch_ops.check_power_status)
>  		codec->patch_ops.check_power_status(codec, nid);
> diff -r 1cb5fe1b2443 pci/hda/patch_sigmatel.c
> --- a/pci/hda/patch_sigmatel.c	Thu Jan 17 17:44:49 2008 +0100
> +++ b/pci/hda/patch_sigmatel.c	Thu Jan 17 20:17:50 2008 -0500
> @@ -638,10 +638,10 @@ static struct snd_kcontrol_new stac92hd7
>  	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
>  
>  	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
> -	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1a, 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),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1b, 0x0, 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),
> @@ -664,10 +664,10 @@ static struct snd_kcontrol_new stac92hd7
>  	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
>  
>  	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
> -	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1a, 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),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1b, 0x0, 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),
> @@ -690,10 +690,10 @@ static struct snd_kcontrol_new stac92hd7
>  	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
>  
>  	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
> -	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1a, 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),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1b, 0x0, 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),
> @@ -716,11 +716,11 @@ static struct snd_kcontrol_new stac92hd7
>  	STAC_INPUT_SOURCE(2),
>  
>  	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
> -	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x12, 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_MUTE_IDX("Capture Switch", 0x1, 0x13, 0x0, HDA_OUTPUT),
>  	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
>  
>  	HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
> @@ -735,11 +735,11 @@ static struct snd_kcontrol_new stac92hd7
>  	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
>  
>  	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
> -	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
> +	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x12, 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_MUTE_IDX("Capture Switch", 0x1, 0x13, 0x0, HDA_OUTPUT),
>  	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
>  
>  	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x14, 0x1, 0, HDA_INPUT),
> 


More information about the Alsa-devel mailing list