public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Add TI-Nspire irqchip support
@ 2013-05-30 11:23 Daniel Tang
  2013-05-30 14:53 ` Thomas Gleixner
  0 siblings, 1 reply; 4+ messages in thread
From: Daniel Tang @ 2013-05-30 11:23 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: linux-kernel@vger.kernel.org

Hi,

This patch adds a driver for the interrupt controller found in the TI-Nspire calculator series.

Cheers,
Daniel Tang

Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
---
 .../interrupt-controller/lsi,zevio-intc.txt        |  18 +++
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-zevio.c                        | 177 +++++++++++++++++++++
 3 files changed, 196 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt
 create mode 100644 drivers/irqchip/irq-zevio.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt
new file mode 100644
index 0000000..aee38e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt
@@ -0,0 +1,18 @@
+TI-NSPIRE interrupt controller
+
+Required properties:
+- compatible: Compatible property value should be "lsi,zevio-intc".
+
+- reg: Physical base address of the controller and length of memory mapped
+	region.
+
+- interrupt-controller : Identifies the node as an interrupt controller
+
+Example:
+
+interrupt-controller {
+	compatible = "lsi,zevio-intc";
+	interrupt-controller;
+	reg = <0xDC000000 0x1000>;
+	#interrupt-cells = <1>;
+};
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..f313d14 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -15,4 +15,5 @@ obj-$(CONFIG_SIRF_IRQ)			+= irq-sirfsoc.o
 obj-$(CONFIG_RENESAS_INTC_IRQPIN)	+= irq-renesas-intc-irqpin.o
 obj-$(CONFIG_RENESAS_IRQC)		+= irq-renesas-irqc.o
 obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
+obj-$(CONFIG_ARCH_NSPIRE)		+= irq-zevio.o
 obj-$(CONFIG_ARCH_VT8500)		+= irq-vt8500.o
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
new file mode 100644
index 0000000..7786f73
--- /dev/null
+++ b/drivers/irqchip/irq-zevio.c
@@ -0,0 +1,177 @@
+/*
+ *  linux/drivers/irqchip/irq-zevio.c
+ *
+ *  Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/mach/irq.h>
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define IO_STATUS	0x000
+#define IO_RAW_STATUS	0x004
+#define IO_ENABLE	0x008
+#define IO_DISABLE	0x00C
+#define IO_CURRENT	0x020
+#define IO_RESET	0x028
+#define IO_MAX_PRIOTY	0x02C
+
+#define IO_IRQ_BASE	0x000
+#define IO_FIQ_BASE	0x100
+
+#define IO_INVERT_SEL	0x200
+#define IO_STICKY_SEL	0x204
+#define IO_PRIORITY_SEL	0x300
+
+#define MAX_INTRS	32
+#define FIQ_START	MAX_INTRS
+
+
+static void __iomem *irq_io_base;
+static struct irq_domain *zevio_irq_domain;
+
+static void zevio_irq_ack(struct irq_data *irqd)
+{
+	void __iomem *base = irq_io_base;
+
+	if (irqd->hwirq < FIQ_START)
+		base += IO_IRQ_BASE;
+	else
+		base += IO_FIQ_BASE;
+
+	readl(base + IO_RESET);
+}
+
+static void zevio_irq_unmask(struct irq_data *irqd)
+{
+	void __iomem *base = irq_io_base;
+	int irqnr = irqd->hwirq;
+
+	if (irqnr < FIQ_START) {
+		base += IO_IRQ_BASE;
+	} else {
+		irqnr -= MAX_INTRS;
+		base += IO_FIQ_BASE;
+	}
+
+	writel((1<<irqnr), base + IO_ENABLE);
+}
+
+static void zevio_irq_mask(struct irq_data *irqd)
+{
+	void __iomem *base = irq_io_base;
+	int irqnr = irqd->hwirq;
+
+	if (irqnr < FIQ_START) {
+		base += IO_IRQ_BASE;
+	} else {
+		irqnr -= FIQ_START;
+		base += IO_FIQ_BASE;
+	}
+
+	writel((1<<irqnr), base + IO_DISABLE);
+}
+
+static struct irq_chip zevio_irq_chip = {
+	.name		= "zevio_irq",
+	.irq_ack	= zevio_irq_ack,
+	.irq_mask	= zevio_irq_mask,
+	.irq_unmask	= zevio_irq_unmask,
+};
+
+
+static int zevio_irq_map(struct irq_domain *dom, unsigned int virq,
+		irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(virq, &zevio_irq_chip, handle_level_irq);
+	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops zevio_irq_ops = {
+	.map = zevio_irq_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static void init_base(void __iomem *base)
+{
+	/* Disable all interrupts */
+	writel(~0, base + IO_DISABLE);
+
+	/* Accept interrupts of all priorities */
+	writel(0xF, base + IO_MAX_PRIOTY);
+
+	/* Reset existing interrupts */
+	readl(base + IO_RESET);
+}
+
+static int process_base(void __iomem *base, struct pt_regs *regs)
+{
+	int irqnr;
+
+
+	if (!readl(base + IO_STATUS))
+		return 0;
+
+	irqnr = readl(base + IO_CURRENT);
+	irqnr = irq_find_mapping(zevio_irq_domain, irqnr);
+	handle_IRQ(irqnr, regs);
+
+	return 1;
+}
+
+asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
+{
+	while (process_base(irq_io_base + IO_FIQ_BASE, regs))
+		;
+	while (process_base(irq_io_base + IO_IRQ_BASE, regs))
+		;
+}
+
+static int __init zevio_of_init(struct device_node *node,
+				struct device_node *parent)
+{
+	if (WARN_ON(irq_io_base))
+		return -EBUSY;
+
+	irq_io_base = of_iomap(node, 0);
+	BUG_ON(!irq_io_base);
+
+	/* Do not invert interrupt status bits */
+	writel(~0, irq_io_base + IO_INVERT_SEL);
+
+	/* Disable sticky interrupts */
+	writel(0, irq_io_base + IO_STICKY_SEL);
+
+	/* We don't use IRQ priorities. Set each IRQ to highest priority. */
+	memset_io(irq_io_base + IO_PRIORITY_SEL, 0, MAX_INTRS * sizeof(u32));
+
+	/* Init IRQ and FIQ */
+	init_base(irq_io_base + IO_IRQ_BASE);
+	init_base(irq_io_base + IO_FIQ_BASE);
+
+	zevio_irq_domain = irq_domain_add_linear(node, MAX_INTRS,
+						 &zevio_irq_ops, NULL);
+
+	BUG_ON(!zevio_irq_domain);
+
+	set_handle_irq(zevio_handle_irq);
+
+	pr_info("TI-NSPIRE classic IRQ controller\n");
+	return 0;
+}
+
+IRQCHIP_DECLARE(zevio_irq, "lsi,zevio-intc", zevio_of_init);
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add TI-Nspire irqchip support
  2013-05-30 11:23 [PATCH] Add TI-Nspire irqchip support Daniel Tang
@ 2013-05-30 14:53 ` Thomas Gleixner
  2013-05-31 12:06   ` Grant Likely
  0 siblings, 1 reply; 4+ messages in thread
From: Thomas Gleixner @ 2013-05-30 14:53 UTC (permalink / raw)
  To: Daniel Tang; +Cc: linux-kernel@vger.kernel.org

On Thu, 30 May 2013, Daniel Tang wrote:
 
> Hi,
> 
> This patch adds a driver for the interrupt controller found in the TI-Nspire calculator series.
> 
> Cheers,
> Daniel Tang

This is NOT a proper changelog.
 
> Signed-off-by: Daniel Tang <dt.tangr@gmail.com>

Also please read through this mail thread:

     https://lkml.org/lkml/2013/5/2/406

and rework your patches against:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core

> +static void __iomem *irq_io_base;
> +static struct irq_domain *zevio_irq_domain;
> +
> +static void zevio_irq_ack(struct irq_data *irqd)
> +{
> +	void __iomem *base = irq_io_base;
> +
> +	if (irqd->hwirq < FIQ_START)
> +		base += IO_IRQ_BASE;
> +	else
> +		base += IO_FIQ_BASE;

This is horrible. If you redo this against the generic irq chip then
provide a separate base with the proper offsets to each chip. So you
can avoid this clumsy conditionals completely.

> +	readl(base + IO_RESET);
> +}
> +
> +static void zevio_irq_unmask(struct irq_data *irqd)
> +{
> +	void __iomem *base = irq_io_base;
> +	int irqnr = irqd->hwirq;
> +
> +	if (irqnr < FIQ_START) {
> +		base += IO_IRQ_BASE;
> +	} else {
> +		irqnr -= MAX_INTRS;
> +		base += IO_FIQ_BASE;
> +	}
> +
> +	writel((1<<irqnr), base + IO_ENABLE);

Replace with the generic function

> +}
> +
> +static void zevio_irq_mask(struct irq_data *irqd)
> +{
> +	void __iomem *base = irq_io_base;
> +	int irqnr = irqd->hwirq;
> +
> +	if (irqnr < FIQ_START) {
> +		base += IO_IRQ_BASE;
> +	} else {
> +		irqnr -= FIQ_START;
> +		base += IO_FIQ_BASE;
> +	}
> +
> +	writel((1<<irqnr), base + IO_DISABLE);

Replace with the generic function

> +static int process_base(void __iomem *base, struct pt_regs *regs)
> +{
> +	int irqnr;
> +
> +
> +	if (!readl(base + IO_STATUS))
> +		return 0;
> +
> +	irqnr = readl(base + IO_CURRENT);
> +	irqnr = irq_find_mapping(zevio_irq_domain, irqnr);
> +	handle_IRQ(irqnr, regs);
> +
> +	return 1;
> +}
> +
> +asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
> +{
> +	while (process_base(irq_io_base + IO_FIQ_BASE, regs))
> +		;

Wheee. That's ugly as hell. Why don't you move the while loop into process_base() ?

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add TI-Nspire irqchip support
  2013-05-30 14:53 ` Thomas Gleixner
