Skip to content

Commit 529ea36

Browse files
tsbogendMarc Zyngier
authored andcommitted
irqchip: Add support for IDT 79rc3243x interrupt controller
IDT 79rc3243x SoCs have rather simple interrupt controllers connected to the MIPS CPU interrupt lines. Each of them has room for up to 32 interrupts. Signed-off-by: Thomas Bogendoerfer <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 817aad5 commit 529ea36

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

drivers/irqchip/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,4 +583,9 @@ config WPCM450_AIC
583583
help
584584
Support for the interrupt controller in the Nuvoton WPCM450 BMC SoC.
585585

586+
config IRQ_IDT3243X
587+
bool
588+
select GENERIC_IRQ_CHIP
589+
select IRQ_DOMAIN
590+
586591
endmenu

drivers/irqchip/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,4 @@ obj-$(CONFIG_MST_IRQ) += irq-mst-intc.o
114114
obj-$(CONFIG_SL28CPLD_INTC) += irq-sl28cpld.o
115115
obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o
116116
obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o
117+
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o

drivers/irqchip/irq-idt3243x.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Driver for IDT/Renesas 79RC3243x Interrupt Controller.
4+
*/
5+
6+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7+
8+
#include <linux/interrupt.h>
9+
#include <linux/irq.h>
10+
#include <linux/irqchip.h>
11+
#include <linux/irqchip/chained_irq.h>
12+
#include <linux/irqdomain.h>
13+
#include <linux/of_address.h>
14+
#include <linux/of_irq.h>
15+
16+
#define IDT_PIC_NR_IRQS 32
17+
18+
#define IDT_PIC_IRQ_PEND 0x00
19+
#define IDT_PIC_IRQ_MASK 0x08
20+
21+
struct idt_pic_data {
22+
void __iomem *base;
23+
struct irq_domain *irq_domain;
24+
struct irq_chip_generic *gc;
25+
};
26+
27+
static void idt_irq_dispatch(struct irq_desc *desc)
28+
{
29+
struct idt_pic_data *idtpic = irq_desc_get_handler_data(desc);
30+
struct irq_chip *host_chip = irq_desc_get_chip(desc);
31+
u32 pending, hwirq, virq;
32+
33+
chained_irq_enter(host_chip, desc);
34+
35+
pending = irq_reg_readl(idtpic->gc, IDT_PIC_IRQ_PEND);
36+
pending &= ~idtpic->gc->mask_cache;
37+
while (pending) {
38+
hwirq = __fls(pending);
39+
virq = irq_linear_revmap(idtpic->irq_domain, hwirq);
40+
if (virq)
41+
generic_handle_irq(virq);
42+
pending &= ~(1 << hwirq);
43+
}
44+
45+
chained_irq_exit(host_chip, desc);
46+
}
47+
48+
static int idt_pic_init(struct device_node *of_node, struct device_node *parent)
49+
{
50+
struct irq_domain *domain;
51+
struct idt_pic_data *idtpic;
52+
struct irq_chip_generic *gc;
53+
struct irq_chip_type *ct;
54+
unsigned int parent_irq;
55+
int ret = 0;
56+
57+
idtpic = kzalloc(sizeof(*idtpic), GFP_KERNEL);
58+
if (!idtpic) {
59+
ret = -ENOMEM;
60+
goto out_err;
61+
}
62+
63+
parent_irq = irq_of_parse_and_map(of_node, 0);
64+
if (!parent_irq) {
65+
pr_err("Failed to map parent IRQ!\n");
66+
ret = -EINVAL;
67+
goto out_free;
68+
}
69+
70+
idtpic->base = of_iomap(of_node, 0);
71+
if (!idtpic->base) {
72+
pr_err("Failed to map base address!\n");
73+
ret = -ENOMEM;
74+
goto out_unmap_irq;
75+
}
76+
77+
domain = irq_domain_add_linear(of_node, IDT_PIC_NR_IRQS,
78+
&irq_generic_chip_ops, NULL);
79+
if (!domain) {
80+
pr_err("Failed to add irqdomain!\n");
81+
ret = -ENOMEM;
82+
goto out_iounmap;
83+
}
84+
idtpic->irq_domain = domain;
85+
86+
ret = irq_alloc_domain_generic_chips(domain, 32, 1, "IDTPIC",
87+
handle_level_irq, 0,
88+
IRQ_NOPROBE | IRQ_LEVEL, 0);
89+
if (ret)
90+
goto out_domain_remove;
91+
92+
gc = irq_get_domain_generic_chip(domain, 0);
93+
gc->reg_base = idtpic->base;
94+
gc->private = idtpic;
95+
96+
ct = gc->chip_types;
97+
ct->regs.mask = IDT_PIC_IRQ_MASK;
98+
ct->chip.irq_mask = irq_gc_mask_set_bit;
99+
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
100+
idtpic->gc = gc;
101+
102+
/* Mask interrupts. */
103+
writel(0xffffffff, idtpic->base + IDT_PIC_IRQ_MASK);
104+
gc->mask_cache = 0xffffffff;
105+
106+
irq_set_chained_handler_and_data(parent_irq,
107+
idt_irq_dispatch, idtpic);
108+
109+
return 0;
110+
111+
out_domain_remove:
112+
irq_domain_remove(domain);
113+
out_iounmap:
114+
iounmap(idtpic->base);
115+
out_unmap_irq:
116+
irq_dispose_mapping(parent_irq);
117+
out_free:
118+
kfree(idtpic);
119+
out_err:
120+
pr_err("Failed to initialize! (errno = %d)\n", ret);
121+
return ret;
122+
}
123+
124+
IRQCHIP_DECLARE(idt_pic, "idt,32434-pic", idt_pic_init);

0 commit comments

Comments
 (0)