aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/irqchip/Kconfig10
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c577
4 files changed, 589 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 461db0a8233f..055467fb2019 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15352,6 +15352,7 @@ F: drivers/reset/reset-ti-sci.c
15352F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt 15352F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
15353F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt 15353F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
15354F: drivers/irqchip/irq-ti-sci-intr.c 15354F: drivers/irqchip/irq-ti-sci-intr.c
15355F: drivers/irqchip/irq-ti-sci-inta.c
15355 15356
15356Texas Instruments ASoC drivers 15357Texas Instruments ASoC drivers
15357M: Peter Ujfalusi <peter.ujfalusi@ti.com> 15358M: Peter Ujfalusi <peter.ujfalusi@ti.com>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 88bce736d1de..2c8d5daad57c 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -429,6 +429,16 @@ config TI_SCI_INTR_IRQCHIP
429 If you wish to use interrupt router irq resources managed by the 429 If you wish to use interrupt router irq resources managed by the
430 TI System Controller, say Y here. Otherwise, say N. 430 TI System Controller, say Y here. Otherwise, say N.
431 431
432config TI_SCI_INTA_IRQCHIP
433 bool
434 depends on TI_SCI_PROTOCOL
435 select IRQ_DOMAIN_HIERARCHY
436 help
437 This enables the irqchip driver support for K3 Interrupt aggregator
438 over TI System Control Interface available on some new TI's SoCs.
439 If you wish to use interrupt aggregator irq resources managed by the
440 TI System Controller, say Y here. Otherwise, say N.
441
432endmenu 442endmenu
433 443
434config SIFIVE_PLIC 444config SIFIVE_PLIC
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index fa5c865788b5..8a33013da953 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -98,3 +98,4 @@ obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
98obj-$(CONFIG_MADERA_IRQ) += irq-madera.o 98obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
99obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o 99obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
100obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o 100obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
101obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
new file mode 100644
index 000000000000..87e0abe0041f
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -0,0 +1,577 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments' K3 Interrupt Aggregator irqchip driver
4 *
5 * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Lokesh Vutla <lokeshvutla@ti.com>
7 */
8
9#include <linux/err.h>
10#include <linux/io.h>
11#include <linux/irqchip.h>
12#include <linux/irqdomain.h>
13#include <linux/interrupt.h>
14#include <linux/msi.h>
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/of_address.h>
18#include <linux/of_irq.h>
19#include <linux/of_platform.h>
20#include <linux/irqchip/chained_irq.h>
21#include <linux/soc/ti/ti_sci_protocol.h>
22#include <asm-generic/msi.h>
23
24#define TI_SCI_DEV_ID_MASK 0xffff
25#define TI_SCI_DEV_ID_SHIFT 16
26#define TI_SCI_IRQ_ID_MASK 0xffff
27#define TI_SCI_IRQ_ID_SHIFT 0
28#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
29 (TI_SCI_DEV_ID_MASK))
30#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
31
32#define MAX_EVENTS_PER_VINT 64
33#define VINT_ENABLE_SET_OFFSET 0x0
34#define VINT_ENABLE_CLR_OFFSET 0x8
35#define VINT_STATUS_OFFSET 0x18
36
37/**
38 * struct ti_sci_inta_event_desc - Description of an event coming to
39 * Interrupt Aggregator. This serves
40 * as a mapping table for global event,
41 * hwirq and vint bit.
42 * @global_event: Global event number corresponding to this event
43 * @hwirq: Hwirq of the incoming interrupt
44 * @vint_bit: Corresponding vint bit to which this event is attached.
45 */
46struct ti_sci_inta_event_desc {
47 u16 global_event;
48 u32 hwirq;
49 u8 vint_bit;
50};
51
52/**
53 * struct ti_sci_inta_vint_desc - Description of a virtual interrupt coming out
54 * of Interrupt Aggregator.
55 * @domain: Pointer to IRQ domain to which this vint belongs.
56 * @list: List entry for the vint list
57 * @event_map: Bitmap to manage the allocation of events to vint.
58 * @events: Array of event descriptors assigned to this vint.
59 * @parent_virq: Linux IRQ number that gets attached to parent
60 * @vint_id: TISCI vint ID
61 */
62struct ti_sci_inta_vint_desc {
63 struct irq_domain *domain;
64 struct list_head list;
65 DECLARE_BITMAP(event_map, MAX_EVENTS_PER_VINT);
66 struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT];
67 unsigned int parent_virq;
68 u16 vint_id;
69};
70
71/**
72 * struct ti_sci_inta_irq_domain - Structure representing a TISCI based
73 * Interrupt Aggregator IRQ domain.
74 * @sci: Pointer to TISCI handle
75 * @vint: TISCI resource pointer representing IA inerrupts.
76 * @global_event: TISCI resource pointer representing global events.
77 * @vint_list: List of the vints active in the system
78 * @vint_mutex: Mutex to protect vint_list
79 * @base: Base address of the memory mapped IO registers
80 * @pdev: Pointer to platform device.
81 */
82struct ti_sci_inta_irq_domain {
83 const struct ti_sci_handle *sci;
84 struct ti_sci_resource *vint;
85 struct ti_sci_resource *global_event;
86 struct list_head vint_list;
87 /* Mutex to protect vint list */
88 struct mutex vint_mutex;
89 void __iomem *base;
90 struct platform_device *pdev;
91};
92
93#define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
94 events[i])
95
96/**
97 * ti_sci_inta_irq_handler() - Chained IRQ handler for the vint irqs
98 * @desc: Pointer to irq_desc corresponding to the irq
99 */
100static void ti_sci_inta_irq_handler(struct irq_desc *desc)
101{
102 struct ti_sci_inta_vint_desc *vint_desc;
103 struct ti_sci_inta_irq_domain *inta;
104 struct irq_domain *domain;
105 unsigned int virq, bit;
106 unsigned long val;
107
108 vint_desc = irq_desc_get_handler_data(desc);
109 domain = vint_desc->domain;
110 inta = domain->host_data;
111
112 chained_irq_enter(irq_desc_get_chip(desc), desc);
113
114 val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 +
115 VINT_STATUS_OFFSET);
116
117 for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) {
118 virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq);
119 if (virq)
120 generic_handle_irq(virq);
121 }
122
123 chained_irq_exit(irq_desc_get_chip(desc), desc);
124}
125
126/**
127 * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
128 * @domain: IRQ domain corresponding to Interrupt Aggregator
129 *
130 * Return 0 if all went well else corresponding error value.
131 */
132static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_domain *domain)
133{
134 struct ti_sci_inta_irq_domain *inta = domain->host_data;
135 struct ti_sci_inta_vint_desc *vint_desc;
136 struct irq_fwspec parent_fwspec;
137 unsigned int parent_virq;
138 u16 vint_id;
139
140 vint_id = ti_sci_get_free_resource(inta->vint);
141 if (vint_id == TI_SCI_RESOURCE_NULL)
142 return ERR_PTR(-EINVAL);
143
144 vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
145 if (!vint_desc)
146 return ERR_PTR(-ENOMEM);
147
148 vint_desc->domain = domain;
149 vint_desc->vint_id = vint_id;
150 INIT_LIST_HEAD(&vint_desc->list);
151
152 parent_fwspec.fwnode = of_node_to_fwnode(of_irq_find_parent(dev_of_node(&inta->pdev->dev)));
153 parent_fwspec.param_count = 2;
154 parent_fwspec.param[0] = inta->pdev->id;
155 parent_fwspec.param[1] = vint_desc->vint_id;
156
157 parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
158 if (parent_virq <= 0) {
159 kfree(vint_desc);
160 return ERR_PTR(parent_virq);
161 }
162 vint_desc->parent_virq = parent_virq;
163
164 list_add_tail(&vint_desc->list, &inta->vint_list);
165 irq_set_chained_handler_and_data(vint_desc->parent_virq,
166 ti_sci_inta_irq_handler, vint_desc);
167
168 return vint_desc;
169}
170
171/**
172 * ti_sci_inta_alloc_event() - Attach an event to a IA vint.
173 * @vint_desc: Pointer to vint_desc to which the event gets attached
174 * @free_bit: Bit inside vint to which event gets attached
175 * @hwirq: hwirq of the input event
176 *
177 * Return event_desc pointer if all went ok else appropriate error value.
178 */
179static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta_vint_desc *vint_desc,
180 u16 free_bit,
181 u32 hwirq)
182{
183 struct ti_sci_inta_irq_domain *inta = vint_desc->domain->host_data;
184 struct ti_sci_inta_event_desc *event_desc;
185 u16 dev_id, dev_index;
186 int err;
187
188 dev_id = HWIRQ_TO_DEVID(hwirq);
189 dev_index = HWIRQ_TO_IRQID(hwirq);
190
191 event_desc = &vint_desc->events[free_bit];
192 event_desc->hwirq = hwirq;
193 event_desc->vint_bit = free_bit;
194 event_desc->global_event = ti_sci_get_free_resource(inta->global_event);
195 if (event_desc->global_event == TI_SCI_RESOURCE_NULL)
196 return ERR_PTR(-EINVAL);
197
198 err = inta->sci->ops.rm_irq_ops.set_event_map(inta->sci,
199 dev_id, dev_index,
200 inta->pdev->id,
201 vint_desc->vint_id,
202 event_desc->global_event,
203 free_bit);
204 if (err)
205 goto free_global_event;
206
207 return event_desc;
208free_global_event:
209 ti_sci_release_resource(inta->global_event, event_desc->global_event);
210 return ERR_PTR(err);
211}
212
213/**
214 * ti_sci_inta_alloc_irq() - Allocate an irq within INTA domain
215 * @domain: irq_domain pointer corresponding to INTA
216 * @hwirq: hwirq of the input event
217 *
218 * Note: Allocation happens in the following manner:
219 * - Find a free bit available in any of the vints available in the list.
220 * - If not found, allocate a vint from the vint pool
221 * - Attach the free bit to input hwirq.
222 * Return event_desc if all went ok else appropriate error value.
223 */
224static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *domain,
225 u32 hwirq)
226{
227 struct ti_sci_inta_irq_domain *inta = domain->host_data;
228 struct ti_sci_inta_vint_desc *vint_desc = NULL;
229 struct ti_sci_inta_event_desc *event_desc;
230 u16 free_bit;
231
232 mutex_lock(&inta->vint_mutex);
233 list_for_each_entry(vint_desc, &inta->vint_list, list) {
234 free_bit = find_first_zero_bit(vint_desc->event_map,
235 MAX_EVENTS_PER_VINT);
236 if (free_bit != MAX_EVENTS_PER_VINT) {
237 set_bit(free_bit, vint_desc->event_map);
238 goto alloc_event;
239 }
240 }
241
242 /* No free bits available. Allocate a new vint */
243 vint_desc = ti_sci_inta_alloc_parent_irq(domain);
244 if (IS_ERR(vint_desc)) {
245 mutex_unlock(&inta->vint_mutex);
246 return ERR_PTR(PTR_ERR(vint_desc));
247 }
248
249 free_bit = find_first_zero_bit(vint_desc->event_map,
250 MAX_EVENTS_PER_VINT);
251 set_bit(free_bit, vint_desc->event_map);
252
253alloc_event:
254 event_desc = ti_sci_inta_alloc_event(vint_desc, free_bit, hwirq);
255 if (IS_ERR(event_desc))
256 clear_bit(free_bit, vint_desc->event_map);
257
258 mutex_unlock(&inta->vint_mutex);
259 return event_desc;
260}
261
262/**
263 * ti_sci_inta_free_parent_irq() - Free a parent irq to INTA
264 * @inta: Pointer to inta domain.
265 * @vint_desc: Pointer to vint_desc that needs to be freed.
266 */
267static void ti_sci_inta_free_parent_irq(struct ti_sci_inta_irq_domain *inta,
268 struct ti_sci_inta_vint_desc *vint_desc)
269{
270 if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) == MAX_EVENTS_PER_VINT) {
271 list_del(&vint_desc->list);
272 ti_sci_release_resource(inta->vint, vint_desc->vint_id);
273 irq_dispose_mapping(vint_desc->parent_virq);
274 kfree(vint_desc);
275 }
276}
277
278/**
279 * ti_sci_inta_free_irq() - Free an IRQ within INTA domain
280 * @event_desc: Pointer to event_desc that needs to be freed.
281 * @hwirq: Hwirq number within INTA domain that needs to be freed
282 */
283static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
284 u32 hwirq)
285{
286 struct ti_sci_inta_vint_desc *vint_desc;
287 struct ti_sci_inta_irq_domain *inta;
288
289 vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
290 inta = vint_desc->domain->host_data;
291 /* free event irq */
292 mutex_lock(&inta->vint_mutex);
293 inta->sci->ops.rm_irq_ops.free_event_map(inta->sci,
294 HWIRQ_TO_DEVID(hwirq),
295 HWIRQ_TO_IRQID(hwirq),
296 inta->pdev->id,
297 vint_desc->vint_id,
298 event_desc->global_event,
299 event_desc->vint_bit);
300
301 clear_bit(event_desc->vint_bit, vint_desc->event_map);
302 ti_sci_release_resource(inta->global_event, event_desc->global_event);
303 event_desc->global_event = TI_SCI_RESOURCE_NULL;
304 event_desc->hwirq = 0;
305
306 ti_sci_inta_free_parent_irq(inta, vint_desc);
307 mutex_unlock(&inta->vint_mutex);
308}
309
310/**
311 * ti_sci_inta_request_resources() - Allocate resources for input irq
312 * @data: Pointer to corresponding irq_data
313 *
314 * Note: This is the core api where the actual allocation happens for input
315 * hwirq. This allocation involves creating a parent irq for vint.
316 * If this is done in irq_domain_ops.alloc() then a deadlock is reached
317 * for allocation. So this allocation is being done in request_resources()
318 *
319 * Return: 0 if all went well else corresponding error.
320 */
321static int ti_sci_inta_request_resources(struct irq_data *data)
322{
323 struct ti_sci_inta_event_desc *event_desc;
324
325 event_desc = ti_sci_inta_alloc_irq(data->domain, data->hwirq);
326 if (IS_ERR(event_desc))
327 return PTR_ERR(event_desc);
328
329 data->chip_data = event_desc;
330
331 return 0;
332}
333
334/**
335 * ti_sci_inta_release_resources - Release resources for input irq
336 * @data: Pointer to corresponding irq_data
337 *
338 * Note: Corresponding to request_resources(), all the unmapping and deletion
339 * of parent vint irqs happens in this api.
340 */
341static void ti_sci_inta_release_resources(struct irq_data *data)
342{
343 struct ti_sci_inta_event_desc *event_desc;
344
345 event_desc = irq_data_get_irq_chip_data(data);
346 ti_sci_inta_free_irq(event_desc, data->hwirq);
347}
348
349/**
350 * ti_sci_inta_manage_event() - Control the event based on the offset
351 * @data: Pointer to corresponding irq_data
352 * @offset: register offset using which event is controlled.
353 */
354static void ti_sci_inta_manage_event(struct irq_data *data, u32 offset)
355{
356 struct ti_sci_inta_event_desc *event_desc;
357 struct ti_sci_inta_vint_desc *vint_desc;
358 struct ti_sci_inta_irq_domain *inta;
359
360 event_desc = irq_data_get_irq_chip_data(data);
361 vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
362 inta = data->domain->host_data;
363
364 writeq_relaxed(BIT(event_desc->vint_bit),
365 inta->base + vint_desc->vint_id * 0x1000 + offset);
366}
367
368/**
369 * ti_sci_inta_mask_irq() - Mask an event
370 * @data: Pointer to corresponding irq_data
371 */
372static void ti_sci_inta_mask_irq(struct irq_data *data)
373{
374 ti_sci_inta_manage_event(data, VINT_ENABLE_CLR_OFFSET);
375}
376
377/**
378 * ti_sci_inta_unmask_irq() - Unmask an event
379 * @data: Pointer to corresponding irq_data
380 */
381static void ti_sci_inta_unmask_irq(struct irq_data *data)
382{
383 ti_sci_inta_manage_event(data, VINT_ENABLE_SET_OFFSET);
384}
385
386/**
387 * ti_sci_inta_ack_irq() - Ack an event
388 * @data: Pointer to corresponding irq_data
389 */
390static void ti_sci_inta_ack_irq(struct irq_data *data)
391{
392 /*
393 * Do not clear the event if hardware is capable of sending
394 * a down event.
395 */
396 if (irqd_get_trigger_type(data) != IRQF_TRIGGER_HIGH)
397 ti_sci_inta_manage_event(data, VINT_STATUS_OFFSET);
398}
399
400static int ti_sci_inta_set_affinity(struct irq_data *d,
401 const struct cpumask *mask_val, bool force)
402{
403 return -EINVAL;
404}
405
406/**
407 * ti_sci_inta_set_type() - Update the trigger type of the irq.
408 * @data: Pointer to corresponding irq_data
409 * @type: Trigger type as specified by user
410 *
411 * Note: This updates the handle_irq callback for level msi.
412 *
413 * Return 0 if all went well else appropriate error.
414 */
415static int ti_sci_inta_set_type(struct irq_data *data, unsigned int type)
416{
417 /*
418 * .alloc default sets handle_edge_irq. But if the user specifies
419 * that IRQ is level MSI, then update the handle to handle_level_irq
420 */
421 switch (type & IRQ_TYPE_SENSE_MASK) {
422 case IRQF_TRIGGER_HIGH:
423 irq_set_handler_locked(data, handle_level_irq);
424 return 0;
425 case IRQF_TRIGGER_RISING:
426 return 0;
427 default:
428 return -EINVAL;
429 }
430
431 return -EINVAL;
432}
433
434static struct irq_chip ti_sci_inta_irq_chip = {
435 .name = "INTA",
436 .irq_ack = ti_sci_inta_ack_irq,
437 .irq_mask = ti_sci_inta_mask_irq,
438 .irq_set_type = ti_sci_inta_set_type,
439 .irq_unmask = ti_sci_inta_unmask_irq,
440 .irq_set_affinity = ti_sci_inta_set_affinity,
441 .irq_request_resources = ti_sci_inta_request_resources,
442 .irq_release_resources = ti_sci_inta_release_resources,
443};
444
445/**
446 * ti_sci_inta_irq_domain_free() - Free an IRQ from the IRQ domain
447 * @domain: Domain to which the irqs belong
448 * @virq: base linux virtual IRQ to be freed.
449 * @nr_irqs: Number of continuous irqs to be freed
450 */
451static void ti_sci_inta_irq_domain_free(struct irq_domain *domain,
452 unsigned int virq, unsigned int nr_irqs)
453{
454 struct irq_data *data = irq_domain_get_irq_data(domain, virq);
455
456 irq_domain_reset_irq_data(data);
457}
458
459/**
460 * ti_sci_inta_irq_domain_alloc() - Allocate Interrupt aggregator IRQs
461 * @domain: Point to the interrupt aggregator IRQ domain
462 * @virq: Corresponding Linux virtual IRQ number
463 * @nr_irqs: Continuous irqs to be allocated
464 * @data: Pointer to firmware specifier
465 *
466 * No actual allocation happens here.
467 *
468 * Return 0 if all went well else appropriate error value.
469 */
470static int ti_sci_inta_irq_domain_alloc(struct irq_domain *domain,
471 unsigned int virq, unsigned int nr_irqs,
472 void *data)
473{
474 msi_alloc_info_t *arg = data;
475
476 irq_domain_set_info(domain, virq, arg->hwirq, &ti_sci_inta_irq_chip,
477 NULL, handle_edge_irq, NULL, NULL);
478
479 return 0;
480}
481
482static const struct irq_domain_ops ti_sci_inta_irq_domain_ops = {
483 .free = ti_sci_inta_irq_domain_free,
484 .alloc = ti_sci_inta_irq_domain_alloc,
485};
486
487static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
488{
489 struct irq_domain *parent_domain, *domain;
490 struct device_node *parent_node, *node;
491 struct ti_sci_inta_irq_domain *inta;
492 struct device *dev = &pdev->dev;
493 struct resource *res;
494 int ret;
495
496 node = dev_of_node(dev);
497 parent_node = of_irq_find_parent(node);
498 if (!parent_node) {
499 dev_err(dev, "Failed to get IRQ parent node\n");
500 return -ENODEV;
501 }
502
503 parent_domain = irq_find_host(parent_node);
504 if (!parent_domain)
505 return -EPROBE_DEFER;
506
507 inta = devm_kzalloc(dev, sizeof(*inta), GFP_KERNEL);
508 if (!inta)
509 return -ENOMEM;
510
511 inta->pdev = pdev;
512 inta->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
513 if (IS_ERR(inta->sci)) {
514 ret = PTR_ERR(inta->sci);
515 if (ret != -EPROBE_DEFER)
516 dev_err(dev, "ti,sci read fail %d\n", ret);
517 inta->sci = NULL;
518 return ret;
519 }
520
521 ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &pdev->id);
522 if (ret) {
523 dev_err(dev, "missing 'ti,sci-dev-id' property\n");
524 return -EINVAL;
525 }
526
527 inta->vint = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
528 "ti,sci-rm-range-vint");
529 if (IS_ERR(inta->vint)) {
530 dev_err(dev, "VINT resource allocation failed\n");
531 return PTR_ERR(inta->vint);
532 }
533
534 inta->global_event = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
535 "ti,sci-rm-range-global-event");
536 if (IS_ERR(inta->global_event)) {
537 dev_err(dev, "Global event resource allocation failed\n");
538 return PTR_ERR(inta->global_event);
539 }
540
541 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
542 inta->base = devm_ioremap_resource(dev, res);
543 if (IS_ERR(inta->base))
544 return -ENODEV;
545
546 domain = irq_domain_add_linear(dev_of_node(dev),
547 ti_sci_get_num_resources(inta->vint),
548 &ti_sci_inta_irq_domain_ops, inta);
549 if (!domain) {
550 dev_err(dev, "Failed to allocate IRQ domain\n");
551 return -ENOMEM;
552 }
553
554 INIT_LIST_HEAD(&inta->vint_list);
555 mutex_init(&inta->vint_mutex);
556
557 return 0;
558}
559
560static const struct of_device_id ti_sci_inta_irq_domain_of_match[] = {
561 { .compatible = "ti,sci-inta", },
562 { /* sentinel */ },
563};
564MODULE_DEVICE_TABLE(of, ti_sci_inta_irq_domain_of_match);
565
566static struct platform_driver ti_sci_inta_irq_domain_driver = {
567 .probe = ti_sci_inta_irq_domain_probe,
568 .driver = {
569 .name = "ti-sci-inta",
570 .of_match_table = ti_sci_inta_irq_domain_of_match,
571 },
572};
573module_platform_driver(ti_sci_inta_irq_domain_driver);
574
575MODULE_AUTHOR("Lokesh Vutla <lokeshvutla@ticom>");
576MODULE_DESCRIPTION("K3 Interrupt Aggregator driver over TI SCI protocol");
577MODULE_LICENSE("GPL v2");