@ 2013-05-31 12:06   ` Grant Likely
  2013-06-08  1:45     ` Daniel Tang
  0 siblings, 1 reply; 4+ messages in thread
From: Grant Likely @ 2013-05-31 12:06 UTC (permalink / raw)
  To: Thomas Gleixner, Daniel Tang; +Cc: linux-kernel@vger.kernel.org

On Thu, 30 May 2013 16:53:31 +0200 (CEST), Thomas Gleixner <tglx@linutronix.de> wrote:
> On Thu, 30 May 2013, Daniel Tang wrote:
>  
> > Hi,
> > 
> > This patch adds a driver for the interrupt controller found in the TI-Nspire calculator series.
> > 
> > Cheers,
> > Daniel Tang
> 
> This is NOT a proper changelog.

Hi Daniel,

What is the SoC used in the Nspire? Is it something custom for the
calculator, or does it use an existing SoC? I'm just surprised that this
device needs a new interrupt controller driver rather than one of the
drivers that is already in the tree.

If it is a new device, then that is fine, but you should follow the
discussion that Thomas pointed you at below.

g.

>  
> > Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
> 
> Also please read through this mail thread:
> 
>      https://lkml.org/lkml/2013/5/2/406
> 
> and rework your patches against:
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
> 
> > +static void __iomem *irq_io_base;
> > +static struct irq_domain *zevio_irq_domain;
> > +
> > +static void zevio_irq_ack(struct irq_data *irqd)
> > +{
> > +	void __iomem *base = irq_io_base;
> > +
> > +	if (irqd->hwirq < FIQ_START)
> > +		base += IO_IRQ_BASE;
> > +	else
> > +		base += IO_FIQ_BASE;
> 
> This is horrible. If you redo this against the generic irq chip then
> provide a separate base with the proper offsets to each chip. So you
> can avoid this clumsy conditionals completely.
> 
> > +	readl(base + IO_RESET);
> > +}
> > +
> > +static void zevio_irq_unmask(struct irq_data *irqd)
> > +{
> > +	void __iomem *base = irq_io_base;
> > +	int irqnr = irqd->hwirq;
> > +
> > +	if (irqnr < FIQ_START) {
> > +		base += IO_IRQ_BASE;
> > +	} else {
> > +		irqnr -= MAX_INTRS;
> > +		base += IO_FIQ_BASE;
> > +	}
> > +
> > +	writel((1<<irqnr), base + IO_ENABLE);
> 
> Replace with the generic function
> 
> > +}
> > +
> > +static void zevio_irq_mask(struct irq_data *irqd)
> > +{
> > +	void __iomem *base = irq_io_base;
> > +	int irqnr = irqd->hwirq;
> > +
> > +	if (irqnr < FIQ_START) {
> > +		base += IO_IRQ_BASE;
> > +	} else {
> > +		irqnr -= FIQ_START;
> > +		base += IO_FIQ_BASE;
> > +	}
> > +
> > +	writel((1<<irqnr), base + IO_DISABLE);
> 
> Replace with the generic function
> 
> > +static int process_base(void __iomem *base, struct pt_regs *regs)
> > +{
> > +	int irqnr;
> > +
> > +
> > +	if (!readl(base + IO_STATUS))
> > +		return 0;
> > +
> > +	irqnr = readl(base + IO_CURRENT);
> > +	irqnr = irq_find_mapping(zevio_irq_domain, irqnr);
> > +	handle_IRQ(irqnr, regs);
> > +
> > +	return 1;
> > +}
> > +
> > +asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
> > +{
> > +	while (process_base(irq_io_base + IO_FIQ_BASE, regs))
> > +		;
> 
> Wheee. That's ugly as hell. Why don't you move the while loop into process_base() ?
> 
> Thanks,
> 
> 	tglx
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-- 
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add TI-Nspire irqchip support
  2013-05-31 12:06   ` Grant Likely
@ 2013-06-08  1:45     ` Daniel Tang
  0 siblings, 0 replies; 4+ messages in thread
From: Daniel Tang @ 2013-06-08  1:45 UTC (permalink / raw)
  To: Grant Likely; +Cc: Thomas Gleixner, linux-kernel@vger.kernel.org

Hi,

On 31/05/2013, at 10:06 PM, Grant Likely <grant.likely@secretlab.ca> wrote:

> 
> Hi Daniel,
> 
> What is the SoC used in the Nspire? Is it something custom for the
> calculator, or does it use an existing SoC?

It seems to be a custom SoC from what I can see.

> I'm just surprised that this
> device needs a new interrupt controller driver rather than one of the
> drivers that is already in the tree.

I had a brief look in the other driver code and there doesn't seem to be a existing driver for this interrupt controller.

> 
> If it is a new device, then that is fine, but you should follow the
> discussion that Thomas pointed you at below.
> 
> g.
> 

Cheers,
Daniel Tang

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-06-08  1:45 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-30 11:23 [PATCH] Add TI-Nspire irqchip support Daniel Tang
2013-05-30 14:53 ` Thomas Gleixner
2013-05-31 12:06   ` Grant Likely
2013-06-08  1:45     ` Daniel Tang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox