26
26
#include <linux/mutex.h>
27
27
#include <linux/module.h>
28
28
#include <linux/async.h>
29
+ #include <linux/pm.h>
30
+ #include <linux/pm_runtime.h>
29
31
#include <sound/core.h>
30
32
#include "hda_codec.h"
31
33
#include <sound/asoundef.h>
41
43
#include "hda_trace.h"
42
44
43
45
#ifdef CONFIG_PM
44
- #define codec_in_pm (codec ) ((codec)->in_pm)
45
- static void hda_power_work (struct work_struct * work );
46
- static void hda_keep_power_on (struct hda_codec * codec );
47
- #define hda_codec_is_power_on (codec ) ((codec)->power_on)
46
+ #define codec_in_pm (codec ) atomic_read(&(codec)->in_pm)
47
+ #define hda_codec_is_power_on (codec ) \
48
+ (!pm_runtime_suspended(hda_codec_dev(codec)))
48
49
49
50
static void hda_call_pm_notify (struct hda_codec * codec , bool power_up )
50
51
{
@@ -60,7 +61,6 @@ static void hda_call_pm_notify(struct hda_codec *codec, bool power_up)
60
61
61
62
#else
62
63
#define codec_in_pm (codec ) 0
63
- static inline void hda_keep_power_on (struct hda_codec * codec ) {}
64
64
#define hda_codec_is_power_on (codec ) 1
65
65
#define hda_call_pm_notify (codec , state ) {}
66
66
#endif
@@ -1144,10 +1144,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
1144
1144
device_del (hda_codec_dev (codec ));
1145
1145
snd_hda_jack_tbl_clear (codec );
1146
1146
free_init_pincfgs (codec );
1147
- #ifdef CONFIG_PM
1148
- cancel_delayed_work (& codec -> power_work );
1149
1147
flush_workqueue (codec -> bus -> workq );
1150
- #endif
1151
1148
list_del (& codec -> list );
1152
1149
snd_array_free (& codec -> mixers );
1153
1150
snd_array_free (& codec -> nids );
@@ -1178,6 +1175,10 @@ static int snd_hda_codec_dev_register(struct snd_device *device)
1178
1175
struct hda_codec * codec = device -> device_data ;
1179
1176
1180
1177
snd_hda_register_beep_device (codec );
1178
+ if (device_is_registered (hda_codec_dev (codec ))) {
1179
+ snd_hda_power_sync (codec );
1180
+ pm_runtime_enable (hda_codec_dev (codec ));
1181
+ }
1181
1182
return 0 ;
1182
1183
}
1183
1184
@@ -1274,13 +1275,14 @@ int snd_hda_codec_new(struct hda_bus *bus,
1274
1275
codec -> fixup_id = HDA_FIXUP_ID_NOT_SET ;
1275
1276
1276
1277
#ifdef CONFIG_PM
1277
- spin_lock_init (& codec -> power_lock );
1278
- INIT_DELAYED_WORK (& codec -> power_work , hda_power_work );
1279
1278
/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
1280
1279
* the caller has to power down appropriatley after initialization
1281
1280
* phase.
1282
1281
*/
1283
- hda_keep_power_on (codec );
1282
+ pm_runtime_set_active (hda_codec_dev (codec ));
1283
+ pm_runtime_get_noresume (hda_codec_dev (codec ));
1284
+ codec -> power_jiffies = jiffies ;
1285
+ hda_call_pm_notify (codec , true);
1284
1286
#endif
1285
1287
1286
1288
snd_hda_sysfs_init (codec );
@@ -2453,10 +2455,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
2453
2455
2454
2456
/* OK, let it free */
2455
2457
cancel_delayed_work_sync (& codec -> jackpoll_work );
2456
- #ifdef CONFIG_PM
2457
- cancel_delayed_work_sync (& codec -> power_work );
2458
2458
flush_workqueue (bus -> workq );
2459
- #endif
2460
2459
snd_hda_ctls_clear (codec );
2461
2460
/* release PCMs */
2462
2461
for (i = 0 ; i < codec -> num_pcms ; i ++ ) {
@@ -3893,31 +3892,40 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
3893
3892
#endif
3894
3893
3895
3894
#ifdef CONFIG_PM
3895
+ /* update the power on/off account with the current jiffies */
3896
+ static void update_power_acct (struct hda_codec * codec , bool on )
3897
+ {
3898
+ unsigned long delta = jiffies - codec -> power_jiffies ;
3899
+
3900
+ if (on )
3901
+ codec -> power_on_acct += delta ;
3902
+ else
3903
+ codec -> power_off_acct += delta ;
3904
+ codec -> power_jiffies += delta ;
3905
+ }
3906
+
3907
+ void snd_hda_update_power_acct (struct hda_codec * codec )
3908
+ {
3909
+ update_power_acct (codec , hda_codec_is_power_on (codec ));
3910
+ }
3911
+
3896
3912
/*
3897
3913
* call suspend and power-down; used both from PM and power-save
3898
3914
* this function returns the power state in the end
3899
3915
*/
3900
- static unsigned int hda_call_codec_suspend (struct hda_codec * codec , bool in_wq )
3916
+ static unsigned int hda_call_codec_suspend (struct hda_codec * codec )
3901
3917
{
3902
3918
unsigned int state ;
3903
3919
3904
- codec -> in_pm = 1 ;
3920
+ atomic_inc ( & codec -> in_pm ) ;
3905
3921
3906
3922
if (codec -> patch_ops .suspend )
3907
3923
codec -> patch_ops .suspend (codec );
3908
3924
hda_cleanup_all_streams (codec );
3909
3925
state = hda_set_power_state (codec , AC_PWRST_D3 );
3910
- /* Cancel delayed work if we aren't currently running from it. */
3911
- if (!in_wq )
3912
- cancel_delayed_work_sync (& codec -> power_work );
3913
- spin_lock (& codec -> power_lock );
3914
- snd_hda_update_power_acct (codec );
3915
3926
trace_hda_power_down (codec );
3916
- codec -> power_on = 0 ;
3917
- codec -> power_transition = 0 ;
3918
- codec -> power_jiffies = jiffies ;
3919
- spin_unlock (& codec -> power_lock );
3920
- codec -> in_pm = 0 ;
3927
+ update_power_acct (codec , true);
3928
+ atomic_dec (& codec -> in_pm );
3921
3929
return state ;
3922
3930
}
3923
3931
@@ -3942,14 +3950,14 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
3942
3950
*/
3943
3951
static void hda_call_codec_resume (struct hda_codec * codec )
3944
3952
{
3945
- codec -> in_pm = 1 ;
3953
+ atomic_inc ( & codec -> in_pm ) ;
3946
3954
3955
+ trace_hda_power_up (codec );
3947
3956
hda_mark_cmd_cache_dirty (codec );
3948
3957
3949
- /* set as if powered on for avoiding re-entering the resume
3950
- * in the resume / power-save sequence
3951
- */
3952
- hda_keep_power_on (codec );
3958
+ codec -> power_jiffies = jiffies ;
3959
+ hda_call_pm_notify (codec , true);
3960
+
3953
3961
hda_set_power_state (codec , AC_PWRST_D0 );
3954
3962
restore_shutup_pins (codec );
3955
3963
hda_exec_init_verbs (codec );
@@ -3967,34 +3975,38 @@ static void hda_call_codec_resume(struct hda_codec *codec)
3967
3975
hda_jackpoll_work (& codec -> jackpoll_work .work );
3968
3976
else
3969
3977
snd_hda_jack_report_sync (codec );
3970
-
3971
- codec -> in_pm = 0 ;
3972
- snd_hda_power_down (codec ); /* flag down before returning */
3978
+ atomic_dec (& codec -> in_pm );
3973
3979
}
3974
3980
3975
- static int hda_codec_driver_suspend (struct device * dev )
3981
+ static int hda_codec_runtime_suspend (struct device * dev )
3976
3982
{
3977
3983
struct hda_codec * codec = dev_to_hda_codec (dev );
3984
+ unsigned int state ;
3978
3985
int i ;
3979
3986
3980
3987
cancel_delayed_work_sync (& codec -> jackpoll_work );
3981
3988
for (i = 0 ; i < codec -> num_pcms ; i ++ )
3982
3989
snd_pcm_suspend_all (codec -> pcm_info [i ].pcm );
3983
- hda_call_codec_suspend (codec , false);
3990
+ state = hda_call_codec_suspend (codec );
3991
+ if (!codec -> bus -> power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK ))
3992
+ hda_call_pm_notify (codec , false);
3984
3993
return 0 ;
3985
3994
}
3986
3995
3987
- static int hda_codec_driver_resume (struct device * dev )
3996
+ static int hda_codec_runtime_resume (struct device * dev )
3988
3997
{
3989
3998
hda_call_codec_resume (dev_to_hda_codec (dev ));
3999
+ pm_runtime_mark_last_busy (dev );
3990
4000
return 0 ;
3991
4001
}
3992
4002
#endif /* CONFIG_PM */
3993
4003
3994
4004
/* referred in hda_bind.c */
3995
4005
const struct dev_pm_ops hda_codec_driver_pm = {
3996
- SET_SYSTEM_SLEEP_PM_OPS (hda_codec_driver_suspend ,
3997
- hda_codec_driver_resume )
4006
+ SET_SYSTEM_SLEEP_PM_OPS (pm_runtime_force_suspend ,
4007
+ pm_runtime_force_resume )
4008
+ SET_RUNTIME_PM_OPS (hda_codec_runtime_suspend , hda_codec_runtime_resume ,
4009
+ NULL )
3998
4010
};
3999
4011
4000
4012
/**
@@ -4733,127 +4745,66 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
4733
4745
EXPORT_SYMBOL_GPL (snd_hda_add_new_ctls );
4734
4746
4735
4747
#ifdef CONFIG_PM
4736
- static void hda_power_work (struct work_struct * work )
4748
+ /**
4749
+ * snd_hda_power_up - Power-up the codec
4750
+ * @codec: HD-audio codec
4751
+ *
4752
+ * Increment the usage counter and resume the device if not done yet.
4753
+ */
4754
+ void snd_hda_power_up (struct hda_codec * codec )
4737
4755
{
4738
- struct hda_codec * codec =
4739
- container_of (work , struct hda_codec , power_work .work );
4740
- struct hda_bus * bus = codec -> bus ;
4741
- unsigned int state ;
4756
+ struct device * dev = hda_codec_dev (codec );
4742
4757
4743
- spin_lock (& codec -> power_lock );
4744
- if (codec -> power_transition > 0 ) { /* during power-up sequence? */
4745
- spin_unlock (& codec -> power_lock );
4758
+ if (codec_in_pm (codec ))
4746
4759
return ;
4747
- }
4748
- if (!codec -> power_on || codec -> power_count ) {
4749
- codec -> power_transition = 0 ;
4750
- spin_unlock (& codec -> power_lock );
4751
- return ;
4752
- }
4753
- spin_unlock (& codec -> power_lock );
4754
-
4755
- state = hda_call_codec_suspend (codec , true);
4756
- if (!bus -> power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK ))
4757
- hda_call_pm_notify (codec , false);
4760
+ pm_runtime_get_sync (dev );
4758
4761
}
4762
+ EXPORT_SYMBOL_GPL (snd_hda_power_up );
4759
4763
4760
- static void hda_keep_power_on (struct hda_codec * codec )
4764
+ /**
4765
+ * snd_hda_power_down - Power-down the codec
4766
+ * @codec: HD-audio codec
4767
+ *
4768
+ * Decrement the usage counter and schedules the autosuspend if none used.
4769
+ */
4770
+ void snd_hda_power_down (struct hda_codec * codec )
4761
4771
{
4762
- spin_lock (& codec -> power_lock );
4763
- codec -> power_count ++ ;
4764
- codec -> power_on = 1 ;
4765
- codec -> power_jiffies = jiffies ;
4766
- spin_unlock (& codec -> power_lock );
4767
- hda_call_pm_notify (codec , true);
4768
- }
4772
+ struct device * dev = hda_codec_dev (codec );
4769
4773
4770
- /* update the power on/off account with the current jiffies */
4771
- void snd_hda_update_power_acct (struct hda_codec * codec )
4772
- {
4773
- unsigned long delta = jiffies - codec -> power_jiffies ;
4774
- if (codec -> power_on )
4775
- codec -> power_on_acct += delta ;
4776
- else
4777
- codec -> power_off_acct += delta ;
4778
- codec -> power_jiffies += delta ;
4779
- }
4780
-
4781
- /* Transition to powered up, if wait_power_down then wait for a pending
4782
- * transition to D3 to complete. A pending D3 transition is indicated
4783
- * with power_transition == -1. */
4784
- /* call this with codec->power_lock held! */
4785
- static void __snd_hda_power_up (struct hda_codec * codec , bool wait_power_down )
4786
- {
4787
- /* Return if power_on or transitioning to power_on, unless currently
4788
- * powering down. */
4789
- if ((codec -> power_on || codec -> power_transition > 0 ) &&
4790
- !(wait_power_down && codec -> power_transition < 0 ))
4774
+ if (codec_in_pm (codec ))
4791
4775
return ;
4792
- spin_unlock (& codec -> power_lock );
4793
-
4794
- cancel_delayed_work_sync (& codec -> power_work );
4795
-
4796
- spin_lock (& codec -> power_lock );
4797
- /* If the power down delayed work was cancelled above before starting,
4798
- * then there is no need to go through power up here.
4799
- */
4800
- if (codec -> power_on ) {
4801
- if (codec -> power_transition < 0 )
4802
- codec -> power_transition = 0 ;
4803
- return ;
4804
- }
4805
-
4806
- trace_hda_power_up (codec );
4807
- snd_hda_update_power_acct (codec );
4808
- codec -> power_on = 1 ;
4809
- codec -> power_jiffies = jiffies ;
4810
- codec -> power_transition = 1 ; /* avoid reentrance */
4811
- spin_unlock (& codec -> power_lock );
4812
-
4813
- hda_call_codec_resume (codec );
4814
-
4815
- spin_lock (& codec -> power_lock );
4816
- codec -> power_transition = 0 ;
4817
- }
4818
-
4819
- #define power_save (codec ) \
4820
- ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
4821
-
4822
- /* Transition to powered down */
4823
- static void __snd_hda_power_down (struct hda_codec * codec )
4824
- {
4825
- if (!codec -> power_on || codec -> power_count || codec -> power_transition )
4826
- return ;
4827
-
4828
- if (power_save (codec )) {
4829
- codec -> power_transition = -1 ; /* avoid reentrance */
4830
- queue_delayed_work (codec -> bus -> workq , & codec -> power_work ,
4831
- msecs_to_jiffies (power_save (codec ) * 1000 ));
4832
- }
4776
+ pm_runtime_mark_last_busy (dev );
4777
+ pm_runtime_put_autosuspend (dev );
4833
4778
}
4779
+ EXPORT_SYMBOL_GPL (snd_hda_power_down );
4834
4780
4835
4781
/**
4836
- * snd_hda_power_save - Power-up/down/sync the codec
4782
+ * snd_hda_power_sync - Synchronize the power_save option
4837
4783
* @codec: HD-audio codec
4838
- * @delta: the counter delta to change
4839
- * @d3wait: sync for D3 transition complete
4840
4784
*
4841
- * Change the power-up counter via @delta, and power up or down the hardware
4842
- * appropriately. For the power-down, queue to the delayed action.
4843
- * Passing zero to @delta means to synchronize the power state.
4785
+ * Synchronize the runtime PM autosuspend state from the power_save option.
4844
4786
*/
4845
- void snd_hda_power_save (struct hda_codec * codec , int delta , bool d3wait )
4787
+ void snd_hda_power_sync (struct hda_codec * codec )
4846
4788
{
4847
- spin_lock (& codec -> power_lock );
4848
- codec -> power_count += delta ;
4849
- trace_hda_power_count (codec );
4850
- if (delta > 0 )
4851
- __snd_hda_power_up (codec , d3wait );
4852
- else
4853
- __snd_hda_power_down (codec );
4854
- spin_unlock (& codec -> power_lock );
4789
+ struct device * dev = hda_codec_dev (codec );
4790
+ int delay ;
4791
+
4792
+ if (!codec -> bus -> power_save )
4793
+ return ;
4794
+
4795
+ delay = * codec -> bus -> power_save * 1000 ;
4796
+ if (delay > 0 ) {
4797
+ pm_runtime_set_autosuspend_delay (dev , delay );
4798
+ pm_runtime_use_autosuspend (dev );
4799
+ pm_runtime_allow (dev );
4800
+ if (!pm_runtime_suspended (dev ))
4801
+ pm_runtime_mark_last_busy (dev );
4802
+ } else {
4803
+ pm_runtime_dont_use_autosuspend (dev );
4804
+ pm_runtime_forbid (dev );
4805
+ }
4855
4806
}
4856
- EXPORT_SYMBOL_GPL (snd_hda_power_save );
4807
+ EXPORT_SYMBOL_GPL (snd_hda_power_sync );
4857
4808
4858
4809
/**
4859
4810
* snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5542,7 +5493,7 @@ void snd_hda_bus_reset(struct hda_bus *bus)
5542
5493
cancel_delayed_work_sync (& codec -> jackpoll_work );
5543
5494
#ifdef CONFIG_PM
5544
5495
if (hda_codec_is_power_on (codec )) {
5545
- hda_call_codec_suspend (codec , false );
5496
+ hda_call_codec_suspend (codec );
5546
5497
hda_call_codec_resume (codec );
5547
5498
}
5548
5499
#endif
0 commit comments