* [PATCH 1/2] irqchip: add documentation for TS-4800 interrupt controller @ 2015-12-18 19:39 Damien Riegel 2015-12-18 19:39 ` [PATCH 2/2] irqchip: add " Damien Riegel 2015-12-20 3:37 ` [PATCH 1/2] irqchip: add documentation for " Rob Herring 0 siblings, 2 replies; 4+ messages in thread From: Damien Riegel @ 2015-12-18 19:39 UTC (permalink / raw) To: linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, kernel-4ysUXcep3aM1wj+D4I0NRVaTQe2KTcn/, Damien Riegel This is an interrupt-controller implemented in an FPGA, to multiplex interrupts generated from other IPs. The FPGA usually uses a GPIO as a parent interrupt controller to notify that one of the multiplexed interrupts has triggered. Signed-off-by: Damien Riegel <damien.riegel-4ysUXcep3aM1wj+D4I0NRVaTQe2KTcn/@public.gmane.org> --- .../bindings/interrupt-controller/technologic,ts4800.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt b/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt new file mode 100644 index 0000000..7f15f1b --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt @@ -0,0 +1,16 @@ +TS-4800 FPGA interrupt controller + +TS-4800 FPGA has an internal interrupt controller. When one of the +interrupts is triggered, the SoC is notified, usually using a GPIO as +parent interrupt source. + +Required properties: +- compatible: should be "technologic,ts4800-irqc" +- interrupt-controller: identifies the node as an interrupt controller +- reg: physical base address of the controller and length of memory mapped + region +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: phandle to the parent interrupt controller this one is + cascaded from +- interrupts: specifies the interrupt line in the interrupt-parent controller -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] irqchip: add TS-4800 interrupt controller 2015-12-18 19:39 [PATCH 1/2] irqchip: add documentation for TS-4800 interrupt controller Damien Riegel @ 2015-12-18 19:39 ` Damien Riegel 2015-12-21 17:52 ` Marc Zyngier 2015-12-20 3:37 ` [PATCH 1/2] irqchip: add documentation for " Rob Herring 1 sibling, 1 reply; 4+ messages in thread From: Damien Riegel @ 2015-12-18 19:39 UTC (permalink / raw) To: linux-kernel, devicetree Cc: Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, kernel, Damien Riegel This commit adds support for the TS-4800 interrupt controller. This controller is instantiated in a companion FPGA, and multiplex interrupts for other FPGA IPs. As this component is external to the SoC, the SoC might need to reserve pins, so this controller is implemented as a platform driver and doesn't use the IRQCHIP_DECLARE construct. Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com> --- drivers/irqchip/Kconfig | 6 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-ts4800.c | 156 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 drivers/irqchip/irq-ts4800.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 27b52c8..e734772 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -137,6 +137,12 @@ config TB10X_IRQC select IRQ_DOMAIN select GENERIC_IRQ_CHIP +config TS4800_IRQ + tristate "TS-4800 IRQ controller" + select IRQ_DOMAIN + help + Support for the TS-4800 FPGA IRQ controller + config VERSATILE_FPGA_IRQ bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index bb3048f..ca9de01 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o obj-$(CONFIG_ST_IRQCHIP) += irq-st.o obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o +obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c new file mode 100644 index 0000000..f5a4d5b --- /dev/null +++ b/drivers/irqchip/irq-ts4800.c @@ -0,0 +1,156 @@ +/* + * Multiplexed-IRQs driver for TS-4800's FPGA + * + * Copyright (c) 2015 - Savoir-faire Linux + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> + +#define IRQ_MASK 0x4 +#define IRQ_STATUS 0x8 + +struct ts4800_irq_data { + void __iomem *base; + struct irq_domain *domain; + struct irq_chip irq_chip; +}; + +static void ts4800_irq_mask(struct irq_data *d) +{ + struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d); + u16 mask = 1 << d->hwirq; + u16 reg = readw(data->base + IRQ_MASK); + + writew(reg | mask, data->base + IRQ_MASK); +} + +static void ts4800_irq_unmask(struct irq_data *d) +{ + struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d); + u16 mask = 1 << d->hwirq; + u16 reg = readw(data->base + IRQ_MASK); + + writew(reg & ~mask, data->base + IRQ_MASK); +} + +static int ts4800_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct ts4800_irq_data *data = d->host_data; + + irq_set_chip_and_handler(irq, &data->irq_chip, handle_simple_irq); + irq_set_chip_data(irq, data); + irq_set_noprobe(irq); + + return 0; +} + +struct irq_domain_ops ts4800_ic_ops = { + .map = ts4800_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + +static void ts4800_ic_chained_handle_irq(struct irq_desc *desc) +{ + struct ts4800_irq_data *data = irq_desc_get_handler_data(desc); + u16 status = readw(data->base + IRQ_STATUS); + + if (unlikely(status == 0)) { + handle_bad_irq(desc); + return; + } + + do { + unsigned int bit = __ffs(status); + int irq = irq_find_mapping(data->domain, bit); + + status &= ~(1 << bit); + generic_handle_irq(irq); + } while (status); +} + +static int ts4800_ic_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct ts4800_irq_data *data; + struct irq_chip *irq_chip; + struct resource *res; + int parent_irq; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + writew(0xFFFF, data->base + IRQ_MASK); + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) { + dev_err(&pdev->dev, "failed to get parent IRQ\n"); + return -EINVAL; + } + + irq_chip = &data->irq_chip; + irq_chip->name = dev_name(&pdev->dev); + irq_chip->irq_mask = ts4800_irq_mask; + irq_chip->irq_unmask = ts4800_irq_unmask; + + data->domain = irq_domain_add_linear(node, 8, &ts4800_ic_ops, data); + if (!data->domain) { + dev_err(&pdev->dev, "cannot add IRQ domain\n"); + return -ENOMEM; + } + + irq_set_chained_handler_and_data(parent_irq, + ts4800_ic_chained_handle_irq, data); + + platform_set_drvdata(pdev, data); + + return 0; +} + +static int ts4800_ic_remove(struct platform_device *pdev) +{ + struct ts4800_irq_data *data = platform_get_drvdata(pdev); + + irq_domain_remove(data->domain); + + return 0; +} + +static const struct of_device_id ts4800_ic_of_match[] = { + { .compatible = "technologic,ts4800-irqc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ts4800_ic_of_match); + +static struct platform_driver ts4800_ic_driver = { + .probe = ts4800_ic_probe, + .remove = ts4800_ic_remove, + .driver = { + .name = "ts4800-irqc", + .of_match_table = ts4800_ic_of_match, + }, +}; +module_platform_driver(ts4800_ic_driver); + +MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ts4800_irqc"); -- 2.5.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] irqchip: add TS-4800 interrupt controller 2015-12-18 19:39 ` [PATCH 2/2] irqchip: add " Damien Riegel @ 2015-12-21 17:52 ` Marc Zyngier 0 siblings, 0 replies; 4+ messages in thread From: Marc Zyngier @ 2015-12-21 17:52 UTC (permalink / raw) To: Damien Riegel Cc: linux-kernel, devicetree, Thomas Gleixner, Jason Cooper, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, kernel On Fri, 18 Dec 2015 14:39:19 -0500 Damien Riegel <damien.riegel@savoirfairelinux.com> wrote: > This commit adds support for the TS-4800 interrupt controller. This > controller is instantiated in a companion FPGA, and multiplex interrupts > for other FPGA IPs. > > As this component is external to the SoC, the SoC might need to reserve > pins, so this controller is implemented as a platform driver and doesn't > use the IRQCHIP_DECLARE construct. > > Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com> > --- > drivers/irqchip/Kconfig | 6 ++ > drivers/irqchip/Makefile | 1 + > drivers/irqchip/irq-ts4800.c | 156 +++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 163 insertions(+) > create mode 100644 drivers/irqchip/irq-ts4800.c > > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig > index 27b52c8..e734772 100644 > --- a/drivers/irqchip/Kconfig > +++ b/drivers/irqchip/Kconfig > @@ -137,6 +137,12 @@ config TB10X_IRQC > select IRQ_DOMAIN > select GENERIC_IRQ_CHIP > > +config TS4800_IRQ > + tristate "TS-4800 IRQ controller" > + select IRQ_DOMAIN > + help > + Support for the TS-4800 FPGA IRQ controller > + > config VERSATILE_FPGA_IRQ > bool > select IRQ_DOMAIN > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile > index bb3048f..ca9de01 100644 > --- a/drivers/irqchip/Makefile > +++ b/drivers/irqchip/Makefile > @@ -39,6 +39,7 @@ obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o > obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o > obj-$(CONFIG_ST_IRQCHIP) += irq-st.o > obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o > +obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o > obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o > obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o > obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o > diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c > new file mode 100644 > index 0000000..f5a4d5b > --- /dev/null > +++ b/drivers/irqchip/irq-ts4800.c > @@ -0,0 +1,156 @@ > +/* > + * Multiplexed-IRQs driver for TS-4800's FPGA > + * > + * Copyright (c) 2015 - Savoir-faire Linux > + * > + * This file is licensed under the terms of the GNU General Public > + * License version 2. This program is licensed "as is" without any > + * warranty of any kind, whether express or implied. > + */ > + > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/irq.h> > +#include <linux/irqchip.h> > +#include <linux/irqdomain.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/of_irq.h> > +#include <linux/platform_device.h> > + > +#define IRQ_MASK 0x4 > +#define IRQ_STATUS 0x8 > + > +struct ts4800_irq_data { > + void __iomem *base; > + struct irq_domain *domain; > + struct irq_chip irq_chip; > +}; > + > +static void ts4800_irq_mask(struct irq_data *d) > +{ > + struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d); > + u16 mask = 1 << d->hwirq; > + u16 reg = readw(data->base + IRQ_MASK); > + > + writew(reg | mask, data->base + IRQ_MASK); > +} > + > +static void ts4800_irq_unmask(struct irq_data *d) > +{ > + struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d); > + u16 mask = 1 << d->hwirq; > + u16 reg = readw(data->base + IRQ_MASK); > + > + writew(reg & ~mask, data->base + IRQ_MASK); > +} > + > +static int ts4800_irqdomain_map(struct irq_domain *d, unsigned int irq, > + irq_hw_number_t hwirq) > +{ > + struct ts4800_irq_data *data = d->host_data; > + > + irq_set_chip_and_handler(irq, &data->irq_chip, handle_simple_irq); > + irq_set_chip_data(irq, data); > + irq_set_noprobe(irq); > + > + return 0; > +} > + > +struct irq_domain_ops ts4800_ic_ops = { > + .map = ts4800_irqdomain_map, > + .xlate = irq_domain_xlate_onecell, > +}; > + > +static void ts4800_ic_chained_handle_irq(struct irq_desc *desc) > +{ > + struct ts4800_irq_data *data = irq_desc_get_handler_data(desc); > + u16 status = readw(data->base + IRQ_STATUS); > + > + if (unlikely(status == 0)) { > + handle_bad_irq(desc); > + return; > + } > + > + do { > + unsigned int bit = __ffs(status); > + int irq = irq_find_mapping(data->domain, bit); > + > + status &= ~(1 << bit); > + generic_handle_irq(irq); > + } while (status); > +} Please use chained_irq_{enter,exit} to wrap this, or this will never work when combined with a primary irqchip that uses a fasteoi handling method. Thanks, M. -- Without deviation from the norm, progress is not possible. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] irqchip: add documentation for TS-4800 interrupt controller 2015-12-18 19:39 [PATCH 1/2] irqchip: add documentation for TS-4800 interrupt controller Damien Riegel 2015-12-18 19:39 ` [PATCH 2/2] irqchip: add " Damien Riegel @ 2015-12-20 3:37 ` Rob Herring 1 sibling, 0 replies; 4+ messages in thread From: Rob Herring @ 2015-12-20 3:37 UTC (permalink / raw) To: Damien Riegel Cc: linux-kernel, devicetree, Thomas Gleixner, Jason Cooper, Marc Zyngier, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, kernel On Fri, Dec 18, 2015 at 02:39:18PM -0500, Damien Riegel wrote: > This is an interrupt-controller implemented in an FPGA, to multiplex > interrupts generated from other IPs. The FPGA usually uses a GPIO as a > parent interrupt controller to notify that one of the multiplexed > interrupts has triggered. > > Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com> > --- > .../bindings/interrupt-controller/technologic,ts4800.txt | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > create mode 100644 Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt Acked-by: Rob Herring <robh@kernel.org> ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2015-12-21 17:52 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-12-18 19:39 [PATCH 1/2] irqchip: add documentation for TS-4800 interrupt controller Damien Riegel 2015-12-18 19:39 ` [PATCH 2/2] irqchip: add " Damien Riegel 2015-12-21 17:52 ` Marc Zyngier 2015-12-20 3:37 ` [PATCH 1/2] irqchip: add documentation for " Rob Herring
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox