diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b30001f31610..8e561313d094 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -223,7 +223,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) | |||
223 | } | 223 | } |
224 | if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || | 224 | if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || |
225 | (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || | 225 | (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || |
226 | (val == CPUFREQ_RESUMECHANGE)) { | 226 | (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { |
227 | loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); | 227 | loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); |
228 | dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); | 228 | dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); |
229 | } | 229 | } |
@@ -866,11 +866,90 @@ EXPORT_SYMBOL(cpufreq_get); | |||
866 | 866 | ||
867 | 867 | ||
868 | /** | 868 | /** |
869 | * cpufreq_suspend - let the low level driver prepare for suspend | ||
870 | */ | ||
871 | |||
872 | static int cpufreq_suspend(struct sys_device * sysdev, u32 state) | ||
873 | { | ||
874 | int cpu = sysdev->id; | ||
875 | unsigned int ret = 0; | ||
876 | unsigned int cur_freq = 0; | ||
877 | struct cpufreq_policy *cpu_policy; | ||
878 | |||
879 | dprintk("resuming cpu %u\n", cpu); | ||
880 | |||
881 | if (!cpu_online(cpu)) | ||
882 | return 0; | ||
883 | |||
884 | /* we may be lax here as interrupts are off. Nonetheless | ||
885 | * we need to grab the correct cpu policy, as to check | ||
886 | * whether we really run on this CPU. | ||
887 | */ | ||
888 | |||
889 | cpu_policy = cpufreq_cpu_get(cpu); | ||
890 | if (!cpu_policy) | ||
891 | return -EINVAL; | ||
892 | |||
893 | /* only handle each CPU group once */ | ||
894 | if (unlikely(cpu_policy->cpu != cpu)) { | ||
895 | cpufreq_cpu_put(cpu_policy); | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | if (cpufreq_driver->suspend) { | ||
900 | ret = cpufreq_driver->suspend(cpu_policy, state); | ||
901 | if (ret) { | ||
902 | printk(KERN_ERR "cpufreq: suspend failed in ->suspend " | ||
903 | "step on CPU %u\n", cpu_policy->cpu); | ||
904 | cpufreq_cpu_put(cpu_policy); | ||
905 | return ret; | ||
906 | } | ||
907 | } | ||
908 | |||
909 | |||
910 | if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) | ||
911 | goto out; | ||
912 | |||
913 | if (cpufreq_driver->get) | ||
914 | cur_freq = cpufreq_driver->get(cpu_policy->cpu); | ||
915 | |||
916 | if (!cur_freq || !cpu_policy->cur) { | ||
917 | printk(KERN_ERR "cpufreq: suspend failed to assert current " | ||
918 | "frequency is what timing core thinks it is.\n"); | ||
919 | goto out; | ||
920 | } | ||
921 | |||
922 | if (unlikely(cur_freq != cpu_policy->cur)) { | ||
923 | struct cpufreq_freqs freqs; | ||
924 | |||
925 | if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) | ||
926 | printk(KERN_DEBUG "Warning: CPU frequency is %u, " | ||
927 | "cpufreq assumed %u kHz.\n", | ||
928 | cur_freq, cpu_policy->cur); | ||
929 | |||
930 | freqs.cpu = cpu; | ||
931 | freqs.old = cpu_policy->cur; | ||
932 | freqs.new = cur_freq; | ||
933 | |||
934 | notifier_call_chain(&cpufreq_transition_notifier_list, | ||
935 | CPUFREQ_SUSPENDCHANGE, &freqs); | ||
936 | adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); | ||
937 | |||
938 | cpu_policy->cur = cur_freq; | ||
939 | } | ||
940 | |||
941 | out: | ||
942 | cpufreq_cpu_put(cpu_policy); | ||
943 | return 0; | ||
944 | } | ||
945 | |||
946 | /** | ||
869 | * cpufreq_resume - restore proper CPU frequency handling after resume | 947 | * cpufreq_resume - restore proper CPU frequency handling after resume |
870 | * | 948 | * |
871 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) | 949 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) |
872 | * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync | 950 | * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync |
873 | * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored. | 951 | * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are |
952 | * restored. | ||
874 | */ | 953 | */ |
875 | static int cpufreq_resume(struct sys_device * sysdev) | 954 | static int cpufreq_resume(struct sys_device * sysdev) |
876 | { | 955 | { |
@@ -915,21 +994,26 @@ static int cpufreq_resume(struct sys_device * sysdev) | |||
915 | cur_freq = cpufreq_driver->get(cpu_policy->cpu); | 994 | cur_freq = cpufreq_driver->get(cpu_policy->cpu); |
916 | 995 | ||
917 | if (!cur_freq || !cpu_policy->cur) { | 996 | if (!cur_freq || !cpu_policy->cur) { |
918 | printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n"); | 997 | printk(KERN_ERR "cpufreq: resume failed to assert " |
998 | "current frequency is what timing core " | ||
999 | "thinks it is.\n"); | ||
919 | goto out; | 1000 | goto out; |
920 | } | 1001 | } |
921 | 1002 | ||
922 | if (unlikely(cur_freq != cpu_policy->cur)) { | 1003 | if (unlikely(cur_freq != cpu_policy->cur)) { |
923 | struct cpufreq_freqs freqs; | 1004 | struct cpufreq_freqs freqs; |
924 | 1005 | ||
925 | printk(KERN_WARNING "Warning: CPU frequency is %u, " | 1006 | if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) |
926 | "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); | 1007 | printk(KERN_WARNING "Warning: CPU frequency" |
1008 | "is %u, cpufreq assumed %u kHz.\n", | ||
1009 | cur_freq, cpu_policy->cur); | ||
927 | 1010 | ||
928 | freqs.cpu = cpu; | 1011 | freqs.cpu = cpu; |
929 | freqs.old = cpu_policy->cur; | 1012 | freqs.old = cpu_policy->cur; |
930 | freqs.new = cur_freq; | 1013 | freqs.new = cur_freq; |
931 | 1014 | ||
932 | notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); | 1015 | notifier_call_chain(&cpufreq_transition_notifier_list, |
1016 | CPUFREQ_RESUMECHANGE, &freqs); | ||
933 | adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); | 1017 | adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); |
934 | 1018 | ||
935 | cpu_policy->cur = cur_freq; | 1019 | cpu_policy->cur = cur_freq; |
@@ -945,6 +1029,7 @@ out: | |||
945 | static struct sysdev_driver cpufreq_sysdev_driver = { | 1029 | static struct sysdev_driver cpufreq_sysdev_driver = { |
946 | .add = cpufreq_add_dev, | 1030 | .add = cpufreq_add_dev, |
947 | .remove = cpufreq_remove_dev, | 1031 | .remove = cpufreq_remove_dev, |
1032 | .suspend = cpufreq_suspend, | ||
948 | .resume = cpufreq_resume, | 1033 | .resume = cpufreq_resume, |
949 | }; | 1034 | }; |
950 | 1035 | ||