1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2019, Jiaxun Yang <jiaxun.yang@flygoat.com>
4 * Loongson-1 platform IRQ support
7 #include <linux/errno.h>
8 #include <linux/init.h>
9 #include <linux/types.h>
10 #include <linux/interrupt.h>
11 #include <linux/ioport.h>
12 #include <linux/irqchip.h>
13 #include <linux/of_address.h>
14 #include <linux/of_irq.h>
16 #include <linux/irqchip/chained_irq.h>
18 #define LS_REG_INTC_STATUS 0x00
19 #define LS_REG_INTC_EN 0x04
20 #define LS_REG_INTC_SET 0x08
21 #define LS_REG_INTC_CLR 0x0c
22 #define LS_REG_INTC_POL 0x10
23 #define LS_REG_INTC_EDGE 0x14
26 * struct ls1x_intc_priv - private ls1x-intc data.
27 * @domain: IRQ domain.
28 * @intc_base: IO Base of intc registers.
31 struct ls1x_intc_priv
{
32 struct irq_domain
*domain
;
33 void __iomem
*intc_base
;
37 static void ls1x_chained_handle_irq(struct irq_desc
*desc
)
39 struct ls1x_intc_priv
*priv
= irq_desc_get_handler_data(desc
);
40 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
43 chained_irq_enter(chip
, desc
);
44 pending
= readl(priv
->intc_base
+ LS_REG_INTC_STATUS
) &
45 readl(priv
->intc_base
+ LS_REG_INTC_EN
);
51 int bit
= __ffs(pending
);
53 generic_handle_irq(irq_find_mapping(priv
->domain
, bit
));
57 chained_irq_exit(chip
, desc
);
60 static void ls_intc_set_bit(struct irq_chip_generic
*gc
,
65 writel(readl(gc
->reg_base
+ offset
) | mask
,
66 gc
->reg_base
+ offset
);
68 writel(readl(gc
->reg_base
+ offset
) & ~mask
,
69 gc
->reg_base
+ offset
);
72 static int ls_intc_set_type(struct irq_data
*data
, unsigned int type
)
74 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(data
);
75 u32 mask
= data
->mask
;
78 case IRQ_TYPE_LEVEL_HIGH
:
79 ls_intc_set_bit(gc
, LS_REG_INTC_EDGE
, mask
, false);
80 ls_intc_set_bit(gc
, LS_REG_INTC_POL
, mask
, true);
82 case IRQ_TYPE_LEVEL_LOW
:
83 ls_intc_set_bit(gc
, LS_REG_INTC_EDGE
, mask
, false);
84 ls_intc_set_bit(gc
, LS_REG_INTC_POL
, mask
, false);
86 case IRQ_TYPE_EDGE_RISING
:
87 ls_intc_set_bit(gc
, LS_REG_INTC_EDGE
, mask
, true);
88 ls_intc_set_bit(gc
, LS_REG_INTC_POL
, mask
, true);
90 case IRQ_TYPE_EDGE_FALLING
:
91 ls_intc_set_bit(gc
, LS_REG_INTC_EDGE
, mask
, true);
92 ls_intc_set_bit(gc
, LS_REG_INTC_POL
, mask
, false);
98 irqd_set_trigger_type(data
, type
);
99 return irq_setup_alt_chip(data
, type
);
103 static int __init
ls1x_intc_of_init(struct device_node
*node
,
104 struct device_node
*parent
)
106 struct irq_chip_generic
*gc
;
107 struct irq_chip_type
*ct
;
108 struct ls1x_intc_priv
*priv
;
109 int parent_irq
, err
= 0;
111 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
115 priv
->intc_base
= of_iomap(node
, 0);
116 if (!priv
->intc_base
) {
121 parent_irq
= irq_of_parse_and_map(node
, 0);
123 pr_err("ls1x-irq: unable to get parent irq\n");
128 /* Set up an IRQ domain */
129 priv
->domain
= irq_domain_add_linear(node
, 32, &irq_generic_chip_ops
,
132 pr_err("ls1x-irq: cannot add IRQ domain\n");
137 err
= irq_alloc_domain_generic_chips(priv
->domain
, 32, 2,
138 node
->full_name
, handle_level_irq
,
139 IRQ_NOREQUEST
| IRQ_NOPROBE
| IRQ_NOAUTOEN
, 0,
140 IRQ_GC_INIT_MASK_CACHE
);
142 pr_err("ls1x-irq: unable to register IRQ domain\n");
143 goto out_free_domain
;
147 writel(0x0, priv
->intc_base
+ LS_REG_INTC_EN
);
150 writel(0xffffffff, priv
->intc_base
+ LS_REG_INTC_CLR
);
152 /* Set all irqs to high level triggered */
153 writel(0xffffffff, priv
->intc_base
+ LS_REG_INTC_POL
);
155 gc
= irq_get_domain_generic_chip(priv
->domain
, 0);
157 gc
->reg_base
= priv
->intc_base
;
160 ct
[0].type
= IRQ_TYPE_LEVEL_MASK
;
161 ct
[0].regs
.mask
= LS_REG_INTC_EN
;
162 ct
[0].regs
.ack
= LS_REG_INTC_CLR
;
163 ct
[0].chip
.irq_unmask
= irq_gc_mask_set_bit
;
164 ct
[0].chip
.irq_mask
= irq_gc_mask_clr_bit
;
165 ct
[0].chip
.irq_ack
= irq_gc_ack_set_bit
;
166 ct
[0].chip
.irq_set_type
= ls_intc_set_type
;
167 ct
[0].handler
= handle_level_irq
;
169 ct
[1].type
= IRQ_TYPE_EDGE_BOTH
;
170 ct
[1].regs
.mask
= LS_REG_INTC_EN
;
171 ct
[1].regs
.ack
= LS_REG_INTC_CLR
;
172 ct
[1].chip
.irq_unmask
= irq_gc_mask_set_bit
;
173 ct
[1].chip
.irq_mask
= irq_gc_mask_clr_bit
;
174 ct
[1].chip
.irq_ack
= irq_gc_ack_set_bit
;
175 ct
[1].chip
.irq_set_type
= ls_intc_set_type
;
176 ct
[1].handler
= handle_edge_irq
;
178 irq_set_chained_handler_and_data(parent_irq
,
179 ls1x_chained_handle_irq
, priv
);
184 irq_domain_remove(priv
->domain
);
186 iounmap(priv
->intc_base
);
193 IRQCHIP_DECLARE(ls1x_intc
, "loongson,ls1x-intc", ls1x_intc_of_init
);