diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-07-13 12:34:19 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-07-13 12:34:19 -0400 |
commit | 5c0e0088e24c6ba12ced727b9810f729fea20006 (patch) | |
tree | 1229557de0a6a1696f0acc976151f3dba3909825 | |
parent | e3b897c1ae5341daa6f00ef9b70bc7e44f3b1705 (diff) | |
parent | 961e657f5a34e3f4ce2cb74cfab11f5c666b03e5 (diff) |
Merge tag 'davinci-v3.6-dt' of git://gitorious.org/linux-davinci/linux-davinci into next/dt
From Sekhar Nori <nsekhar@ti.com>:
DaVinci DT support
Add DT support for DaVinci cp_intc interrupt controller
* tag 'davinci-v3.6-dt' of git://gitorious.org/linux-davinci/linux-davinci:
ARM: davinci: cp_intc: Add OF support for TI interrupt controller
ARM: davinci: add runtime PM support for clock management
ARM: davinci: cp_intc: Add irq domain support
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | Documentation/devicetree/bindings/arm/davinci/cp-intc.txt | 27 | ||||
-rw-r--r-- | arch/arm/mach-davinci/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/cp_intc.c | 75 | ||||
-rw-r--r-- | arch/arm/mach-davinci/include/mach/cp_intc.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/pm_domain.c | 64 |
6 files changed, 154 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt b/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt new file mode 100644 index 000000000000..597e8a089fe4 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt | |||
@@ -0,0 +1,27 @@ | |||
1 | * TI Common Platform Interrupt Controller | ||
2 | |||
3 | Common Platform Interrupt Controller (cp_intc) is used on | ||
4 | OMAP-L1x SoCs and can support several configurable number | ||
5 | of interrupts. | ||
6 | |||
7 | Main node required properties: | ||
8 | |||
9 | - compatible : should be: | ||
10 | "ti,cp-intc" | ||
11 | - interrupt-controller : Identifies the node as an interrupt controller | ||
12 | - #interrupt-cells : Specifies the number of cells needed to encode an | ||
13 | interrupt source. The type shall be a <u32> and the value shall be 1. | ||
14 | |||
15 | The cell contains the interrupt number in the range [0-128]. | ||
16 | - ti,intc-size: Number of interrupts handled by the interrupt controller. | ||
17 | - reg: physical base address and size of the intc registers map. | ||
18 | |||
19 | Example: | ||
20 | |||
21 | intc: interrupt-controller@1 { | ||
22 | compatible = "ti,cp-intc"; | ||
23 | interrupt-controller; | ||
24 | #interrupt-cells = <1>; | ||
25 | ti,intc-size = <101>; | ||
26 | reg = <0xfffee000 0x2000>; | ||
27 | }; | ||
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 32d837d8eab9..2ce1ef07c13d 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig | |||
@@ -4,6 +4,7 @@ config AINTC | |||
4 | bool | 4 | bool |
5 | 5 | ||
6 | config CP_INTC | 6 | config CP_INTC |
7 | select IRQ_DOMAIN | ||
7 | bool | 8 | bool |
8 | 9 | ||
9 | config ARCH_DAVINCI_DMx | 10 | config ARCH_DAVINCI_DMx |
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 2db78bd5c835..2227effcb0e9 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile | |||
@@ -39,3 +39,4 @@ obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o | |||
39 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | 39 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o |
40 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | 40 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
41 | obj-$(CONFIG_SUSPEND) += pm.o sleep.o | 41 | obj-$(CONFIG_SUSPEND) += pm.o sleep.o |
42 | obj-$(CONFIG_HAVE_CLK) += pm_domain.o | ||
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c index f83152d643c5..006dae8dfe44 100644 --- a/arch/arm/mach-davinci/cp_intc.c +++ b/arch/arm/mach-davinci/cp_intc.c | |||
@@ -9,9 +9,14 @@ | |||
9 | * kind, whether express or implied. | 9 | * kind, whether express or implied. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/export.h> | ||
12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
13 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/irqdomain.h> | ||
14 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_irq.h> | ||
15 | 20 | ||
16 | #include <mach/common.h> | 21 | #include <mach/common.h> |
17 | #include <mach/cp_intc.h> | 22 | #include <mach/cp_intc.h> |
@@ -28,7 +33,7 @@ static inline void cp_intc_write(unsigned long value, unsigned offset) | |||
28 | 33 | ||
29 | static void cp_intc_ack_irq(struct irq_data *d) | 34 | static void cp_intc_ack_irq(struct irq_data *d) |
30 | { | 35 | { |
31 | cp_intc_write(d->irq, CP_INTC_SYS_STAT_IDX_CLR); | 36 | cp_intc_write(d->hwirq, CP_INTC_SYS_STAT_IDX_CLR); |
32 | } | 37 | } |
33 | 38 | ||
34 | /* Disable interrupt */ | 39 | /* Disable interrupt */ |
@@ -36,20 +41,20 @@ static void cp_intc_mask_irq(struct irq_data *d) | |||
36 | { | 41 | { |
37 | /* XXX don't know why we need to disable nIRQ here... */ | 42 | /* XXX don't know why we need to disable nIRQ here... */ |
38 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); | 43 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); |
39 | cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_CLR); | 44 | cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_CLR); |
40 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); | 45 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); |
41 | } | 46 | } |
42 | 47 | ||
43 | /* Enable interrupt */ | 48 | /* Enable interrupt */ |
44 | static void cp_intc_unmask_irq(struct irq_data *d) | 49 | static void cp_intc_unmask_irq(struct irq_data *d) |
45 | { | 50 | { |
46 | cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_SET); | 51 | cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_SET); |
47 | } | 52 | } |
48 | 53 | ||
49 | static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) | 54 | static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) |
50 | { | 55 | { |
51 | unsigned reg = BIT_WORD(d->irq); | 56 | unsigned reg = BIT_WORD(d->hwirq); |
52 | unsigned mask = BIT_MASK(d->irq); | 57 | unsigned mask = BIT_MASK(d->hwirq); |
53 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); | 58 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); |
54 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); | 59 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); |
55 | 60 | ||
@@ -99,18 +104,43 @@ static struct irq_chip cp_intc_irq_chip = { | |||
99 | .irq_set_wake = cp_intc_set_wake, | 104 | .irq_set_wake = cp_intc_set_wake, |
100 | }; | 105 | }; |
101 | 106 | ||
102 | void __init cp_intc_init(void) | 107 | static struct irq_domain *cp_intc_domain; |
108 | |||
109 | static int cp_intc_host_map(struct irq_domain *h, unsigned int virq, | ||
110 | irq_hw_number_t hw) | ||
103 | { | 111 | { |
104 | unsigned long num_irq = davinci_soc_info.intc_irq_num; | 112 | pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw); |
113 | |||
114 | irq_set_chip(virq, &cp_intc_irq_chip); | ||
115 | set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); | ||
116 | irq_set_handler(virq, handle_edge_irq); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static const struct irq_domain_ops cp_intc_host_ops = { | ||
121 | .map = cp_intc_host_map, | ||
122 | .xlate = irq_domain_xlate_onetwocell, | ||
123 | }; | ||
124 | |||
125 | int __init cp_intc_of_init(struct device_node *node, struct device_node *parent) | ||
126 | { | ||
127 | u32 num_irq = davinci_soc_info.intc_irq_num; | ||
105 | u8 *irq_prio = davinci_soc_info.intc_irq_prios; | 128 | u8 *irq_prio = davinci_soc_info.intc_irq_prios; |
106 | u32 *host_map = davinci_soc_info.intc_host_map; | 129 | u32 *host_map = davinci_soc_info.intc_host_map; |
107 | unsigned num_reg = BITS_TO_LONGS(num_irq); | 130 | unsigned num_reg = BITS_TO_LONGS(num_irq); |
108 | int i; | 131 | int i, irq_base; |
109 | 132 | ||
110 | davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; | 133 | davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; |
111 | davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); | 134 | if (node) { |
135 | davinci_intc_base = of_iomap(node, 0); | ||
136 | if (of_property_read_u32(node, "ti,intc-size", &num_irq)) | ||
137 | pr_warn("unable to get intc-size, default to %d\n", | ||
138 | num_irq); | ||
139 | } else { | ||
140 | davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); | ||
141 | } | ||
112 | if (WARN_ON(!davinci_intc_base)) | 142 | if (WARN_ON(!davinci_intc_base)) |
113 | return; | 143 | return -EINVAL; |
114 | 144 | ||
115 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); | 145 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); |
116 | 146 | ||
@@ -165,13 +195,28 @@ void __init cp_intc_init(void) | |||
165 | for (i = 0; host_map[i] != -1; i++) | 195 | for (i = 0; host_map[i] != -1; i++) |
166 | cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); | 196 | cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); |
167 | 197 | ||
168 | /* Set up genirq dispatching for cp_intc */ | 198 | irq_base = irq_alloc_descs(-1, 0, num_irq, 0); |
169 | for (i = 0; i < num_irq; i++) { | 199 | if (irq_base < 0) { |
170 | irq_set_chip(i, &cp_intc_irq_chip); | 200 | pr_warn("Couldn't allocate IRQ numbers\n"); |
171 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 201 | irq_base = 0; |
172 | irq_set_handler(i, handle_edge_irq); | 202 | } |
203 | |||
204 | /* create a legacy host */ | ||
205 | cp_intc_domain = irq_domain_add_legacy(node, num_irq, | ||
206 | irq_base, 0, &cp_intc_host_ops, NULL); | ||
207 | |||
208 | if (!cp_intc_domain) { | ||
209 | pr_err("cp_intc: failed to allocate irq host!\n"); | ||
210 | return -EINVAL; | ||
173 | } | 211 | } |
174 | 212 | ||
175 | /* Enable global interrupt */ | 213 | /* Enable global interrupt */ |
176 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); | 214 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); |
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | void __init cp_intc_init(void) | ||
220 | { | ||
221 | cp_intc_of_init(NULL, NULL); | ||
177 | } | 222 | } |
diff --git a/arch/arm/mach-davinci/include/mach/cp_intc.h b/arch/arm/mach-davinci/include/mach/cp_intc.h index 4e8190eed673..d13d8dfa2b0d 100644 --- a/arch/arm/mach-davinci/include/mach/cp_intc.h +++ b/arch/arm/mach-davinci/include/mach/cp_intc.h | |||
@@ -52,5 +52,6 @@ | |||
52 | #define CP_INTC_VECTOR_ADDR(n) (0x2000 + (n << 2)) | 52 | #define CP_INTC_VECTOR_ADDR(n) (0x2000 + (n << 2)) |
53 | 53 | ||
54 | void __init cp_intc_init(void); | 54 | void __init cp_intc_init(void); |
55 | int __init cp_intc_of_init(struct device_node *, struct device_node *); | ||
55 | 56 | ||
56 | #endif /* __ASM_HARDWARE_CP_INTC_H */ | 57 | #endif /* __ASM_HARDWARE_CP_INTC_H */ |
diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c new file mode 100644 index 000000000000..00946e23c1ee --- /dev/null +++ b/arch/arm/mach-davinci/pm_domain.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Runtime PM support code for DaVinci | ||
3 | * | ||
4 | * Author: Kevin Hilman | ||
5 | * | ||
6 | * Copyright (C) 2012 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/pm_runtime.h> | ||
14 | #include <linux/pm_clock.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | |||
17 | #ifdef CONFIG_PM_RUNTIME | ||
18 | static int davinci_pm_runtime_suspend(struct device *dev) | ||
19 | { | ||
20 | int ret; | ||
21 | |||
22 | dev_dbg(dev, "%s\n", __func__); | ||
23 | |||
24 | ret = pm_generic_runtime_suspend(dev); | ||
25 | if (ret) | ||
26 | return ret; | ||
27 | |||
28 | ret = pm_clk_suspend(dev); | ||
29 | if (ret) { | ||
30 | pm_generic_runtime_resume(dev); | ||
31 | return ret; | ||
32 | } | ||
33 | |||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int davinci_pm_runtime_resume(struct device *dev) | ||
38 | { | ||
39 | dev_dbg(dev, "%s\n", __func__); | ||
40 | |||
41 | pm_clk_resume(dev); | ||
42 | return pm_generic_runtime_resume(dev); | ||
43 | } | ||
44 | #endif | ||
45 | |||
46 | static struct dev_pm_domain davinci_pm_domain = { | ||
47 | .ops = { | ||
48 | SET_RUNTIME_PM_OPS(davinci_pm_runtime_suspend, | ||
49 | davinci_pm_runtime_resume, NULL) | ||
50 | USE_PLATFORM_PM_SLEEP_OPS | ||
51 | }, | ||
52 | }; | ||
53 | |||
54 | static struct pm_clk_notifier_block platform_bus_notifier = { | ||
55 | .pm_domain = &davinci_pm_domain, | ||
56 | }; | ||
57 | |||
58 | static int __init davinci_pm_runtime_init(void) | ||
59 | { | ||
60 | pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | core_initcall(davinci_pm_runtime_init); | ||