aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/intc.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-04-01 10:30:59 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-04-01 22:19:57 -0400
commit2dcec7a988a1895540460a0bf5603bab63d5a3ed (patch)
tree8f03591269afafd31382c118b99cc51c69ad9bf3 /drivers/sh/intc.c
parentf7dd2548c471b1c7758611f6cd6393367d7ff649 (diff)
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 <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh/intc.c')
-rw-r--r--drivers/sh/intc.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index b75f70155823..7fb9b5c4669a 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -22,6 +22,8 @@
22#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/bootmem.h> 23#include <linux/bootmem.h>
24#include <linux/sh_intc.h> 24#include <linux/sh_intc.h>
25#include <linux/sysdev.h>
26#include <linux/list.h>
25 27
26#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ 28#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
27 ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ 29 ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
@@ -40,6 +42,8 @@ struct intc_handle_int {
40}; 42};
41 43
42struct intc_desc_int { 44struct intc_desc_int {
45 struct list_head list;
46 struct sys_device sysdev;
43 unsigned long *reg; 47 unsigned long *reg;
44#ifdef CONFIG_SMP 48#ifdef CONFIG_SMP
45 unsigned long *smp; 49 unsigned long *smp;
@@ -52,6 +56,8 @@ struct intc_desc_int {
52 struct irq_chip chip; 56 struct irq_chip chip;
53}; 57};
54 58
59static LIST_HEAD(intc_list);
60
55#ifdef CONFIG_SMP 61#ifdef CONFIG_SMP
56#define IS_SMP(x) x.smp 62#define IS_SMP(x) x.smp
57#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) 63#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 } 238 }
233} 239}
234 240
241static int intc_set_wake(unsigned int irq, unsigned int on)
242{
243 return 0; /* allow wakeup, but setup hardware in intc_suspend() */
244}
245
235#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) 246#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
236static void intc_mask_ack(unsigned int irq) 247static void intc_mask_ack(unsigned int irq)
237{ 248{
@@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc)
664 675
665 d = alloc_bootmem(sizeof(*d)); 676 d = alloc_bootmem(sizeof(*d));
666 677
678 INIT_LIST_HEAD(&d->list);
679 list_add(&d->list, &intc_list);
680
667 d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; 681 d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
668 d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; 682 d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
669 d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; 683 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 d->chip.disable = intc_disable; 725 d->chip.disable = intc_disable;
712 d->chip.shutdown = intc_disable; 726 d->chip.shutdown = intc_disable;
713 d->chip.set_type = intc_set_sense; 727 d->chip.set_type = intc_set_sense;
728 d->chip.set_wake = intc_set_wake;
714 729
715#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) 730#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
716 if (desc->ack_regs) { 731 if (desc->ack_regs) {
@@ -761,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc)
761 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); 776 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
762 } 777 }
763} 778}
779
780static int intc_suspend(struct sys_device *dev, pm_message_t state)
781{
782 struct intc_desc_int *d;
783 struct irq_desc *desc;
784 int irq;
785
786 /* get intc controller associated with this sysdev */
787 d = container_of(dev, struct intc_desc_int, sysdev);
788
789 /* enable wakeup irqs belonging to this intc controller */
790 for_each_irq_desc(irq, desc) {
791 if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip))
792 intc_enable(irq);
793 }
794
795 return 0;
796}
797
798static struct sysdev_class intc_sysdev_class = {
799 .name = "intc",
800 .suspend = intc_suspend,
801};
802
803/* register this intc as sysdev to allow suspend/resume */
804static int __init register_intc_sysdevs(void)
805{
806 struct intc_desc_int *d;
807 int error;
808 int id = 0;
809
810 error = sysdev_class_register(&intc_sysdev_class);
811 if (!error) {
812 list_for_each_entry(d, &intc_list, list) {
813 d->sysdev.id = id;
814 d->sysdev.cls = &intc_sysdev_class;
815 error = sysdev_register(&d->sysdev);
816 if (error)
817 break;
818 id++;
819 }
820 }
821
822 if (error)
823 pr_warning("intc: sysdev registration error\n");
824
825 return error;
826}
827
828device_initcall(register_intc_sysdevs);