linux/drivers/base/power/generic_ops.c
<<
>>
Prefs
   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 */
  21int 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}
  34EXPORT_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 -EINVAL.
  43 */
  44int 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}
  53EXPORT_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 -EINVAL.
  62 */
  63int 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}
  72EXPORT_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 */
  85static 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 */
 118int pm_generic_suspend(struct device *dev)
 119{
 120        return __pm_generic_call(dev, PM_EVENT_SUSPEND);
 121}
 122EXPORT_SYMBOL_GPL(pm_generic_suspend);
 123
 124/**
 125 * pm_generic_freeze - Generic freeze callback for subsystems.
 126 * @dev: Device to freeze.
 127 */
 128int pm_generic_freeze(struct device *dev)
 129{
 130        return __pm_generic_call(dev, PM_EVENT_FREEZE);
 131}
 132EXPORT_SYMBOL_GPL(pm_generic_freeze);
 133
 134/**
 135 * pm_generic_poweroff - Generic poweroff callback for subsystems.
 136 * @dev: Device to handle.
 137 */
 138int pm_generic_poweroff(struct device *dev)
 139{
 140        return __pm_generic_call(dev, PM_EVENT_HIBERNATE);
 141}
 142EXPORT_SYMBOL_GPL(pm_generic_poweroff);
 143
 144/**
 145 * pm_generic_thaw - Generic thaw callback for subsystems.
 146 * @dev: Device to thaw.
 147 */
 148int pm_generic_thaw(struct device *dev)
 149{
 150        return __pm_generic_call(dev, PM_EVENT_THAW);
 151}
 152EXPORT_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 */
 163static 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) {
 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 */
 201int pm_generic_resume(struct device *dev)
 202{
 203        return __pm_generic_resume(dev, PM_EVENT_RESUME);
 204}
 205EXPORT_SYMBOL_GPL(pm_generic_resume);
 206
 207/**
 208 * pm_generic_restore - Generic restore callback for subsystems.
 209 * @dev: Device to restore.
 210 */
 211int pm_generic_restore(struct device *dev)
 212{
 213        return __pm_generic_resume(dev, PM_EVENT_RESTORE);
 214}
 215EXPORT_SYMBOL_GPL(pm_generic_restore);
 216#endif /* CONFIG_PM_SLEEP */
 217
 218struct 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};
 233EXPORT_SYMBOL_GPL(generic_subsys_pm_ops);
 234