2222#include <linux/interrupt.h>
2323#include <linux/bootmem.h>
2424#include <linux/sh_intc.h>
25+ #include <linux/sysdev.h>
26+ #include <linux/list.h>
2527
2628#define _INTC_MK (fn , mode , addr_e , addr_d , width , shift ) \
2729 ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
@@ -40,6 +42,8 @@ struct intc_handle_int {
4042};
4143
4244struct intc_desc_int {
45+ struct list_head list ;
46+ struct sys_device sysdev ;
4347 unsigned long * reg ;
4448#ifdef CONFIG_SMP
4549 unsigned long * smp ;
@@ -52,6 +56,8 @@ struct intc_desc_int {
5256 struct irq_chip chip ;
5357};
5458
59+ static LIST_HEAD (intc_list );
60+
5561#ifdef CONFIG_SMP
5662#define IS_SMP (x ) x.smp
5763#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)
232238 }
233239}
234240
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+
235246#if defined(CONFIG_CPU_SH3 ) || defined(CONFIG_CPU_SH4A )
236247static void intc_mask_ack (unsigned int irq )
237248{
@@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc)
664675
665676 d = alloc_bootmem (sizeof (* d ));
666677
678+ INIT_LIST_HEAD (& d -> list );
679+ list_add (& d -> list , & intc_list );
680+
667681 d -> nr_reg = desc -> mask_regs ? desc -> nr_mask_regs * 2 : 0 ;
668682 d -> nr_reg += desc -> prio_regs ? desc -> nr_prio_regs * 2 : 0 ;
669683 d -> nr_reg += desc -> sense_regs ? desc -> nr_sense_regs : 0 ;
@@ -711,6 +725,7 @@ void __init register_intc_controller(struct intc_desc *desc)
711725 d -> chip .disable = intc_disable ;
712726 d -> chip .shutdown = intc_disable ;
713727 d -> chip .set_type = intc_set_sense ;
728+ d -> chip .set_wake = intc_set_wake ;
714729
715730#if defined(CONFIG_CPU_SH3 ) || defined(CONFIG_CPU_SH4A )
716731 if (desc -> ack_regs ) {
@@ -761,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc)
761776 intc_register_irq (desc , d , vect -> enum_id , evt2irq (vect -> vect ));
762777 }
763778}
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 );
0 commit comments