1210284Sjmallett// SPDX-License-Identifier: GPL-2.0-only
2232812Sjmallett/*
3215990Sjmallett *  linux/drivers/irqchip/irq-zevio.c
4210284Sjmallett *
5210284Sjmallett *  Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
6215990Sjmallett */
7215990Sjmallett
8215990Sjmallett#include <linux/io.h>
9210284Sjmallett#include <linux/irq.h>
10215990Sjmallett#include <linux/irqchip.h>
11215990Sjmallett#include <linux/of.h>
12210284Sjmallett#include <linux/of_address.h>
13215990Sjmallett#include <linux/of_irq.h>
14215990Sjmallett
15215990Sjmallett#include <asm/mach/irq.h>
16215990Sjmallett#include <asm/exception.h>
17215990Sjmallett
18232812Sjmallett#define IO_STATUS	0x000
19215990Sjmallett#define IO_RAW_STATUS	0x004
20215990Sjmallett#define IO_ENABLE	0x008
21215990Sjmallett#define IO_DISABLE	0x00C
22215990Sjmallett#define IO_CURRENT	0x020
23215990Sjmallett#define IO_RESET	0x028
24215990Sjmallett#define IO_MAX_PRIOTY	0x02C
25215990Sjmallett
26215990Sjmallett#define IO_IRQ_BASE	0x000
27215990Sjmallett#define IO_FIQ_BASE	0x100
28215990Sjmallett
29232812Sjmallett#define IO_INVERT_SEL	0x200
30215990Sjmallett#define IO_STICKY_SEL	0x204
31215990Sjmallett#define IO_PRIORITY_SEL	0x300
32215990Sjmallett
33215990Sjmallett#define MAX_INTRS	32
34215990Sjmallett#define FIQ_START	MAX_INTRS
35215990Sjmallett
36215990Sjmallettstatic struct irq_domain *zevio_irq_domain;
37215990Sjmallettstatic void __iomem *zevio_irq_io;
38210284Sjmallett
39210284Sjmallettstatic void zevio_irq_ack(struct irq_data *irqd)
40210284Sjmallett{
41210284Sjmallett	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd);
42210284Sjmallett	struct irq_chip_regs *regs = &irq_data_get_chip_type(irqd)->regs;
43210284Sjmallett
44210284Sjmallett	readl(gc->reg_base + regs->ack);
45215990Sjmallett}
46210284Sjmallett
47210284Sjmallettstatic void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
48210284Sjmallett{
49210284Sjmallett	int irqnr;
50210284Sjmallett
51210284Sjmallett	while (readl(zevio_irq_io + IO_STATUS)) {
52232812Sjmallett		irqnr = readl(zevio_irq_io + IO_CURRENT);
53210284Sjmallett		generic_handle_domain_irq(zevio_irq_domain, irqnr);
54210284Sjmallett	}
55210284Sjmallett}
56210284Sjmallett
57210284Sjmallettstatic void __init zevio_init_irq_base(void __iomem *base)
58210284Sjmallett{
59210284Sjmallett	/* Disable all interrupts */
60210284Sjmallett	writel(~0, base + IO_DISABLE);
61210284Sjmallett
62210284Sjmallett	/* Accept interrupts of all priorities */
63210284Sjmallett	writel(0xF, base + IO_MAX_PRIOTY);
64210284Sjmallett
65210284Sjmallett	/* Reset existing interrupts */
66210284Sjmallett	readl(base + IO_RESET);
67210284Sjmallett}
68232812Sjmallett
69232812Sjmallettstatic int __init zevio_of_init(struct device_node *node,
70232812Sjmallett				struct device_node *parent)
71232812Sjmallett{
72210284Sjmallett	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
73210284Sjmallett	struct irq_chip_generic *gc;
74210284Sjmallett	int ret;
75210284Sjmallett
76210284Sjmallett	if (WARN_ON(zevio_irq_io || zevio_irq_domain))
77210284Sjmallett		return -EBUSY;
78210284Sjmallett
79210284Sjmallett	zevio_irq_io = of_iomap(node, 0);
80210284Sjmallett	BUG_ON(!zevio_irq_io);
81210284Sjmallett
82210284Sjmallett	/* Do not invert interrupt status bits */
83210284Sjmallett	writel(~0, zevio_irq_io + IO_INVERT_SEL);
84210284Sjmallett
85210284Sjmallett	/* Disable sticky interrupts */
86210284Sjmallett	writel(0, zevio_irq_io + IO_STICKY_SEL);
87
88	/* We don't use IRQ priorities. Set each IRQ to highest priority. */
89	memset_io(zevio_irq_io + IO_PRIORITY_SEL, 0, MAX_INTRS * sizeof(u32));
90
91	/* Init IRQ and FIQ */
92	zevio_init_irq_base(zevio_irq_io + IO_IRQ_BASE);
93	zevio_init_irq_base(zevio_irq_io + IO_FIQ_BASE);
94
95	zevio_irq_domain = irq_domain_add_linear(node, MAX_INTRS,
96						 &irq_generic_chip_ops, NULL);
97	BUG_ON(!zevio_irq_domain);
98
99	ret = irq_alloc_domain_generic_chips(zevio_irq_domain, MAX_INTRS, 1,
100					     "zevio_intc", handle_level_irq,
101					     clr, 0, IRQ_GC_INIT_MASK_CACHE);
102	BUG_ON(ret);
103
104	gc = irq_get_domain_generic_chip(zevio_irq_domain, 0);
105	gc->reg_base				= zevio_irq_io;
106	gc->chip_types[0].chip.irq_ack		= zevio_irq_ack;
107	gc->chip_types[0].chip.irq_mask		= irq_gc_mask_disable_reg;
108	gc->chip_types[0].chip.irq_unmask	= irq_gc_unmask_enable_reg;
109	gc->chip_types[0].regs.mask		= IO_IRQ_BASE + IO_ENABLE;
110	gc->chip_types[0].regs.enable		= IO_IRQ_BASE + IO_ENABLE;
111	gc->chip_types[0].regs.disable		= IO_IRQ_BASE + IO_DISABLE;
112	gc->chip_types[0].regs.ack		= IO_IRQ_BASE + IO_RESET;
113
114	set_handle_irq(zevio_handle_irq);
115
116	pr_info("TI-NSPIRE classic IRQ controller\n");
117	return 0;
118}
119
120IRQCHIP_DECLARE(zevio_irq, "lsi,zevio-intc", zevio_of_init);
121