Commit 2dcec7a9 authored by Magnus Damm's avatar Magnus Damm Committed by Paul Mundt

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: default avatarMagnus Damm <damm@igel.co.jp>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent f7dd2548
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/sh_intc.h> #include <linux/sh_intc.h>
#include <linux/sysdev.h>
#include <linux/list.h>
#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
...@@ -40,6 +42,8 @@ struct intc_handle_int { ...@@ -40,6 +42,8 @@ struct intc_handle_int {
}; };
struct intc_desc_int { struct intc_desc_int {
struct list_head list;
struct sys_device sysdev;
unsigned long *reg; unsigned long *reg;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
unsigned long *smp; unsigned long *smp;
...@@ -52,6 +56,8 @@ struct intc_desc_int { ...@@ -52,6 +56,8 @@ struct intc_desc_int {
struct irq_chip chip; struct irq_chip chip;
}; };
static LIST_HEAD(intc_list);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#define IS_SMP(x) x.smp #define IS_SMP(x) x.smp
#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) #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) ...@@ -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) #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static void intc_mask_ack(unsigned int irq) static void intc_mask_ack(unsigned int irq)
{ {
...@@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc) ...@@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc)
d = alloc_bootmem(sizeof(*d)); 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->mask_regs ? desc->nr_mask_regs * 2 : 0;
d->nr_reg += desc->prio_regs ? desc->nr_prio_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; d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
...@@ -711,6 +725,7 @@ void __init register_intc_controller(struct intc_desc *desc) ...@@ -711,6 +725,7 @@ void __init register_intc_controller(struct intc_desc *desc)
d->chip.disable = intc_disable; d->chip.disable = intc_disable;
d->chip.shutdown = intc_disable; d->chip.shutdown = intc_disable;
d->chip.set_type = intc_set_sense; d->chip.set_type = intc_set_sense;
d->chip.set_wake = intc_set_wake;
#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
if (desc->ack_regs) { if (desc->ack_regs) {
...@@ -761,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc) ...@@ -761,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc)
intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment