diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-14 17:42:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-14 17:42:53 -0500 |
commit | 0beb58783f2168354e2b5297af45fc7db70adf12 (patch) | |
tree | 4debaf4f276990adf1892b7efe57edd344367464 /drivers | |
parent | 6a57d104c8cb5b6adad6784b4ce6e2f7f9961a3a (diff) | |
parent | eabc5fa51c1fae4b66cf883e3a3c2b3ca794494c (diff) |
Merge tag 'dt2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC device-tree updates, take 2, from Olof Johansson:
"This branch contains device-tree updates for the SPEAr platform. They
had dependencies on earlier branches from this merge window, which is
why they were broken out in a separate branch."
* tag 'dt2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc:
ARM: SPEAr3xx: Shirq: Move shirq controller out of plat/
ARM: SPEAr320: DT: Add SPEAr 320 HMI board support
ARM: SPEAr3xx: DT: add shirq node for interrupt multiplexor
ARM: SPEAr3xx: shirq: simplify and move the shared irq multiplexor to DT
ARM: SPEAr1310: Fix AUXDATA for compact flash controller
ARM: SPEAr13xx: Remove fields not required for ssp controller
ARM: SPEAr1310: Move 1310 specific misc register into machine specific files
ARM: SPEAr: DT: Update device nodes
ARM: SPEAr: DT: add uart state to fix warning
ARM: SPEAr: DT: Modify DT bindings for STMMAC
ARM: SPEAr: DT: Fix existing DT support
ARM: SPEAr: DT: Update partition info for MTD devices
ARM: SPEAr: DT: Update pinctrl list
ARM: SPEAr13xx: DT: Add spics gpio controller nodes
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/spear/spear1310_clock.c | 1 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 7 | ||||
-rw-r--r-- | drivers/irqchip/spear-shirq.c | 316 |
3 files changed, 321 insertions, 3 deletions
diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 147e25f00405..ed9af4278619 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <mach/spear.h> | 20 | #include <mach/spear.h> |
21 | #include "clk.h" | 21 | #include "clk.h" |
22 | 22 | ||
23 | #define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000)) | ||
23 | /* PLL related registers and bit values */ | 24 | /* PLL related registers and bit values */ |
24 | #define SPEAR1310_PLL_CFG (VA_MISC_BASE + 0x210) | 25 | #define SPEAR1310_PLL_CFG (VA_MISC_BASE + 0x210) |
25 | /* PLL_CFG bit values */ | 26 | /* PLL_CFG bit values */ |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 02bd37a6187f..bf4609a5bd9d 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o | 1 | obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o |
2 | obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o | 2 | obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o |
3 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o | 3 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o |
4 | obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o | ||
diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c new file mode 100644 index 000000000000..80e1d2fd9d4c --- /dev/null +++ b/drivers/irqchip/spear-shirq.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * SPEAr platform shared irq layer source file | ||
3 | * | ||
4 | * Copyright (C) 2009-2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.linux@gmail.com> | ||
6 | * | ||
7 | * Copyright (C) 2012 ST Microelectronics | ||
8 | * Shiraz Hashim <shiraz.hashim@st.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public | ||
11 | * License version 2. This program is licensed "as is" without any | ||
12 | * warranty of any kind, whether express or implied. | ||
13 | */ | ||
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
15 | |||
16 | #include <linux/err.h> | ||
17 | #include <linux/export.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/irqdomain.h> | ||
22 | #include <linux/irqchip/spear-shirq.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/of_address.h> | ||
25 | #include <linux/of_irq.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | |||
28 | static DEFINE_SPINLOCK(lock); | ||
29 | |||
30 | /* spear300 shared irq registers offsets and masks */ | ||
31 | #define SPEAR300_INT_ENB_MASK_REG 0x54 | ||
32 | #define SPEAR300_INT_STS_MASK_REG 0x58 | ||
33 | |||
34 | static struct spear_shirq spear300_shirq_ras1 = { | ||
35 | .irq_nr = 9, | ||
36 | .irq_bit_off = 0, | ||
37 | .regs = { | ||
38 | .enb_reg = SPEAR300_INT_ENB_MASK_REG, | ||
39 | .status_reg = SPEAR300_INT_STS_MASK_REG, | ||
40 | .clear_reg = -1, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct spear_shirq *spear300_shirq_blocks[] = { | ||
45 | &spear300_shirq_ras1, | ||
46 | }; | ||
47 | |||
48 | /* spear310 shared irq registers offsets and masks */ | ||
49 | #define SPEAR310_INT_STS_MASK_REG 0x04 | ||
50 | |||
51 | static struct spear_shirq spear310_shirq_ras1 = { | ||
52 | .irq_nr = 8, | ||
53 | .irq_bit_off = 0, | ||
54 | .regs = { | ||
55 | .enb_reg = -1, | ||
56 | .status_reg = SPEAR310_INT_STS_MASK_REG, | ||
57 | .clear_reg = -1, | ||
58 | }, | ||
59 | }; | ||
60 | |||
61 | static struct spear_shirq spear310_shirq_ras2 = { | ||
62 | .irq_nr = 5, | ||
63 | .irq_bit_off = 8, | ||
64 | .regs = { | ||
65 | .enb_reg = -1, | ||
66 | .status_reg = SPEAR310_INT_STS_MASK_REG, | ||
67 | .clear_reg = -1, | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | static struct spear_shirq spear310_shirq_ras3 = { | ||
72 | .irq_nr = 1, | ||
73 | .irq_bit_off = 13, | ||
74 | .regs = { | ||
75 | .enb_reg = -1, | ||
76 | .status_reg = SPEAR310_INT_STS_MASK_REG, | ||
77 | .clear_reg = -1, | ||
78 | }, | ||
79 | }; | ||
80 | |||
81 | static struct spear_shirq spear310_shirq_intrcomm_ras = { | ||
82 | .irq_nr = 3, | ||
83 | .irq_bit_off = 14, | ||
84 | .regs = { | ||
85 | .enb_reg = -1, | ||
86 | .status_reg = SPEAR310_INT_STS_MASK_REG, | ||
87 | .clear_reg = -1, | ||
88 | }, | ||
89 | }; | ||
90 | |||
91 | static struct spear_shirq *spear310_shirq_blocks[] = { | ||
92 | &spear310_shirq_ras1, | ||
93 | &spear310_shirq_ras2, | ||
94 | &spear310_shirq_ras3, | ||
95 | &spear310_shirq_intrcomm_ras, | ||
96 | }; | ||
97 | |||
98 | /* spear320 shared irq registers offsets and masks */ | ||
99 | #define SPEAR320_INT_STS_MASK_REG 0x04 | ||
100 | #define SPEAR320_INT_CLR_MASK_REG 0x04 | ||
101 | #define SPEAR320_INT_ENB_MASK_REG 0x08 | ||
102 | |||
103 | static struct spear_shirq spear320_shirq_ras1 = { | ||
104 | .irq_nr = 3, | ||
105 | .irq_bit_off = 7, | ||
106 | .regs = { | ||
107 | .enb_reg = -1, | ||
108 | .status_reg = SPEAR320_INT_STS_MASK_REG, | ||
109 | .clear_reg = SPEAR320_INT_CLR_MASK_REG, | ||
110 | .reset_to_clear = 1, | ||
111 | }, | ||
112 | }; | ||
113 | |||
114 | static struct spear_shirq spear320_shirq_ras2 = { | ||
115 | .irq_nr = 1, | ||
116 | .irq_bit_off = 10, | ||
117 | .regs = { | ||
118 | .enb_reg = -1, | ||
119 | .status_reg = SPEAR320_INT_STS_MASK_REG, | ||
120 | .clear_reg = SPEAR320_INT_CLR_MASK_REG, | ||
121 | .reset_to_clear = 1, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | static struct spear_shirq spear320_shirq_ras3 = { | ||
126 | .irq_nr = 3, | ||
127 | .irq_bit_off = 0, | ||
128 | .invalid_irq = 1, | ||
129 | .regs = { | ||
130 | .enb_reg = SPEAR320_INT_ENB_MASK_REG, | ||
131 | .reset_to_enb = 1, | ||
132 | .status_reg = SPEAR320_INT_STS_MASK_REG, | ||
133 | .clear_reg = SPEAR320_INT_CLR_MASK_REG, | ||
134 | .reset_to_clear = 1, | ||
135 | }, | ||
136 | }; | ||
137 | |||
138 | static struct spear_shirq spear320_shirq_intrcomm_ras = { | ||
139 | .irq_nr = 11, | ||
140 | .irq_bit_off = 11, | ||
141 | .regs = { | ||
142 | .enb_reg = -1, | ||
143 | .status_reg = SPEAR320_INT_STS_MASK_REG, | ||
144 | .clear_reg = SPEAR320_INT_CLR_MASK_REG, | ||
145 | .reset_to_clear = 1, | ||
146 | }, | ||
147 | }; | ||
148 | |||
149 | static struct spear_shirq *spear320_shirq_blocks[] = { | ||
150 | &spear320_shirq_ras3, | ||
151 | &spear320_shirq_ras1, | ||
152 | &spear320_shirq_ras2, | ||
153 | &spear320_shirq_intrcomm_ras, | ||
154 | }; | ||
155 | |||
156 | static void shirq_irq_mask_unmask(struct irq_data *d, bool mask) | ||
157 | { | ||
158 | struct spear_shirq *shirq = irq_data_get_irq_chip_data(d); | ||
159 | u32 val, offset = d->irq - shirq->irq_base; | ||
160 | unsigned long flags; | ||
161 | |||
162 | if (shirq->regs.enb_reg == -1) | ||
163 | return; | ||
164 | |||
165 | spin_lock_irqsave(&lock, flags); | ||
166 | val = readl(shirq->base + shirq->regs.enb_reg); | ||
167 | |||
168 | if (mask ^ shirq->regs.reset_to_enb) | ||
169 | val &= ~(0x1 << shirq->irq_bit_off << offset); | ||
170 | else | ||
171 | val |= 0x1 << shirq->irq_bit_off << offset; | ||
172 | |||
173 | writel(val, shirq->base + shirq->regs.enb_reg); | ||
174 | spin_unlock_irqrestore(&lock, flags); | ||
175 | |||
176 | } | ||
177 | |||
178 | static void shirq_irq_mask(struct irq_data *d) | ||
179 | { | ||
180 | shirq_irq_mask_unmask(d, 1); | ||
181 | } | ||
182 | |||
183 | static void shirq_irq_unmask(struct irq_data *d) | ||
184 | { | ||
185 | shirq_irq_mask_unmask(d, 0); | ||
186 | } | ||
187 | |||
188 | static struct irq_chip shirq_chip = { | ||
189 | .name = "spear-shirq", | ||
190 | .irq_ack = shirq_irq_mask, | ||
191 | .irq_mask = shirq_irq_mask, | ||
192 | .irq_unmask = shirq_irq_unmask, | ||
193 | }; | ||
194 | |||
195 | static void shirq_handler(unsigned irq, struct irq_desc *desc) | ||
196 | { | ||
197 | u32 i, j, val, mask, tmp; | ||
198 | struct irq_chip *chip; | ||
199 | struct spear_shirq *shirq = irq_get_handler_data(irq); | ||
200 | |||
201 | chip = irq_get_chip(irq); | ||
202 | chip->irq_ack(&desc->irq_data); | ||
203 | |||
204 | mask = ((0x1 << shirq->irq_nr) - 1) << shirq->irq_bit_off; | ||
205 | while ((val = readl(shirq->base + shirq->regs.status_reg) & | ||
206 | mask)) { | ||
207 | |||
208 | val >>= shirq->irq_bit_off; | ||
209 | for (i = 0, j = 1; i < shirq->irq_nr; i++, j <<= 1) { | ||
210 | |||
211 | if (!(j & val)) | ||
212 | continue; | ||
213 | |||
214 | generic_handle_irq(shirq->irq_base + i); | ||
215 | |||
216 | /* clear interrupt */ | ||
217 | if (shirq->regs.clear_reg == -1) | ||
218 | continue; | ||
219 | |||
220 | tmp = readl(shirq->base + shirq->regs.clear_reg); | ||
221 | if (shirq->regs.reset_to_clear) | ||
222 | tmp &= ~(j << shirq->irq_bit_off); | ||
223 | else | ||
224 | tmp |= (j << shirq->irq_bit_off); | ||
225 | writel(tmp, shirq->base + shirq->regs.clear_reg); | ||
226 | } | ||
227 | } | ||
228 | chip->irq_unmask(&desc->irq_data); | ||
229 | } | ||
230 | |||
231 | static void __init spear_shirq_register(struct spear_shirq *shirq) | ||
232 | { | ||
233 | int i; | ||
234 | |||
235 | if (shirq->invalid_irq) | ||
236 | return; | ||
237 | |||
238 | irq_set_chained_handler(shirq->irq, shirq_handler); | ||
239 | for (i = 0; i < shirq->irq_nr; i++) { | ||
240 | irq_set_chip_and_handler(shirq->irq_base + i, | ||
241 | &shirq_chip, handle_simple_irq); | ||
242 | set_irq_flags(shirq->irq_base + i, IRQF_VALID); | ||
243 | irq_set_chip_data(shirq->irq_base + i, shirq); | ||
244 | } | ||
245 | |||
246 | irq_set_handler_data(shirq->irq, shirq); | ||
247 | } | ||
248 | |||
249 | static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr, | ||
250 | struct device_node *np) | ||
251 | { | ||
252 | int i, irq_base, hwirq = 0, irq_nr = 0; | ||
253 | static struct irq_domain *shirq_domain; | ||
254 | void __iomem *base; | ||
255 | |||
256 | base = of_iomap(np, 0); | ||
257 | if (!base) { | ||
258 | pr_err("%s: failed to map shirq registers\n", __func__); | ||
259 | return -ENXIO; | ||
260 | } | ||
261 | |||
262 | for (i = 0; i < block_nr; i++) | ||
263 | irq_nr += shirq_blocks[i]->irq_nr; | ||
264 | |||
265 | irq_base = irq_alloc_descs(-1, 0, irq_nr, 0); | ||
266 | if (IS_ERR_VALUE(irq_base)) { | ||
267 | pr_err("%s: irq desc alloc failed\n", __func__); | ||
268 | goto err_unmap; | ||
269 | } | ||
270 | |||
271 | shirq_domain = irq_domain_add_legacy(np, irq_nr, irq_base, 0, | ||
272 | &irq_domain_simple_ops, NULL); | ||
273 | if (WARN_ON(!shirq_domain)) { | ||
274 | pr_warn("%s: irq domain init failed\n", __func__); | ||
275 | goto err_free_desc; | ||
276 | } | ||
277 | |||
278 | for (i = 0; i < block_nr; i++) { | ||
279 | shirq_blocks[i]->base = base; | ||
280 | shirq_blocks[i]->irq_base = irq_find_mapping(shirq_domain, | ||
281 | hwirq); | ||
282 | shirq_blocks[i]->irq = irq_of_parse_and_map(np, i); | ||
283 | |||
284 | spear_shirq_register(shirq_blocks[i]); | ||
285 | hwirq += shirq_blocks[i]->irq_nr; | ||
286 | } | ||
287 | |||
288 | return 0; | ||
289 | |||
290 | err_free_desc: | ||
291 | irq_free_descs(irq_base, irq_nr); | ||
292 | err_unmap: | ||
293 | iounmap(base); | ||
294 | return -ENXIO; | ||
295 | } | ||
296 | |||
297 | int __init spear300_shirq_of_init(struct device_node *np, | ||
298 | struct device_node *parent) | ||
299 | { | ||
300 | return shirq_init(spear300_shirq_blocks, | ||
301 | ARRAY_SIZE(spear300_shirq_blocks), np); | ||
302 | } | ||
303 | |||
304 | int __init spear310_shirq_of_init(struct device_node *np, | ||
305 | struct device_node *parent) | ||
306 | { | ||
307 | return shirq_init(spear310_shirq_blocks, | ||
308 | ARRAY_SIZE(spear310_shirq_blocks), np); | ||
309 | } | ||
310 | |||
311 | int __init spear320_shirq_of_init(struct device_node *np, | ||
312 | struct device_node *parent) | ||
313 | { | ||
314 | return shirq_init(spear320_shirq_blocks, | ||
315 | ARRAY_SIZE(spear320_shirq_blocks), np); | ||
316 | } | ||