summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 {
struct stm32_desc_pin *pins;
u32 npins;
u32 pkg;
+ u16 irqmux_map;
+ spinlock_t irqmux_lock;
};
static inline int stm32_gpio_pin(int gpio)
@@ -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,
@@ -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 */
@@ -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;