2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - pxa / irq . c
*
2008-03-04 06:42:26 +03:00
* Generic PXA IRQ handling
2005-04-17 02:20:36 +04:00
*
* Author : Nicolas Pitre
* Created : Jun 15 , 2001
* Copyright : MontaVista Software Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
2008-01-29 02:00:02 +03:00
# include <linux/sysdev.h>
2005-04-17 02:20:36 +04:00
2008-08-04 13:41:28 +04:00
# include <asm/arch/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/irq.h>
# include <asm/mach/irq.h>
# include <asm/arch/pxa-regs.h>
# include "generic.h"
2008-03-04 08:53:05 +03:00
# define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f)
# define _ICMR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR))
# define _ICLR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR))
2005-04-17 02:20:36 +04:00
/*
* This is for peripheral IRQs internal to the PXA chip .
*/
2008-03-04 08:53:05 +03:00
static int pxa_internal_irq_nr ;
static void pxa_mask_irq ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
2008-03-04 08:53:05 +03:00
_ICMR ( irq ) & = ~ ( 1 < < IRQ_BIT ( irq ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-03-04 08:53:05 +03:00
static void pxa_unmask_irq ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
2008-03-04 08:53:05 +03:00
_ICMR ( irq ) | = 1 < < IRQ_BIT ( irq ) ;
2005-04-17 02:20:36 +04:00
}
2008-03-04 08:53:05 +03:00
static struct irq_chip pxa_internal_irq_chip = {
2006-08-02 01:26:25 +04:00
. name = " SC " ,
2008-03-04 08:53:05 +03:00
. ack = pxa_mask_irq ,
. mask = pxa_mask_irq ,
. unmask = pxa_unmask_irq ,
2005-04-17 02:20:36 +04:00
} ;
2008-03-04 09:19:58 +03:00
void __init pxa_init_irq ( int irq_nr , set_wake_t fn )
2007-06-06 09:36:04 +04:00
{
int irq ;
2008-03-04 08:53:05 +03:00
pxa_internal_irq_nr = irq_nr ;
2007-06-06 09:36:04 +04:00
2008-03-04 08:53:05 +03:00
for ( irq = 0 ; irq < irq_nr ; irq + = 32 ) {
_ICMR ( irq ) = 0 ; /* disable all IRQs */
_ICLR ( irq ) = 0 ; /* all IRQs are IRQ, not FIQ */
}
2007-06-06 09:36:04 +04:00
/* only unmasked interrupts kick us out of idle */
ICCR = 1 ;
2008-03-04 08:53:05 +03:00
for ( irq = PXA_IRQ ( 0 ) ; irq < PXA_IRQ ( irq_nr ) ; irq + + ) {
set_irq_chip ( irq , & pxa_internal_irq_chip ) ;
2007-06-06 09:32:38 +04:00
set_irq_handler ( irq , handle_level_irq ) ;
set_irq_flags ( irq , IRQF_VALID ) ;
}
2005-04-17 02:20:36 +04:00
2008-03-04 09:19:58 +03:00
pxa_internal_irq_chip . set_wake = fn ;
2007-08-29 13:22:17 +04:00
}
2008-01-29 02:00:02 +03:00
# ifdef CONFIG_PM
static unsigned long saved_icmr [ 2 ] ;
static int pxa_irq_suspend ( struct sys_device * dev , pm_message_t state )
{
2008-03-04 08:53:05 +03:00
int i , irq = PXA_IRQ ( 0 ) ;
for ( i = 0 ; irq < PXA_IRQ ( pxa_internal_irq_nr ) ; i + + , irq + = 32 ) {
saved_icmr [ i ] = _ICMR ( irq ) ;
_ICMR ( irq ) = 0 ;
2008-01-29 02:00:02 +03:00
}
return 0 ;
}
static int pxa_irq_resume ( struct sys_device * dev )
{
2008-03-04 08:53:05 +03:00
int i , irq = PXA_IRQ ( 0 ) ;
for ( i = 0 ; irq < PXA_IRQ ( pxa_internal_irq_nr ) ; i + + , irq + = 32 ) {
_ICMR ( irq ) = saved_icmr [ i ] ;
_ICLR ( irq ) = 0 ;
2008-01-29 02:00:02 +03:00
}
2008-03-04 08:53:05 +03:00
ICCR = 1 ;
2008-01-29 02:00:02 +03:00
return 0 ;
}
# else
# define pxa_irq_suspend NULL
# define pxa_irq_resume NULL
# endif
struct sysdev_class pxa_irq_sysclass = {
. name = " irq " ,
. suspend = pxa_irq_suspend ,
. resume = pxa_irq_resume ,
} ;
static int __init pxa_irq_init ( void )
{
return sysdev_class_register ( & pxa_irq_sysclass ) ;
}
core_initcall ( pxa_irq_init ) ;