Skip to content

Commit 8eb2dfe

Browse files
atorguelinusw
authored andcommitted
pinctrl: stm32: add lock mechanism for irqmux selection
GPIOs are split between several banks (A, B, ...) and each bank can have up to 16 lines. Those GPIOs could be used as interrupt lines thanks to exti lines. As there are only 16 exti lines, a mux is used to select which gpio line is connected to which exti line. Mapping is done as follow: -A0, B0, C0.. -->exti_line_0 (X0 selected by mux_0) -A1, B1, C1.. -->exti_line_1 (X1 selected by mux_1) ... This patch adds a protection to avoid overriding on mux_n for exti_line_n. Signed-off-by: Alexandre Torgue <[email protected]> Signed-off-by: Linus Walleij <[email protected]>
1 parent a45623d commit 8eb2dfe

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

drivers/pinctrl/stm32/pinctrl-stm32.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ struct stm32_pinctrl {
111111
struct stm32_desc_pin *pins;
112112
u32 npins;
113113
u32 pkg;
114+
u16 irqmux_map;
115+
spinlock_t irqmux_lock;
114116
};
115117

116118
static inline int stm32_gpio_pin(int gpio)
@@ -359,9 +361,53 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
359361
{
360362
struct stm32_gpio_bank *bank = d->host_data;
361363
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
364+
unsigned long flags;
365+
int ret = 0;
366+
367+
/*
368+
* gpio irq mux is shared between several banks, a lock has to be done
369+
* to avoid overriding.
370+
*/
371+
spin_lock_irqsave(&pctl->irqmux_lock, flags);
372+
if (pctl->hwlock)
373+
ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
374+
375+
if (ret) {
376+
dev_err(pctl->dev, "Can't get hwspinlock\n");
377+
goto unlock;
378+
}
379+
380+
if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
381+
dev_err(pctl->dev, "irq line %ld already requested.\n",
382+
irq_data->hwirq);
383+
ret = -EBUSY;
384+
if (pctl->hwlock)
385+
hwspin_unlock(pctl->hwlock);
386+
goto unlock;
387+
} else {
388+
pctl->irqmux_map |= BIT(irq_data->hwirq);
389+
}
362390

363391
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
364-
return 0;
392+
393+
if (pctl->hwlock)
394+
hwspin_unlock(pctl->hwlock);
395+
396+
unlock:
397+
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
398+
return ret;
399+
}
400+
401+
static void stm32_gpio_domain_deactivate(struct irq_domain *d,
402+
struct irq_data *irq_data)
403+
{
404+
struct stm32_gpio_bank *bank = d->host_data;
405+
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
406+
unsigned long flags;
407+
408+
spin_lock_irqsave(&pctl->irqmux_lock, flags);
409+
pctl->irqmux_map &= ~BIT(irq_data->hwirq);
410+
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
365411
}
366412

367413
static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -390,6 +436,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = {
390436
.alloc = stm32_gpio_domain_alloc,
391437
.free = irq_domain_free_irqs_common,
392438
.activate = stm32_gpio_domain_activate,
439+
.deactivate = stm32_gpio_domain_deactivate,
393440
};
394441

395442
/* Pinctrl functions */
@@ -1350,6 +1397,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
13501397
pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
13511398
}
13521399

1400+
spin_lock_init(&pctl->irqmux_lock);
1401+
13531402
pctl->dev = dev;
13541403
pctl->match_data = match->data;
13551404

0 commit comments

Comments
 (0)