#include <linux/cpu.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
+#include <linux/syscore_ops.h>
 
 #include <trace/events/power.h>
 
 }
 EXPORT_SYMBOL(cpufreq_get);
 
+static struct sysdev_driver cpufreq_sysdev_driver = {
+       .add            = cpufreq_add_dev,
+       .remove         = cpufreq_remove_dev,
+};
+
 
 /**
- *     cpufreq_suspend - let the low level driver prepare for suspend
+ * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
+ *
+ * This function is only executed for the boot processor.  The other CPUs
+ * have been put offline by means of CPU hotplug.
  */
-
-static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
+static int cpufreq_bp_suspend(void)
 {
        int ret = 0;
 
-       int cpu = sysdev->id;
+       int cpu = smp_processor_id();
        struct cpufreq_policy *cpu_policy;
 
        dprintk("suspending cpu %u\n", cpu);
 
-       if (!cpu_online(cpu))
-               return 0;
-
-       /* we may be lax here as interrupts are off. Nonetheless
-        * we need to grab the correct cpu policy, as to check
-        * whether we really run on this CPU.
-        */
-
+       /* If there's no policy for the boot CPU, we have nothing to do. */
        cpu_policy = cpufreq_cpu_get(cpu);
        if (!cpu_policy)
-               return -EINVAL;
-
-       /* only handle each CPU group once */
-       if (unlikely(cpu_policy->cpu != cpu))
-               goto out;
+               return 0;
 
        if (cpufreq_driver->suspend) {
                ret = cpufreq_driver->suspend(cpu_policy);
                                        "step on CPU %u\n", cpu_policy->cpu);
        }
 
-out:
        cpufreq_cpu_put(cpu_policy);
        return ret;
 }
 
 /**
- *     cpufreq_resume -  restore proper CPU frequency handling after resume
+ * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
  *
  *     1.) resume CPUfreq hardware support (cpufreq_driver->resume())
  *     2.) schedule call cpufreq_update_policy() ASAP as interrupts are
  *         what we believe it to be. This is a bit later than when it
  *         should be, but nonethteless it's better than calling
  *         cpufreq_driver->get() here which might re-enable interrupts...
+ *
+ * This function is only executed for the boot CPU.  The other CPUs have not
+ * been turned on yet.
  */
-static int cpufreq_resume(struct sys_device *sysdev)
+static void cpufreq_bp_resume(void)
 {
        int ret = 0;
 
-       int cpu = sysdev->id;
+       int cpu = smp_processor_id();
        struct cpufreq_policy *cpu_policy;
 
        dprintk("resuming cpu %u\n", cpu);
 
-       if (!cpu_online(cpu))
-               return 0;
-
-       /* we may be lax here as interrupts are off. Nonetheless
-        * we need to grab the correct cpu policy, as to check
-        * whether we really run on this CPU.
-        */
-
+       /* If there's no policy for the boot CPU, we have nothing to do. */
        cpu_policy = cpufreq_cpu_get(cpu);
        if (!cpu_policy)
-               return -EINVAL;
-
-       /* only handle each CPU group once */
-       if (unlikely(cpu_policy->cpu != cpu))
-               goto fail;
+               return;
 
        if (cpufreq_driver->resume) {
                ret = cpufreq_driver->resume(cpu_policy);
 
 fail:
        cpufreq_cpu_put(cpu_policy);
-       return ret;
 }
 
-static struct sysdev_driver cpufreq_sysdev_driver = {
-       .add            = cpufreq_add_dev,
-       .remove         = cpufreq_remove_dev,
-       .suspend        = cpufreq_suspend,
-       .resume         = cpufreq_resume,
+static struct syscore_ops cpufreq_syscore_ops = {
+       .suspend        = cpufreq_bp_suspend,
+       .resume         = cpufreq_bp_resume,
 };
 
 
        cpufreq_global_kobject = kobject_create_and_add("cpufreq",
                                                &cpu_sysdev_class.kset.kobj);
        BUG_ON(!cpufreq_global_kobject);
+       register_syscore_ops(&cpufreq_syscore_ops);
 
        return 0;
 }