@@ -6,6 +6,7 @@
*/
#include <linux/bitops.h>
+#include <linux/hwspinlock.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -20,6 +21,8 @@
#define IRQS_PER_BANK 32
+#define HWSPINLOCK_TIMEOUT 5 /* msec */
+
struct stm32_exti_bank {
u32 imr_ofst;
u32 emr_ofst;
@@ -47,6 +50,7 @@ struct stm32_exti_drv_data {
struct stm32_exti_chip_data {
struct stm32_exti_host_data *host_data;
const struct stm32_exti_bank *reg_bank;
+ struct hwspinlock *hwlock;
struct raw_spinlock rlock;
u32 wake_active;
u32 mask_cache;
@@ -275,25 +279,34 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
struct stm32_exti_chip_data *chip_data = gc->private;
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
u32 rtsr, ftsr;
- int err;
+ int err = 0;
irq_gc_lock(gc);
+ if (chip_data->hwlock)
+ err = hwspin_lock_timeout(chip_data->hwlock,
+ HWSPINLOCK_TIMEOUT);
+
+ if (err)
+ goto unlock;
+
rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
- if (err) {
- irq_gc_unlock(gc);
- return err;
- }
+ if (err)
+ goto unspinlock;
irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
+unspinlock:
+ if (chip_data->hwlock)
+ hwspin_unlock(chip_data->hwlock);
+unlock:
irq_gc_unlock(gc);
- return 0;
+ return err;
}
static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data,
@@ -670,6 +683,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
int nr_irqs, ret, i;
struct irq_chip_generic *gc;
struct irq_domain *domain;
+ struct hwspinlock *hwlock = NULL;
host_data = stm32_exti_host_init(drv_data, node);
if (!host_data)
@@ -692,12 +706,22 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
goto out_free_domain;
}
+ /* hwspinlock is optional */
+ ret = of_hwspin_lock_get_id(node, 0);
+ if (ret < 0) {
+ if (ret == -EPROBE_DEFER)
+ goto out_free_domain;
+ } else {
+ hwlock = hwspin_lock_request_specific(ret);
+ }
+
for (i = 0; i < drv_data->bank_nr; i++) {
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;
stm32_bank = drv_data->exti_banks[i];
chip_data = stm32_exti_chip_init(host_data, i, node);
+ chip_data->hwlock = hwlock;
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
If a hwspinlock is defined in device tree use it to protect configuration registers. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com> --- drivers/irqchip/irq-stm32-exti.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) -- 2.15.0