summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Torgue <alexandre.torgue@st.com>2019-05-10 03:43:03 -0400
committerLinus Walleij <linus.walleij@linaro.org>2019-05-24 07:25:34 -0400
commit8eb2dfee9fb1277f635ce369ef8669df0ec421bc (patch)
tree5dabf8afdf4745656d165ee7c0a840ad6ef5220d
parenta45623ddd0520d43d16d9943efd3a851d7247e19 (diff)
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 <alexandre.torgue@st.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c51
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index 335aea59c8d1..92e35fb930be 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -111,6 +111,8 @@ struct stm32_pinctrl {
111 struct stm32_desc_pin *pins; 111 struct stm32_desc_pin *pins;
112 u32 npins; 112 u32 npins;
113 u32 pkg; 113 u32 pkg;
114 u16 irqmux_map;
115 spinlock_t irqmux_lock;
114}; 116};
115 117
116static inline int stm32_gpio_pin(int gpio) 118static inline int stm32_gpio_pin(int gpio)
@@ -359,9 +361,53 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
359{ 361{
360 struct stm32_gpio_bank *bank = d->host_data; 362 struct stm32_gpio_bank *bank = d->host_data;
361 struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 363 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 }
362 390
363 regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); 391 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
396unlock:
397 spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
398 return ret;
399}
400
401static 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);
365} 411}
366 412
367static int stm32_gpio_domain_alloc(struct irq_domain *d, 413static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -390,6 +436,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = {
390 .alloc = stm32_gpio_domain_alloc, 436 .alloc = stm32_gpio_domain_alloc,
391 .free = irq_domain_free_irqs_common, 437 .free = irq_domain_free_irqs_common,
392 .activate = stm32_gpio_domain_activate, 438 .activate = stm32_gpio_domain_activate,
439 .deactivate = stm32_gpio_domain_deactivate,
393}; 440};
394 441
395/* Pinctrl functions */ 442/* Pinctrl functions */
@@ -1350,6 +1397,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
1350 pctl->hwlock = hwspin_lock_request_specific(hwlock_id); 1397 pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
1351 } 1398 }
1352 1399
1400 spin_lock_init(&pctl->irqmux_lock);
1401
1353 pctl->dev = dev; 1402 pctl->dev = dev;
1354 pctl->match_data = match->data; 1403 pctl->match_data = match->data;
1355 1404