diff options
| author | Ludovic Barre <ludovic.barre@st.com> | 2018-04-26 12:18:27 -0400 |
|---|---|---|
| committer | Marc Zyngier <marc.zyngier@arm.com> | 2018-05-24 07:38:20 -0400 |
| commit | d9e2b19b02744068b1cc16ca7d5249a62e789601 (patch) | |
| tree | 2b9b363d6174e550c665a1f3173418aa0897eff1 | |
| parent | be6230f0c2bd5d2fe7530d04d015d454f235f21d (diff) | |
irqchip/stm32: Add suspend support
This patch adds suspend feature.
-Use default irq_set_wake function to store wakeup request.
-Suspend function set wake_active into imr of each bank
and save rising/falling trigger registers.
-Resume function restore the mask_cache interrupt into
imr of each bank and restore rising/falling trigger registers.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
| -rw-r--r-- | drivers/irqchip/irq-stm32-exti.c | 69 |
1 files changed, 52 insertions, 17 deletions
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 69a4453c2952..1e0966714e83 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c | |||
| @@ -29,6 +29,14 @@ struct stm32_exti_bank { | |||
| 29 | 29 | ||
| 30 | #define UNDEF_REG ~0 | 30 | #define UNDEF_REG ~0 |
| 31 | 31 | ||
| 32 | struct stm32_exti_chip_data { | ||
| 33 | const struct stm32_exti_bank *reg_bank; | ||
| 34 | u32 rtsr_cache; | ||
| 35 | u32 ftsr_cache; | ||
| 36 | }; | ||
| 37 | |||
| 38 | static struct stm32_exti_chip_data *stm32_exti_data; | ||
| 39 | |||
| 32 | static const struct stm32_exti_bank stm32f4xx_exti_b1 = { | 40 | static const struct stm32_exti_bank stm32f4xx_exti_b1 = { |
| 33 | .imr_ofst = 0x00, | 41 | .imr_ofst = 0x00, |
| 34 | .emr_ofst = 0x04, | 42 | .emr_ofst = 0x04, |
| @@ -81,7 +89,8 @@ static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { | |||
| 81 | 89 | ||
| 82 | static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) | 90 | static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) |
| 83 | { | 91 | { |
| 84 | const struct stm32_exti_bank *stm32_bank = gc->private; | 92 | struct stm32_exti_chip_data *chip_data = gc->private; |
| 93 | const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; | ||
| 85 | unsigned long pending; | 94 | unsigned long pending; |
| 86 | 95 | ||
| 87 | pending = irq_reg_readl(gc, stm32_bank->rpr_ofst); | 96 | pending = irq_reg_readl(gc, stm32_bank->rpr_ofst); |
| @@ -119,7 +128,8 @@ static void stm32_irq_handler(struct irq_desc *desc) | |||
| 119 | static int stm32_irq_set_type(struct irq_data *data, unsigned int type) | 128 | static int stm32_irq_set_type(struct irq_data *data, unsigned int type) |
| 120 | { | 129 | { |
| 121 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); | 130 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); |
| 122 | const struct stm32_exti_bank *stm32_bank = gc->private; | 131 | struct stm32_exti_chip_data *chip_data = gc->private; |
| 132 | const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; | ||
| 123 | int pin = data->hwirq % IRQS_PER_BANK; | 133 | int pin = data->hwirq % IRQS_PER_BANK; |
| 124 | u32 rtsr, ftsr; | 134 | u32 rtsr, ftsr; |
| 125 | 135 | ||
| @@ -154,25 +164,36 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) | |||
| 154 | return 0; | 164 | return 0; |
| 155 | } | 165 | } |
| 156 | 166 | ||
| 157 | static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) | 167 | static void stm32_irq_suspend(struct irq_chip_generic *gc) |
| 158 | { | 168 | { |
| 159 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); | 169 | struct stm32_exti_chip_data *chip_data = gc->private; |
| 160 | const struct stm32_exti_bank *stm32_bank = gc->private; | 170 | const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; |
| 161 | int pin = data->hwirq % IRQS_PER_BANK; | ||
| 162 | u32 imr; | ||
| 163 | 171 | ||
| 164 | irq_gc_lock(gc); | 172 | irq_gc_lock(gc); |
| 165 | 173 | ||
| 166 | imr = irq_reg_readl(gc, stm32_bank->imr_ofst); | 174 | /* save rtsr, ftsr registers */ |
| 167 | if (on) | 175 | chip_data->rtsr_cache = irq_reg_readl(gc, stm32_bank->rtsr_ofst); |
| 168 | imr |= BIT(pin); | 176 | chip_data->ftsr_cache = irq_reg_readl(gc, stm32_bank->ftsr_ofst); |
| 169 | else | 177 | |
| 170 | imr &= ~BIT(pin); | 178 | irq_reg_writel(gc, gc->wake_active, stm32_bank->imr_ofst); |
| 171 | irq_reg_writel(gc, imr, stm32_bank->imr_ofst); | ||
| 172 | 179 | ||
| 173 | irq_gc_unlock(gc); | 180 | irq_gc_unlock(gc); |
| 181 | } | ||
| 174 | 182 | ||
| 175 | return 0; | 183 | static void stm32_irq_resume(struct irq_chip_generic *gc) |
| 184 | { | ||
| 185 | struct stm32_exti_chip_data *chip_data = gc->private; | ||
| 186 | const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; | ||
| 187 | |||
| 188 | irq_gc_lock(gc); | ||
| 189 | |||
| 190 | /* restore rtsr, ftsr registers */ | ||
| 191 | irq_reg_writel(gc, chip_data->rtsr_cache, stm32_bank->rtsr_ofst); | ||
| 192 | irq_reg_writel(gc, chip_data->ftsr_cache, stm32_bank->ftsr_ofst); | ||
| 193 | |||
| 194 | irq_reg_writel(gc, gc->mask_cache, stm32_bank->imr_ofst); | ||
| 195 | |||
| 196 | irq_gc_unlock(gc); | ||
| 176 | } | 197 | } |
| 177 | 198 | ||
| 178 | static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, | 199 | static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, |
| @@ -205,7 +226,8 @@ static const struct irq_domain_ops irq_exti_domain_ops = { | |||
| 205 | static void stm32_irq_ack(struct irq_data *d) | 226 | static void stm32_irq_ack(struct irq_data *d) |
| 206 | { | 227 | { |
| 207 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | 228 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
| 208 | const struct stm32_exti_bank *stm32_bank = gc->private; | 229 | struct stm32_exti_chip_data *chip_data = gc->private; |
| 230 | const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; | ||
| 209 | 231 | ||
| 210 | irq_gc_lock(gc); | 232 | irq_gc_lock(gc); |
| 211 | 233 | ||
| @@ -232,6 +254,11 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, | |||
| 232 | return -ENOMEM; | 254 | return -ENOMEM; |
| 233 | } | 255 | } |
| 234 | 256 | ||
| 257 | stm32_exti_data = kcalloc(bank_nr, sizeof(*stm32_exti_data), | ||
| 258 | GFP_KERNEL); | ||
| 259 | if (!stm32_exti_data) | ||
| 260 | return -ENOMEM; | ||
| 261 | |||
| 235 | domain = irq_domain_add_linear(node, bank_nr * IRQS_PER_BANK, | 262 | domain = irq_domain_add_linear(node, bank_nr * IRQS_PER_BANK, |
| 236 | &irq_exti_domain_ops, NULL); | 263 | &irq_exti_domain_ops, NULL); |
| 237 | if (!domain) { | 264 | if (!domain) { |
| @@ -251,8 +278,11 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, | |||
| 251 | 278 | ||
| 252 | for (i = 0; i < bank_nr; i++) { | 279 | for (i = 0; i < bank_nr; i++) { |
| 253 | const struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; | 280 | const struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; |
| 281 | struct stm32_exti_chip_data *chip_data = &stm32_exti_data[i]; | ||
| 254 | u32 irqs_mask; | 282 | u32 irqs_mask; |
| 255 | 283 | ||
| 284 | chip_data->reg_bank = stm32_bank; | ||
| 285 | |||
| 256 | gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); | 286 | gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); |
| 257 | 287 | ||
| 258 | gc->reg_base = base; | 288 | gc->reg_base = base; |
| @@ -261,9 +291,13 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, | |||
| 261 | gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; | 291 | gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; |
| 262 | gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; | 292 | gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; |
| 263 | gc->chip_types->chip.irq_set_type = stm32_irq_set_type; | 293 | gc->chip_types->chip.irq_set_type = stm32_irq_set_type; |
| 264 | gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; | 294 | gc->chip_types->chip.irq_set_wake = irq_gc_set_wake; |
| 295 | gc->suspend = stm32_irq_suspend; | ||
| 296 | gc->resume = stm32_irq_resume; | ||
| 297 | gc->wake_enabled = IRQ_MSK(IRQS_PER_BANK); | ||
| 298 | |||
| 265 | gc->chip_types->regs.mask = stm32_bank->imr_ofst; | 299 | gc->chip_types->regs.mask = stm32_bank->imr_ofst; |
| 266 | gc->private = (void *)stm32_bank; | 300 | gc->private = (void *)chip_data; |
| 267 | 301 | ||
| 268 | /* Determine number of irqs supported */ | 302 | /* Determine number of irqs supported */ |
| 269 | writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); | 303 | writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); |
| @@ -300,6 +334,7 @@ out_free_domain: | |||
| 300 | irq_domain_remove(domain); | 334 | irq_domain_remove(domain); |
| 301 | out_unmap: | 335 | out_unmap: |
| 302 | iounmap(base); | 336 | iounmap(base); |
| 337 | kfree(stm32_exti_data); | ||
| 303 | return ret; | 338 | return ret; |
| 304 | } | 339 | } |
| 305 | 340 | ||
