diff options
Diffstat (limited to 'kernel/irq/generic-chip.c')
-rw-r--r-- | kernel/irq/generic-chip.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index eb23e5924260..31a9db711906 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c | |||
@@ -8,9 +8,13 @@ | |||
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | #include <linux/interrupt.h> | 9 | #include <linux/interrupt.h> |
10 | #include <linux/kernel_stat.h> | 10 | #include <linux/kernel_stat.h> |
11 | #include <linux/syscore_ops.h> | ||
11 | 12 | ||
12 | #include "internals.h" | 13 | #include "internals.h" |
13 | 14 | ||
15 | static LIST_HEAD(gc_list); | ||
16 | static DEFINE_RAW_SPINLOCK(gc_lock); | ||
17 | |||
14 | static inline struct irq_chip_regs *cur_regs(struct irq_data *d) | 18 | static inline struct irq_chip_regs *cur_regs(struct irq_data *d) |
15 | { | 19 | { |
16 | return &container_of(d->chip, struct irq_chip_type, chip)->regs; | 20 | return &container_of(d->chip, struct irq_chip_type, chip)->regs; |
@@ -219,6 +223,10 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | |||
219 | struct irq_chip_type *ct = gc->chip_types; | 223 | struct irq_chip_type *ct = gc->chip_types; |
220 | unsigned int i; | 224 | unsigned int i; |
221 | 225 | ||
226 | raw_spin_lock(&gc_lock); | ||
227 | list_add_tail(&gc->list, &gc_list); | ||
228 | raw_spin_unlock(&gc_lock); | ||
229 | |||
222 | /* Init mask cache ? */ | 230 | /* Init mask cache ? */ |
223 | if (flags & IRQ_GC_INIT_MASK_CACHE) | 231 | if (flags & IRQ_GC_INIT_MASK_CACHE) |
224 | gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); | 232 | gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); |
@@ -259,3 +267,88 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type) | |||
259 | } | 267 | } |
260 | return -EINVAL; | 268 | return -EINVAL; |
261 | } | 269 | } |
270 | |||
271 | /** | ||
272 | * irq_remove_generic_chip - Remove a chip | ||
273 | * @gc: Generic irq chip holding all data | ||
274 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | ||
275 | * @clr: IRQ_* bits to clear | ||
276 | * @set: IRQ_* bits to set | ||
277 | * | ||
278 | * Remove up to 32 interrupts starting from gc->irq_base. | ||
279 | */ | ||
280 | void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
281 | unsigned int clr, unsigned int set) | ||
282 | { | ||
283 | unsigned int i = gc->irq_base; | ||
284 | |||
285 | raw_spin_lock(&gc_lock); | ||
286 | list_del(&gc->list); | ||
287 | raw_spin_unlock(&gc_lock); | ||
288 | |||
289 | for (; msk; msk >>= 1, i++) { | ||
290 | if (!msk & 0x01) | ||
291 | continue; | ||
292 | |||
293 | /* Remove handler first. That will mask the irq line */ | ||
294 | irq_set_handler(i, NULL); | ||
295 | irq_set_chip(i, &no_irq_chip); | ||
296 | irq_set_chip_data(i, NULL); | ||
297 | irq_modify_status(i, clr, set); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | #ifdef CONFIG_PM | ||
302 | static int irq_gc_suspend(void) | ||
303 | { | ||
304 | struct irq_chip_generic *gc; | ||
305 | |||
306 | list_for_each_entry(gc, &gc_list, list) { | ||
307 | struct irq_chip_type *ct = gc->chip_types; | ||
308 | |||
309 | if (ct->chip.irq_suspend) | ||
310 | ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); | ||
311 | } | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static void irq_gc_resume(void) | ||
316 | { | ||
317 | struct irq_chip_generic *gc; | ||
318 | |||
319 | list_for_each_entry(gc, &gc_list, list) { | ||
320 | struct irq_chip_type *ct = gc->chip_types; | ||
321 | |||
322 | if (ct->chip.irq_resume) | ||
323 | ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); | ||
324 | } | ||
325 | } | ||
326 | #else | ||
327 | #define irq_gc_suspend NULL | ||
328 | #define irq_gc_resume NULL | ||
329 | #endif | ||
330 | |||
331 | static void irq_gc_shutdown(void) | ||
332 | { | ||
333 | struct irq_chip_generic *gc; | ||
334 | |||
335 | list_for_each_entry(gc, &gc_list, list) { | ||
336 | struct irq_chip_type *ct = gc->chip_types; | ||
337 | |||
338 | if (ct->chip.irq_pm_shutdown) | ||
339 | ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static struct syscore_ops irq_gc_syscore_ops = { | ||
344 | .suspend = irq_gc_suspend, | ||
345 | .resume = irq_gc_resume, | ||
346 | .shutdown = irq_gc_shutdown, | ||
347 | }; | ||
348 | |||
349 | static int __init irq_gc_init_ops(void) | ||
350 | { | ||
351 | register_syscore_ops(&irq_gc_syscore_ops); | ||
352 | return 0; | ||
353 | } | ||
354 | device_initcall(irq_gc_init_ops); | ||