.. | .. |
---|
69 | 69 | |
---|
70 | 70 | static bool suspend_device_irq(struct irq_desc *desc) |
---|
71 | 71 | { |
---|
| 72 | + unsigned long chipflags = irq_desc_get_chip(desc)->flags; |
---|
| 73 | + struct irq_data *irqd = &desc->irq_data; |
---|
| 74 | + |
---|
72 | 75 | if (!desc->action || irq_desc_is_chained(desc) || |
---|
73 | 76 | desc->no_suspend_depth) |
---|
74 | 77 | return false; |
---|
75 | 78 | |
---|
76 | | - if (irqd_is_wakeup_set(&desc->irq_data)) { |
---|
77 | | - irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED); |
---|
| 79 | + if (irqd_is_wakeup_set(irqd)) { |
---|
| 80 | + irqd_set(irqd, IRQD_WAKEUP_ARMED); |
---|
| 81 | + |
---|
| 82 | + if ((chipflags & IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND) && |
---|
| 83 | + irqd_irq_disabled(irqd)) { |
---|
| 84 | + /* |
---|
| 85 | + * Interrupt marked for wakeup is in disabled state. |
---|
| 86 | + * Enable interrupt here to unmask/enable in irqchip |
---|
| 87 | + * to be able to resume with such interrupts. |
---|
| 88 | + */ |
---|
| 89 | + __enable_irq(desc); |
---|
| 90 | + irqd_set(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND); |
---|
| 91 | + } |
---|
78 | 92 | /* |
---|
79 | 93 | * We return true here to force the caller to issue |
---|
80 | 94 | * synchronize_irq(). We need to make sure that the |
---|
.. | .. |
---|
93 | 107 | * chip level. The chip implementation indicates that with |
---|
94 | 108 | * IRQCHIP_MASK_ON_SUSPEND. |
---|
95 | 109 | */ |
---|
96 | | - if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND) |
---|
| 110 | + if (chipflags & IRQCHIP_MASK_ON_SUSPEND) |
---|
97 | 111 | mask_irq(desc); |
---|
98 | 112 | return true; |
---|
99 | 113 | } |
---|
.. | .. |
---|
137 | 151 | |
---|
138 | 152 | static void resume_irq(struct irq_desc *desc) |
---|
139 | 153 | { |
---|
140 | | - irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); |
---|
| 154 | + struct irq_data *irqd = &desc->irq_data; |
---|
| 155 | + |
---|
| 156 | + irqd_clear(irqd, IRQD_WAKEUP_ARMED); |
---|
| 157 | + |
---|
| 158 | + if (irqd_is_enabled_on_suspend(irqd)) { |
---|
| 159 | + /* |
---|
| 160 | + * Interrupt marked for wakeup was enabled during suspend |
---|
| 161 | + * entry. Disable such interrupts to restore them back to |
---|
| 162 | + * original state. |
---|
| 163 | + */ |
---|
| 164 | + __disable_irq(desc); |
---|
| 165 | + irqd_clear(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND); |
---|
| 166 | + } |
---|
141 | 167 | |
---|
142 | 168 | if (desc->istate & IRQS_SUSPENDED) |
---|
143 | 169 | goto resume; |
---|
.. | .. |
---|
177 | 203 | } |
---|
178 | 204 | |
---|
179 | 205 | /** |
---|
| 206 | + * rearm_wake_irq - rearm a wakeup interrupt line after signaling wakeup |
---|
| 207 | + * @irq: Interrupt to rearm |
---|
| 208 | + */ |
---|
| 209 | +void rearm_wake_irq(unsigned int irq) |
---|
| 210 | +{ |
---|
| 211 | + unsigned long flags; |
---|
| 212 | + struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
---|
| 213 | + |
---|
| 214 | + if (!desc) |
---|
| 215 | + return; |
---|
| 216 | + |
---|
| 217 | + if (!(desc->istate & IRQS_SUSPENDED) || |
---|
| 218 | + !irqd_is_wakeup_set(&desc->irq_data)) |
---|
| 219 | + goto unlock; |
---|
| 220 | + |
---|
| 221 | + desc->istate &= ~IRQS_SUSPENDED; |
---|
| 222 | + irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED); |
---|
| 223 | + __enable_irq(desc); |
---|
| 224 | + |
---|
| 225 | +unlock: |
---|
| 226 | + irq_put_desc_busunlock(desc, flags); |
---|
| 227 | +} |
---|
| 228 | + |
---|
| 229 | +/** |
---|
180 | 230 | * irq_pm_syscore_ops - enable interrupt lines early |
---|
181 | 231 | * |
---|
182 | 232 | * Enable all interrupt lines with %IRQF_EARLY_RESUME set. |
---|