| .. | .. |
|---|
| 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. |
|---|