]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/irqchip/irq-tb10x.c
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Abilis Systems interrupt controller driver
5 * Copyright (C) Abilis Systems 2012
7 * Author: Christian Ruppert <christian.ruppert@abilis.com>
10 #include <linux/interrupt.h>
11 #include <linux/irqdomain.h>
12 #include <linux/irq.h>
13 #include <linux/irqchip.h>
14 #include <linux/of_irq.h>
15 #include <linux/of_address.h>
16 #include <linux/of_platform.h>
18 #include <linux/slab.h>
19 #include <linux/bitops.h>
21 #define AB_IRQCTL_INT_ENABLE 0x00
22 #define AB_IRQCTL_INT_STATUS 0x04
23 #define AB_IRQCTL_SRC_MODE 0x08
24 #define AB_IRQCTL_SRC_POLARITY 0x0C
25 #define AB_IRQCTL_INT_MODE 0x10
26 #define AB_IRQCTL_INT_POLARITY 0x14
27 #define AB_IRQCTL_INT_FORCE 0x18
29 #define AB_IRQCTL_MAXIRQ 32
31 static inline void ab_irqctl_writereg(struct irq_chip_generic
*gc
, u32 reg
,
34 irq_reg_writel(gc
, val
, reg
);
37 static inline u32
ab_irqctl_readreg(struct irq_chip_generic
*gc
, u32 reg
)
39 return irq_reg_readl(gc
, reg
);
42 static int tb10x_irq_set_type(struct irq_data
*data
, unsigned int flow_type
)
44 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(data
);
45 uint32_t im
, mod
, pol
;
51 mod
= ab_irqctl_readreg(gc
, AB_IRQCTL_SRC_MODE
) | im
;
52 pol
= ab_irqctl_readreg(gc
, AB_IRQCTL_SRC_POLARITY
) | im
;
54 switch (flow_type
& IRQF_TRIGGER_MASK
) {
55 case IRQ_TYPE_EDGE_FALLING
:
58 case IRQ_TYPE_LEVEL_HIGH
:
62 flow_type
= IRQ_TYPE_LEVEL_LOW
;
63 case IRQ_TYPE_LEVEL_LOW
:
67 case IRQ_TYPE_EDGE_RISING
:
71 pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
76 irqd_set_trigger_type(data
, flow_type
);
77 irq_setup_alt_chip(data
, flow_type
);
79 ab_irqctl_writereg(gc
, AB_IRQCTL_SRC_MODE
, mod
);
80 ab_irqctl_writereg(gc
, AB_IRQCTL_SRC_POLARITY
, pol
);
81 ab_irqctl_writereg(gc
, AB_IRQCTL_INT_STATUS
, im
);
85 return IRQ_SET_MASK_OK
;
88 static void tb10x_irq_cascade(struct irq_desc
*desc
)
90 struct irq_domain
*domain
= irq_desc_get_handler_data(desc
);
91 unsigned int irq
= irq_desc_get_irq(desc
);
93 generic_handle_irq(irq_find_mapping(domain
, irq
));
96 static int __init
of_tb10x_init_irq(struct device_node
*ictl
,
97 struct device_node
*parent
)
99 int i
, ret
, nrirqs
= of_irq_count(ictl
);
101 struct irq_chip_generic
*gc
;
102 struct irq_domain
*domain
;
103 void __iomem
*reg_base
;
105 if (of_address_to_resource(ictl
, 0, &mem
)) {
106 pr_err("%pOFn: No registers declared in DeviceTree.\n",
111 if (!request_mem_region(mem
.start
, resource_size(&mem
),
113 pr_err("%pOFn: Request mem region failed.\n", ictl
);
117 reg_base
= ioremap(mem
.start
, resource_size(&mem
));
120 pr_err("%pOFn: ioremap failed.\n", ictl
);
124 domain
= irq_domain_add_linear(ictl
, AB_IRQCTL_MAXIRQ
,
125 &irq_generic_chip_ops
, NULL
);
128 pr_err("%pOFn: Could not register interrupt domain.\n",
130 goto irq_domain_add_fail
;
133 ret
= irq_alloc_domain_generic_chips(domain
, AB_IRQCTL_MAXIRQ
,
134 2, ictl
->name
, handle_level_irq
,
135 IRQ_NOREQUEST
, IRQ_NOPROBE
,
136 IRQ_GC_INIT_MASK_CACHE
);
138 pr_err("%pOFn: Could not allocate generic interrupt chip.\n",
143 gc
= domain
->gc
->gc
[0];
144 gc
->reg_base
= reg_base
;
146 gc
->chip_types
[0].type
= IRQ_TYPE_LEVEL_MASK
;
147 gc
->chip_types
[0].chip
.irq_mask
= irq_gc_mask_clr_bit
;
148 gc
->chip_types
[0].chip
.irq_unmask
= irq_gc_mask_set_bit
;
149 gc
->chip_types
[0].chip
.irq_set_type
= tb10x_irq_set_type
;
150 gc
->chip_types
[0].regs
.mask
= AB_IRQCTL_INT_ENABLE
;
152 gc
->chip_types
[1].type
= IRQ_TYPE_EDGE_BOTH
;
153 gc
->chip_types
[1].chip
.name
= gc
->chip_types
[0].chip
.name
;
154 gc
->chip_types
[1].chip
.irq_ack
= irq_gc_ack_set_bit
;
155 gc
->chip_types
[1].chip
.irq_mask
= irq_gc_mask_clr_bit
;
156 gc
->chip_types
[1].chip
.irq_unmask
= irq_gc_mask_set_bit
;
157 gc
->chip_types
[1].chip
.irq_set_type
= tb10x_irq_set_type
;
158 gc
->chip_types
[1].regs
.ack
= AB_IRQCTL_INT_STATUS
;
159 gc
->chip_types
[1].regs
.mask
= AB_IRQCTL_INT_ENABLE
;
160 gc
->chip_types
[1].handler
= handle_edge_irq
;
162 for (i
= 0; i
< nrirqs
; i
++) {
163 unsigned int irq
= irq_of_parse_and_map(ictl
, i
);
165 irq_set_chained_handler_and_data(irq
, tb10x_irq_cascade
,
169 ab_irqctl_writereg(gc
, AB_IRQCTL_INT_ENABLE
, 0);
170 ab_irqctl_writereg(gc
, AB_IRQCTL_INT_MODE
, 0);
171 ab_irqctl_writereg(gc
, AB_IRQCTL_INT_POLARITY
, 0);
172 ab_irqctl_writereg(gc
, AB_IRQCTL_INT_STATUS
, ~0UL);
177 irq_domain_remove(domain
);
181 release_mem_region(mem
.start
, resource_size(&mem
));
184 IRQCHIP_DECLARE(tb10x_intc
, "abilis,tb10x-ictl", of_tb10x_init_irq
);