1 /* 2 * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems 3 * 4 * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. 5 * 6 * This file is released under the GPLv2. 7 */ 8 9 #include <linux/pm.h> 10 #include <linux/pm_runtime.h> 11 12 #ifdef CONFIG_PM_RUNTIME 13 /** 14 * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. 15 * @dev: Device to handle. 16 * 17 * If PM operations are defined for the @dev's driver and they include 18 * ->runtime_idle(), execute it and return its error code, if nonzero. 19 * Otherwise, execute pm_runtime_suspend() for the device and return 0. 20 */ 21 int pm_generic_runtime_idle(struct device *dev) 22 { 23 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 24 25 if (pm && pm->runtime_idle) { 26 int ret = pm->runtime_idle(dev); 27 if (ret) 28 return ret; 29 } 30 31 pm_runtime_suspend(dev); 32 return 0; 33 } 34 EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); 35 36 /** 37 * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. 38 * @dev: Device to suspend. 39 * 40 * If PM operations are defined for the @dev's driver and they include 41 * ->runtime_suspend(), execute it and return its error code. Otherwise, 42 * return 0. 43 */ 44 int pm_generic_runtime_suspend(struct device *dev) 45 { 46 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 47 int ret; 48 49 ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0; 50 51 return ret; 52 } 53 EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); 54 55 /** 56 * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. 57 * @dev: Device to resume. 58 * 59 * If PM operations are defined for the @dev's driver and they include 60 * ->runtime_resume(), execute it and return its error code. Otherwise, 61 * return 0. 62 */ 63 int pm_generic_runtime_resume(struct device *dev) 64 { 65 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 66 int ret; 67 68 ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0; 69 70 return ret; 71 } 72 EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); 73 #endif /* CONFIG_PM_RUNTIME */ 74 75 #ifdef CONFIG_PM_SLEEP 76 /** 77 * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. 78 * @dev: Device to handle. 79 * @event: PM transition of the system under way. 80 * 81 * If the device has not been suspended at run time, execute the 82 * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and 83 * return its error code. Otherwise, return zero. 84 */ 85 static int __pm_generic_call(struct device *dev, int event) 86 { 87 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 88 int (*callback)(struct device *); 89 90 if (!pm || pm_runtime_suspended(dev)) 91 return 0; 92 93 switch (event) { 94 case PM_EVENT_SUSPEND: 95 callback = pm->suspend; 96 break; 97 case PM_EVENT_FREEZE: 98 callback = pm->freeze; 99 break; 100 case PM_EVENT_HIBERNATE: 101 callback = pm->poweroff; 102 break; 103 case PM_EVENT_THAW: 104 callback = pm->thaw; 105 break; 106 default: 107 callback = NULL; 108 break; 109 } 110 111 return callback ? callback(dev) : 0; 112 } 113 114 /** 115 * pm_generic_suspend - Generic suspend callback for subsystems. 116 * @dev: Device to suspend. 117 */ 118 int pm_generic_suspend(struct device *dev) 119 { 120 return __pm_generic_call(dev, PM_EVENT_SUSPEND); 121 } 122 EXPORT_SYMBOL_GPL(pm_generic_suspend); 123 124 /** 125 * pm_generic_freeze - Generic freeze callback for subsystems. 126 * @dev: Device to freeze. 127 */ 128 int pm_generic_freeze(struct device *dev) 129 { 130 return __pm_generic_call(dev, PM_EVENT_FREEZE); 131 } 132 EXPORT_SYMBOL_GPL(pm_generic_freeze); 133 134 /** 135 * pm_generic_poweroff - Generic poweroff callback for subsystems. 136 * @dev: Device to handle. 137 */ 138 int pm_generic_poweroff(struct device *dev) 139 { 140 return __pm_generic_call(dev, PM_EVENT_HIBERNATE); 141 } 142 EXPORT_SYMBOL_GPL(pm_generic_poweroff); 143 144 /** 145 * pm_generic_thaw - Generic thaw callback for subsystems. 146 * @dev: Device to thaw. 147 */ 148 int pm_generic_thaw(struct device *dev) 149 { 150 return __pm_generic_call(dev, PM_EVENT_THAW); 151 } 152 EXPORT_SYMBOL_GPL(pm_generic_thaw); 153 154 /** 155 * __pm_generic_resume - Generic resume/restore callback for subsystems. 156 * @dev: Device to handle. 157 * @event: PM transition of the system under way. 158 * 159 * Execute the resume/resotre callback provided by the @dev's driver, if 160 * defined. If it returns 0, change the device's runtime PM status to 'active'. 161 * Return the callback's error code. 162 */ 163 static int __pm_generic_resume(struct device *dev, int event) 164 { 165 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 166 int (*callback)(struct device *); 167 int ret; 168 169 if (!pm) 170 return 0; 171 172 switch (event) { 173 case PM_EVENT_RESUME: 174 callback = pm->resume; 175 break; 176 case PM_EVENT_RESTORE: 177 callback = pm->restore; 178 break; 179 default: 180 callback = NULL; 181 break; 182 } 183 184 if (!callback) 185 return 0; 186 187 ret = callback(dev); 188 if (!ret && pm_runtime_enabled(dev)) { 189 pm_runtime_disable(dev); 190 pm_runtime_set_active(dev); 191 pm_runtime_enable(dev); 192 } 193 194 return ret; 195 } 196 197 /** 198 * pm_generic_resume - Generic resume callback for subsystems. 199 * @dev: Device to resume. 200 */ 201 int pm_generic_resume(struct device *dev) 202 { 203 return __pm_generic_resume(dev, PM_EVENT_RESUME); 204 } 205 EXPORT_SYMBOL_GPL(pm_generic_resume); 206 207 /** 208 * pm_generic_restore - Generic restore callback for subsystems. 209 * @dev: Device to restore. 210 */ 211 int pm_generic_restore(struct device *dev) 212 { 213 return __pm_generic_resume(dev, PM_EVENT_RESTORE); 214 } 215 EXPORT_SYMBOL_GPL(pm_generic_restore); 216 #endif /* CONFIG_PM_SLEEP */ 217 218 struct dev_pm_ops generic_subsys_pm_ops = { 219 #ifdef CONFIG_PM_SLEEP 220 .suspend = pm_generic_suspend, 221 .resume = pm_generic_resume, 222 .freeze = pm_generic_freeze, 223 .thaw = pm_generic_thaw, 224 .poweroff = pm_generic_poweroff, 225 .restore = pm_generic_restore, 226 #endif 227 #ifdef CONFIG_PM_RUNTIME 228 .runtime_suspend = pm_generic_runtime_suspend, 229 .runtime_resume = pm_generic_runtime_resume, 230 .runtime_idle = pm_generic_runtime_idle, 231 #endif 232 }; 233 EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); 234