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