@@ -468,10 +468,16 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
* @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
* @irq_cpu_online: configure an interrupt source for a secondary CPU
* @irq_cpu_offline: un-configure an interrupt source for a secondary CPU
+ * @irq_suspend_one: called on an every irq to suspend it; called even if
+ * this IRQ is configured for wakeup
+ * @irq_resume_one: called on an every irq to resume it; called even if
+ * this IRQ is configured for wakeup
* @irq_suspend: function called from core code on suspend once per
- * chip, when one or more interrupts are installed
+ * chip, when one or more interrupts are installed;
+ * only works if using irq/generic-chip
* @irq_resume: function called from core code on resume once per chip,
- * when one ore more interrupts are installed
+ * when one ore more interrupts are installed;
+ * only works if using irq/generic-chip
* @irq_pm_shutdown: function called from core code on shutdown once per chip
* @irq_calc_mask: Optional function to set irq_data.mask for special cases
* @irq_print_chip: optional to print special chip info in show_interrupts
@@ -515,6 +521,9 @@ struct irq_chip {
void (*irq_cpu_online)(struct irq_data *data);
void (*irq_cpu_offline)(struct irq_data *data);
+ void (*irq_suspend_one)(struct irq_data *data);
+ void (*irq_resume_one)(struct irq_data *data);
+
void (*irq_suspend)(struct irq_data *data);
void (*irq_resume)(struct irq_data *data);
void (*irq_pm_shutdown)(struct irq_data *data);
@@ -447,6 +447,22 @@ void unmask_threaded_irq(struct irq_desc *desc)
unmask_irq(desc);
}
+void suspend_one_irq(struct irq_desc *desc)
+{
+ struct irq_chip *chip = desc->irq_data.chip;
+
+ if (chip->irq_suspend_one)
+ chip->irq_suspend_one(&desc->irq_data);
+}
+
+void resume_one_irq(struct irq_desc *desc)
+{
+ struct irq_chip *chip = desc->irq_data.chip;
+
+ if (chip->irq_resume_one)
+ chip->irq_resume_one(&desc->irq_data);
+}
+
/*
* handle_nested_irq - Handle a nested irq from a irq thread
* @irq: the interrupt number
@@ -90,6 +90,8 @@ extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
extern void mask_irq(struct irq_desc *desc);
extern void unmask_irq(struct irq_desc *desc);
extern void unmask_threaded_irq(struct irq_desc *desc);
+extern void suspend_one_irq(struct irq_desc *desc);
+extern void resume_one_irq(struct irq_desc *desc);
#ifdef CONFIG_SPARSE_IRQ
static inline void irq_mark_irq(unsigned int irq) { }
@@ -69,19 +69,23 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
static bool suspend_device_irq(struct irq_desc *desc)
{
+ bool sync = false;
+
if (!desc->action || irq_desc_is_chained(desc) ||
desc->no_suspend_depth)
- return false;
+ goto exit;
if (irqd_is_wakeup_set(&desc->irq_data)) {
irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);
+
/*
* We return true here to force the caller to issue
* synchronize_irq(). We need to make sure that the
* IRQD_WAKEUP_ARMED is visible before we return from
* suspend_device_irqs().
*/
- return true;
+ sync = true;
+ goto exit;
}
desc->istate |= IRQS_SUSPENDED;
@@ -95,7 +99,10 @@ static bool suspend_device_irq(struct irq_desc *desc)
*/
if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
mask_irq(desc);
- return true;
+
+exit:
+ suspend_one_irq(desc);
+ return sync;
}
/**
@@ -137,6 +144,8 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs);
static void resume_irq(struct irq_desc *desc)
{
+ resume_one_irq(desc);
+
irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED);
if (desc->istate & IRQS_SUSPENDED)