diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-01-24 17:22:18 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-02-09 10:34:16 -0500 |
commit | ced8d21cf104c9924e98f78954e873577366d156 (patch) | |
tree | faf102722b0d08027bfd2d3e4e928e79f0af0141 /arch/arm/mach-sa1100 | |
parent | 9590e898742cd6cd50aab1109a115faf42befaf7 (diff) |
ARM: sa11x0: neponset: implement support for sparse IRQs
Implement the necessary allocation/freeing functionality to support
sparse IRQs with the Neponset device. On non-sparse IRQ platforms,
this allows us to dynamically allocate from within the available IRQ
number space.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-sa1100')
-rw-r--r-- | arch/arm/mach-sa1100/include/mach/irqs.h | 8 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/neponset.c | 111 |
2 files changed, 61 insertions, 58 deletions
diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h index d18f21abef80..9e07634a4670 100644 --- a/arch/arm/mach-sa1100/include/mach/irqs.h +++ b/arch/arm/mach-sa1100/include/mach/irqs.h | |||
@@ -82,11 +82,3 @@ | |||
82 | #else | 82 | #else |
83 | #define NR_IRQS (IRQ_BOARD_START) | 83 | #define NR_IRQS (IRQ_BOARD_START) |
84 | #endif | 84 | #endif |
85 | |||
86 | /* | ||
87 | * Board specific IRQs. Define them here. | ||
88 | * Do not surround them with ifdefs. | ||
89 | */ | ||
90 | #define IRQ_NEPONSET_SMC9196 (IRQ_BOARD_START + 0) | ||
91 | #define IRQ_NEPONSET_USAR (IRQ_BOARD_START + 1) | ||
92 | #define IRQ_NEPONSET_SA1111 (IRQ_BOARD_START + 2) | ||
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index 164bc9801ed7..47681960783b 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/err.h> | 4 | #include <linux/err.h> |
5 | #include <linux/init.h> | 5 | #include <linux/init.h> |
6 | #include <linux/ioport.h> | 6 | #include <linux/ioport.h> |
7 | #include <linux/irq.h> | ||
7 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
8 | #include <linux/module.h> | 9 | #include <linux/module.h> |
9 | #include <linux/platform_device.h> | 10 | #include <linux/platform_device.h> |
@@ -11,9 +12,7 @@ | |||
11 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
12 | 13 | ||
13 | #include <asm/mach-types.h> | 14 | #include <asm/mach-types.h> |
14 | #include <asm/irq.h> | ||
15 | #include <asm/mach/map.h> | 15 | #include <asm/mach/map.h> |
16 | #include <asm/mach/irq.h> | ||
17 | #include <asm/mach/serial_sa1100.h> | 16 | #include <asm/mach/serial_sa1100.h> |
18 | #include <asm/hardware/sa1111.h> | 17 | #include <asm/hardware/sa1111.h> |
19 | #include <asm/sizes.h> | 18 | #include <asm/sizes.h> |
@@ -22,9 +21,15 @@ | |||
22 | #include <mach/assabet.h> | 21 | #include <mach/assabet.h> |
23 | #include <mach/neponset.h> | 22 | #include <mach/neponset.h> |
24 | 23 | ||
24 | #define NEP_IRQ_SMC91X 0 | ||
25 | #define NEP_IRQ_USAR 1 | ||
26 | #define NEP_IRQ_SA1111 2 | ||
27 | #define NEP_IRQ_NR 3 | ||
28 | |||
25 | struct neponset_drvdata { | 29 | struct neponset_drvdata { |
26 | struct platform_device *sa1111; | 30 | struct platform_device *sa1111; |
27 | struct platform_device *smc91x; | 31 | struct platform_device *smc91x; |
32 | unsigned irq_base; | ||
28 | #ifdef CONFIG_PM_SLEEP | 33 | #ifdef CONFIG_PM_SLEEP |
29 | u32 ncr0; | 34 | u32 ncr0; |
30 | u32 mdm_ctl_0; | 35 | u32 mdm_ctl_0; |
@@ -104,9 +109,9 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = { | |||
104 | * ensure that the IRQ signal is deasserted before returning. This | 109 | * ensure that the IRQ signal is deasserted before returning. This |
105 | * is rather unfortunate. | 110 | * is rather unfortunate. |
106 | */ | 111 | */ |
107 | static void | 112 | static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc) |
108 | neponset_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
109 | { | 113 | { |
114 | struct neponset_drvdata *d = irq_desc_get_handler_data(desc); | ||
110 | unsigned int irr; | 115 | unsigned int irr; |
111 | 116 | ||
112 | while (1) { | 117 | while (1) { |
@@ -141,26 +146,21 @@ neponset_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
141 | */ | 146 | */ |
142 | desc->irq_data.chip->irq_ack(&desc->irq_data); | 147 | desc->irq_data.chip->irq_ack(&desc->irq_data); |
143 | 148 | ||
144 | if (irr & IRR_ETHERNET) { | 149 | if (irr & IRR_ETHERNET) |
145 | generic_handle_irq(IRQ_NEPONSET_SMC9196); | 150 | generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X); |
146 | } | ||
147 | 151 | ||
148 | if (irr & IRR_USAR) { | 152 | if (irr & IRR_USAR) |
149 | generic_handle_irq(IRQ_NEPONSET_USAR); | 153 | generic_handle_irq(d->irq_base + NEP_IRQ_USAR); |
150 | } | ||
151 | 154 | ||
152 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | 155 | desc->irq_data.chip->irq_unmask(&desc->irq_data); |
153 | } | 156 | } |
154 | 157 | ||
155 | if (irr & IRR_SA1111) { | 158 | if (irr & IRR_SA1111) |
156 | generic_handle_irq(IRQ_NEPONSET_SA1111); | 159 | generic_handle_irq(d->irq_base + NEP_IRQ_SA1111); |
157 | } | ||
158 | } | 160 | } |
159 | } | 161 | } |
160 | 162 | ||
161 | /* | 163 | /* Yes, we really do not have any kind of masking or unmasking */ |
162 | * Yes, we really do not have any kind of masking or unmasking | ||
163 | */ | ||
164 | static void nochip_noop(struct irq_data *irq) | 164 | static void nochip_noop(struct irq_data *irq) |
165 | { | 165 | { |
166 | } | 166 | } |
@@ -172,25 +172,17 @@ static struct irq_chip nochip = { | |||
172 | .irq_unmask = nochip_noop, | 172 | .irq_unmask = nochip_noop, |
173 | }; | 173 | }; |
174 | 174 | ||
175 | static struct resource sa1111_resources[] = { | ||
176 | [0] = DEFINE_RES_MEM(0x40000000, SZ_8K), | ||
177 | [1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SA1111), | ||
178 | }; | ||
179 | |||
180 | static struct sa1111_platform_data sa1111_info = { | 175 | static struct sa1111_platform_data sa1111_info = { |
181 | .irq_base = IRQ_BOARD_END, | 176 | .irq_base = IRQ_BOARD_END, |
182 | }; | 177 | }; |
183 | 178 | ||
184 | static struct resource smc91x_resources[] = { | ||
185 | [0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"), | ||
186 | [1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196), | ||
187 | [2] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000, | ||
188 | 0x02000000, "smc91x-attrib"), | ||
189 | }; | ||
190 | |||
191 | static int __devinit neponset_probe(struct platform_device *dev) | 179 | static int __devinit neponset_probe(struct platform_device *dev) |
192 | { | 180 | { |
193 | struct neponset_drvdata *d; | 181 | struct neponset_drvdata *d; |
182 | struct resource sa1111_resources[] = { | ||
183 | DEFINE_RES_MEM(0x40000000, SZ_8K), | ||
184 | { .flags = IORESOURCE_IRQ }, | ||
185 | }; | ||
194 | struct platform_device_info sa1111_devinfo = { | 186 | struct platform_device_info sa1111_devinfo = { |
195 | .parent = &dev->dev, | 187 | .parent = &dev->dev, |
196 | .name = "sa1111", | 188 | .name = "sa1111", |
@@ -201,6 +193,13 @@ static int __devinit neponset_probe(struct platform_device *dev) | |||
201 | .size_data = sizeof(sa1111_info), | 193 | .size_data = sizeof(sa1111_info), |
202 | .dma_mask = 0xffffffffUL, | 194 | .dma_mask = 0xffffffffUL, |
203 | }; | 195 | }; |
196 | struct resource smc91x_resources[] = { | ||
197 | DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, | ||
198 | 0x02000000, "smc91x-regs"), | ||
199 | DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000, | ||
200 | 0x02000000, "smc91x-attrib"), | ||
201 | { .flags = IORESOURCE_IRQ }, | ||
202 | }; | ||
204 | struct platform_device_info smc91x_devinfo = { | 203 | struct platform_device_info smc91x_devinfo = { |
205 | .parent = &dev->dev, | 204 | .parent = &dev->dev, |
206 | .name = "smc91x", | 205 | .name = "smc91x", |
@@ -216,47 +215,59 @@ static int __devinit neponset_probe(struct platform_device *dev) | |||
216 | goto err_alloc; | 215 | goto err_alloc; |
217 | } | 216 | } |
218 | 217 | ||
219 | sa1100_register_uart_fns(&neponset_port_fns); | 218 | ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1); |
219 | if (ret <= 0) { | ||
220 | dev_err(&dev->dev, "unable to allocate %u irqs: %d\n", | ||
221 | NEP_IRQ_NR, ret); | ||
222 | if (ret == 0) | ||
223 | ret = -ENOMEM; | ||
224 | goto err_irq_alloc; | ||
225 | } | ||
226 | |||
227 | d->irq_base = ret; | ||
228 | |||
229 | irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip, | ||
230 | handle_simple_irq); | ||
231 | set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE); | ||
232 | irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip, | ||
233 | handle_simple_irq); | ||
234 | set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE); | ||
235 | irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); | ||
220 | 236 | ||
221 | /* | ||
222 | * Install handler for GPIO25. | ||
223 | */ | ||
224 | irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING); | 237 | irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING); |
238 | irq_set_handler_data(IRQ_GPIO25, d); | ||
225 | irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler); | 239 | irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler); |
226 | 240 | ||
227 | /* | 241 | /* |
228 | * We would set IRQ_GPIO25 to be a wake-up IRQ, but | 242 | * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately |
229 | * unfortunately something on the Neponset activates | 243 | * something on the Neponset activates this IRQ on sleep (eth?) |
230 | * this IRQ on sleep (ethernet?) | ||
231 | */ | 244 | */ |
232 | #if 0 | 245 | #if 0 |
233 | enable_irq_wake(IRQ_GPIO25); | 246 | enable_irq_wake(IRQ_GPIO25); |
234 | #endif | 247 | #endif |
235 | 248 | ||
236 | /* | 249 | dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n", |
237 | * Setup other Neponset IRQs. SA1111 will be done by the | 250 | d->irq_base, d->irq_base + NEP_IRQ_NR - 1); |
238 | * generic SA1111 code. | ||
239 | */ | ||
240 | irq_set_chip_and_handler(IRQ_NEPONSET_SMC9196, &nochip, | ||
241 | handle_simple_irq); | ||
242 | set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); | ||
243 | irq_set_chip_and_handler(IRQ_NEPONSET_USAR, &nochip, | ||
244 | handle_simple_irq); | ||
245 | set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); | ||
246 | irq_set_chip(IRQ_NEPONSET_SA1111, &nochip); | ||
247 | 251 | ||
248 | /* | 252 | sa1100_register_uart_fns(&neponset_port_fns); |
249 | * Disable GPIO 0/1 drivers so the buttons work on the module. | 253 | |
250 | */ | 254 | /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */ |
251 | NCR_0 = NCR_GP01_OFF; | 255 | NCR_0 = NCR_GP01_OFF; |
252 | 256 | ||
257 | sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111; | ||
258 | sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111; | ||
253 | d->sa1111 = platform_device_register_full(&sa1111_devinfo); | 259 | d->sa1111 = platform_device_register_full(&sa1111_devinfo); |
260 | |||
261 | smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X; | ||
262 | smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X; | ||
254 | d->smc91x = platform_device_register_full(&smc91x_devinfo); | 263 | d->smc91x = platform_device_register_full(&smc91x_devinfo); |
255 | 264 | ||
256 | platform_set_drvdata(dev, d); | 265 | platform_set_drvdata(dev, d); |
257 | 266 | ||
258 | return 0; | 267 | return 0; |
259 | 268 | ||
269 | err_irq_alloc: | ||
270 | kfree(d); | ||
260 | err_alloc: | 271 | err_alloc: |
261 | return ret; | 272 | return ret; |
262 | } | 273 | } |
@@ -270,7 +281,7 @@ static int __devexit neponset_remove(struct platform_device *dev) | |||
270 | if (!IS_ERR(d->smc91x)) | 281 | if (!IS_ERR(d->smc91x)) |
271 | platform_device_unregister(d->smc91x); | 282 | platform_device_unregister(d->smc91x); |
272 | irq_set_chained_handler(IRQ_GPIO25, NULL); | 283 | irq_set_chained_handler(IRQ_GPIO25, NULL); |
273 | 284 | irq_free_descs(d->irq_base, NEP_IRQ_NR); | |
274 | kfree(d); | 285 | kfree(d); |
275 | 286 | ||
276 | return 0; | 287 | return 0; |