2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / mach - sa1100 / irq . c
*
* Copyright ( C ) 1999 - 2001 Nicolas Pitre
*
* Generic IRQ handling for the SA11x0 , GPIO 11 - 27 IRQ demultiplexing .
*
* 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>
2006-07-01 22:32:38 +01:00
# include <linux/interrupt.h>
2012-06-06 11:42:36 +01:00
# include <linux/io.h>
2006-07-01 22:32:38 +01:00
# include <linux/irq.h>
2014-11-28 15:56:54 +01:00
# include <linux/irqdomain.h>
2005-04-16 15:20:36 -07:00
# include <linux/ioport.h>
2011-04-22 22:03:03 +02:00
# include <linux/syscore_ops.h>
2005-04-16 15:20:36 -07:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2012-02-24 00:06:51 +01:00
# include <mach/irqs.h>
2005-04-16 15:20:36 -07:00
# include <asm/mach/irq.h>
2014-11-28 15:55:16 +01:00
# include <asm/exception.h>
2005-04-16 15:20:36 -07:00
# include "generic.h"
2014-11-28 15:57:52 +01:00
/*
* We don ' t need to ACK IRQs on the SA1100 unless they ' re GPIOs
* this is for internal IRQs i . e . from IRQ LCD to RTCAlrm .
*/
static void sa1100_mask_irq ( struct irq_data * d )
{
ICMR & = ~ BIT ( d - > hwirq ) ;
}
static void sa1100_unmask_irq ( struct irq_data * d )
{
ICMR | = BIT ( d - > hwirq ) ;
}
/*
* Apart form GPIOs , only the RTC alarm can be a wakeup event .
*/
static int sa1100_set_wake ( struct irq_data * d , unsigned int on )
{
if ( BIT ( d - > hwirq ) = = IC_RTCAlrm ) {
if ( on )
PWER | = PWER_RTC ;
else
PWER & = ~ PWER_RTC ;
return 0 ;
}
return - EINVAL ;
}
static struct irq_chip sa1100_normal_chip = {
. name = " SC " ,
. irq_ack = sa1100_mask_irq ,
. irq_mask = sa1100_mask_irq ,
. irq_unmask = sa1100_unmask_irq ,
. irq_set_wake = sa1100_set_wake ,
} ;
static int sa1100_normal_irqdomain_map ( struct irq_domain * d ,
unsigned int irq , irq_hw_number_t hwirq )
{
irq_set_chip_and_handler ( irq , & sa1100_normal_chip ,
handle_level_irq ) ;
set_irq_flags ( irq , IRQF_VALID ) ;
return 0 ;
}
static struct irq_domain_ops sa1100_normal_irqdomain_ops = {
. map = sa1100_normal_irqdomain_map ,
. xlate = irq_domain_xlate_onetwocell ,
} ;
static struct irq_domain * sa1100_normal_irqdomain ;
2012-01-12 10:25:29 +00:00
static struct resource irq_resource =
DEFINE_RES_MEM_NAMED ( 0x90050000 , SZ_64K , " irqs " ) ;
2005-04-16 15:20:36 -07:00
static struct sa1100irq_state {
unsigned int saved ;
unsigned int icmr ;
unsigned int iclr ;
unsigned int iccr ;
} sa1100irq_state ;
2011-04-22 22:03:03 +02:00
static int sa1100irq_suspend ( void )
2005-04-16 15:20:36 -07:00
{
struct sa1100irq_state * st = & sa1100irq_state ;
st - > saved = 1 ;
st - > icmr = ICMR ;
st - > iclr = ICLR ;
st - > iccr = ICCR ;
/*
* Disable all GPIO - based interrupts .
*/
ICMR & = ~ ( IC_GPIO11_27 | IC_GPIO10 | IC_GPIO9 | IC_GPIO8 | IC_GPIO7 |
IC_GPIO6 | IC_GPIO5 | IC_GPIO4 | IC_GPIO3 | IC_GPIO2 |
IC_GPIO1 | IC_GPIO0 ) ;
return 0 ;
}
2011-04-22 22:03:03 +02:00
static void sa1100irq_resume ( void )
2005-04-16 15:20:36 -07:00
{
struct sa1100irq_state * st = & sa1100irq_state ;
if ( st - > saved ) {
ICCR = st - > iccr ;
ICLR = st - > iclr ;
ICMR = st - > icmr ;
}
}
2011-04-22 22:03:03 +02:00
static struct syscore_ops sa1100irq_syscore_ops = {
2005-04-16 15:20:36 -07:00
. suspend = sa1100irq_suspend ,
. resume = sa1100irq_resume ,
} ;
static int __init sa1100irq_init_devicefs ( void )
{
2011-04-22 22:03:03 +02:00
register_syscore_ops ( & sa1100irq_syscore_ops ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
device_initcall ( sa1100irq_init_devicefs ) ;
2014-11-28 15:55:16 +01:00
static asmlinkage void __exception_irq_entry
sa1100_handle_irq ( struct pt_regs * regs )
{
uint32_t icip , icmr , mask ;
do {
icip = ( ICIP ) ;
icmr = ( ICMR ) ;
mask = icip & icmr ;
if ( mask = = 0 )
break ;
2015-01-15 02:33:23 +01:00
handle_domain_irq ( sa1100_normal_irqdomain ,
ffs ( mask ) - 1 , regs ) ;
2014-11-28 15:55:16 +01:00
} while ( 1 ) ;
}
2005-04-16 15:20:36 -07:00
void __init sa1100_init_irq ( void )
{
request_resource ( & iomem_resource , & irq_resource ) ;
/* disable all IRQs */
ICMR = 0 ;
/* all IRQs are IRQ, not FIQ */
ICLR = 0 ;
/*
* Whatever the doc says , this has to be set for the wait - on - irq
* instruction to work . . . on a SA1100 rev 9 at least .
*/
ICCR = 1 ;
2015-01-15 02:31:48 +01:00
sa1100_normal_irqdomain = irq_domain_add_simple ( NULL ,
32 , IRQ_GPIO0_SC ,
2015-01-15 02:29:16 +01:00
& sa1100_normal_irqdomain_ops , NULL ) ;
2014-11-28 15:55:16 +01:00
set_handle_irq ( sa1100_handle_irq ) ;
2008-04-10 13:31:47 +01:00
sa1100_init_gpio ( ) ;
2005-04-16 15:20:36 -07:00
}