2 * Texas Instruments Keystone IRQ controller IP driver
4 * Copyright (C) 2014 Texas Instruments, Inc.
5 * Author: Sajesh Kumar Saran <sajesh@ti.com>
6 * Grygorii Strashko <grygorii.strashko@ti.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation version 2.
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
13 * kind, whether express or implied; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #include <linux/irq.h>
19 #include <linux/bitops.h>
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/interrupt.h>
23 #include <linux/irqdomain.h>
24 #include <linux/irqchip.h>
26 #include <linux/of_platform.h>
27 #include <linux/mfd/syscon.h>
28 #include <linux/regmap.h>
30 /* The source ID bits start from 4 to 31 (total 28 bits)*/
32 #define KEYSTONE_N_IRQ (32 - BIT_OFS)
34 struct keystone_irq_device
{
39 struct irq_domain
*irqd
;
40 struct regmap
*devctrl_regs
;
42 raw_spinlock_t wa_lock
;
45 static inline u32
keystone_irq_readl(struct keystone_irq_device
*kirq
)
50 ret
= regmap_read(kirq
->devctrl_regs
, kirq
->devctrl_offset
, &val
);
52 dev_dbg(kirq
->dev
, "irq read failed ret(%d)\n", ret
);
57 keystone_irq_writel(struct keystone_irq_device
*kirq
, u32 value
)
61 ret
= regmap_write(kirq
->devctrl_regs
, kirq
->devctrl_offset
, value
);
63 dev_dbg(kirq
->dev
, "irq write failed ret(%d)\n", ret
);
66 static void keystone_irq_setmask(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
, "mask %lu [%x]\n", d
->hwirq
, kirq
->mask
);
74 static void keystone_irq_unmask(struct irq_data
*d
)
76 struct keystone_irq_device
*kirq
= irq_data_get_irq_chip_data(d
);
78 kirq
->mask
&= ~BIT(d
->hwirq
);
79 dev_dbg(kirq
->dev
, "unmask %lu [%x]\n", d
->hwirq
, kirq
->mask
);
82 static void keystone_irq_ack(struct irq_data
*d
)
84 /* nothing to do here */
87 static irqreturn_t
keystone_irq_handler(int irq
, void *keystone_irq
)
89 struct keystone_irq_device
*kirq
= keystone_irq
;
90 unsigned long wa_lock_flags
;
91 unsigned long pending
;
94 dev_dbg(kirq
->dev
, "start irq %d\n", irq
);
96 pending
= keystone_irq_readl(kirq
);
97 keystone_irq_writel(kirq
, pending
);
99 dev_dbg(kirq
->dev
, "pending 0x%lx, mask 0x%x\n", pending
, kirq
->mask
);
101 pending
= (pending
>> BIT_OFS
) & ~kirq
->mask
;
103 dev_dbg(kirq
->dev
, "pending after mask 0x%lx\n", pending
);
105 for (src
= 0; src
< KEYSTONE_N_IRQ
; src
++) {
106 if (BIT(src
) & pending
) {
107 virq
= irq_find_mapping(kirq
->irqd
, src
);
108 dev_dbg(kirq
->dev
, "dispatch bit %d, virq %d\n",
111 dev_warn(kirq
->dev
, "spurious irq detected hwirq %d, virq %d\n",
113 raw_spin_lock_irqsave(&kirq
->wa_lock
, wa_lock_flags
);
114 generic_handle_irq(virq
);
115 raw_spin_unlock_irqrestore(&kirq
->wa_lock
,
120 dev_dbg(kirq
->dev
, "end irq %d\n", irq
);
124 static int keystone_irq_map(struct irq_domain
*h
, unsigned int virq
,
127 struct keystone_irq_device
*kirq
= h
->host_data
;
129 irq_set_chip_data(virq
, kirq
);
130 irq_set_chip_and_handler(virq
, &kirq
->chip
, handle_level_irq
);
135 static const struct irq_domain_ops keystone_irq_ops
= {
136 .map
= keystone_irq_map
,
137 .xlate
= irq_domain_xlate_onecell
,
140 static int keystone_irq_probe(struct platform_device
*pdev
)
142 struct device
*dev
= &pdev
->dev
;
143 struct device_node
*np
= dev
->of_node
;
144 struct keystone_irq_device
*kirq
;
150 kirq
= devm_kzalloc(dev
, sizeof(*kirq
), GFP_KERNEL
);
155 syscon_regmap_lookup_by_phandle(np
, "ti,syscon-dev");
156 if (IS_ERR(kirq
->devctrl_regs
))
157 return PTR_ERR(kirq
->devctrl_regs
);
159 ret
= of_property_read_u32_index(np
, "ti,syscon-dev", 1,
160 &kirq
->devctrl_offset
);
162 dev_err(dev
, "couldn't read the devctrl_offset offset!\n");
166 kirq
->irq
= platform_get_irq(pdev
, 0);
172 kirq
->chip
.name
= "keystone-irq";
173 kirq
->chip
.irq_ack
= keystone_irq_ack
;
174 kirq
->chip
.irq_mask
= keystone_irq_setmask
;
175 kirq
->chip
.irq_unmask
= keystone_irq_unmask
;
177 kirq
->irqd
= irq_domain_add_linear(np
, KEYSTONE_N_IRQ
,
178 &keystone_irq_ops
, kirq
);
180 dev_err(dev
, "IRQ domain registration failed\n");
184 raw_spin_lock_init(&kirq
->wa_lock
);
186 platform_set_drvdata(pdev
, kirq
);
188 ret
= request_irq(kirq
->irq
, keystone_irq_handler
,
189 0, dev_name(dev
), kirq
);
191 irq_domain_remove(kirq
->irqd
);
195 /* clear all source bits */
196 keystone_irq_writel(kirq
, ~0x0);
198 dev_info(dev
, "irqchip registered, nr_irqs %u\n", KEYSTONE_N_IRQ
);
203 static int keystone_irq_remove(struct platform_device
*pdev
)
205 struct keystone_irq_device
*kirq
= platform_get_drvdata(pdev
);
208 free_irq(kirq
->irq
, kirq
);
210 for (hwirq
= 0; hwirq
< KEYSTONE_N_IRQ
; hwirq
++)
211 irq_dispose_mapping(irq_find_mapping(kirq
->irqd
, hwirq
));
213 irq_domain_remove(kirq
->irqd
);
217 static const struct of_device_id keystone_irq_dt_ids
[] = {
218 { .compatible
= "ti,keystone-irq", },
221 MODULE_DEVICE_TABLE(of
, keystone_irq_dt_ids
);
223 static struct platform_driver keystone_irq_device_driver
= {
224 .probe
= keystone_irq_probe
,
225 .remove
= keystone_irq_remove
,
227 .name
= "keystone_irq",
228 .of_match_table
= of_match_ptr(keystone_irq_dt_ids
),
232 module_platform_driver(keystone_irq_device_driver
);
234 MODULE_AUTHOR("Texas Instruments");
235 MODULE_AUTHOR("Sajesh Kumar Saran");
236 MODULE_AUTHOR("Grygorii Strashko");
237 MODULE_DESCRIPTION("Keystone IRQ chip");
238 MODULE_LICENSE("GPL v2");