Commit 7e71330169d8056536b299290544980bccc6b300

Authored by Grant Likely
1 parent 08a543ad33

dt/irq: add irq_domain_generate_simple() helper

irq_domain_generate_simple() is an easy way to generate an irq translation
domain for simple irq controllers.  It assumes a flat 1:1 mapping from
hardware irq number to an offset of the first linux irq number assigned
to the controller

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

Showing 2 changed files with 68 additions and 0 deletions Side-by-side Diff

include/linux/irqdomain.h
... ... @@ -16,6 +16,7 @@
16 16 #define _LINUX_IRQDOMAIN_H
17 17  
18 18 #include <linux/irq.h>
  19 +#include <linux/mod_devicetable.h>
19 20  
20 21 #ifdef CONFIG_IRQ_DOMAIN
21 22 struct device_node;
... ... @@ -77,6 +78,15 @@
77 78 extern void irq_domain_add(struct irq_domain *domain);
78 79 extern void irq_domain_del(struct irq_domain *domain);
79 80 #endif /* CONFIG_IRQ_DOMAIN */
  81 +
  82 +#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
  83 +extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
  84 +extern void irq_domain_generate_simple(const struct of_device_id *match,
  85 + u64 phys_base, unsigned int irq_start);
  86 +#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
  87 +static inline void irq_domain_generate_simple(const struct of_device_id *match,
  88 + u64 phys_base, unsigned int irq_start) { }
  89 +#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
80 90  
81 91 #endif /* _LINUX_IRQDOMAIN_H */
kernel/irq/irqdomain.c
... ... @@ -3,6 +3,8 @@
3 3 #include <linux/module.h>
4 4 #include <linux/mutex.h>
5 5 #include <linux/of.h>
  6 +#include <linux/of_address.h>
  7 +#include <linux/slab.h>
6 8  
7 9 static LIST_HEAD(irq_domain_list);
8 10 static DEFINE_MUTEX(irq_domain_mutex);
... ... @@ -119,5 +121,61 @@
119 121 */
120 122 }
121 123 EXPORT_SYMBOL_GPL(irq_dispose_mapping);
  124 +
  125 +int irq_domain_simple_dt_translate(struct irq_domain *d,
  126 + struct device_node *controller,
  127 + const u32 *intspec, unsigned int intsize,
  128 + unsigned long *out_hwirq, unsigned int *out_type)
  129 +{
  130 + if (d->of_node != controller)
  131 + return -EINVAL;
  132 + if (intsize < 1)
  133 + return -EINVAL;
  134 +
  135 + *out_hwirq = intspec[0];
  136 + *out_type = IRQ_TYPE_NONE;
  137 + if (intsize > 1)
  138 + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
  139 + return 0;
  140 +}
  141 +
  142 +struct irq_domain_ops irq_domain_simple_ops = {
  143 + .dt_translate = irq_domain_simple_dt_translate,
  144 +};
  145 +EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
  146 +
  147 +/**
  148 + * irq_domain_create_simple() - Set up a 'simple' translation range
  149 + */
  150 +void irq_domain_add_simple(struct device_node *controller, int irq_base)
  151 +{
  152 + struct irq_domain *domain;
  153 +
  154 + domain = kzalloc(sizeof(*domain), GFP_KERNEL);
  155 + if (!domain) {
  156 + WARN_ON(1);
  157 + return;
  158 + }
  159 +
  160 + domain->irq_base = irq_base;
  161 + domain->of_node = of_node_get(controller);
  162 + domain->ops = &irq_domain_simple_ops;
  163 + irq_domain_add(domain);
  164 +}
  165 +EXPORT_SYMBOL_GPL(irq_domain_add_simple);
  166 +
  167 +void irq_domain_generate_simple(const struct of_device_id *match,
  168 + u64 phys_base, unsigned int irq_start)
  169 +{
  170 + struct device_node *node;
  171 + pr_info("looking for phys_base=%llx, irq_start=%i\n",
  172 + (unsigned long long) phys_base, (int) irq_start);
  173 + node = of_find_matching_node_by_address(NULL, match, phys_base);
  174 + if (node)
  175 + irq_domain_add_simple(node, irq_start);
  176 + else
  177 + pr_info("no node found\n");
  178 +}
  179 +EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
122 180 #endif /* CONFIG_OF_IRQ */