]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/irq/manage.c
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[linux-2.6-omap-h63xx.git] / kernel / irq / manage.c
index 4e461438e48bfe687f4ced338a0f2c69791fb33e..92be519eff26fe3fd467eb6ca0e3e063a36f50ce 100644 (file)
@@ -137,16 +137,40 @@ EXPORT_SYMBOL(enable_irq);
  *     @irq:   interrupt to control
  *     @on:    enable/disable power management wakeup
  *
- *     Enable/disable power management wakeup mode
+ *     Enable/disable power management wakeup mode, which is
+ *     disabled by default.  Enables and disables must match,
+ *     just as they match for non-wakeup mode support.
+ *
+ *     Wakeup mode lets this IRQ wake the system from sleep
+ *     states like "suspend to RAM".
  */
 int set_irq_wake(unsigned int irq, unsigned int on)
 {
        struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
        int ret = -ENXIO;
+       int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake;
 
+       /* wakeup-capable irqs can be shared between drivers that
+        * don't need to have the same sleep mode behaviors.
+        */
        spin_lock_irqsave(&desc->lock, flags);
-       if (desc->chip->set_wake)
+       if (on) {
+               if (desc->wake_depth++ == 0)
+                       desc->status |= IRQ_WAKEUP;
+               else
+                       set_wake = NULL;
+       } else {
+               if (desc->wake_depth == 0) {
+                       printk(KERN_WARNING "Unbalanced IRQ %d "
+                                       "wake disable\n", irq);
+                       WARN_ON(1);
+               } else if (--desc->wake_depth == 0)
+                       desc->status &= ~IRQ_WAKEUP;
+               else
+                       set_wake = NULL;
+       }
+       if (set_wake)
                ret = desc->chip->set_wake(irq, on);
        spin_unlock_irqrestore(&desc->lock, flags);
        return ret;