From f7dd2548c471b1c7758611f6cd6393367d7ff649 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 1 Apr 2009 14:20:58 +0000 Subject: sh: intc: install enable, disable and shutdown callbacks Modify the intc code to install a disable callback. The current solution without a disable callback results in use of the generic default_disable() function. This function is a no-op so suspend_device_irqs() will not disable any intc interrupts at suspend time without this patch. Also, install enable and shutdown callbacks while at it. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/sh/intc.c') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 2269fbcaa18..b75f7015582 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -707,6 +707,9 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.mask = intc_disable; d->chip.unmask = intc_enable; d->chip.mask_ack = intc_disable; + d->chip.enable = intc_enable; + d->chip.disable = intc_disable; + d->chip.shutdown = intc_disable; d->chip.set_type = intc_set_sense; #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) -- cgit v1.2.3-70-g09d2 From 2dcec7a988a1895540460a0bf5603bab63d5a3ed Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 1 Apr 2009 14:30:59 +0000 Subject: sh: intc: set_irq_wake() support Add set_irq_wake() support to intc using sysdev and suspend. The intc controllers are put on a list at registration time and registered as sysdev devices later on during the boot. The sysdev class suspend callback is used to find irqs with wakeup enabled belonging to our intc controller. Such irqs are simply enabled so wakeup interrupts may reach the cpu. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'drivers/sh/intc.c') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index b75f7015582..7fb9b5c4669 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ @@ -40,6 +42,8 @@ struct intc_handle_int { }; struct intc_desc_int { + struct list_head list; + struct sys_device sysdev; unsigned long *reg; #ifdef CONFIG_SMP unsigned long *smp; @@ -52,6 +56,8 @@ struct intc_desc_int { struct irq_chip chip; }; +static LIST_HEAD(intc_list); + #ifdef CONFIG_SMP #define IS_SMP(x) x.smp #define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) @@ -232,6 +238,11 @@ static void intc_disable(unsigned int irq) } } +static int intc_set_wake(unsigned int irq, unsigned int on) +{ + return 0; /* allow wakeup, but setup hardware in intc_suspend() */ +} + #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) static void intc_mask_ack(unsigned int irq) { @@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc) d = alloc_bootmem(sizeof(*d)); + INIT_LIST_HEAD(&d->list); + list_add(&d->list, &intc_list); + d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; @@ -711,6 +725,7 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.disable = intc_disable; d->chip.shutdown = intc_disable; d->chip.set_type = intc_set_sense; + d->chip.set_wake = intc_set_wake; #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) if (desc->ack_regs) { @@ -761,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc) intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); } } + +static int intc_suspend(struct sys_device *dev, pm_message_t state) +{ + struct intc_desc_int *d; + struct irq_desc *desc; + int irq; + + /* get intc controller associated with this sysdev */ + d = container_of(dev, struct intc_desc_int, sysdev); + + /* enable wakeup irqs belonging to this intc controller */ + for_each_irq_desc(irq, desc) { + if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip)) + intc_enable(irq); + } + + return 0; +} + +static struct sysdev_class intc_sysdev_class = { + .name = "intc", + .suspend = intc_suspend, +}; + +/* register this intc as sysdev to allow suspend/resume */ +static int __init register_intc_sysdevs(void) +{ + struct intc_desc_int *d; + int error; + int id = 0; + + error = sysdev_class_register(&intc_sysdev_class); + if (!error) { + list_for_each_entry(d, &intc_list, list) { + d->sysdev.id = id; + d->sysdev.cls = &intc_sysdev_class; + error = sysdev_register(&d->sysdev); + if (error) + break; + id++; + } + } + + if (error) + pr_warning("intc: sysdev registration error\n"); + + return error; +} + +device_initcall(register_intc_sysdevs); -- cgit v1.2.3-70-g09d2 From 7fd87b3f1a6955da0a21b4fd99f8939701055172 Mon Sep 17 00:00:00 2001 From: Francesco VIRLINZI Date: Mon, 6 Apr 2009 07:17:04 +0000 Subject: sh: intc: Added resume from hibernation support to the intc It's required for all modules loaded in the previous runtime session because not initilized duing the kernel start-up. Signed-off-by: Francesco Virlinzi Signed-off-by: Paul Mundt --- drivers/sh/intc.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'drivers/sh/intc.c') diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 7fb9b5c4669..12d13d99b6f 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -44,6 +44,7 @@ struct intc_handle_int { struct intc_desc_int { struct list_head list; struct sys_device sysdev; + pm_message_t state; unsigned long *reg; #ifdef CONFIG_SMP unsigned long *smp; @@ -786,18 +787,44 @@ static int intc_suspend(struct sys_device *dev, pm_message_t state) /* get intc controller associated with this sysdev */ d = container_of(dev, struct intc_desc_int, sysdev); - /* enable wakeup irqs belonging to this intc controller */ - for_each_irq_desc(irq, desc) { - if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip)) - intc_enable(irq); + switch (state.event) { + case PM_EVENT_ON: + if (d->state.event != PM_EVENT_FREEZE) + break; + for_each_irq_desc(irq, desc) { + if (desc->chip != &d->chip) + continue; + if (desc->status & IRQ_DISABLED) + intc_disable(irq); + else + intc_enable(irq); + } + break; + case PM_EVENT_FREEZE: + /* nothing has to be done */ + break; + case PM_EVENT_SUSPEND: + /* enable wakeup irqs belonging to this intc controller */ + for_each_irq_desc(irq, desc) { + if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip)) + intc_enable(irq); + } + break; } + d->state = state; return 0; } +static int intc_resume(struct sys_device *dev) +{ + return intc_suspend(dev, PMSG_ON); +} + static struct sysdev_class intc_sysdev_class = { .name = "intc", .suspend = intc_suspend, + .resume = intc_resume, }; /* register this intc as sysdev to allow suspend/resume */ -- cgit v1.2.3-70-g09d2