[alsa-devel] [PATCH] ALSA: hda - Handle open while transitioning to D3.
Takashi Iwai
tiwai at suse.de
Mon Jun 18 09:43:52 CEST 2012
At Fri, 15 Jun 2012 19:36:23 -0700,
Dylan Reid wrote:
>
> This addresses an issue encountered when a pcm is opened while
> transitioning to low power state (codec->power_on == 1 &&
> codec->power_transition == -1). Add snd_pcm_power_up_d3wait to
> hda_codec. This function is used to power up from azx_open as opposed
> to snd_hda_power_up used from codec_exec_verb. When powering up from
> azx_open, wait for pending power downs to complete, avoiding the power
> up continuing in parallel with the power down on the work queue.
>
> The specific issue seen was with the CS4210 codec, it powers off the ADC
> and DAC nid in its suspend handler. If it is re-opened before the
> ~100ms power down process completes, the ADC and DAC nid are initialized
> while powered down and audio is lost until another suspend/resume cycle.
>
> Signed-off-by: Dylan Reid <dgreid at chromium.org>
Thanks. Applied.
Takashi
> ---
> sound/pci/hda/hda_codec.c | 46 ++++++++++++++++++++++++++++++++++++--------
> sound/pci/hda/hda_codec.h | 2 +
> sound/pci/hda/hda_intel.c | 2 +-
> 3 files changed, 40 insertions(+), 10 deletions(-)
>
> diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
> index 851e6ec..604699c 100644
> --- a/sound/pci/hda/hda_codec.c
> +++ b/sound/pci/hda/hda_codec.c
> @@ -4423,20 +4423,19 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
> codec->power_jiffies += delta;
> }
>
> -/**
> - * snd_hda_power_up - Power-up the codec
> - * @codec: HD-audio codec
> - *
> - * Increment the power-up counter and power up the hardware really when
> - * not turned on yet.
> - */
> -void snd_hda_power_up(struct hda_codec *codec)
> +/* Transition to powered up, if wait_power_down then wait for a pending
> + * transition to D3 to complete. A pending D3 transition is indicated
> + * with power_transition == -1. */
> +static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
> {
> struct hda_bus *bus = codec->bus;
>
> spin_lock(&codec->power_lock);
> codec->power_count++;
> - if (codec->power_on || codec->power_transition > 0) {
> + /* Return if power_on or transitioning to power_on, unless currently
> + * powering down. */
> + if ((codec->power_on || codec->power_transition > 0) &&
> + !(wait_power_down && codec->power_transition < 0)) {
> spin_unlock(&codec->power_lock);
> return;
> }
> @@ -4460,8 +4459,37 @@ void snd_hda_power_up(struct hda_codec *codec)
> codec->power_transition = 0;
> spin_unlock(&codec->power_lock);
> }
> +
> +/**
> + * snd_hda_power_up - Power-up the codec
> + * @codec: HD-audio codec
> + *
> + * Increment the power-up counter and power up the hardware really when
> + * not turned on yet.
> + */
> +void snd_hda_power_up(struct hda_codec *codec)
> +{
> + __snd_hda_power_up(codec, false);
> +}
> EXPORT_SYMBOL_HDA(snd_hda_power_up);
>
> +/**
> + * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
> + * D3 transition to complete. This differs from snd_hda_power_up() when
> + * power_transition == -1. snd_hda_power_up sees this case as a nop,
> + * snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
> + * back up.
> + * @codec: HD-audio codec
> + *
> + * Cancel any power down operation hapenning on the work queue, then power up.
> + */
> +void snd_hda_power_up_d3wait(struct hda_codec *codec)
> +{
> + /* This will cancel and wait for pending power_work to complete. */
> + __snd_hda_power_up(codec, true);
> +}
> +EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait);
> +
> #define power_save(codec) \
> ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
>
> diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
> index 71864cdd..a4ac1de 100644
> --- a/sound/pci/hda/hda_codec.h
> +++ b/sound/pci/hda/hda_codec.h
> @@ -1059,10 +1059,12 @@ const char *snd_hda_get_jack_location(u32 cfg);
> */
> #ifdef CONFIG_SND_HDA_POWER_SAVE
> void snd_hda_power_up(struct hda_codec *codec);
> +void snd_hda_power_up_d3wait(struct hda_codec *codec);
> void snd_hda_power_down(struct hda_codec *codec);
> void snd_hda_update_power_acct(struct hda_codec *codec);
> #else
> static inline void snd_hda_power_up(struct hda_codec *codec) {}
> +static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {}
> static inline void snd_hda_power_down(struct hda_codec *codec) {}
> #endif
>
> diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
> index 8f85d30..86758dd 100644
> --- a/sound/pci/hda/hda_intel.c
> +++ b/sound/pci/hda/hda_intel.c
> @@ -1767,7 +1767,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
> buff_step);
> snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
> buff_step);
> - snd_hda_power_up(apcm->codec);
> + snd_hda_power_up_d3wait(apcm->codec);
> err = hinfo->ops.open(hinfo, apcm->codec, substream);
> if (err < 0) {
> azx_release_device(azx_dev);
> --
> 1.7.9.rc0
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
More information about the Alsa-devel
mailing list