aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-08-31 10:46:56 -0400
committerTakashi Iwai <tiwai@suse.de>2012-08-31 10:50:28 -0400
commit08fa20ae20eb378225e5519db4e07f663ce405fa (patch)
tree55dc3c093360f12df2956017800fc802698facc9 /sound/pci/hda/hda_codec.c
parent5a798394c85f3bca963505d3be49180416fce132 (diff)
ALSA: hda - Yet another fix for D3 stop-clock refcounting
The call of pm_notify callback in snd_hda_codec_free() should be with the check of the current state whether pm_notify(false) is called or not, instead of codec->power_on check. For improving the code readability and fixing this inconsistency, codec->d3_stop_clk_ok is renamed to codec->pm_down_notified, and this flag is set only when runtime PM down is called. The new name reflects to a more direct purpose of the flag. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8a72f7b30a33..8e7dbb0921e6 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1206,7 +1206,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
1206 if (codec->patch_ops.free) 1206 if (codec->patch_ops.free)
1207 codec->patch_ops.free(codec); 1207 codec->patch_ops.free(codec);
1208#ifdef CONFIG_PM 1208#ifdef CONFIG_PM
1209 if (codec->power_on) 1209 if (!codec->pm_down_notified) /* cancel leftover refcounts */
1210 hda_call_pm_notify(codec->bus, false); 1210 hda_call_pm_notify(codec->bus, false);
1211#endif 1211#endif
1212 module_put(codec->owner); 1212 module_put(codec->owner);
@@ -1222,7 +1222,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
1222static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, 1222static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
1223 hda_nid_t fg, unsigned int power_state); 1223 hda_nid_t fg, unsigned int power_state);
1224 1224
1225static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 1225static unsigned int hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
1226 unsigned int power_state); 1226 unsigned int power_state);
1227 1227
1228/** 1228/**
@@ -3564,18 +3564,14 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
3564} 3564}
3565 3565
3566/* 3566/*
3567 * set power state of the codec 3567 * set power state of the codec, and return the power state
3568 */ 3568 */
3569static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 3569static unsigned int hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
3570 unsigned int power_state) 3570 unsigned int power_state)
3571{ 3571{
3572 int count; 3572 int count;
3573 unsigned int state; 3573 unsigned int state;
3574 3574
3575#ifdef CONFIG_PM
3576 codec->d3_stop_clk_ok = 0;
3577#endif
3578
3579 /* this delay seems necessary to avoid click noise at power-down */ 3575 /* this delay seems necessary to avoid click noise at power-down */
3580 if (power_state == AC_PWRST_D3) { 3576 if (power_state == AC_PWRST_D3) {
3581 /* transition time less than 10ms for power down */ 3577 /* transition time less than 10ms for power down */
@@ -3599,11 +3595,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
3599 break; 3595 break;
3600 } 3596 }
3601 3597
3602#ifdef CONFIG_PM 3598 return state;
3603 if (!codec->bus->power_keep_link_on && power_state == AC_PWRST_D3
3604 && codec->d3_stop_clk && (state & AC_PWRST_CLK_STOP_OK))
3605 codec->d3_stop_clk_ok = 1;
3606#endif
3607} 3599}
3608 3600
3609#ifdef CONFIG_SND_HDA_HWDEP 3601#ifdef CONFIG_SND_HDA_HWDEP
@@ -3620,13 +3612,16 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
3620#ifdef CONFIG_PM 3612#ifdef CONFIG_PM
3621/* 3613/*
3622 * call suspend and power-down; used both from PM and power-save 3614 * call suspend and power-down; used both from PM and power-save
3615 * this function returns the power state in the end
3623 */ 3616 */
3624static void hda_call_codec_suspend(struct hda_codec *codec) 3617static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
3625{ 3618{
3619 unsigned int state;
3620
3626 if (codec->patch_ops.suspend) 3621 if (codec->patch_ops.suspend)
3627 codec->patch_ops.suspend(codec); 3622 codec->patch_ops.suspend(codec);
3628 hda_cleanup_all_streams(codec); 3623 hda_cleanup_all_streams(codec);
3629 hda_set_power_state(codec, 3624 state = hda_set_power_state(codec,
3630 codec->afg ? codec->afg : codec->mfg, 3625 codec->afg ? codec->afg : codec->mfg,
3631 AC_PWRST_D3); 3626 AC_PWRST_D3);
3632 cancel_delayed_work(&codec->power_work); 3627 cancel_delayed_work(&codec->power_work);
@@ -3637,6 +3632,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
3637 codec->power_transition = 0; 3632 codec->power_transition = 0;
3638 codec->power_jiffies = jiffies; 3633 codec->power_jiffies = jiffies;
3639 spin_unlock(&codec->power_lock); 3634 spin_unlock(&codec->power_lock);
3635 return state;
3640} 3636}
3641 3637
3642/* 3638/*
@@ -4438,6 +4434,7 @@ static void hda_power_work(struct work_struct *work)
4438 struct hda_codec *codec = 4434 struct hda_codec *codec =
4439 container_of(work, struct hda_codec, power_work.work); 4435 container_of(work, struct hda_codec, power_work.work);
4440 struct hda_bus *bus = codec->bus; 4436 struct hda_bus *bus = codec->bus;
4437 unsigned int state;
4441 4438
4442 spin_lock(&codec->power_lock); 4439 spin_lock(&codec->power_lock);
4443 if (codec->power_transition > 0) { /* during power-up sequence? */ 4440 if (codec->power_transition > 0) { /* during power-up sequence? */
@@ -4451,9 +4448,12 @@ static void hda_power_work(struct work_struct *work)
4451 } 4448 }
4452 spin_unlock(&codec->power_lock); 4449 spin_unlock(&codec->power_lock);
4453 4450
4454 hda_call_codec_suspend(codec); 4451 state = hda_call_codec_suspend(codec);
4455 if (codec->d3_stop_clk_ok) 4452 codec->pm_down_notified = 0;
4453 if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
4454 codec->pm_down_notified = 1;
4456 hda_call_pm_notify(bus, false); 4455 hda_call_pm_notify(bus, false);
4456 }
4457} 4457}
4458 4458
4459static void hda_keep_power_on(struct hda_codec *codec) 4459static void hda_keep_power_on(struct hda_codec *codec)
@@ -4510,8 +4510,11 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
4510 codec->power_transition = 1; /* avoid reentrance */ 4510 codec->power_transition = 1; /* avoid reentrance */
4511 spin_unlock(&codec->power_lock); 4511 spin_unlock(&codec->power_lock);
4512 4512
4513 if (codec->d3_stop_clk_ok) /* flag set at suspend */ 4513 if (codec->pm_down_notified) {
4514 codec->pm_down_notified = 0;
4514 hda_call_pm_notify(bus, true); 4515 hda_call_pm_notify(bus, true);
4516 }
4517
4515 hda_call_codec_resume(codec); 4518 hda_call_codec_resume(codec);
4516 4519
4517 spin_lock(&codec->power_lock); 4520 spin_lock(&codec->power_lock);