1 /* 2 * driver.c - driver support 3 * 4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 5 * Shaohua Li <shaohua.li@intel.com> 6 * Adam Belay <abelay@novell.com> 7 * 8 * This code is licenced under the GPL. 9 */ 10 11 #include <linux/mutex.h> 12 #include <linux/module.h> 13 #include <linux/cpuidle.h> 14 15 #include "cpuidle.h" 16 17 static struct cpuidle_driver *cpuidle_curr_driver; 18 DEFINE_SPINLOCK(cpuidle_driver_lock); 19 20 static void __cpuidle_register_driver(struct cpuidle_driver *drv) 21 { 22 int i; 23 /* 24 * cpuidle driver should set the drv->power_specified bit 25 * before registering if the driver provides 26 * power_usage numbers. 27 * 28 * If power_specified is not set, 29 * we fill in power_usage with decreasing values as the 30 * cpuidle code has an implicit assumption that state Cn 31 * uses less power than C(n-1). 32 * 33 * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned 34 * an power value of -1. So we use -2, -3, etc, for other 35 * c-states. 36 */ 37 if (!drv->power_specified) { 38 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) 39 drv->states[i].power_usage = -1 - i; 40 } 41 } 42 43 44 /** 45 * cpuidle_register_driver - registers a driver 46 * @drv: the driver 47 */ 48 int cpuidle_register_driver(struct cpuidle_driver *drv) 49 { 50 if (!drv || !drv->state_count) 51 return -EINVAL; 52 53 if (cpuidle_disabled()) 54 return -ENODEV; 55 56 spin_lock(&cpuidle_driver_lock); 57 if (cpuidle_curr_driver) { 58 spin_unlock(&cpuidle_driver_lock); 59 return -EBUSY; 60 } 61 __cpuidle_register_driver(drv); 62 cpuidle_curr_driver = drv; 63 spin_unlock(&cpuidle_driver_lock); 64 65 return 0; 66 } 67 68 EXPORT_SYMBOL_GPL(cpuidle_register_driver); 69 70 /** 71 * cpuidle_get_driver - return the current driver 72 */ 73 struct cpuidle_driver *cpuidle_get_driver(void) 74 { 75 return cpuidle_curr_driver; 76 } 77 EXPORT_SYMBOL_GPL(cpuidle_get_driver); 78 79 /** 80 * cpuidle_unregister_driver - unregisters a driver 81 * @drv: the driver 82 */ 83 void cpuidle_unregister_driver(struct cpuidle_driver *drv) 84 { 85 if (drv != cpuidle_curr_driver) { 86 WARN(1, "invalid cpuidle_unregister_driver(%s)\n", 87 drv->name); 88 return; 89 } 90 91 spin_lock(&cpuidle_driver_lock); 92 cpuidle_curr_driver = NULL; 93 spin_unlock(&cpuidle_driver_lock); 94 } 95 96 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); 97