aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/generic-chip.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-04-15 16:36:08 -0400
committerThomas Gleixner <tglx@linutronix.de>2011-04-23 09:56:24 -0400
commitcfefd21e693dca791bf9ecfc9dd3794facad533c (patch)
tree20915250e5c9749eea148cab17534b70c094386f /kernel/irq/generic-chip.c
parent7d8280624797bbe2f5170bd3c85c75a8c9c74242 (diff)
genirq: Add chip suspend and resume callbacks
These callbacks are only called in the syscore suspend/resume code on interrupt chips which have been registered via the generic irq chip mechanism. Calling those callbacks per irq would be rather icky, but with the generic irq chip mechanism we can call this per registered chip. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: linux-arm-kernel@lists.infradead.org
Diffstat (limited to 'kernel/irq/generic-chip.c')
-rw-r--r--kernel/irq/generic-chip.c93
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
15static LIST_HEAD(gc_list);
16static DEFINE_RAW_SPINLOCK(gc_lock);
17
14static inline struct irq_chip_regs *cur_regs(struct irq_data *d) 18static 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 */
280void 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
302static 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
315static 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
331static 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
343static struct syscore_ops irq_gc_syscore_ops = {
344 .suspend = irq_gc_suspend,
345 .resume = irq_gc_resume,
346 .shutdown = irq_gc_shutdown,
347};
348
349static int __init irq_gc_init_ops(void)
350{
351 register_syscore_ops(&irq_gc_syscore_ops);
352 return 0;
353}
354device_initcall(irq_gc_init_ops);