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 | ||
