aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-30 02:32:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-30 02:32:02 -0400
commitcb7dee8d22f3e9320424e769d860fbd9712a0666 (patch)
tree58f33d70453e7cd26ec78e96f33ca7a9673df26e /kernel
parent49267fc82ad2825132be3b016d8eb58a90cb0c36 (diff)
parent6124a4e430b64d1577438c8648c59e996d02e73e (diff)
Merge branch 'next/dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc
* 'next/dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc: (21 commits) arm/dt: tegra devicetree support arm/versatile: Add device tree support dt/irq: add irq_domain_generate_simple() helper irq: add irq_domain translation infrastructure dmaengine: imx-sdma: add device tree probe support dmaengine: imx-sdma: sdma_get_firmware does not need to copy fw_name dmaengine: imx-sdma: use platform_device_id to identify sdma version mmc: sdhci-esdhc-imx: add device tree probe support mmc: sdhci-pltfm: dt device does not pass parent to sdhci_alloc_host mmc: sdhci-esdhc-imx: get rid of the uses of cpu_is_mx() mmc: sdhci-esdhc-imx: do not reference platform data after probe mmc: sdhci-esdhc-imx: extend card_detect and write_protect support for mx5 net/fec: add device tree probe support net: ibm_newemac: convert it to use of_get_phy_mode dt/net: add helper function of_get_phy_mode net/fec: gasket needs to be enabled for some i.mx serial/imx: add device tree probe support serial/imx: get rid of the uses of cpu_is_mx1() arm/dt: Add dtb make rule arm/dt: Add skeleton dtsi file ...
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/Kconfig4
-rw-r--r--kernel/irq/Makefile1
-rw-r--r--kernel/irq/irqdomain.c180
3 files changed, 185 insertions, 0 deletions
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index d1d051b38e0b..5a38bf4de641 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -52,6 +52,10 @@ config IRQ_EDGE_EOI_HANDLER
52config GENERIC_IRQ_CHIP 52config GENERIC_IRQ_CHIP
53 bool 53 bool
54 54
55# Generic irq_domain hw <--> linux irq number translation
56config IRQ_DOMAIN
57 bool
58
55# Support forced irq threading 59# Support forced irq threading
56config IRQ_FORCED_THREADING 60config IRQ_FORCED_THREADING
57 bool 61 bool
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index 73290056cfb6..fff17381f0af 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -2,6 +2,7 @@
2obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o 2obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
3obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o 3obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
4obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o 4obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
5obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
5obj-$(CONFIG_PROC_FS) += proc.o 6obj-$(CONFIG_PROC_FS) += proc.o
6obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o 7obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
7obj-$(CONFIG_PM_SLEEP) += pm.o 8obj-$(CONFIG_PM_SLEEP) += pm.o
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
new file mode 100644
index 000000000000..d5828da3fd38
--- /dev/null
+++ b/kernel/irq/irqdomain.c
@@ -0,0 +1,180 @@
1#include <linux/irq.h>
2#include <linux/irqdomain.h>
3#include <linux/module.h>
4#include <linux/mutex.h>
5#include <linux/of.h>
6#include <linux/of_address.h>
7#include <linux/slab.h>
8
9static LIST_HEAD(irq_domain_list);
10static DEFINE_MUTEX(irq_domain_mutex);
11
12/**
13 * irq_domain_add() - Register an irq_domain
14 * @domain: ptr to initialized irq_domain structure
15 *
16 * Registers an irq_domain structure. The irq_domain must at a minimum be
17 * initialized with an ops structure pointer, and either a ->to_irq hook or
18 * a valid irq_base value. Everything else is optional.
19 */
20void irq_domain_add(struct irq_domain *domain)
21{
22 struct irq_data *d;
23 int hwirq;
24
25 /*
26 * This assumes that the irq_domain owner has already allocated
27 * the irq_descs. This block will be removed when support for dynamic
28 * allocation of irq_descs is added to irq_domain.
29 */
30 for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
31 d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
32 if (d || d->domain) {
33 /* things are broken; just report, don't clean up */
34 WARN(1, "error: irq_desc already assigned to a domain");
35 return;
36 }
37 d->domain = domain;
38 d->hwirq = hwirq;
39 }
40
41 mutex_lock(&irq_domain_mutex);
42 list_add(&domain->list, &irq_domain_list);
43 mutex_unlock(&irq_domain_mutex);
44}
45
46/**
47 * irq_domain_del() - Unregister an irq_domain
48 * @domain: ptr to registered irq_domain.
49 */
50void irq_domain_del(struct irq_domain *domain)
51{
52 struct irq_data *d;
53 int hwirq;
54
55 mutex_lock(&irq_domain_mutex);
56 list_del(&domain->list);
57 mutex_unlock(&irq_domain_mutex);
58
59 /* Clear the irq_domain assignments */
60 for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
61 d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
62 d->domain = NULL;
63 }
64}
65
66#if defined(CONFIG_OF_IRQ)
67/**
68 * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
69 *
70 * Used by the device tree interrupt mapping code to translate a device tree
71 * interrupt specifier to a valid linux irq number. Returns either a valid
72 * linux IRQ number or 0.
73 *
74 * When the caller no longer need the irq number returned by this function it
75 * should arrange to call irq_dispose_mapping().
76 */
77unsigned int irq_create_of_mapping(struct device_node *controller,
78 const u32 *intspec, unsigned int intsize)
79{
80 struct irq_domain *domain;
81 unsigned long hwirq;
82 unsigned int irq, type;
83 int rc = -EINVAL;
84
85 /* Find a domain which can translate the irq spec */
86 mutex_lock(&irq_domain_mutex);
87 list_for_each_entry(domain, &irq_domain_list, list) {
88 if (!domain->ops->dt_translate)
89 continue;
90 rc = domain->ops->dt_translate(domain, controller,
91 intspec, intsize, &hwirq, &type);
92 if (rc == 0)
93 break;
94 }
95 mutex_unlock(&irq_domain_mutex);
96
97 if (rc != 0)
98 return 0;
99
100 irq = irq_domain_to_irq(domain, hwirq);
101 if (type != IRQ_TYPE_NONE)
102 irq_set_irq_type(irq, type);
103 pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
104 controller->full_name, (int)hwirq, irq, type);
105 return irq;
106}
107EXPORT_SYMBOL_GPL(irq_create_of_mapping);
108
109/**
110 * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
111 * @irq: linux irq number to be discarded
112 *
113 * Calling this function indicates the caller no longer needs a reference to
114 * the linux irq number returned by a prior call to irq_create_of_mapping().
115 */
116void irq_dispose_mapping(unsigned int irq)
117{
118 /*
119 * nothing yet; will be filled when support for dynamic allocation of
120 * irq_descs is added to irq_domain
121 */
122}
123EXPORT_SYMBOL_GPL(irq_dispose_mapping);
124
125int 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
142struct irq_domain_ops irq_domain_simple_ops = {
143 .dt_translate = irq_domain_simple_dt_translate,
144};
145EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
146
147/**
148 * irq_domain_create_simple() - Set up a 'simple' translation range
149 */
150void 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}
165EXPORT_SYMBOL_GPL(irq_domain_add_simple);
166
167void 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}
179EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
180#endif /* CONFIG_OF_IRQ */