1 // SPDX-License-Identifier: GPL-2.0-only
3 * Texas Instruments Keystone IRQ controller IP driver
5 * Copyright (C) 2014 Texas Instruments, Inc.
6 * Author: Sajesh Kumar Saran <sajesh@ti.com>
7 * Grygorii Strashko <grygorii.strashko@ti.com>
10 #include <linux/irq.h>
11 #include <linux/bitops.h>
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/interrupt.h>
15 #include <linux/irqdomain.h>
16 #include <linux/irqchip.h>
18 #include <linux/platform_device.h>
19 #include <linux/mfd/syscon.h>
20 #include <linux/regmap.h>
22 /* The source ID bits start from 4 to 31 (total 28 bits)*/
24 #define KEYSTONE_N_IRQ (32 - BIT_OFS)
26 struct keystone_irq_device
{
31 struct irq_domain
*irqd
;
32 struct regmap
*devctrl_regs
;
34 raw_spinlock_t wa_lock
;
37 static inline u32
keystone_irq_readl(struct keystone_irq_device
*kirq
)
42 ret
= regmap_read(kirq
->devctrl_regs
, kirq
->devctrl_offset
, &val
);
44 dev_dbg(kirq
->dev
, "irq read failed ret(%d)\n", ret
);
49 keystone_irq_writel(struct keystone_irq_device
*kirq
, u32 value
)
53 ret
= regmap_write(kirq
->devctrl_regs
, kirq
->devctrl_offset
, value
);
55 dev_dbg(kirq
->dev
, "irq write failed ret(%d)\n", ret
);
58 static void keystone_irq_setmask(struct irq_data
*d
)
60 struct keystone_irq_device
*kirq
= irq_data_get_irq_chip_data(d
);
62 kirq
->mask
|= BIT(d
->hwirq
);
63 dev_dbg(kirq
->dev
, "mask %lu [%x]\n", d
->hwirq
, kirq
->mask
);
66 static void keystone_irq_unmask(struct irq_data
*d
)
68 struct keystone_irq_device
*kirq
= irq_data_get_irq_chip_data(d
);
70 kirq
->mask
&= ~BIT(d
->hwirq
);
71 dev_dbg(kirq
->dev
, "unmask %lu [%x]\n", d
->hwirq
, kirq
->mask
);
74 static void keystone_irq_ack(struct irq_data
*d
)
76 /* nothing to do here */
79 static irqreturn_t
keystone_irq_handler(int irq
, void *keystone_irq
)
81 struct keystone_irq_device
*kirq
= keystone_irq
;
82 unsigned long wa_lock_flags
;
83 unsigned long pending
;
86 dev_dbg(kirq
->dev
, "start irq %d\n", irq
);
88 pending
= keystone_irq_readl(kirq
);
89 keystone_irq_writel(kirq
, pending
);
91 dev_dbg(kirq
->dev
, "pending 0x%lx, mask 0x%x\n", pending
, kirq
->mask
);
93 pending
= (pending
>> BIT_OFS
) & ~kirq
->mask
;
95 dev_dbg(kirq
->dev
, "pending after mask 0x%lx\n", pending
);
97 for (src
= 0; src
< KEYSTONE_N_IRQ
; src
++) {
98 if (BIT(src
) & pending
) {
99 raw_spin_lock_irqsave(&kirq
->wa_lock
, wa_lock_flags
);
100 err
= generic_handle_domain_irq(kirq
->irqd
, src
);
101 raw_spin_unlock_irqrestore(&kirq
->wa_lock
,
105 dev_warn_ratelimited(kirq
->dev
, "spurious irq detected hwirq %d\n",
110 dev_dbg(kirq
->dev
, "end irq %d\n", irq
);
114 static int keystone_irq_map(struct irq_domain
*h
, unsigned int virq
,
117 struct keystone_irq_device
*kirq
= h
->host_data
;
119 irq_set_chip_data(virq
, kirq
);
120 irq_set_chip_and_handler(virq
, &kirq
->chip
, handle_level_irq
);
125 static const struct irq_domain_ops keystone_irq_ops
= {
126 .map
= keystone_irq_map
,
127 .xlate
= irq_domain_xlate_onecell
,
130 static int keystone_irq_probe(struct platform_device
*pdev
)
132 struct device
*dev
= &pdev
->dev
;
133 struct device_node
*np
= dev
->of_node
;
134 struct keystone_irq_device
*kirq
;
140 kirq
= devm_kzalloc(dev
, sizeof(*kirq
), GFP_KERNEL
);
145 syscon_regmap_lookup_by_phandle(np
, "ti,syscon-dev");
146 if (IS_ERR(kirq
->devctrl_regs
))
147 return PTR_ERR(kirq
->devctrl_regs
);
149 ret
= of_property_read_u32_index(np
, "ti,syscon-dev", 1,
150 &kirq
->devctrl_offset
);
152 dev_err(dev
, "couldn't read the devctrl_offset offset!\n");
156 kirq
->irq
= platform_get_irq(pdev
, 0);
162 kirq
->chip
.name
= "keystone-irq";
163 kirq
->chip
.irq_ack
= keystone_irq_ack
;
164 kirq
->chip
.irq_mask
= keystone_irq_setmask
;
165 kirq
->chip
.irq_unmask
= keystone_irq_unmask
;
167 kirq
->irqd
= irq_domain_add_linear(np
, KEYSTONE_N_IRQ
,
168 &keystone_irq_ops
, kirq
);
170 dev_err(dev
, "IRQ domain registration failed\n");
174 raw_spin_lock_init(&kirq
->wa_lock
);
176 platform_set_drvdata(pdev
, kirq
);
178 ret
= request_irq(kirq
->irq
, keystone_irq_handler
,
179 0, dev_name(dev
), kirq
);
181 irq_domain_remove(kirq
->irqd
);
185 /* clear all source bits */
186 keystone_irq_writel(kirq
, ~0x0);
188 dev_info(dev
, "irqchip registered, nr_irqs %u\n", KEYSTONE_N_IRQ
);
193 static void keystone_irq_remove(struct platform_device
*pdev
)
195 struct keystone_irq_device
*kirq
= platform_get_drvdata(pdev
);
198 free_irq(kirq
->irq
, kirq
);
200 for (hwirq
= 0; hwirq
< KEYSTONE_N_IRQ
; hwirq
++)
201 irq_dispose_mapping(irq_find_mapping(kirq
->irqd
, hwirq
));
203 irq_domain_remove(kirq
->irqd
);
206 static const struct of_device_id keystone_irq_dt_ids
[] = {
207 { .compatible
= "ti,keystone-irq", },
210 MODULE_DEVICE_TABLE(of
, keystone_irq_dt_ids
);
212 static struct platform_driver keystone_irq_device_driver
= {
213 .probe
= keystone_irq_probe
,
214 .remove
= keystone_irq_remove
,
216 .name
= "keystone_irq",
217 .of_match_table
= of_match_ptr(keystone_irq_dt_ids
),
221 module_platform_driver(keystone_irq_device_driver
);
223 MODULE_AUTHOR("Texas Instruments");
224 MODULE_AUTHOR("Sajesh Kumar Saran");
225 MODULE_AUTHOR("Grygorii Strashko");
226 MODULE_DESCRIPTION("Keystone IRQ chip");
227 MODULE_LICENSE("GPL v2");