diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ad0101e2d4ffea059b68723d4cc8d4d977318aa7..5e0bdea6c5c8b99a361c3adb92cc7451c181bf50 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4411,20 +4411,16 @@ void snd_hda_update_power_acct(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. */ +/* call this with codec->power_lock held! */ 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++; - trace_hda_power_count(codec); /* 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); + !(wait_power_down && codec->power_transition < 0)) return; - } spin_unlock(&codec->power_lock); cancel_delayed_work_sync(&codec->power_work); @@ -4433,10 +4429,9 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) /* If the power down delayed work was cancelled above before starting, * then there is no need to go through power up here. */ - if (codec->power_on) { - spin_unlock(&codec->power_lock); + if (codec->power_on) return; - } + trace_hda_power_up(codec); snd_hda_update_power_acct(codec); codec->power_on = 1; @@ -4450,66 +4445,45 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) spin_lock(&codec->power_lock); 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); +#define power_save(codec) \ + ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) -/** - * 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) +/* Transition to powered down */ +static void __snd_hda_power_down(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); + if (!codec->power_on || codec->power_count || codec->power_transition) + return; -#define power_save(codec) \ - ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) + if (power_save(codec)) { + codec->power_transition = -1; /* avoid reentrance */ + queue_delayed_work(codec->bus->workq, &codec->power_work, + msecs_to_jiffies(power_save(codec) * 1000)); + } +} /** - * snd_hda_power_down - Power-down the codec + * snd_hda_power_save - Power-up/down/sync the codec * @codec: HD-audio codec + * @delta: the counter delta to change * - * Decrement the power-up counter and schedules the power-off work if - * the counter rearches to zero. + * Change the power-up counter via @delta, and power up or down the hardware + * appropriately. For the power-down, queue to the delayed action. + * Passing zero to @delta means to synchronize the power state. */ -void snd_hda_power_down(struct hda_codec *codec) +void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) { spin_lock(&codec->power_lock); - --codec->power_count; + codec->power_count += delta; trace_hda_power_count(codec); - if (!codec->power_on || codec->power_count || codec->power_transition) { - spin_unlock(&codec->power_lock); - return; - } - if (power_save(codec)) { - codec->power_transition = -1; /* avoid reentrance */ - queue_delayed_work(codec->bus->workq, &codec->power_work, - msecs_to_jiffies(power_save(codec) * 1000)); - } + if (delta > 0) + __snd_hda_power_up(codec, d3wait); + else + __snd_hda_power_down(codec); spin_unlock(&codec->power_lock); } -EXPORT_SYMBOL_HDA(snd_hda_power_down); +EXPORT_SYMBOL_HDA(snd_hda_power_save); /** * snd_hda_check_amp_list_power - Check the amp list and update the power diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index d772c2521cd9014268a3d2a067c688058b860f1a..1d4dfce631a0f1900d17132db2d7e0f19d32f985 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -1062,16 +1062,64 @@ const char *snd_hda_get_jack_location(u32 cfg); * power saving */ #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_power_save(struct hda_codec *codec, int delta, bool d3wait); 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) {} +static inline void snd_hda_power_save(struct hda_codec *codec, int delta, + bool d3wait) {} #endif +/** + * 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. + */ +static inline void snd_hda_power_up(struct hda_codec *codec) +{ + snd_hda_power_save(codec, 1, false); +} + +/** + * 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. + */ +static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) +{ + snd_hda_power_save(codec, 1, true); +} + +/** + * snd_hda_power_down - Power-down the codec + * @codec: HD-audio codec + * + * Decrement the power-up counter and schedules the power-off work if + * the counter rearches to zero. + */ +static inline void snd_hda_power_down(struct hda_codec *codec) +{ + snd_hda_power_save(codec, -1, false); +} + +/** + * snd_hda_power_sync - Synchronize the power-save status + * @codec: HD-audio codec + * + * Synchronize the actual power state with the power account; + * called when power_save parameter is changed + */ +static inline void snd_hda_power_sync(struct hda_codec *codec) +{ + snd_hda_power_save(codec, 0, false); +} + #ifdef CONFIG_SND_HDA_PATCH_LOADER /* * patch firmware