| From b5a236c175b0d984552a5f7c9d35141024c2b261 Mon Sep 17 00:00:00 2001 |
| From: Hui Wang <hui.wang@canonical.com> |
| Date: Tue, 19 Mar 2019 09:28:44 +0800 |
| Subject: ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec |
| |
| From: Hui Wang <hui.wang@canonical.com> |
| |
| commit b5a236c175b0d984552a5f7c9d35141024c2b261 upstream. |
| |
| Recently we found the audio jack detection stop working after suspend |
| on many machines with Realtek codec. Sometimes the audio selection |
| dialogue didn't show up after users plugged headhphone/headset into |
| the headset jack, sometimes after uses plugged headphone/headset, then |
| click the sound icon on the upper-right corner of gnome-desktop, it |
| also showed the speaker rather than the headphone. |
| |
| The root cause is that before suspend, the codec already call the |
| runtime_suspend since this codec is not used by any apps, then in |
| resume, it will not call runtime_resume for this codec. But for some |
| realtek codec (so far, alc236, alc255 and alc891) with the specific |
| BIOS, if it doesn't run runtime_resume after suspend, all codec |
| functions including jack detection stop working anymore. |
| |
| This problem existed for a long time, but it was not exposed, that is |
| because when problem happens, if users play sound or open |
| sound-setting to check audio device, this will trigger calling to |
| runtime_resume (via snd_hda_power_up), then the codec starts working |
| again before users notice this problem. |
| |
| Since we don't know how many codec and BIOS combinations have this |
| problem, to fix it, let the driver call runtime_resume for all codecs |
| in pm_resume, maybe for some codecs, this is not needed, but it is |
| harmless. After a codec is runtime resumed, if it is not used by any |
| apps, it will be runtime suspended soon and furthermore we don't run |
| suspend frequently, this change will not add much power consumption. |
| |
| Fixes: cc72da7d4d06 ("ALSA: hda - Use standard runtime PM for codec power-save control") |
| Signed-off-by: Hui Wang <hui.wang@canonical.com> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/pci/hda/hda_codec.c | 20 +++++++++++++++++--- |
| 1 file changed, 17 insertions(+), 3 deletions(-) |
| |
| --- a/sound/pci/hda/hda_codec.c |
| +++ b/sound/pci/hda/hda_codec.c |
| @@ -3038,6 +3038,20 @@ static int hda_codec_runtime_resume(stru |
| #endif /* CONFIG_PM */ |
| |
| #ifdef CONFIG_PM_SLEEP |
| +static int hda_codec_force_resume(struct device *dev) |
| +{ |
| + int ret; |
| + |
| + /* The get/put pair below enforces the runtime resume even if the |
| + * device hasn't been used at suspend time. This trick is needed to |
| + * update the jack state change during the sleep. |
| + */ |
| + pm_runtime_get_noresume(dev); |
| + ret = pm_runtime_force_resume(dev); |
| + pm_runtime_put(dev); |
| + return ret; |
| +} |
| + |
| static int hda_codec_pm_suspend(struct device *dev) |
| { |
| dev->power.power_state = PMSG_SUSPEND; |
| @@ -3047,7 +3061,7 @@ static int hda_codec_pm_suspend(struct d |
| static int hda_codec_pm_resume(struct device *dev) |
| { |
| dev->power.power_state = PMSG_RESUME; |
| - return pm_runtime_force_resume(dev); |
| + return hda_codec_force_resume(dev); |
| } |
| |
| static int hda_codec_pm_freeze(struct device *dev) |
| @@ -3059,13 +3073,13 @@ static int hda_codec_pm_freeze(struct de |
| static int hda_codec_pm_thaw(struct device *dev) |
| { |
| dev->power.power_state = PMSG_THAW; |
| - return pm_runtime_force_resume(dev); |
| + return hda_codec_force_resume(dev); |
| } |
| |
| static int hda_codec_pm_restore(struct device *dev) |
| { |
| dev->power.power_state = PMSG_RESTORE; |
| - return pm_runtime_force_resume(dev); |
| + return hda_codec_force_resume(dev); |
| } |
| #endif /* CONFIG_PM_SLEEP */ |
| |