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/irqdomain.h>
23 #include <linux/irqchip.h>
24 #include <linux/irqchip/chained_irq.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
;
44 static inline u32
keystone_irq_readl(struct keystone_irq_device
*kirq
)
49 ret
= regmap_read(kirq
->devctrl_regs
, kirq
->devctrl_offset
, &val
);
51 dev_dbg(kirq
->dev
, "irq read failed ret(%d)\n", ret
);
56 keystone_irq_writel(struct keystone_irq_device
*kirq
, u32 value
)
60 ret
= regmap_write(kirq
->devctrl_regs
, kirq
->devctrl_offset
, value
);
62 dev_dbg(kirq
->dev
, "irq write failed ret(%d)\n", ret
);
65 static void keystone_irq_setmask(struct irq_data
*d
)
67 struct keystone_irq_device
*kirq
= irq_data_get_irq_chip_data(d
);
69 kirq
->mask
|= BIT(d
->hwirq
);
70 dev_dbg(kirq
->dev
, "mask %lu [%x]\n", d
->hwirq
, kirq
->mask
);
73 static void keystone_irq_unmask(struct irq_data
*d
)
75 struct keystone_irq_device
*kirq
= irq_data_get_irq_chip_data(d
);
77 kirq
->mask
&= ~BIT(d
->hwirq
);
78 dev_dbg(kirq
->dev
, "unmask %lu [%x]\n", d
->hwirq
, kirq
->mask
);
81 static void keystone_irq_ack(struct irq_data
*d
)
83 /* nothing to do here */
86 static void keystone_irq_handler(struct irq_desc
*desc
)
88 unsigned int irq
= irq_desc_get_irq(desc
);
89 struct keystone_irq_device
*kirq
= irq_desc_get_handler_data(desc
);
90 unsigned long pending
;
93 dev_dbg(kirq
->dev
, "start irq %d\n", irq
);
95 chained_irq_enter(irq_desc_get_chip(desc
), desc
);
97 pending
= keystone_irq_readl(kirq
);
98 keystone_irq_writel(kirq
, pending
);
100 dev_dbg(kirq
->dev
, "pending 0x%lx, mask 0x%x\n", pending
, kirq
->mask
);
102 pending
= (pending
>> BIT_OFS
) & ~kirq
->mask
;
104 dev_dbg(kirq
->dev
, "pending after mask 0x%lx\n", pending
);
106 for (src
= 0; src
< KEYSTONE_N_IRQ
; src
++) {
107 if (BIT(src
) & pending
) {
108 virq
= irq_find_mapping(kirq
->irqd
, src
);
109 dev_dbg(kirq
->dev
, "dispatch bit %d, virq %d\n",
112 dev_warn(kirq
->dev
, "spurious irq detected hwirq %d, virq %d\n",
114 generic_handle_irq(virq
);
118 chained_irq_exit(irq_desc_get_chip(desc
), desc
);
120 dev_dbg(kirq
->dev
, "end irq %d\n", irq
);
123 static int keystone_irq_map(struct irq_domain
*h
, unsigned int virq
,
126 struct keystone_irq_device
*kirq
= h
->host_data
;
128 irq_set_chip_data(virq
, kirq
);
129 irq_set_chip_and_handler(virq
, &kirq
->chip
, handle_level_irq
);
134 static const struct irq_domain_ops keystone_irq_ops
= {
135 .map
= keystone_irq_map
,
136 .xlate
= irq_domain_xlate_onecell
,
139 static int keystone_irq_probe(struct platform_device
*pdev
)
141 struct device
*dev
= &pdev
->dev
;
142 struct device_node
*np
= dev
->of_node
;
143 struct keystone_irq_device
*kirq
;
149 kirq
= devm_kzalloc(dev
, sizeof(*kirq
), GFP_KERNEL
);
154 syscon_regmap_lookup_by_phandle(np
, "ti,syscon-dev");
155 if (IS_ERR(kirq
->devctrl_regs
))
156 return PTR_ERR(kirq
->devctrl_regs
);
158 ret
= of_property_read_u32_index(np
, "ti,syscon-dev", 1,
159 &kirq
->devctrl_offset
);
161 dev_err(dev
, "couldn't read the devctrl_offset offset!\n");
165 kirq
->irq
= platform_get_irq(pdev
, 0);
167 dev_err(dev
, "no irq resource %d\n", kirq
->irq
);
173 kirq
->chip
.name
= "keystone-irq";
174 kirq
->chip
.irq_ack
= keystone_irq_ack
;
175 kirq
->chip
.irq_mask
= keystone_irq_setmask
;
176 kirq
->chip
.irq_unmask
= keystone_irq_unmask
;
178 kirq
->irqd
= irq_domain_add_linear(np
, KEYSTONE_N_IRQ
,
179 &keystone_irq_ops
, kirq
);
181 dev_err(dev
, "IRQ domain registration failed\n");
185 platform_set_drvdata(pdev
, kirq
);
187 irq_set_chained_handler_and_data(kirq
->irq
, keystone_irq_handler
, kirq
);
189 /* clear all source bits */
190 keystone_irq_writel(kirq
, ~0x0);
192 dev_info(dev
, "irqchip registered, nr_irqs %u\n", KEYSTONE_N_IRQ
);
197 static int keystone_irq_remove(struct platform_device
*pdev
)
199 struct keystone_irq_device
*kirq
= platform_get_drvdata(pdev
);
202 for (hwirq
= 0; hwirq
< KEYSTONE_N_IRQ
; hwirq
++)
203 irq_dispose_mapping(irq_find_mapping(kirq
->irqd
, hwirq
));
205 irq_domain_remove(kirq
->irqd
);
209 static const struct of_device_id keystone_irq_dt_ids
[] = {
210 { .compatible
= "ti,keystone-irq", },
213 MODULE_DEVICE_TABLE(of
, keystone_irq_dt_ids
);
215 static struct platform_driver keystone_irq_device_driver
= {
216 .probe
= keystone_irq_probe
,
217 .remove
= keystone_irq_remove
,
219 .name
= "keystone_irq",
220 .of_match_table
= of_match_ptr(keystone_irq_dt_ids
),
224 module_platform_driver(keystone_irq_device_driver
);
226 MODULE_AUTHOR("Texas Instruments");
227 MODULE_AUTHOR("Sajesh Kumar Saran");
228 MODULE_AUTHOR("Grygorii Strashko");
229 MODULE_DESCRIPTION("Keystone IRQ chip");
230 MODULE_LICENSE("GPL v2");