From: tip-bot for Alexandre TORGUE <tipbot@zytor.com>
To: linux-tip-commits@vger.kernel.org
Cc: alexandre.torgue@st.com, jason@lakedaemon.net, mingo@kernel.org,
tglx@linutronix.de, hpa@zytor.com, daniel.thompson@linaro.org,
linus.walleij@linaro.org, robh+dt@kernel.org,
mark.rutland@arm.com, linux-kernel@vger.kernel.org,
marc.zyngier@arm.com
Subject: [tip:irq/core] drivers/irqchip: Add STM32 external interrupts support
Date: Wed, 21 Sep 2016 05:19:35 -0700 [thread overview]
Message-ID: <tip-e072041688ca73f125719815fa4b0fd23a45152c@git.kernel.org> (raw)
In-Reply-To: <1474387259-18926-3-git-send-email-alexandre.torgue@st.com>
Commit-ID: e072041688ca73f125719815fa4b0fd23a45152c
Gitweb: http://git.kernel.org/tip/e072041688ca73f125719815fa4b0fd23a45152c
Author: Alexandre TORGUE <alexandre.torgue@st.com>
AuthorDate: Tue, 20 Sep 2016 18:00:57 +0200
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Wed, 21 Sep 2016 14:13:21 +0200
drivers/irqchip: Add STM32 external interrupts support
The STM32 external interrupt controller consists of edge detectors that
generate interrupts requests or wake-up events.
Each line can be independently configured as interrupt or wake-up source,
and triggers either on rising, falling or both edges. Each line can also
be masked independently.
Originally-from: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: arnd@arndb.de
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: bruherrera@gmail.com
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: linux-gpio@vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: lee.jones@linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/1474387259-18926-3-git-send-email-alexandre.torgue@st.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
drivers/irqchip/Kconfig | 4 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-stm32-exti.c | 201 +++++++++++++++++++++++++++++++++++++++
3 files changed, 206 insertions(+)
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 9aeea1d..329c941 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -265,3 +265,7 @@ config EZNPS_GIC
select IRQ_DOMAIN
help
Support the EZchip NPS400 global interrupt controller
+
+config STM32_EXTI
+ bool
+ select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 4c203b6..96383b2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -71,3 +71,4 @@ obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
+obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
new file mode 100644
index 0000000..491568c
--- /dev/null
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define EXTI_IMR 0x0
+#define EXTI_EMR 0x4
+#define EXTI_RTSR 0x8
+#define EXTI_FTSR 0xc
+#define EXTI_SWIER 0x10
+#define EXTI_PR 0x14
+
+static void stm32_irq_handler(struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ struct irq_chip_generic *gc = domain->gc->gc[0];
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long pending;
+ int n;
+
+ chained_irq_enter(chip, desc);
+
+ while ((pending = irq_reg_readl(gc, EXTI_PR))) {
+ for_each_set_bit(n, &pending, BITS_PER_LONG) {
+ generic_handle_irq(irq_find_mapping(domain, n));
+ irq_reg_writel(gc, BIT(n), EXTI_PR);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static int stm32_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ int pin = data->hwirq;
+ u32 rtsr, ftsr;
+
+ irq_gc_lock(gc);
+
+ rtsr = irq_reg_readl(gc, EXTI_RTSR);
+ ftsr = irq_reg_readl(gc, EXTI_FTSR);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ rtsr |= BIT(pin);
+ ftsr &= ~BIT(pin);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ rtsr &= ~BIT(pin);
+ ftsr |= BIT(pin);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ rtsr |= BIT(pin);
+ ftsr |= BIT(pin);
+ break;
+ default:
+ irq_gc_unlock(gc);
+ return -EINVAL;
+ }
+
+ irq_reg_writel(gc, rtsr, EXTI_RTSR);
+ irq_reg_writel(gc, ftsr, EXTI_FTSR);
+
+ irq_gc_unlock(gc);
+
+ return 0;
+}
+
+static int stm32_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ int pin = data->hwirq;
+ u32 emr;
+
+ irq_gc_lock(gc);
+
+ emr = irq_reg_readl(gc, EXTI_EMR);
+ if (on)
+ emr |= BIT(pin);
+ else
+ emr &= ~BIT(pin);
+ irq_reg_writel(gc, emr, EXTI_EMR);
+
+ irq_gc_unlock(gc);
+
+ return 0;
+}
+
+static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs, void *data)
+{
+ struct irq_chip_generic *gc = d->gc->gc[0];
+ struct irq_fwspec *fwspec = data;
+ irq_hw_number_t hwirq;
+
+ hwirq = fwspec->param[0];
+
+ irq_map_generic_chip(d, virq, hwirq);
+ irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc,
+ handle_simple_irq, NULL, NULL);
+
+ return 0;
+}
+
+static void stm32_exti_free(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *data = irq_domain_get_irq_data(d, virq);
+
+ irq_domain_reset_irq_data(data);
+}
+
+struct irq_domain_ops irq_exti_domain_ops = {
+ .map = irq_map_generic_chip,
+ .xlate = irq_domain_xlate_onetwocell,
+ .alloc = stm32_exti_alloc,
+ .free = stm32_exti_free,
+};
+
+static int __init stm32_exti_init(struct device_node *node,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int nr_irqs, nr_exti, ret, i;
+ struct irq_chip_generic *gc;
+ struct irq_domain *domain;
+ void *base;
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("%s: Unable to map registers\n", node->full_name);
+ return -ENOMEM;
+ }
+
+ /* Determine number of irqs supported */
+ writel_relaxed(~0UL, base + EXTI_RTSR);
+ nr_exti = fls(readl_relaxed(base + EXTI_RTSR));
+ writel_relaxed(0, base + EXTI_RTSR);
+
+ pr_info("%s: %d External IRQs detected\n", node->full_name, nr_exti);
+
+ domain = irq_domain_add_linear(node, nr_exti,
+ &irq_exti_domain_ops, NULL);
+ if (!domain) {
+ pr_err("%s: Could not register interrupt domain.\n",
+ node->name);
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, nr_exti, 1, "exti",
+ handle_edge_irq, clr, 0, 0);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ node->full_name);
+ goto out_free_domain;
+ }
+
+ gc = domain->gc->gc[0];
+ gc->reg_base = base;
+ gc->chip_types->type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types->chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types->chip.irq_set_type = stm32_irq_set_type;
+ gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake;
+ gc->chip_types->regs.ack = EXTI_PR;
+ gc->chip_types->regs.mask = EXTI_IMR;
+ gc->chip_types->handler = handle_edge_irq;
+
+ nr_irqs = of_irq_count(node);
+ for (i = 0; i < nr_irqs; i++) {
+ unsigned int irq = irq_of_parse_and_map(node, i);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, stm32_irq_handler);
+ }
+
+ return 0;
+
+out_free_domain:
+ irq_domain_remove(domain);
+out_unmap:
+ iounmap(base);
+ return ret;
+}
+
+IRQCHIP_DECLARE(stm32_exti, "st,stm32-exti", stm32_exti_init);
next prev parent reply other threads:[~2016-09-21 12:19 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-20 16:00 [PATCH v6 0/4] Add STM32 EXTI interrupt controller support Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 16:00 ` [PATCH v6 1/4] Documentation: dt-bindings: Document STM32 EXTI controller bindings Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-21 12:19 ` [tip:irq/core] Documentation/dt-bindings: " tip-bot for Alexandre TORGUE
2016-09-20 16:00 ` [PATCH v6 2/4] drivers: irqchip: Add STM32 external interrupts support Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 20:16 ` Thomas Gleixner
2016-09-20 20:16 ` Thomas Gleixner
2016-09-21 7:45 ` Alexandre Torgue
2016-09-21 7:45 ` Alexandre Torgue
2016-09-21 7:45 ` Alexandre Torgue
[not found] ` <f7875786-9b5e-075a-59c8-cd32fb1c4583-qxv4g6HH51o@public.gmane.org>
2016-09-21 7:50 ` Thomas Gleixner
2016-09-21 7:50 ` Thomas Gleixner
2016-09-21 7:50 ` Thomas Gleixner
2016-09-21 7:54 ` Maxime Coquelin
2016-09-21 7:54 ` Maxime Coquelin
2016-09-21 7:54 ` Maxime Coquelin
2016-09-21 12:19 ` tip-bot for Alexandre TORGUE [this message]
2016-09-20 16:00 ` [PATCH v6 3/4] ARM: STM32: Select external interrupts controller Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-21 12:20 ` [tip:irq/core] ARM/STM32: " tip-bot for Alexandre TORGUE
2016-09-20 16:00 ` [PATCH v6 4/4] ARM: dts: Add EXTI controller node to stm32f429 Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-20 16:00 ` Alexandre TORGUE
2016-09-21 12:20 ` [tip:irq/core] ARM/dts: " tip-bot for Alexandre TORGUE
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=tip-e072041688ca73f125719815fa4b0fd23a45152c@git.kernel.org \
--to=tipbot@zytor.com \
--cc=alexandre.torgue@st.com \
--cc=daniel.thompson@linaro.org \
--cc=hpa@zytor.com \
--cc=jason@lakedaemon.net \
--cc=linus.walleij@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tip-commits@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=mark.rutland@arm.com \
--cc=mingo@kernel.org \
--cc=robh+dt@kernel.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.