diff options
author | Lukasz Luba <l.luba@partner.samsung.com> | 2018-12-05 06:05:53 -0500 |
---|---|---|
committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2018-12-10 21:09:47 -0500 |
commit | 83f8ca45afbf041e312909f442128b99657d90b7 (patch) | |
tree | d9f1ef6d6749aaaa6963cea58747a8024a24f61e /drivers/devfreq/devfreq.c | |
parent | 633141721b5bfce7017033a767208af591134b8f (diff) |
PM / devfreq: add support for suspend/resume of a devfreq device
The patch prepares devfreq device for handling suspend/resume
functionality. The new fields will store needed information during this
process. Devfreq framework handles opp-suspend DT entry and there is no
need of modyfications in the drivers code. It uses atomic variables to
make sure no race condition affects the process.
Suggested-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
Suggested-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Lukasz Luba <l.luba@partner.samsung.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r-- | drivers/devfreq/devfreq.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index a9fd61bbacf1..46517b61b3a2 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
@@ -316,6 +316,10 @@ static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq, | |||
316 | "Couldn't update frequency transition information.\n"); | 316 | "Couldn't update frequency transition information.\n"); |
317 | 317 | ||
318 | devfreq->previous_freq = new_freq; | 318 | devfreq->previous_freq = new_freq; |
319 | |||
320 | if (devfreq->suspend_freq) | ||
321 | devfreq->resume_freq = cur_freq; | ||
322 | |||
319 | return err; | 323 | return err; |
320 | } | 324 | } |
321 | 325 | ||
@@ -667,6 +671,9 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
667 | } | 671 | } |
668 | devfreq->max_freq = devfreq->scaling_max_freq; | 672 | devfreq->max_freq = devfreq->scaling_max_freq; |
669 | 673 | ||
674 | devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); | ||
675 | atomic_set(&devfreq->suspend_count, 0); | ||
676 | |||
670 | dev_set_name(&devfreq->dev, "devfreq%d", | 677 | dev_set_name(&devfreq->dev, "devfreq%d", |
671 | atomic_inc_return(&devfreq_no)); | 678 | atomic_inc_return(&devfreq_no)); |
672 | err = device_register(&devfreq->dev); | 679 | err = device_register(&devfreq->dev); |
@@ -867,14 +874,28 @@ EXPORT_SYMBOL(devm_devfreq_remove_device); | |||
867 | */ | 874 | */ |
868 | int devfreq_suspend_device(struct devfreq *devfreq) | 875 | int devfreq_suspend_device(struct devfreq *devfreq) |
869 | { | 876 | { |
877 | int ret; | ||
878 | |||
870 | if (!devfreq) | 879 | if (!devfreq) |
871 | return -EINVAL; | 880 | return -EINVAL; |
872 | 881 | ||
873 | if (!devfreq->governor) | 882 | if (atomic_inc_return(&devfreq->suspend_count) > 1) |
874 | return 0; | 883 | return 0; |
875 | 884 | ||
876 | return devfreq->governor->event_handler(devfreq, | 885 | if (devfreq->governor) { |
877 | DEVFREQ_GOV_SUSPEND, NULL); | 886 | ret = devfreq->governor->event_handler(devfreq, |
887 | DEVFREQ_GOV_SUSPEND, NULL); | ||
888 | if (ret) | ||
889 | return ret; | ||
890 | } | ||
891 | |||
892 | if (devfreq->suspend_freq) { | ||
893 | ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0); | ||
894 | if (ret) | ||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | return 0; | ||
878 | } | 899 | } |
879 | EXPORT_SYMBOL(devfreq_suspend_device); | 900 | EXPORT_SYMBOL(devfreq_suspend_device); |
880 | 901 | ||
@@ -888,14 +909,28 @@ EXPORT_SYMBOL(devfreq_suspend_device); | |||
888 | */ | 909 | */ |
889 | int devfreq_resume_device(struct devfreq *devfreq) | 910 | int devfreq_resume_device(struct devfreq *devfreq) |
890 | { | 911 | { |
912 | int ret; | ||
913 | |||
891 | if (!devfreq) | 914 | if (!devfreq) |
892 | return -EINVAL; | 915 | return -EINVAL; |
893 | 916 | ||
894 | if (!devfreq->governor) | 917 | if (atomic_dec_return(&devfreq->suspend_count) >= 1) |
895 | return 0; | 918 | return 0; |
896 | 919 | ||
897 | return devfreq->governor->event_handler(devfreq, | 920 | if (devfreq->resume_freq) { |
898 | DEVFREQ_GOV_RESUME, NULL); | 921 | ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0); |
922 | if (ret) | ||
923 | return ret; | ||
924 | } | ||
925 | |||
926 | if (devfreq->governor) { | ||
927 | ret = devfreq->governor->event_handler(devfreq, | ||
928 | DEVFREQ_GOV_RESUME, NULL); | ||
929 | if (ret) | ||
930 | return ret; | ||
931 | } | ||
932 | |||
933 | return 0; | ||
899 | } | 934 | } |
900 | EXPORT_SYMBOL(devfreq_resume_device); | 935 | EXPORT_SYMBOL(devfreq_resume_device); |
901 | 936 | ||