Merge branch 'pm-cpufreq'
[firefly-linux-kernel-4.4.55.git] / drivers / cpuidle / cpuidle.c
index 0da795b9dbbf19b083130b8ea776f420ad4f51c5..c3a93fece819e71adb5fcae2acd84f885c0f2583 100644 (file)
@@ -24,6 +24,7 @@
 #include "cpuidle.h"
 
 DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
+DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
 
 DEFINE_MUTEX(cpuidle_lock);
 LIST_HEAD(cpuidle_detected_devices);
@@ -453,6 +454,77 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
 
+/**
+ * cpuidle_unregister: unregister a driver and the devices. This function
+ * can be used only if the driver has been previously registered through
+ * the cpuidle_register function.
+ *
+ * @drv: a valid pointer to a struct cpuidle_driver
+ */
+void cpuidle_unregister(struct cpuidle_driver *drv)
+{
+       int cpu;
+       struct cpuidle_device *device;
+
+       for_each_possible_cpu(cpu) {
+               device = &per_cpu(cpuidle_dev, cpu);
+               cpuidle_unregister_device(device);
+       }
+
+       cpuidle_unregister_driver(drv);
+}
+EXPORT_SYMBOL_GPL(cpuidle_unregister);
+
+/**
+ * cpuidle_register: registers the driver and the cpu devices with the
+ * coupled_cpus passed as parameter. This function is used for all common
+ * initialization pattern there are in the arch specific drivers. The
+ * devices is globally defined in this file.
+ *
+ * @drv         : a valid pointer to a struct cpuidle_driver
+ * @coupled_cpus: a cpumask for the coupled states
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int cpuidle_register(struct cpuidle_driver *drv,
+                    const struct cpumask *const coupled_cpus)
+{
+       int ret, cpu;
+       struct cpuidle_device *device;
+
+       ret = cpuidle_register_driver(drv);
+       if (ret) {
+               pr_err("failed to register cpuidle driver\n");
+               return ret;
+       }
+
+       for_each_possible_cpu(cpu) {
+               device = &per_cpu(cpuidle_dev, cpu);
+               device->cpu = cpu;
+
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+               /*
+                * On multiplatform for ARM, the coupled idle states could
+                * enabled in the kernel even if the cpuidle driver does not
+                * use it. Note, coupled_cpus is a struct copy.
+                */
+               if (coupled_cpus)
+                       device->coupled_cpus = *coupled_cpus;
+#endif
+               ret = cpuidle_register_device(device);
+               if (!ret)
+                       continue;
+
+               pr_err("Failed to register cpuidle device for cpu%d\n", cpu);
+
+               cpuidle_unregister(drv);
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cpuidle_register);
+
 #ifdef CONFIG_SMP
 
 static void smp_callback(void *v)