summaryrefslogtreecommitdiff
path: root/drivers/misc/irq-uclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/irq-uclass.c')
-rw-r--r--drivers/misc/irq-uclass.c66
1 files changed, 65 insertions, 1 deletions
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index 79eb7c200dc..ac778593c96 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq)
return ops->read_and_clear(irq);
}
+int irq_get_interrupt_parent(const struct udevice *dev,
+ struct udevice **interrupt_parent)
+{
+ struct ofnode_phandle_args phandle_args;
+ struct udevice *irq = NULL;
+ ofnode node;
+ int ret;
+
+ if (!dev || !interrupt_parent)
+ return -EINVAL;
+
+ *interrupt_parent = NULL;
+
+ node = dev_ofnode(dev);
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
+ while (ofnode_valid(node)) {
+ ret = ofnode_parse_phandle_with_args(node, "interrupt-parent",
+ NULL, 0, 0, &phandle_args);
+ if (!ret && !device_get_global_by_ofnode(phandle_args.node, &irq))
+ break;
+ node = ofnode_get_parent(node);
+ }
+
+ if (!irq) {
+ log_err("Cannot find an interrupt parent for device %s\n", dev->name);
+ return -ENODEV;
+ }
+ *interrupt_parent = irq;
+
+ return 0;
+}
+
#if CONFIG_IS_ENABLED(OF_PLATDATA)
int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
struct irq *irq)
@@ -142,10 +176,40 @@ err:
int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
{
struct ofnode_phandle_args args;
- int ret;
+ struct udevice *interrupt_parent;
+ int ret, size, i;
+ const __be32 *list;
+ u32 count;
ret = dev_read_phandle_with_args(dev, "interrupts-extended",
"#interrupt-cells", 0, index, &args);
+ if (ret) {
+ list = dev_read_prop(dev, "interrupts", &size);
+ if (!list)
+ return -ENOENT;
+
+ ret = irq_get_interrupt_parent(dev, &interrupt_parent);
+ if (ret)
+ return -ENODEV;
+ args.node = dev_ofnode(interrupt_parent);
+
+ if (dev_read_u32(interrupt_parent, "#interrupt-cells", &count)) {
+ log_err("%s: could not get #interrupt-cells for %s\n",
+ __func__, dev->name);
+ return -ENOENT;
+ }
+
+ if (index * count >= size / sizeof(*list))
+ return -ENOENT;
+ if (count > OF_MAX_PHANDLE_ARGS)
+ count = OF_MAX_PHANDLE_ARGS;
+ args.args_count = count;
+ for (i = 0; i < count; i++)
+ args.args[i] = be32_to_cpup(&list[index * count + i]);
+
+ return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
+ "interrupts", index, irq);
+ }
return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
"interrupts-extended", index > 0, irq);