Skip to content

Commit

Permalink
pinctrl: stm32: add lock mechanism for irqmux selection
Browse files Browse the repository at this point in the history
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 <alexandre.torgue@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Alexandre Torgue authored and Linus Walleij committed May 24, 2019
1 parent a45623d commit 8eb2dfe
Showing 1 changed file with 50 additions and 1 deletion.
51 changes: 50 additions & 1 deletion drivers/pinctrl/stm32/pinctrl-stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ struct stm32_pinctrl {
struct stm32_desc_pin *pins;
u32 npins;
u32 pkg;
u16 irqmux_map;
spinlock_t irqmux_lock;
};

static inline int stm32_gpio_pin(int gpio)
Expand Down Expand Up @@ -359,9 +361,53 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
{
struct stm32_gpio_bank *bank = d->host_data;
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
int ret = 0;

/*
* gpio irq mux is shared between several banks, a lock has to be done
* to avoid overriding.
*/
spin_lock_irqsave(&pctl->irqmux_lock, flags);
if (pctl->hwlock)
ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);

if (ret) {
dev_err(pctl->dev, "Can't get hwspinlock\n");
goto unlock;
}

if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
dev_err(pctl->dev, "irq line %ld already requested.\n",
irq_data->hwirq);
ret = -EBUSY;
if (pctl->hwlock)
hwspin_unlock(pctl->hwlock);
goto unlock;
} else {
pctl->irqmux_map |= BIT(irq_data->hwirq);
}

regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
return 0;

if (pctl->hwlock)
hwspin_unlock(pctl->hwlock);

unlock:
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
return ret;
}

static void stm32_gpio_domain_deactivate(struct irq_domain *d,
struct irq_data *irq_data)
{
struct stm32_gpio_bank *bank = d->host_data;
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;

spin_lock_irqsave(&pctl->irqmux_lock, flags);
pctl->irqmux_map &= ~BIT(irq_data->hwirq);
spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
}

static int stm32_gpio_domain_alloc(struct irq_domain *d,
Expand Down Expand Up @@ -390,6 +436,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = {
.alloc = stm32_gpio_domain_alloc,
.free = irq_domain_free_irqs_common,
.activate = stm32_gpio_domain_activate,
.deactivate = stm32_gpio_domain_deactivate,
};

/* Pinctrl functions */
Expand Down Expand Up @@ -1350,6 +1397,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
}

spin_lock_init(&pctl->irqmux_lock);

pctl->dev = dev;
pctl->match_data = match->data;

Expand Down

0 comments on commit 8eb2dfe

Please sign in to comment.