diff options
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/intc.c | 65 |
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 | ||
42 | struct intc_desc_int { | 44 | struct 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 | ||
59 | static 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 | ||
241 | static 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) |
236 | static void intc_mask_ack(unsigned int irq) | 247 | static 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 | |||
780 | static 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 | |||
798 | static 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 */ | ||
804 | static 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 | |||
828 | device_initcall(register_intc_sysdevs); | ||