18de50dc2SBenjamin Gaignard // SPDX-License-Identifier: GPL-2.0
2e0720416SAlexandre TORGUE /*
3e0720416SAlexandre TORGUE * Copyright (C) Maxime Coquelin 2015
48de50dc2SBenjamin Gaignard * Copyright (C) STMicroelectronics 2017
5e0720416SAlexandre TORGUE * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
6e0720416SAlexandre TORGUE */
7e0720416SAlexandre TORGUE
8e0720416SAlexandre TORGUE #include <linux/bitops.h>
9fb94109bSBenjamin Gaignard #include <linux/delay.h>
10fb94109bSBenjamin Gaignard #include <linux/hwspinlock.h>
11e0720416SAlexandre TORGUE #include <linux/interrupt.h>
12e0720416SAlexandre TORGUE #include <linux/io.h>
13e0720416SAlexandre TORGUE #include <linux/irq.h>
14e0720416SAlexandre TORGUE #include <linux/irqchip.h>
15e0720416SAlexandre TORGUE #include <linux/irqchip/chained_irq.h>
16e0720416SAlexandre TORGUE #include <linux/irqdomain.h>
17ee076750SRob Herring #include <linux/mod_devicetable.h>
18cfbf9e49SFabien Dessenne #include <linux/module.h>
19e0720416SAlexandre TORGUE #include <linux/of_address.h>
20e0720416SAlexandre TORGUE #include <linux/of_irq.h>
21ee076750SRob Herring #include <linux/platform_device.h>
2273958b31SLudovic Barre #include <linux/syscore_ops.h>
23e0720416SAlexandre TORGUE
24927abfc4SLudovic Barre #include <dt-bindings/interrupt-controller/arm-gic.h>
25927abfc4SLudovic Barre
266dd64ee1SLudovic Barre #define IRQS_PER_BANK 32
276dd64ee1SLudovic Barre
28fb94109bSBenjamin Gaignard #define HWSPNLCK_TIMEOUT 1000 /* usec */
29fb94109bSBenjamin Gaignard
306dd64ee1SLudovic Barre struct stm32_exti_bank {
316dd64ee1SLudovic Barre u32 imr_ofst;
326dd64ee1SLudovic Barre u32 emr_ofst;
336dd64ee1SLudovic Barre u32 rtsr_ofst;
346dd64ee1SLudovic Barre u32 ftsr_ofst;
356dd64ee1SLudovic Barre u32 swier_ofst;
36be6230f0SLudovic Barre u32 rpr_ofst;
37be6230f0SLudovic Barre u32 fpr_ofst;
38ce4ef8f9SAntonio Borneo u32 trg_ofst;
396dd64ee1SLudovic Barre };
406dd64ee1SLudovic Barre
41be6230f0SLudovic Barre #define UNDEF_REG ~0
42be6230f0SLudovic Barre
43f9fc1745SLudovic Barre struct stm32_exti_drv_data {
44f9fc1745SLudovic Barre const struct stm32_exti_bank **exti_banks;
45c2974933SAntonio Borneo const u8 *desc_irqs;
46f9fc1745SLudovic Barre u32 bank_nr;
47f9fc1745SLudovic Barre };
48f9fc1745SLudovic Barre
49d9e2b19bSLudovic Barre struct stm32_exti_chip_data {
50f9fc1745SLudovic Barre struct stm32_exti_host_data *host_data;
51d9e2b19bSLudovic Barre const struct stm32_exti_bank *reg_bank;
52927abfc4SLudovic Barre struct raw_spinlock rlock;
53927abfc4SLudovic Barre u32 wake_active;
54927abfc4SLudovic Barre u32 mask_cache;
55d9e2b19bSLudovic Barre u32 rtsr_cache;
56d9e2b19bSLudovic Barre u32 ftsr_cache;
57d9e2b19bSLudovic Barre };
58d9e2b19bSLudovic Barre
59f9fc1745SLudovic Barre struct stm32_exti_host_data {
60f9fc1745SLudovic Barre void __iomem *base;
61f9fc1745SLudovic Barre struct stm32_exti_chip_data *chips_data;
62f9fc1745SLudovic Barre const struct stm32_exti_drv_data *drv_data;
63fb94109bSBenjamin Gaignard struct hwspinlock *hwlock;
64f9fc1745SLudovic Barre };
65d9e2b19bSLudovic Barre
6673958b31SLudovic Barre static struct stm32_exti_host_data *stm32_host_data;
6773958b31SLudovic Barre
686dd64ee1SLudovic Barre static const struct stm32_exti_bank stm32f4xx_exti_b1 = {
696dd64ee1SLudovic Barre .imr_ofst = 0x00,
706dd64ee1SLudovic Barre .emr_ofst = 0x04,
716dd64ee1SLudovic Barre .rtsr_ofst = 0x08,
726dd64ee1SLudovic Barre .ftsr_ofst = 0x0C,
736dd64ee1SLudovic Barre .swier_ofst = 0x10,
74be6230f0SLudovic Barre .rpr_ofst = 0x14,
75be6230f0SLudovic Barre .fpr_ofst = UNDEF_REG,
76ce4ef8f9SAntonio Borneo .trg_ofst = UNDEF_REG,
776dd64ee1SLudovic Barre };
786dd64ee1SLudovic Barre
796dd64ee1SLudovic Barre static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = {
806dd64ee1SLudovic Barre &stm32f4xx_exti_b1,
816dd64ee1SLudovic Barre };
826dd64ee1SLudovic Barre
83f9fc1745SLudovic Barre static const struct stm32_exti_drv_data stm32f4xx_drv_data = {
84f9fc1745SLudovic Barre .exti_banks = stm32f4xx_exti_banks,
85f9fc1745SLudovic Barre .bank_nr = ARRAY_SIZE(stm32f4xx_exti_banks),
86f9fc1745SLudovic Barre };
87f9fc1745SLudovic Barre
88539c603eSLudovic Barre static const struct stm32_exti_bank stm32h7xx_exti_b1 = {
89539c603eSLudovic Barre .imr_ofst = 0x80,
90539c603eSLudovic Barre .emr_ofst = 0x84,
91539c603eSLudovic Barre .rtsr_ofst = 0x00,
92539c603eSLudovic Barre .ftsr_ofst = 0x04,
93539c603eSLudovic Barre .swier_ofst = 0x08,
94be6230f0SLudovic Barre .rpr_ofst = 0x88,
95be6230f0SLudovic Barre .fpr_ofst = UNDEF_REG,
96ce4ef8f9SAntonio Borneo .trg_ofst = UNDEF_REG,
97539c603eSLudovic Barre };
98539c603eSLudovic Barre
99539c603eSLudovic Barre static const struct stm32_exti_bank stm32h7xx_exti_b2 = {
100539c603eSLudovic Barre .imr_ofst = 0x90,
101539c603eSLudovic Barre .emr_ofst = 0x94,
102539c603eSLudovic Barre .rtsr_ofst = 0x20,
103539c603eSLudovic Barre .ftsr_ofst = 0x24,
104539c603eSLudovic Barre .swier_ofst = 0x28,
105be6230f0SLudovic Barre .rpr_ofst = 0x98,
106be6230f0SLudovic Barre .fpr_ofst = UNDEF_REG,
107ce4ef8f9SAntonio Borneo .trg_ofst = UNDEF_REG,
108539c603eSLudovic Barre };
109539c603eSLudovic Barre
110539c603eSLudovic Barre static const struct stm32_exti_bank stm32h7xx_exti_b3 = {
111539c603eSLudovic Barre .imr_ofst = 0xA0,
112539c603eSLudovic Barre .emr_ofst = 0xA4,
113539c603eSLudovic Barre .rtsr_ofst = 0x40,
114539c603eSLudovic Barre .ftsr_ofst = 0x44,
115539c603eSLudovic Barre .swier_ofst = 0x48,
116be6230f0SLudovic Barre .rpr_ofst = 0xA8,
117be6230f0SLudovic Barre .fpr_ofst = UNDEF_REG,
118ce4ef8f9SAntonio Borneo .trg_ofst = UNDEF_REG,
119539c603eSLudovic Barre };
120539c603eSLudovic Barre
121539c603eSLudovic Barre static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = {
122539c603eSLudovic Barre &stm32h7xx_exti_b1,
123539c603eSLudovic Barre &stm32h7xx_exti_b2,
124539c603eSLudovic Barre &stm32h7xx_exti_b3,
125539c603eSLudovic Barre };
126539c603eSLudovic Barre
127f9fc1745SLudovic Barre static const struct stm32_exti_drv_data stm32h7xx_drv_data = {
128f9fc1745SLudovic Barre .exti_banks = stm32h7xx_exti_banks,
129f9fc1745SLudovic Barre .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks),
130f9fc1745SLudovic Barre };
131f9fc1745SLudovic Barre
132927abfc4SLudovic Barre static const struct stm32_exti_bank stm32mp1_exti_b1 = {
133927abfc4SLudovic Barre .imr_ofst = 0x80,
134b38040f0SAlexandre Torgue .emr_ofst = UNDEF_REG,
135927abfc4SLudovic Barre .rtsr_ofst = 0x00,
136927abfc4SLudovic Barre .ftsr_ofst = 0x04,
137927abfc4SLudovic Barre .swier_ofst = 0x08,
138927abfc4SLudovic Barre .rpr_ofst = 0x0C,
139927abfc4SLudovic Barre .fpr_ofst = 0x10,
140ce4ef8f9SAntonio Borneo .trg_ofst = 0x3EC,
141927abfc4SLudovic Barre };
142927abfc4SLudovic Barre
143927abfc4SLudovic Barre static const struct stm32_exti_bank stm32mp1_exti_b2 = {
144927abfc4SLudovic Barre .imr_ofst = 0x90,
145b38040f0SAlexandre Torgue .emr_ofst = UNDEF_REG,
146927abfc4SLudovic Barre .rtsr_ofst = 0x20,
147927abfc4SLudovic Barre .ftsr_ofst = 0x24,
148927abfc4SLudovic Barre .swier_ofst = 0x28,
149927abfc4SLudovic Barre .rpr_ofst = 0x2C,
150927abfc4SLudovic Barre .fpr_ofst = 0x30,
151ce4ef8f9SAntonio Borneo .trg_ofst = 0x3E8,
152927abfc4SLudovic Barre };
153927abfc4SLudovic Barre
154927abfc4SLudovic Barre static const struct stm32_exti_bank stm32mp1_exti_b3 = {
155927abfc4SLudovic Barre .imr_ofst = 0xA0,
156b38040f0SAlexandre Torgue .emr_ofst = UNDEF_REG,
157927abfc4SLudovic Barre .rtsr_ofst = 0x40,
158927abfc4SLudovic Barre .ftsr_ofst = 0x44,
159927abfc4SLudovic Barre .swier_ofst = 0x48,
160927abfc4SLudovic Barre .rpr_ofst = 0x4C,
161927abfc4SLudovic Barre .fpr_ofst = 0x50,
162ce4ef8f9SAntonio Borneo .trg_ofst = 0x3E4,
163927abfc4SLudovic Barre };
164927abfc4SLudovic Barre
165927abfc4SLudovic Barre static const struct stm32_exti_bank *stm32mp1_exti_banks[] = {
166927abfc4SLudovic Barre &stm32mp1_exti_b1,
167927abfc4SLudovic Barre &stm32mp1_exti_b2,
168927abfc4SLudovic Barre &stm32mp1_exti_b3,
169927abfc4SLudovic Barre };
170927abfc4SLudovic Barre
1719d6a5fe1SAlexandre Torgue static struct irq_chip stm32_exti_h_chip;
1729d6a5fe1SAlexandre Torgue static struct irq_chip stm32_exti_h_chip_direct;
1739d6a5fe1SAlexandre Torgue
174c2974933SAntonio Borneo #define EXTI_INVALID_IRQ U8_MAX
175c2974933SAntonio Borneo #define STM32MP1_DESC_IRQ_SIZE (ARRAY_SIZE(stm32mp1_exti_banks) * IRQS_PER_BANK)
176c2974933SAntonio Borneo
17748f31e49SAntonio Borneo /*
17848f31e49SAntonio Borneo * Use some intentionally tricky logic here to initialize the whole array to
17948f31e49SAntonio Borneo * EXTI_INVALID_IRQ, but then override certain fields, requiring us to indicate
18048f31e49SAntonio Borneo * that we "know" that there are overrides in this structure, and we'll need to
18148f31e49SAntonio Borneo * disable that warning from W=1 builds.
18248f31e49SAntonio Borneo */
18348f31e49SAntonio Borneo __diag_push();
18448f31e49SAntonio Borneo __diag_ignore_all("-Woverride-init",
18548f31e49SAntonio Borneo "logic to initialize all and then override some is OK");
18648f31e49SAntonio Borneo
187c2974933SAntonio Borneo static const u8 stm32mp1_desc_irq[] = {
188c2974933SAntonio Borneo /* default value */
189c2974933SAntonio Borneo [0 ... (STM32MP1_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ,
190c2974933SAntonio Borneo
191c2974933SAntonio Borneo [0] = 6,
192c2974933SAntonio Borneo [1] = 7,
193c2974933SAntonio Borneo [2] = 8,
194c2974933SAntonio Borneo [3] = 9,
195c2974933SAntonio Borneo [4] = 10,
196c2974933SAntonio Borneo [5] = 23,
197c2974933SAntonio Borneo [6] = 64,
198c2974933SAntonio Borneo [7] = 65,
199c2974933SAntonio Borneo [8] = 66,
200c2974933SAntonio Borneo [9] = 67,
201c2974933SAntonio Borneo [10] = 40,
202c2974933SAntonio Borneo [11] = 42,
203c2974933SAntonio Borneo [12] = 76,
204c2974933SAntonio Borneo [13] = 77,
205c2974933SAntonio Borneo [14] = 121,
206c2974933SAntonio Borneo [15] = 127,
207c2974933SAntonio Borneo [16] = 1,
208c2974933SAntonio Borneo [19] = 3,
209c2974933SAntonio Borneo [21] = 31,
210c2974933SAntonio Borneo [22] = 33,
211c2974933SAntonio Borneo [23] = 72,
212c2974933SAntonio Borneo [24] = 95,
213c2974933SAntonio Borneo [25] = 107,
214c2974933SAntonio Borneo [26] = 37,
215c2974933SAntonio Borneo [27] = 38,
216c2974933SAntonio Borneo [28] = 39,
217c2974933SAntonio Borneo [29] = 71,
218c2974933SAntonio Borneo [30] = 52,
219c2974933SAntonio Borneo [31] = 53,
220c2974933SAntonio Borneo [32] = 82,
221c2974933SAntonio Borneo [33] = 83,
2221c518796SMarek Vasut [46] = 151,
223c2974933SAntonio Borneo [47] = 93,
224c2974933SAntonio Borneo [48] = 138,
225c2974933SAntonio Borneo [50] = 139,
226c2974933SAntonio Borneo [52] = 140,
227c2974933SAntonio Borneo [53] = 141,
228c2974933SAntonio Borneo [54] = 135,
229c2974933SAntonio Borneo [61] = 100,
230c2974933SAntonio Borneo [65] = 144,
231c2974933SAntonio Borneo [68] = 143,
232c2974933SAntonio Borneo [70] = 62,
233c2974933SAntonio Borneo [73] = 129,
234927abfc4SLudovic Barre };
235927abfc4SLudovic Barre
236c2974933SAntonio Borneo static const u8 stm32mp13_desc_irq[] = {
237c2974933SAntonio Borneo /* default value */
238c2974933SAntonio Borneo [0 ... (STM32MP1_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ,
239c2974933SAntonio Borneo
240c2974933SAntonio Borneo [0] = 6,
241c2974933SAntonio Borneo [1] = 7,
242c2974933SAntonio Borneo [2] = 8,
243c2974933SAntonio Borneo [3] = 9,
244c2974933SAntonio Borneo [4] = 10,
245c2974933SAntonio Borneo [5] = 24,
246c2974933SAntonio Borneo [6] = 65,
247c2974933SAntonio Borneo [7] = 66,
248c2974933SAntonio Borneo [8] = 67,
249c2974933SAntonio Borneo [9] = 68,
250c2974933SAntonio Borneo [10] = 41,
251c2974933SAntonio Borneo [11] = 43,
252c2974933SAntonio Borneo [12] = 77,
253c2974933SAntonio Borneo [13] = 78,
254c2974933SAntonio Borneo [14] = 106,
255c2974933SAntonio Borneo [15] = 109,
256c2974933SAntonio Borneo [16] = 1,
257c2974933SAntonio Borneo [19] = 3,
258c2974933SAntonio Borneo [21] = 32,
259c2974933SAntonio Borneo [22] = 34,
260c2974933SAntonio Borneo [23] = 73,
261c2974933SAntonio Borneo [24] = 93,
262c2974933SAntonio Borneo [25] = 114,
263c2974933SAntonio Borneo [26] = 38,
264c2974933SAntonio Borneo [27] = 39,
265c2974933SAntonio Borneo [28] = 40,
266c2974933SAntonio Borneo [29] = 72,
267c2974933SAntonio Borneo [30] = 53,
268c2974933SAntonio Borneo [31] = 54,
269c2974933SAntonio Borneo [32] = 83,
270c2974933SAntonio Borneo [33] = 84,
271c2974933SAntonio Borneo [44] = 96,
272c2974933SAntonio Borneo [47] = 92,
273c2974933SAntonio Borneo [48] = 116,
274c2974933SAntonio Borneo [50] = 117,
275c2974933SAntonio Borneo [52] = 118,
276c2974933SAntonio Borneo [53] = 119,
277c2974933SAntonio Borneo [68] = 63,
278c2974933SAntonio Borneo [70] = 98,
27904133bb1SAlexandre Torgue };
28004133bb1SAlexandre Torgue
28148f31e49SAntonio Borneo __diag_pop();
28248f31e49SAntonio Borneo
283927abfc4SLudovic Barre static const struct stm32_exti_drv_data stm32mp1_drv_data = {
284927abfc4SLudovic Barre .exti_banks = stm32mp1_exti_banks,
285927abfc4SLudovic Barre .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks),
286927abfc4SLudovic Barre .desc_irqs = stm32mp1_desc_irq,
287927abfc4SLudovic Barre };
288927abfc4SLudovic Barre
28904133bb1SAlexandre Torgue static const struct stm32_exti_drv_data stm32mp13_drv_data = {
29004133bb1SAlexandre Torgue .exti_banks = stm32mp1_exti_banks,
29104133bb1SAlexandre Torgue .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks),
29204133bb1SAlexandre Torgue .desc_irqs = stm32mp13_desc_irq,
29304133bb1SAlexandre Torgue };
29404133bb1SAlexandre Torgue
stm32_exti_pending(struct irq_chip_generic * gc)2956dd64ee1SLudovic Barre static unsigned long stm32_exti_pending(struct irq_chip_generic *gc)
2966dd64ee1SLudovic Barre {
297d9e2b19bSLudovic Barre struct stm32_exti_chip_data *chip_data = gc->private;
298d9e2b19bSLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
299be6230f0SLudovic Barre unsigned long pending;
3006dd64ee1SLudovic Barre
301be6230f0SLudovic Barre pending = irq_reg_readl(gc, stm32_bank->rpr_ofst);
302be6230f0SLudovic Barre if (stm32_bank->fpr_ofst != UNDEF_REG)
303be6230f0SLudovic Barre pending |= irq_reg_readl(gc, stm32_bank->fpr_ofst);
304be6230f0SLudovic Barre
305be6230f0SLudovic Barre return pending;
3066dd64ee1SLudovic Barre }
3076dd64ee1SLudovic Barre
stm32_irq_handler(struct irq_desc * desc)308e0720416SAlexandre TORGUE static void stm32_irq_handler(struct irq_desc *desc)
309e0720416SAlexandre TORGUE {
310e0720416SAlexandre TORGUE struct irq_domain *domain = irq_desc_get_handler_data(desc);
311e0720416SAlexandre TORGUE struct irq_chip *chip = irq_desc_get_chip(desc);
312046a6ee2SMarc Zyngier unsigned int nbanks = domain->gc->num_chips;
3136dd64ee1SLudovic Barre struct irq_chip_generic *gc;
314e0720416SAlexandre TORGUE unsigned long pending;
3156dd64ee1SLudovic Barre int n, i, irq_base = 0;
316e0720416SAlexandre TORGUE
317e0720416SAlexandre TORGUE chained_irq_enter(chip, desc);
318e0720416SAlexandre TORGUE
3196dd64ee1SLudovic Barre for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) {
3206dd64ee1SLudovic Barre gc = irq_get_domain_generic_chip(domain, irq_base);
3216dd64ee1SLudovic Barre
3226dd64ee1SLudovic Barre while ((pending = stm32_exti_pending(gc))) {
323046a6ee2SMarc Zyngier for_each_set_bit(n, &pending, IRQS_PER_BANK)
324046a6ee2SMarc Zyngier generic_handle_domain_irq(domain, irq_base + n);
325e0720416SAlexandre TORGUE }
326e0720416SAlexandre TORGUE }
327e0720416SAlexandre TORGUE
328e0720416SAlexandre TORGUE chained_irq_exit(chip, desc);
329e0720416SAlexandre TORGUE }
330e0720416SAlexandre TORGUE
stm32_exti_set_type(struct irq_data * d,unsigned int type,u32 * rtsr,u32 * ftsr)3315a2490e0SLudovic Barre static int stm32_exti_set_type(struct irq_data *d,
3325a2490e0SLudovic Barre unsigned int type, u32 *rtsr, u32 *ftsr)
333e0720416SAlexandre TORGUE {
3345a2490e0SLudovic Barre u32 mask = BIT(d->hwirq % IRQS_PER_BANK);
3355a2490e0SLudovic Barre
3365a2490e0SLudovic Barre switch (type) {
3375a2490e0SLudovic Barre case IRQ_TYPE_EDGE_RISING:
3385a2490e0SLudovic Barre *rtsr |= mask;
3395a2490e0SLudovic Barre *ftsr &= ~mask;
3405a2490e0SLudovic Barre break;
3415a2490e0SLudovic Barre case IRQ_TYPE_EDGE_FALLING:
3425a2490e0SLudovic Barre *rtsr &= ~mask;
3435a2490e0SLudovic Barre *ftsr |= mask;
3445a2490e0SLudovic Barre break;
3455a2490e0SLudovic Barre case IRQ_TYPE_EDGE_BOTH:
3465a2490e0SLudovic Barre *rtsr |= mask;
3475a2490e0SLudovic Barre *ftsr |= mask;
3485a2490e0SLudovic Barre break;
3495a2490e0SLudovic Barre default:
3505a2490e0SLudovic Barre return -EINVAL;
3515a2490e0SLudovic Barre }
3525a2490e0SLudovic Barre
3535a2490e0SLudovic Barre return 0;
3545a2490e0SLudovic Barre }
3555a2490e0SLudovic Barre
stm32_irq_set_type(struct irq_data * d,unsigned int type)3565a2490e0SLudovic Barre static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
3575a2490e0SLudovic Barre {
3585a2490e0SLudovic Barre struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
359d9e2b19bSLudovic Barre struct stm32_exti_chip_data *chip_data = gc->private;
360d9e2b19bSLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
3615257169aSFabien Dessenne struct hwspinlock *hwlock = chip_data->host_data->hwlock;
362e0720416SAlexandre TORGUE u32 rtsr, ftsr;
3635a2490e0SLudovic Barre int err;
364e0720416SAlexandre TORGUE
365e0720416SAlexandre TORGUE irq_gc_lock(gc);
366e0720416SAlexandre TORGUE
3675257169aSFabien Dessenne if (hwlock) {
3685257169aSFabien Dessenne err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT);
3695257169aSFabien Dessenne if (err) {
3705257169aSFabien Dessenne pr_err("%s can't get hwspinlock (%d)\n", __func__, err);
371fb94109bSBenjamin Gaignard goto unlock;
3725257169aSFabien Dessenne }
3735257169aSFabien Dessenne }
374fb94109bSBenjamin Gaignard
3756dd64ee1SLudovic Barre rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
3766dd64ee1SLudovic Barre ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
377e0720416SAlexandre TORGUE
3785a2490e0SLudovic Barre err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
379fb94109bSBenjamin Gaignard if (err)
380fb94109bSBenjamin Gaignard goto unspinlock;
381e0720416SAlexandre TORGUE
3826dd64ee1SLudovic Barre irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
3836dd64ee1SLudovic Barre irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
384e0720416SAlexandre TORGUE
385fb94109bSBenjamin Gaignard unspinlock:
3865257169aSFabien Dessenne if (hwlock)
3875257169aSFabien Dessenne hwspin_unlock_in_atomic(hwlock);
388fb94109bSBenjamin Gaignard unlock:
389e0720416SAlexandre TORGUE irq_gc_unlock(gc);
390e0720416SAlexandre TORGUE
391fb94109bSBenjamin Gaignard return err;
392e0720416SAlexandre TORGUE }
393e0720416SAlexandre TORGUE
stm32_chip_suspend(struct stm32_exti_chip_data * chip_data,u32 wake_active)3945a2490e0SLudovic Barre static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data,
3955a2490e0SLudovic Barre u32 wake_active)
3965a2490e0SLudovic Barre {
3975a2490e0SLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
3985a2490e0SLudovic Barre void __iomem *base = chip_data->host_data->base;
3995a2490e0SLudovic Barre
4005a2490e0SLudovic Barre /* save rtsr, ftsr registers */
4015a2490e0SLudovic Barre chip_data->rtsr_cache = readl_relaxed(base + stm32_bank->rtsr_ofst);
4025a2490e0SLudovic Barre chip_data->ftsr_cache = readl_relaxed(base + stm32_bank->ftsr_ofst);
4035a2490e0SLudovic Barre
4045a2490e0SLudovic Barre writel_relaxed(wake_active, base + stm32_bank->imr_ofst);
4055a2490e0SLudovic Barre }
4065a2490e0SLudovic Barre
stm32_chip_resume(struct stm32_exti_chip_data * chip_data,u32 mask_cache)4075a2490e0SLudovic Barre static void stm32_chip_resume(struct stm32_exti_chip_data *chip_data,
4085a2490e0SLudovic Barre u32 mask_cache)
4095a2490e0SLudovic Barre {
4105a2490e0SLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
4115a2490e0SLudovic Barre void __iomem *base = chip_data->host_data->base;
4125a2490e0SLudovic Barre
4135a2490e0SLudovic Barre /* restore rtsr, ftsr, registers */
4145a2490e0SLudovic Barre writel_relaxed(chip_data->rtsr_cache, base + stm32_bank->rtsr_ofst);
4155a2490e0SLudovic Barre writel_relaxed(chip_data->ftsr_cache, base + stm32_bank->ftsr_ofst);
4165a2490e0SLudovic Barre
4175a2490e0SLudovic Barre writel_relaxed(mask_cache, base + stm32_bank->imr_ofst);
4185a2490e0SLudovic Barre }
4195a2490e0SLudovic Barre
stm32_irq_suspend(struct irq_chip_generic * gc)420d9e2b19bSLudovic Barre static void stm32_irq_suspend(struct irq_chip_generic *gc)
421e0720416SAlexandre TORGUE {
422d9e2b19bSLudovic Barre struct stm32_exti_chip_data *chip_data = gc->private;
423e0720416SAlexandre TORGUE
424e0720416SAlexandre TORGUE irq_gc_lock(gc);
4255a2490e0SLudovic Barre stm32_chip_suspend(chip_data, gc->wake_active);
426e0720416SAlexandre TORGUE irq_gc_unlock(gc);
427d9e2b19bSLudovic Barre }
428e0720416SAlexandre TORGUE
stm32_irq_resume(struct irq_chip_generic * gc)429d9e2b19bSLudovic Barre static void stm32_irq_resume(struct irq_chip_generic *gc)
430d9e2b19bSLudovic Barre {
431d9e2b19bSLudovic Barre struct stm32_exti_chip_data *chip_data = gc->private;
432d9e2b19bSLudovic Barre
433d9e2b19bSLudovic Barre irq_gc_lock(gc);
4345a2490e0SLudovic Barre stm32_chip_resume(chip_data, gc->mask_cache);
435d9e2b19bSLudovic Barre irq_gc_unlock(gc);
436e0720416SAlexandre TORGUE }
437e0720416SAlexandre TORGUE
stm32_exti_alloc(struct irq_domain * d,unsigned int virq,unsigned int nr_irqs,void * data)438e0720416SAlexandre TORGUE static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq,
439e0720416SAlexandre TORGUE unsigned int nr_irqs, void *data)
440e0720416SAlexandre TORGUE {
441e0720416SAlexandre TORGUE struct irq_fwspec *fwspec = data;
442e0720416SAlexandre TORGUE irq_hw_number_t hwirq;
443e0720416SAlexandre TORGUE
444e0720416SAlexandre TORGUE hwirq = fwspec->param[0];
445e0720416SAlexandre TORGUE
446e0720416SAlexandre TORGUE irq_map_generic_chip(d, virq, hwirq);
447e0720416SAlexandre TORGUE
448e0720416SAlexandre TORGUE return 0;
449e0720416SAlexandre TORGUE }
450e0720416SAlexandre TORGUE
stm32_exti_free(struct irq_domain * d,unsigned int virq,unsigned int nr_irqs)451e0720416SAlexandre TORGUE static void stm32_exti_free(struct irq_domain *d, unsigned int virq,
452e0720416SAlexandre TORGUE unsigned int nr_irqs)
453e0720416SAlexandre TORGUE {
454e0720416SAlexandre TORGUE struct irq_data *data = irq_domain_get_irq_data(d, virq);
455e0720416SAlexandre TORGUE
456e0720416SAlexandre TORGUE irq_domain_reset_irq_data(data);
457e0720416SAlexandre TORGUE }
458e0720416SAlexandre TORGUE
459ea80aa2aSLudovic Barre static const struct irq_domain_ops irq_exti_domain_ops = {
460e0720416SAlexandre TORGUE .map = irq_map_generic_chip,
461e0720416SAlexandre TORGUE .alloc = stm32_exti_alloc,
462e0720416SAlexandre TORGUE .free = stm32_exti_free,
463*8554cba1SBen Wolsieffer .xlate = irq_domain_xlate_twocell,
464e0720416SAlexandre TORGUE };
465e0720416SAlexandre TORGUE
stm32_irq_ack(struct irq_data * d)466be6230f0SLudovic Barre static void stm32_irq_ack(struct irq_data *d)
467be6230f0SLudovic Barre {
468be6230f0SLudovic Barre struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
469d9e2b19bSLudovic Barre struct stm32_exti_chip_data *chip_data = gc->private;
470d9e2b19bSLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
471be6230f0SLudovic Barre
472be6230f0SLudovic Barre irq_gc_lock(gc);
473be6230f0SLudovic Barre
474be6230f0SLudovic Barre irq_reg_writel(gc, d->mask, stm32_bank->rpr_ofst);
475be6230f0SLudovic Barre if (stm32_bank->fpr_ofst != UNDEF_REG)
476be6230f0SLudovic Barre irq_reg_writel(gc, d->mask, stm32_bank->fpr_ofst);
477be6230f0SLudovic Barre
478be6230f0SLudovic Barre irq_gc_unlock(gc);
479be6230f0SLudovic Barre }
480927abfc4SLudovic Barre
481e579076aSqiuguorui1 /* directly set the target bit without reading first. */
stm32_exti_write_bit(struct irq_data * d,u32 reg)482e579076aSqiuguorui1 static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg)
483e579076aSqiuguorui1 {
484e579076aSqiuguorui1 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
485e579076aSqiuguorui1 void __iomem *base = chip_data->host_data->base;
486e579076aSqiuguorui1 u32 val = BIT(d->hwirq % IRQS_PER_BANK);
487e579076aSqiuguorui1
488e579076aSqiuguorui1 writel_relaxed(val, base + reg);
489e579076aSqiuguorui1 }
490e579076aSqiuguorui1
stm32_exti_set_bit(struct irq_data * d,u32 reg)491927abfc4SLudovic Barre static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg)
492927abfc4SLudovic Barre {
493927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
494927abfc4SLudovic Barre void __iomem *base = chip_data->host_data->base;
495927abfc4SLudovic Barre u32 val;
496927abfc4SLudovic Barre
497927abfc4SLudovic Barre val = readl_relaxed(base + reg);
498927abfc4SLudovic Barre val |= BIT(d->hwirq % IRQS_PER_BANK);
499927abfc4SLudovic Barre writel_relaxed(val, base + reg);
500927abfc4SLudovic Barre
501927abfc4SLudovic Barre return val;
502927abfc4SLudovic Barre }
503927abfc4SLudovic Barre
stm32_exti_clr_bit(struct irq_data * d,u32 reg)504927abfc4SLudovic Barre static inline u32 stm32_exti_clr_bit(struct irq_data *d, u32 reg)
505927abfc4SLudovic Barre {
506927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
507927abfc4SLudovic Barre void __iomem *base = chip_data->host_data->base;
508927abfc4SLudovic Barre u32 val;
509927abfc4SLudovic Barre
510927abfc4SLudovic Barre val = readl_relaxed(base + reg);
511927abfc4SLudovic Barre val &= ~BIT(d->hwirq % IRQS_PER_BANK);
512927abfc4SLudovic Barre writel_relaxed(val, base + reg);
513927abfc4SLudovic Barre
514927abfc4SLudovic Barre return val;
515927abfc4SLudovic Barre }
516927abfc4SLudovic Barre
stm32_exti_h_eoi(struct irq_data * d)517927abfc4SLudovic Barre static void stm32_exti_h_eoi(struct irq_data *d)
518927abfc4SLudovic Barre {
519927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
520927abfc4SLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
521927abfc4SLudovic Barre
522927abfc4SLudovic Barre raw_spin_lock(&chip_data->rlock);
523927abfc4SLudovic Barre
524e579076aSqiuguorui1 stm32_exti_write_bit(d, stm32_bank->rpr_ofst);
525927abfc4SLudovic Barre if (stm32_bank->fpr_ofst != UNDEF_REG)
526e579076aSqiuguorui1 stm32_exti_write_bit(d, stm32_bank->fpr_ofst);
527927abfc4SLudovic Barre
528927abfc4SLudovic Barre raw_spin_unlock(&chip_data->rlock);
529927abfc4SLudovic Barre
530927abfc4SLudovic Barre if (d->parent_data->chip)
531927abfc4SLudovic Barre irq_chip_eoi_parent(d);
532927abfc4SLudovic Barre }
533927abfc4SLudovic Barre
stm32_exti_h_mask(struct irq_data * d)534927abfc4SLudovic Barre static void stm32_exti_h_mask(struct irq_data *d)
535927abfc4SLudovic Barre {
536927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
537927abfc4SLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
538927abfc4SLudovic Barre
539927abfc4SLudovic Barre raw_spin_lock(&chip_data->rlock);
540927abfc4SLudovic Barre chip_data->mask_cache = stm32_exti_clr_bit(d, stm32_bank->imr_ofst);
541927abfc4SLudovic Barre raw_spin_unlock(&chip_data->rlock);
542927abfc4SLudovic Barre
543927abfc4SLudovic Barre if (d->parent_data->chip)
544927abfc4SLudovic Barre irq_chip_mask_parent(d);
545927abfc4SLudovic Barre }
546927abfc4SLudovic Barre
stm32_exti_h_unmask(struct irq_data * d)547927abfc4SLudovic Barre static void stm32_exti_h_unmask(struct irq_data *d)
548927abfc4SLudovic Barre {
549927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
550927abfc4SLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
551927abfc4SLudovic Barre
552927abfc4SLudovic Barre raw_spin_lock(&chip_data->rlock);
553927abfc4SLudovic Barre chip_data->mask_cache = stm32_exti_set_bit(d, stm32_bank->imr_ofst);
554927abfc4SLudovic Barre raw_spin_unlock(&chip_data->rlock);
555927abfc4SLudovic Barre
556927abfc4SLudovic Barre if (d->parent_data->chip)
557927abfc4SLudovic Barre irq_chip_unmask_parent(d);
558927abfc4SLudovic Barre }
559927abfc4SLudovic Barre
stm32_exti_h_set_type(struct irq_data * d,unsigned int type)560927abfc4SLudovic Barre static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
561927abfc4SLudovic Barre {
562927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
563927abfc4SLudovic Barre const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
5645257169aSFabien Dessenne struct hwspinlock *hwlock = chip_data->host_data->hwlock;
565927abfc4SLudovic Barre void __iomem *base = chip_data->host_data->base;
566927abfc4SLudovic Barre u32 rtsr, ftsr;
567927abfc4SLudovic Barre int err;
568927abfc4SLudovic Barre
569927abfc4SLudovic Barre raw_spin_lock(&chip_data->rlock);
570fb94109bSBenjamin Gaignard
5715257169aSFabien Dessenne if (hwlock) {
5725257169aSFabien Dessenne err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT);
5735257169aSFabien Dessenne if (err) {
5745257169aSFabien Dessenne pr_err("%s can't get hwspinlock (%d)\n", __func__, err);
575fb94109bSBenjamin Gaignard goto unlock;
5765257169aSFabien Dessenne }
5775257169aSFabien Dessenne }
578fb94109bSBenjamin Gaignard
579927abfc4SLudovic Barre rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst);
580927abfc4SLudovic Barre ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst);
581927abfc4SLudovic Barre
582927abfc4SLudovic Barre err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
583fb94109bSBenjamin Gaignard if (err)
584fb94109bSBenjamin Gaignard goto unspinlock;
585927abfc4SLudovic Barre
586927abfc4SLudovic Barre writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst);
587927abfc4SLudovic Barre writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
588fb94109bSBenjamin Gaignard
589fb94109bSBenjamin Gaignard unspinlock:
5905257169aSFabien Dessenne if (hwlock)
5915257169aSFabien Dessenne hwspin_unlock_in_atomic(hwlock);
592fb94109bSBenjamin Gaignard unlock:
593927abfc4SLudovic Barre raw_spin_unlock(&chip_data->rlock);
594927abfc4SLudovic Barre
595fb94109bSBenjamin Gaignard return err;
596927abfc4SLudovic Barre }
597927abfc4SLudovic Barre
stm32_exti_h_set_wake(struct irq_data * d,unsigned int on)598927abfc4SLudovic Barre static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
599927abfc4SLudovic Barre {
600927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
601927abfc4SLudovic Barre u32 mask = BIT(d->hwirq % IRQS_PER_BANK);
602927abfc4SLudovic Barre
603927abfc4SLudovic Barre raw_spin_lock(&chip_data->rlock);
604927abfc4SLudovic Barre
605927abfc4SLudovic Barre if (on)
606927abfc4SLudovic Barre chip_data->wake_active |= mask;
607927abfc4SLudovic Barre else
608927abfc4SLudovic Barre chip_data->wake_active &= ~mask;
609927abfc4SLudovic Barre
610927abfc4SLudovic Barre raw_spin_unlock(&chip_data->rlock);
611927abfc4SLudovic Barre
612927abfc4SLudovic Barre return 0;
613927abfc4SLudovic Barre }
614927abfc4SLudovic Barre
stm32_exti_h_set_affinity(struct irq_data * d,const struct cpumask * dest,bool force)615927abfc4SLudovic Barre static int stm32_exti_h_set_affinity(struct irq_data *d,
616927abfc4SLudovic Barre const struct cpumask *dest, bool force)
617927abfc4SLudovic Barre {
618927abfc4SLudovic Barre if (d->parent_data->chip)
619927abfc4SLudovic Barre return irq_chip_set_affinity_parent(d, dest, force);
620927abfc4SLudovic Barre
6213e17683fSLudovic Barre return IRQ_SET_MASK_OK_DONE;
622927abfc4SLudovic Barre }
623927abfc4SLudovic Barre
stm32_exti_h_suspend(void)624cfbf9e49SFabien Dessenne static int __maybe_unused stm32_exti_h_suspend(void)
62573958b31SLudovic Barre {
62673958b31SLudovic Barre struct stm32_exti_chip_data *chip_data;
62773958b31SLudovic Barre int i;
62873958b31SLudovic Barre
62973958b31SLudovic Barre for (i = 0; i < stm32_host_data->drv_data->bank_nr; i++) {
63073958b31SLudovic Barre chip_data = &stm32_host_data->chips_data[i];
63173958b31SLudovic Barre raw_spin_lock(&chip_data->rlock);
63273958b31SLudovic Barre stm32_chip_suspend(chip_data, chip_data->wake_active);
63373958b31SLudovic Barre raw_spin_unlock(&chip_data->rlock);
63473958b31SLudovic Barre }
63573958b31SLudovic Barre
63673958b31SLudovic Barre return 0;
63773958b31SLudovic Barre }
63873958b31SLudovic Barre
stm32_exti_h_resume(void)639cfbf9e49SFabien Dessenne static void __maybe_unused stm32_exti_h_resume(void)
64073958b31SLudovic Barre {
64173958b31SLudovic Barre struct stm32_exti_chip_data *chip_data;
64273958b31SLudovic Barre int i;
64373958b31SLudovic Barre
64473958b31SLudovic Barre for (i = 0; i < stm32_host_data->drv_data->bank_nr; i++) {
64573958b31SLudovic Barre chip_data = &stm32_host_data->chips_data[i];
64673958b31SLudovic Barre raw_spin_lock(&chip_data->rlock);
64773958b31SLudovic Barre stm32_chip_resume(chip_data, chip_data->mask_cache);
64873958b31SLudovic Barre raw_spin_unlock(&chip_data->rlock);
64973958b31SLudovic Barre }
65073958b31SLudovic Barre }
65173958b31SLudovic Barre
65273958b31SLudovic Barre static struct syscore_ops stm32_exti_h_syscore_ops = {
653cfbf9e49SFabien Dessenne #ifdef CONFIG_PM_SLEEP
65473958b31SLudovic Barre .suspend = stm32_exti_h_suspend,
65573958b31SLudovic Barre .resume = stm32_exti_h_resume,
656cfbf9e49SFabien Dessenne #endif
65773958b31SLudovic Barre };
65873958b31SLudovic Barre
stm32_exti_h_syscore_init(struct stm32_exti_host_data * host_data)659cfbf9e49SFabien Dessenne static void stm32_exti_h_syscore_init(struct stm32_exti_host_data *host_data)
66073958b31SLudovic Barre {
661cfbf9e49SFabien Dessenne stm32_host_data = host_data;
66273958b31SLudovic Barre register_syscore_ops(&stm32_exti_h_syscore_ops);
66373958b31SLudovic Barre }
664cfbf9e49SFabien Dessenne
stm32_exti_h_syscore_deinit(void)665cfbf9e49SFabien Dessenne static void stm32_exti_h_syscore_deinit(void)
666cfbf9e49SFabien Dessenne {
667cfbf9e49SFabien Dessenne unregister_syscore_ops(&stm32_exti_h_syscore_ops);
668cfbf9e49SFabien Dessenne }
66973958b31SLudovic Barre
stm32_exti_h_retrigger(struct irq_data * d)67025591d4cSAlexandre Torgue static int stm32_exti_h_retrigger(struct irq_data *d)
67125591d4cSAlexandre Torgue {
67225591d4cSAlexandre Torgue struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
67325591d4cSAlexandre Torgue const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
67425591d4cSAlexandre Torgue void __iomem *base = chip_data->host_data->base;
67525591d4cSAlexandre Torgue u32 mask = BIT(d->hwirq % IRQS_PER_BANK);
67625591d4cSAlexandre Torgue
67725591d4cSAlexandre Torgue writel_relaxed(mask, base + stm32_bank->swier_ofst);
67825591d4cSAlexandre Torgue
67925591d4cSAlexandre Torgue return 0;
68025591d4cSAlexandre Torgue }
68125591d4cSAlexandre Torgue
682927abfc4SLudovic Barre static struct irq_chip stm32_exti_h_chip = {
683927abfc4SLudovic Barre .name = "stm32-exti-h",
684927abfc4SLudovic Barre .irq_eoi = stm32_exti_h_eoi,
685927abfc4SLudovic Barre .irq_mask = stm32_exti_h_mask,
686927abfc4SLudovic Barre .irq_unmask = stm32_exti_h_unmask,
68725591d4cSAlexandre Torgue .irq_retrigger = stm32_exti_h_retrigger,
688927abfc4SLudovic Barre .irq_set_type = stm32_exti_h_set_type,
689927abfc4SLudovic Barre .irq_set_wake = stm32_exti_h_set_wake,
690927abfc4SLudovic Barre .flags = IRQCHIP_MASK_ON_SUSPEND,
691a84277bfSArnd Bergmann .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? stm32_exti_h_set_affinity : NULL,
692927abfc4SLudovic Barre };
693927abfc4SLudovic Barre
6949d6a5fe1SAlexandre Torgue static struct irq_chip stm32_exti_h_chip_direct = {
6959d6a5fe1SAlexandre Torgue .name = "stm32-exti-h-direct",
6969d6a5fe1SAlexandre Torgue .irq_eoi = irq_chip_eoi_parent,
6979d6a5fe1SAlexandre Torgue .irq_ack = irq_chip_ack_parent,
698f8b3eb42SLoic Pallardy .irq_mask = stm32_exti_h_mask,
699f8b3eb42SLoic Pallardy .irq_unmask = stm32_exti_h_unmask,
7009d6a5fe1SAlexandre Torgue .irq_retrigger = irq_chip_retrigger_hierarchy,
7019d6a5fe1SAlexandre Torgue .irq_set_type = irq_chip_set_type_parent,
7029d6a5fe1SAlexandre Torgue .irq_set_wake = stm32_exti_h_set_wake,
7039d6a5fe1SAlexandre Torgue .flags = IRQCHIP_MASK_ON_SUSPEND,
7049d6a5fe1SAlexandre Torgue .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? irq_chip_set_affinity_parent : NULL,
7059d6a5fe1SAlexandre Torgue };
7069d6a5fe1SAlexandre Torgue
stm32_exti_h_domain_alloc(struct irq_domain * dm,unsigned int virq,unsigned int nr_irqs,void * data)707927abfc4SLudovic Barre static int stm32_exti_h_domain_alloc(struct irq_domain *dm,
708927abfc4SLudovic Barre unsigned int virq,
709927abfc4SLudovic Barre unsigned int nr_irqs, void *data)
710927abfc4SLudovic Barre {
711927abfc4SLudovic Barre struct stm32_exti_host_data *host_data = dm->host_data;
712927abfc4SLudovic Barre struct stm32_exti_chip_data *chip_data;
713c2974933SAntonio Borneo u8 desc_irq;
714927abfc4SLudovic Barre struct irq_fwspec *fwspec = data;
715927abfc4SLudovic Barre struct irq_fwspec p_fwspec;
716927abfc4SLudovic Barre irq_hw_number_t hwirq;
7179d6a5fe1SAlexandre Torgue int bank;
718ce4ef8f9SAntonio Borneo u32 event_trg;
719ce4ef8f9SAntonio Borneo struct irq_chip *chip;
720927abfc4SLudovic Barre
721927abfc4SLudovic Barre hwirq = fwspec->param[0];
722c16ae609SAntonio Borneo if (hwirq >= host_data->drv_data->bank_nr * IRQS_PER_BANK)
723c16ae609SAntonio Borneo return -EINVAL;
724c16ae609SAntonio Borneo
725927abfc4SLudovic Barre bank = hwirq / IRQS_PER_BANK;
726927abfc4SLudovic Barre chip_data = &host_data->chips_data[bank];
727927abfc4SLudovic Barre
728ce4ef8f9SAntonio Borneo event_trg = readl_relaxed(host_data->base + chip_data->reg_bank->trg_ofst);
729ce4ef8f9SAntonio Borneo chip = (event_trg & BIT(hwirq % IRQS_PER_BANK)) ?
730ce4ef8f9SAntonio Borneo &stm32_exti_h_chip : &stm32_exti_h_chip_direct;
731ce4ef8f9SAntonio Borneo
732ce4ef8f9SAntonio Borneo irq_domain_set_hwirq_and_chip(dm, virq, hwirq, chip, chip_data);
733c2974933SAntonio Borneo
7348fc7a619SAntonio Borneo if (!host_data->drv_data->desc_irqs)
735c2974933SAntonio Borneo return -EINVAL;
736c2974933SAntonio Borneo
737c2974933SAntonio Borneo desc_irq = host_data->drv_data->desc_irqs[hwirq];
738c2974933SAntonio Borneo if (desc_irq != EXTI_INVALID_IRQ) {
739927abfc4SLudovic Barre p_fwspec.fwnode = dm->parent->fwnode;
740927abfc4SLudovic Barre p_fwspec.param_count = 3;
741927abfc4SLudovic Barre p_fwspec.param[0] = GIC_SPI;
742c2974933SAntonio Borneo p_fwspec.param[1] = desc_irq;
743927abfc4SLudovic Barre p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
744927abfc4SLudovic Barre
745927abfc4SLudovic Barre return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec);
746927abfc4SLudovic Barre }
747927abfc4SLudovic Barre
748927abfc4SLudovic Barre return 0;
749927abfc4SLudovic Barre }
750927abfc4SLudovic Barre
751f9fc1745SLudovic Barre static struct
stm32_exti_host_init(const struct stm32_exti_drv_data * dd,struct device_node * node)752f9fc1745SLudovic Barre stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
753f9fc1745SLudovic Barre struct device_node *node)
754e0720416SAlexandre TORGUE {
755f9fc1745SLudovic Barre struct stm32_exti_host_data *host_data;
756e0720416SAlexandre TORGUE
757f9fc1745SLudovic Barre host_data = kzalloc(sizeof(*host_data), GFP_KERNEL);
758f9fc1745SLudovic Barre if (!host_data)
759f9fc1745SLudovic Barre return NULL;
760f9fc1745SLudovic Barre
761f9fc1745SLudovic Barre host_data->drv_data = dd;
762f9fc1745SLudovic Barre host_data->chips_data = kcalloc(dd->bank_nr,
763f9fc1745SLudovic Barre sizeof(struct stm32_exti_chip_data),
764f9fc1745SLudovic Barre GFP_KERNEL);
765f9fc1745SLudovic Barre if (!host_data->chips_data)
7664096165dSDan Carpenter goto free_host_data;
767f9fc1745SLudovic Barre
768f9fc1745SLudovic Barre host_data->base = of_iomap(node, 0);
769f9fc1745SLudovic Barre if (!host_data->base) {
770e81f54c6SRob Herring pr_err("%pOF: Unable to map registers\n", node);
7714096165dSDan Carpenter goto free_chips_data;
772e0720416SAlexandre TORGUE }
773e0720416SAlexandre TORGUE
77473958b31SLudovic Barre stm32_host_data = host_data;
77573958b31SLudovic Barre
776f9fc1745SLudovic Barre return host_data;
7774096165dSDan Carpenter
7784096165dSDan Carpenter free_chips_data:
7794096165dSDan Carpenter kfree(host_data->chips_data);
7804096165dSDan Carpenter free_host_data:
7814096165dSDan Carpenter kfree(host_data);
7824096165dSDan Carpenter
7834096165dSDan Carpenter return NULL;
784f9fc1745SLudovic Barre }
785d9e2b19bSLudovic Barre
786f9fc1745SLudovic Barre static struct
stm32_exti_chip_init(struct stm32_exti_host_data * h_data,u32 bank_idx,struct device_node * node)787f9fc1745SLudovic Barre stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
788cfbf9e49SFabien Dessenne u32 bank_idx,
789cfbf9e49SFabien Dessenne struct device_node *node)
790f9fc1745SLudovic Barre {
791f9fc1745SLudovic Barre const struct stm32_exti_bank *stm32_bank;
792f9fc1745SLudovic Barre struct stm32_exti_chip_data *chip_data;
793f9fc1745SLudovic Barre void __iomem *base = h_data->base;
794f9fc1745SLudovic Barre
795f9fc1745SLudovic Barre stm32_bank = h_data->drv_data->exti_banks[bank_idx];
796f9fc1745SLudovic Barre chip_data = &h_data->chips_data[bank_idx];
797f9fc1745SLudovic Barre chip_data->host_data = h_data;
798f9fc1745SLudovic Barre chip_data->reg_bank = stm32_bank;
799f9fc1745SLudovic Barre
800927abfc4SLudovic Barre raw_spin_lock_init(&chip_data->rlock);
801927abfc4SLudovic Barre
802f9fc1745SLudovic Barre /*
803f9fc1745SLudovic Barre * This IP has no reset, so after hot reboot we should
804f9fc1745SLudovic Barre * clear registers to avoid residue
805f9fc1745SLudovic Barre */
806f9fc1745SLudovic Barre writel_relaxed(0, base + stm32_bank->imr_ofst);
807b38040f0SAlexandre Torgue if (stm32_bank->emr_ofst != UNDEF_REG)
808f9fc1745SLudovic Barre writel_relaxed(0, base + stm32_bank->emr_ofst);
809f9fc1745SLudovic Barre
810cfbf9e49SFabien Dessenne pr_info("%pOF: bank%d\n", node, bank_idx);
811f9fc1745SLudovic Barre
812f9fc1745SLudovic Barre return chip_data;
813f9fc1745SLudovic Barre }
814f9fc1745SLudovic Barre
stm32_exti_init(const struct stm32_exti_drv_data * drv_data,struct device_node * node)815f9fc1745SLudovic Barre static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
816f9fc1745SLudovic Barre struct device_node *node)
817f9fc1745SLudovic Barre {
818f9fc1745SLudovic Barre struct stm32_exti_host_data *host_data;
819f9fc1745SLudovic Barre unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
820f9fc1745SLudovic Barre int nr_irqs, ret, i;
821f9fc1745SLudovic Barre struct irq_chip_generic *gc;
822f9fc1745SLudovic Barre struct irq_domain *domain;
823f9fc1745SLudovic Barre
824f9fc1745SLudovic Barre host_data = stm32_exti_host_init(drv_data, node);
8254096165dSDan Carpenter if (!host_data)
8264096165dSDan Carpenter return -ENOMEM;
827f9fc1745SLudovic Barre
828f9fc1745SLudovic Barre domain = irq_domain_add_linear(node, drv_data->bank_nr * IRQS_PER_BANK,
829e0720416SAlexandre TORGUE &irq_exti_domain_ops, NULL);
830e0720416SAlexandre TORGUE if (!domain) {
831f9c75bcaSYangtao Li pr_err("%pOFn: Could not register interrupt domain.\n",
832f9c75bcaSYangtao Li node);
833e0720416SAlexandre TORGUE ret = -ENOMEM;
834e0720416SAlexandre TORGUE goto out_unmap;
835e0720416SAlexandre TORGUE }
836e0720416SAlexandre TORGUE
8376dd64ee1SLudovic Barre ret = irq_alloc_domain_generic_chips(domain, IRQS_PER_BANK, 1, "exti",
838e0720416SAlexandre TORGUE handle_edge_irq, clr, 0, 0);
839e0720416SAlexandre TORGUE if (ret) {
840e81f54c6SRob Herring pr_err("%pOF: Could not allocate generic interrupt chip.\n",
841e81f54c6SRob Herring node);
842e0720416SAlexandre TORGUE goto out_free_domain;
843e0720416SAlexandre TORGUE }
844e0720416SAlexandre TORGUE
845f9fc1745SLudovic Barre for (i = 0; i < drv_data->bank_nr; i++) {
846f9fc1745SLudovic Barre const struct stm32_exti_bank *stm32_bank;
847f9fc1745SLudovic Barre struct stm32_exti_chip_data *chip_data;
8486dd64ee1SLudovic Barre
849f9fc1745SLudovic Barre stm32_bank = drv_data->exti_banks[i];
850cfbf9e49SFabien Dessenne chip_data = stm32_exti_chip_init(host_data, i, node);
851d9e2b19bSLudovic Barre
8526dd64ee1SLudovic Barre gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
8536dd64ee1SLudovic Barre
854f9fc1745SLudovic Barre gc->reg_base = host_data->base;
855e0720416SAlexandre TORGUE gc->chip_types->type = IRQ_TYPE_EDGE_BOTH;
856be6230f0SLudovic Barre gc->chip_types->chip.irq_ack = stm32_irq_ack;
857e0720416SAlexandre TORGUE gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit;
858e0720416SAlexandre TORGUE gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit;
859e0720416SAlexandre TORGUE gc->chip_types->chip.irq_set_type = stm32_irq_set_type;
860d9e2b19bSLudovic Barre gc->chip_types->chip.irq_set_wake = irq_gc_set_wake;
861d9e2b19bSLudovic Barre gc->suspend = stm32_irq_suspend;
862d9e2b19bSLudovic Barre gc->resume = stm32_irq_resume;
863d9e2b19bSLudovic Barre gc->wake_enabled = IRQ_MSK(IRQS_PER_BANK);
864d9e2b19bSLudovic Barre
8656dd64ee1SLudovic Barre gc->chip_types->regs.mask = stm32_bank->imr_ofst;
866d9e2b19bSLudovic Barre gc->private = (void *)chip_data;
8676dd64ee1SLudovic Barre }
868e0720416SAlexandre TORGUE
869e0720416SAlexandre TORGUE nr_irqs = of_irq_count(node);
870e0720416SAlexandre TORGUE for (i = 0; i < nr_irqs; i++) {
871e0720416SAlexandre TORGUE unsigned int irq = irq_of_parse_and_map(node, i);
872e0720416SAlexandre TORGUE
873e0720416SAlexandre TORGUE irq_set_handler_data(irq, domain);
874e0720416SAlexandre TORGUE irq_set_chained_handler(irq, stm32_irq_handler);
875e0720416SAlexandre TORGUE }
876e0720416SAlexandre TORGUE
877e0720416SAlexandre TORGUE return 0;
878e0720416SAlexandre TORGUE
879e0720416SAlexandre TORGUE out_free_domain:
880e0720416SAlexandre TORGUE irq_domain_remove(domain);
881e0720416SAlexandre TORGUE out_unmap:
882f9fc1745SLudovic Barre iounmap(host_data->base);
883f9fc1745SLudovic Barre kfree(host_data->chips_data);
884f9fc1745SLudovic Barre kfree(host_data);
885e0720416SAlexandre TORGUE return ret;
886e0720416SAlexandre TORGUE }
887e0720416SAlexandre TORGUE
888927abfc4SLudovic Barre static const struct irq_domain_ops stm32_exti_h_domain_ops = {
889927abfc4SLudovic Barre .alloc = stm32_exti_h_domain_alloc,
890927abfc4SLudovic Barre .free = irq_domain_free_irqs_common,
8911d47f48bSLoic Pallardy .xlate = irq_domain_xlate_twocell,
892927abfc4SLudovic Barre };
893927abfc4SLudovic Barre
stm32_exti_remove_irq(void * data)894cfbf9e49SFabien Dessenne static void stm32_exti_remove_irq(void *data)
895927abfc4SLudovic Barre {
896cfbf9e49SFabien Dessenne struct irq_domain *domain = data;
897927abfc4SLudovic Barre
898cfbf9e49SFabien Dessenne irq_domain_remove(domain);
899927abfc4SLudovic Barre }
900927abfc4SLudovic Barre
stm32_exti_remove(struct platform_device * pdev)901cfbf9e49SFabien Dessenne static int stm32_exti_remove(struct platform_device *pdev)
902cfbf9e49SFabien Dessenne {
903cfbf9e49SFabien Dessenne stm32_exti_h_syscore_deinit();
904cfbf9e49SFabien Dessenne return 0;
905cfbf9e49SFabien Dessenne }
906cfbf9e49SFabien Dessenne
stm32_exti_probe(struct platform_device * pdev)907cfbf9e49SFabien Dessenne static int stm32_exti_probe(struct platform_device *pdev)
908cfbf9e49SFabien Dessenne {
909cfbf9e49SFabien Dessenne int ret, i;
910cfbf9e49SFabien Dessenne struct device *dev = &pdev->dev;
911cfbf9e49SFabien Dessenne struct device_node *np = dev->of_node;
912cfbf9e49SFabien Dessenne struct irq_domain *parent_domain, *domain;
913cfbf9e49SFabien Dessenne struct stm32_exti_host_data *host_data;
914cfbf9e49SFabien Dessenne const struct stm32_exti_drv_data *drv_data;
915cfbf9e49SFabien Dessenne
916cfbf9e49SFabien Dessenne host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
9174096165dSDan Carpenter if (!host_data)
9184096165dSDan Carpenter return -ENOMEM;
919927abfc4SLudovic Barre
920cfbf9e49SFabien Dessenne /* check for optional hwspinlock which may be not available yet */
921cfbf9e49SFabien Dessenne ret = of_hwspin_lock_get_id(np, 0);
922cfbf9e49SFabien Dessenne if (ret == -EPROBE_DEFER)
923cfbf9e49SFabien Dessenne /* hwspinlock framework not yet ready */
924cfbf9e49SFabien Dessenne return ret;
925927abfc4SLudovic Barre
926cfbf9e49SFabien Dessenne if (ret >= 0) {
927cfbf9e49SFabien Dessenne host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
928cfbf9e49SFabien Dessenne if (!host_data->hwlock) {
929cfbf9e49SFabien Dessenne dev_err(dev, "Failed to request hwspinlock\n");
930cfbf9e49SFabien Dessenne return -EINVAL;
931927abfc4SLudovic Barre }
932cfbf9e49SFabien Dessenne } else if (ret != -ENOENT) {
933cfbf9e49SFabien Dessenne /* note: ENOENT is a valid case (means 'no hwspinlock') */
934cfbf9e49SFabien Dessenne dev_err(dev, "Failed to get hwspinlock\n");
935927abfc4SLudovic Barre return ret;
936927abfc4SLudovic Barre }
937927abfc4SLudovic Barre
938cfbf9e49SFabien Dessenne /* initialize host_data */
939cfbf9e49SFabien Dessenne drv_data = of_device_get_match_data(dev);
940cfbf9e49SFabien Dessenne if (!drv_data) {
941cfbf9e49SFabien Dessenne dev_err(dev, "no of match data\n");
942cfbf9e49SFabien Dessenne return -ENODEV;
943cfbf9e49SFabien Dessenne }
944cfbf9e49SFabien Dessenne host_data->drv_data = drv_data;
945cfbf9e49SFabien Dessenne
946cfbf9e49SFabien Dessenne host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr,
947cfbf9e49SFabien Dessenne sizeof(*host_data->chips_data),
948cfbf9e49SFabien Dessenne GFP_KERNEL);
949cfbf9e49SFabien Dessenne if (!host_data->chips_data)
950cfbf9e49SFabien Dessenne return -ENOMEM;
951cfbf9e49SFabien Dessenne
952fd9ac236SCai Huoqing host_data->base = devm_platform_ioremap_resource(pdev, 0);
953fbb80d5aSZhen Lei if (IS_ERR(host_data->base))
954cfbf9e49SFabien Dessenne return PTR_ERR(host_data->base);
955cfbf9e49SFabien Dessenne
956cfbf9e49SFabien Dessenne for (i = 0; i < drv_data->bank_nr; i++)
957cfbf9e49SFabien Dessenne stm32_exti_chip_init(host_data, i, np);
958cfbf9e49SFabien Dessenne
959cfbf9e49SFabien Dessenne parent_domain = irq_find_host(of_irq_find_parent(np));
960cfbf9e49SFabien Dessenne if (!parent_domain) {
961cfbf9e49SFabien Dessenne dev_err(dev, "GIC interrupt-parent not found\n");
962cfbf9e49SFabien Dessenne return -EINVAL;
963cfbf9e49SFabien Dessenne }
964cfbf9e49SFabien Dessenne
965cfbf9e49SFabien Dessenne domain = irq_domain_add_hierarchy(parent_domain, 0,
966cfbf9e49SFabien Dessenne drv_data->bank_nr * IRQS_PER_BANK,
967cfbf9e49SFabien Dessenne np, &stm32_exti_h_domain_ops,
968cfbf9e49SFabien Dessenne host_data);
969cfbf9e49SFabien Dessenne
970cfbf9e49SFabien Dessenne if (!domain) {
971cfbf9e49SFabien Dessenne dev_err(dev, "Could not register exti domain\n");
972cfbf9e49SFabien Dessenne return -ENOMEM;
973cfbf9e49SFabien Dessenne }
974cfbf9e49SFabien Dessenne
975cfbf9e49SFabien Dessenne ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, domain);
976cfbf9e49SFabien Dessenne if (ret)
977cfbf9e49SFabien Dessenne return ret;
978cfbf9e49SFabien Dessenne
979cfbf9e49SFabien Dessenne stm32_exti_h_syscore_init(host_data);
980cfbf9e49SFabien Dessenne
981cfbf9e49SFabien Dessenne return 0;
982cfbf9e49SFabien Dessenne }
983cfbf9e49SFabien Dessenne
984cfbf9e49SFabien Dessenne /* platform driver only for MP1 */
985cfbf9e49SFabien Dessenne static const struct of_device_id stm32_exti_ids[] = {
986cfbf9e49SFabien Dessenne { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data},
98704133bb1SAlexandre Torgue { .compatible = "st,stm32mp13-exti", .data = &stm32mp13_drv_data},
988cfbf9e49SFabien Dessenne {},
989cfbf9e49SFabien Dessenne };
990cfbf9e49SFabien Dessenne MODULE_DEVICE_TABLE(of, stm32_exti_ids);
991cfbf9e49SFabien Dessenne
992cfbf9e49SFabien Dessenne static struct platform_driver stm32_exti_driver = {
993cfbf9e49SFabien Dessenne .probe = stm32_exti_probe,
994cfbf9e49SFabien Dessenne .remove = stm32_exti_remove,
995cfbf9e49SFabien Dessenne .driver = {
996cfbf9e49SFabien Dessenne .name = "stm32_exti",
997cfbf9e49SFabien Dessenne .of_match_table = stm32_exti_ids,
998cfbf9e49SFabien Dessenne },
999cfbf9e49SFabien Dessenne };
1000cfbf9e49SFabien Dessenne
stm32_exti_arch_init(void)1001cfbf9e49SFabien Dessenne static int __init stm32_exti_arch_init(void)
1002cfbf9e49SFabien Dessenne {
1003cfbf9e49SFabien Dessenne return platform_driver_register(&stm32_exti_driver);
1004cfbf9e49SFabien Dessenne }
1005cfbf9e49SFabien Dessenne
stm32_exti_arch_exit(void)1006cfbf9e49SFabien Dessenne static void __exit stm32_exti_arch_exit(void)
1007cfbf9e49SFabien Dessenne {
1008cfbf9e49SFabien Dessenne return platform_driver_unregister(&stm32_exti_driver);
1009cfbf9e49SFabien Dessenne }
1010cfbf9e49SFabien Dessenne
1011cfbf9e49SFabien Dessenne arch_initcall(stm32_exti_arch_init);
1012cfbf9e49SFabien Dessenne module_exit(stm32_exti_arch_exit);
1013cfbf9e49SFabien Dessenne
1014cfbf9e49SFabien Dessenne /* no platform driver for F4 and H7 */
stm32f4_exti_of_init(struct device_node * np,struct device_node * parent)10156dd64ee1SLudovic Barre static int __init stm32f4_exti_of_init(struct device_node *np,
10166dd64ee1SLudovic Barre struct device_node *parent)
10176dd64ee1SLudovic Barre {
1018f9fc1745SLudovic Barre return stm32_exti_init(&stm32f4xx_drv_data, np);
10196dd64ee1SLudovic Barre }
10206dd64ee1SLudovic Barre
10216dd64ee1SLudovic Barre IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init);
1022539c603eSLudovic Barre
stm32h7_exti_of_init(struct device_node * np,struct device_node * parent)1023539c603eSLudovic Barre static int __init stm32h7_exti_of_init(struct device_node *np,
1024539c603eSLudovic Barre struct device_node *parent)
1025539c603eSLudovic Barre {
1026f9fc1745SLudovic Barre return stm32_exti_init(&stm32h7xx_drv_data, np);
1027539c603eSLudovic Barre }
1028539c603eSLudovic Barre
1029539c603eSLudovic Barre IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
1030