linux/drivers/base/power/wakeirq.c
<<
>>
Prefs
   1/*
   2 * wakeirq.c - Device wakeirq helper functions
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
   9 * kind, whether express or implied; without even the implied warranty
  10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/slab.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/pm_wakeirq.h>
  20
  21#include "power.h"
  22
  23/**
  24 * dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
  25 * @dev: Device entry
  26 * @irq: Device wake-up capable interrupt
  27 * @wirq: Wake irq specific data
  28 *
  29 * Internal function to attach either a device IO interrupt or a
  30 * dedicated wake-up interrupt as a wake IRQ.
  31 */
  32static int dev_pm_attach_wake_irq(struct device *dev, int irq,
  33                                  struct wake_irq *wirq)
  34{
  35        unsigned long flags;
  36
  37        if (!dev || !wirq)
  38                return -EINVAL;
  39
  40        spin_lock_irqsave(&dev->power.lock, flags);
  41        if (dev_WARN_ONCE(dev, dev->power.wakeirq,
  42                          "wake irq already initialized\n")) {
  43                spin_unlock_irqrestore(&dev->power.lock, flags);
  44                return -EEXIST;
  45        }
  46
  47        dev->power.wakeirq = wirq;
  48        device_wakeup_attach_irq(dev, wirq);
  49
  50        spin_unlock_irqrestore(&dev->power.lock, flags);
  51        return 0;
  52}
  53
  54/**
  55 * dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
  56 * @dev: Device entry
  57 * @irq: Device IO interrupt
  58 *
  59 * Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
  60 * automatically configured for wake-up from suspend  based
  61 * on the device specific sysfs wakeup entry. Typically called
  62 * during driver probe after calling device_init_wakeup().
  63 */
  64int dev_pm_set_wake_irq(struct device *dev, int irq)
  65{
  66        struct wake_irq *wirq;
  67        int err;
  68
  69        if (irq < 0)
  70                return -EINVAL;
  71
  72        wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
  73        if (!wirq)
  74                return -ENOMEM;
  75
  76        wirq->dev = dev;
  77        wirq->irq = irq;
  78
  79        err = dev_pm_attach_wake_irq(dev, irq, wirq);
  80        if (err)
  81                kfree(wirq);
  82
  83        return err;
  84}
  85EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
  86
  87/**
  88 * dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
  89 * @dev: Device entry
  90 *
  91 * Detach a device wake IRQ and free resources.
  92 *
  93 * Note that it's OK for drivers to call this without calling
  94 * dev_pm_set_wake_irq() as all the driver instances may not have
  95 * a wake IRQ configured. This avoid adding wake IRQ specific
  96 * checks into the drivers.
  97 */
  98void dev_pm_clear_wake_irq(struct device *dev)
  99{
 100        struct wake_irq *wirq = dev->power.wakeirq;
 101        unsigned long flags;
 102
 103        if (!wirq)
 104                return;
 105
 106        spin_lock_irqsave(&dev->power.lock, flags);
 107        device_wakeup_detach_irq(dev);
 108        dev->power.wakeirq = NULL;
 109        spin_unlock_irqrestore(&dev->power.lock, flags);
 110
 111        if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) {
 112                free_irq(wirq->irq, wirq);
 113                wirq->status &= ~WAKE_IRQ_DEDICATED_MASK;
 114        }
 115        kfree(wirq->name);
 116        kfree(wirq);
 117}
 118EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
 119
 120/**
 121 * handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
 122 * @irq: Device specific dedicated wake-up interrupt
 123 * @_wirq: Wake IRQ data
 124 *
 125 * Some devices have a separate wake-up interrupt in addition to the
 126 * device IO interrupt. The wake-up interrupt signals that a device
 127 * should be woken up from it's idle state. This handler uses device
 128 * specific pm_runtime functions to wake the device, and then it's
 129 * up to the device to do whatever it needs to. Note that as the
 130 * device may need to restore context and start up regulators, we
 131 * use a threaded IRQ.
 132 *
 133 * Also note that we are not resending the lost device interrupts.
 134 * We assume that the wake-up interrupt just needs to wake-up the
 135 * device, and then device's pm_runtime_resume() can deal with the
 136 * situation.
 137 */
 138static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
 139{
 140        struct wake_irq *wirq = _wirq;
 141        int res;
 142
 143        /* Maybe abort suspend? */
 144        if (irqd_is_wakeup_set(irq_get_irq_data(irq))) {
 145                pm_wakeup_event(wirq->dev, 0);
 146
 147                return IRQ_HANDLED;
 148        }
 149
 150        /* We don't want RPM_ASYNC or RPM_NOWAIT here */
 151        res = pm_runtime_resume(wirq->dev);
 152        if (res < 0)
 153                dev_warn(wirq->dev,
 154                         "wake IRQ with no resume: %i\n", res);
 155
 156        return IRQ_HANDLED;
 157}
 158
 159/**
 160 * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
 161 * @dev: Device entry
 162 * @irq: Device wake-up interrupt
 163 *
 164 * Unless your hardware has separate wake-up interrupts in addition
 165 * to the device IO interrupts, you don't need this.
 166 *
 167 * Sets up a threaded interrupt handler for a device that has
 168 * a dedicated wake-up interrupt in addition to the device IO
 169 * interrupt.
 170 *
 171 * The interrupt starts disabled, and needs to be managed for
 172 * the device by the bus code or the device driver using
 173 * dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
 174 * functions.
 175 */
 176int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
 177{
 178        struct wake_irq *wirq;
 179        int err;
 180
 181        if (irq < 0)
 182                return -EINVAL;
 183
 184        wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
 185        if (!wirq)
 186                return -ENOMEM;
 187
 188        wirq->name = kasprintf(GFP_KERNEL, "%s:wakeup", dev_name(dev));
 189        if (!wirq->name) {
 190                err = -ENOMEM;
 191                goto err_free;
 192        }
 193
 194        wirq->dev = dev;
 195        wirq->irq = irq;
 196        irq_set_status_flags(irq, IRQ_NOAUTOEN);
 197
 198        /* Prevent deferred spurious wakeirqs with disable_irq_nosync() */
 199        irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
 200
 201        /*
 202         * Consumer device may need to power up and restore state
 203         * so we use a threaded irq.
 204         */
 205        err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
 206                                   IRQF_ONESHOT, wirq->name, wirq);
 207        if (err)
 208                goto err_free_name;
 209
 210        err = dev_pm_attach_wake_irq(dev, irq, wirq);
 211        if (err)
 212                goto err_free_irq;
 213
 214        wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED;
 215
 216        return err;
 217
 218err_free_irq:
 219        free_irq(irq, wirq);
 220err_free_name:
 221        kfree(wirq->name);
 222err_free:
 223        kfree(wirq);
 224
 225        return err;
 226}
 227EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
 228
 229/**
 230 * dev_pm_enable_wake_irq - Enable device wake-up interrupt
 231 * @dev: Device
 232 *
 233 * Optionally called from the bus code or the device driver for
 234 * runtime_resume() to override the PM runtime core managed wake-up
 235 * interrupt handling to enable the wake-up interrupt.
 236 *
 237 * Note that for runtime_suspend()) the wake-up interrupts
 238 * should be unconditionally enabled unlike for suspend()
 239 * that is conditional.
 240 */
 241void dev_pm_enable_wake_irq(struct device *dev)
 242{
 243        struct wake_irq *wirq = dev->power.wakeirq;
 244
 245        if (wirq && (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED))
 246                enable_irq(wirq->irq);
 247}
 248EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
 249
 250/**
 251 * dev_pm_disable_wake_irq - Disable device wake-up interrupt
 252 * @dev: Device
 253 *
 254 * Optionally called from the bus code or the device driver for
 255 * runtime_suspend() to override the PM runtime core managed wake-up
 256 * interrupt handling to disable the wake-up interrupt.
 257 */
 258void dev_pm_disable_wake_irq(struct device *dev)
 259{
 260        struct wake_irq *wirq = dev->power.wakeirq;
 261
 262        if (wirq && (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED))
 263                disable_irq_nosync(wirq->irq);
 264}
 265EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
 266
 267/**
 268 * dev_pm_enable_wake_irq_check - Checks and enables wake-up interrupt
 269 * @dev: Device
 270 * @can_change_status: Can change wake-up interrupt status
 271 *
 272 * Enables wakeirq conditionally. We need to enable wake-up interrupt
 273 * lazily on the first rpm_suspend(). This is needed as the consumer device
 274 * starts in RPM_SUSPENDED state, and the the first pm_runtime_get() would
 275 * otherwise try to disable already disabled wakeirq. The wake-up interrupt
 276 * starts disabled with IRQ_NOAUTOEN set.
 277 *
 278 * Should be only called from rpm_suspend() and rpm_resume() path.
 279 * Caller must hold &dev->power.lock to change wirq->status
 280 */
 281void dev_pm_enable_wake_irq_check(struct device *dev,
 282                                  bool can_change_status)
 283{
 284        struct wake_irq *wirq = dev->power.wakeirq;
 285
 286        if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
 287                return;
 288
 289        if (likely(wirq->status & WAKE_IRQ_DEDICATED_MANAGED)) {
 290                goto enable;
 291        } else if (can_change_status) {
 292                wirq->status |= WAKE_IRQ_DEDICATED_MANAGED;
 293                goto enable;
 294        }
 295
 296        return;
 297
 298enable:
 299        enable_irq(wirq->irq);
 300}
 301
 302/**
 303 * dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt
 304 * @dev: Device
 305 *
 306 * Disables wake-up interrupt conditionally based on status.
 307 * Should be only called from rpm_suspend() and rpm_resume() path.
 308 */
 309void dev_pm_disable_wake_irq_check(struct device *dev)
 310{
 311        struct wake_irq *wirq = dev->power.wakeirq;
 312
 313        if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
 314                return;
 315
 316        if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED)
 317                disable_irq_nosync(wirq->irq);
 318}
 319
 320/**
 321 * dev_pm_arm_wake_irq - Arm device wake-up
 322 * @wirq: Device wake-up interrupt
 323 *
 324 * Sets up the wake-up event conditionally based on the
 325 * device_may_wake().
 326 */
 327void dev_pm_arm_wake_irq(struct wake_irq *wirq)
 328{
 329        if (!wirq)
 330                return;
 331
 332        if (device_may_wakeup(wirq->dev)) {
 333                if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
 334                    !pm_runtime_status_suspended(wirq->dev))
 335                        enable_irq(wirq->irq);
 336
 337                enable_irq_wake(wirq->irq);
 338        }
 339}
 340
 341/**
 342 * dev_pm_disarm_wake_irq - Disarm device wake-up
 343 * @wirq: Device wake-up interrupt
 344 *
 345 * Clears up the wake-up event conditionally based on the
 346 * device_may_wake().
 347 */
 348void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
 349{
 350        if (!wirq)
 351                return;
 352
 353        if (device_may_wakeup(wirq->dev)) {
 354                disable_irq_wake(wirq->irq);
 355
 356                if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
 357                    !pm_runtime_status_suspended(wirq->dev))
 358                        disable_irq_nosync(wirq->irq);
 359        }
 360}
 361