2007-02-16 12:12:31 +01:00
/* linux/arch/arm/mach-s3c2443/irq.c
*
* Copyright ( c ) 2007 Simtec Electronics
* Ben Dooks < ben @ simtec . co . uk >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/sysdev.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2007-02-16 12:12:31 +01:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2007-02-16 12:12:31 +01:00
# include <asm/irq.h>
# include <asm/mach/irq.h>
2008-08-05 16:14:15 +01:00
# include <mach/regs-irq.h>
# include <mach/regs-gpio.h>
2007-02-16 12:12:31 +01:00
2008-10-07 22:26:09 +01:00
# include <plat/cpu.h>
# include <plat/pm.h>
# include <plat/irq.h>
2007-02-16 12:12:31 +01:00
2007-02-16 13:02:42 +01:00
# define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
2007-02-16 12:12:31 +01:00
2007-02-16 13:02:42 +01:00
static inline void s3c2443_irq_demux ( unsigned int irq , unsigned int len )
2007-02-16 12:12:31 +01:00
{
unsigned int subsrc , submsk ;
2007-02-16 13:02:42 +01:00
unsigned int end ;
2007-02-16 12:12:31 +01:00
/* read the current pending interrupts, and the mask
* for what it is available */
subsrc = __raw_readl ( S3C2410_SUBSRCPND ) ;
submsk = __raw_readl ( S3C2410_INTSUBMSK ) ;
2007-02-16 13:02:42 +01:00
subsrc & = ~ submsk ;
subsrc > > = ( irq - S3C2410_IRQSUB ( 0 ) ) ;
subsrc & = ( 1 < < len ) - 1 ;
end = len + irq ;
for ( ; irq < end & & subsrc ; irq + + ) {
if ( subsrc & 1 )
2008-10-09 13:36:24 +01:00
generic_handle_irq ( irq ) ;
2007-02-16 13:02:42 +01:00
subsrc > > = 1 ;
2007-02-16 12:12:31 +01:00
}
}
2007-02-16 13:02:42 +01:00
/* WDT/AC97 sub interrupts */
static void s3c2443_irq_demux_wdtac97 ( unsigned int irq , struct irq_desc * desc )
{
s3c2443_irq_demux ( IRQ_S3C2443_WDT , 4 ) ;
}
2007-02-16 12:12:31 +01:00
2007-02-16 13:02:42 +01:00
# define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
# define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
2007-02-16 12:12:31 +01:00
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_wdtac97_mask ( struct irq_data * data )
2007-02-16 12:12:31 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_mask ( data - > irq , INTMSK_WDTAC97 , SUBMSK_WDTAC97 ) ;
2007-02-16 12:12:31 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_wdtac97_unmask ( struct irq_data * data )
2007-02-16 12:12:31 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_unmask ( data - > irq , INTMSK_WDTAC97 ) ;
2007-02-16 12:12:31 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_wdtac97_ack ( struct irq_data * data )
2007-02-16 12:12:31 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_maskack ( data - > irq , INTMSK_WDTAC97 , SUBMSK_WDTAC97 ) ;
2007-02-16 12:12:31 +01:00
}
2007-02-16 13:02:42 +01:00
static struct irq_chip s3c2443_irq_wdtac97 = {
2011-01-03 19:15:54 +09:00
. irq_mask = s3c2443_irq_wdtac97_mask ,
. irq_unmask = s3c2443_irq_wdtac97_unmask ,
. irq_ack = s3c2443_irq_wdtac97_ack ,
2007-02-16 12:12:31 +01:00
} ;
2007-02-16 13:02:42 +01:00
/* LCD sub interrupts */
static void s3c2443_irq_demux_lcd ( unsigned int irq , struct irq_desc * desc )
2007-02-16 12:12:31 +01:00
{
2007-02-16 13:02:42 +01:00
s3c2443_irq_demux ( IRQ_S3C2443_LCD1 , 4 ) ;
}
2007-02-16 12:12:31 +01:00
2007-02-16 13:02:42 +01:00
# define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
# define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_lcd_mask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_mask ( data - > irq , INTMSK_LCD , SUBMSK_LCD ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_lcd_unmask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_unmask ( data - > irq , INTMSK_LCD ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_lcd_ack ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_maskack ( data - > irq , INTMSK_LCD , SUBMSK_LCD ) ;
2007-02-16 13:02:42 +01:00
}
static struct irq_chip s3c2443_irq_lcd = {
2011-01-03 19:15:54 +09:00
. irq_mask = s3c2443_irq_lcd_mask ,
. irq_unmask = s3c2443_irq_lcd_unmask ,
. irq_ack = s3c2443_irq_lcd_ack ,
2007-02-16 13:02:42 +01:00
} ;
/* DMA sub interrupts */
static void s3c2443_irq_demux_dma ( unsigned int irq , struct irq_desc * desc )
{
2007-03-16 17:11:43 +01:00
s3c2443_irq_demux ( IRQ_S3C2443_DMA0 , 6 ) ;
2007-02-16 13:02:42 +01:00
}
# define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
# define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_dma_mask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_mask ( data - > irq , INTMSK_DMA , SUBMSK_DMA ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_dma_unmask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_unmask ( data - > irq , INTMSK_DMA ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_dma_ack ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_maskack ( data - > irq , INTMSK_DMA , SUBMSK_DMA ) ;
2007-02-16 13:02:42 +01:00
}
static struct irq_chip s3c2443_irq_dma = {
2011-01-03 19:15:54 +09:00
. irq_mask = s3c2443_irq_dma_mask ,
. irq_unmask = s3c2443_irq_dma_unmask ,
. irq_ack = s3c2443_irq_dma_ack ,
2007-02-16 13:02:42 +01:00
} ;
/* UART3 sub interrupts */
static void s3c2443_irq_demux_uart3 ( unsigned int irq , struct irq_desc * desc )
{
2010-10-21 06:45:48 +05:30
s3c2443_irq_demux ( IRQ_S3C2443_RX3 , 3 ) ;
2007-02-16 13:02:42 +01:00
}
2007-02-16 12:12:31 +01:00
2007-02-16 13:02:42 +01:00
# define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
2010-10-21 06:45:48 +05:30
# define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
2007-02-16 12:12:31 +01:00
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_uart3_mask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_mask ( data - > irq , INTMSK_UART3 , SUBMSK_UART3 ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_uart3_unmask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_unmask ( data - > irq , INTMSK_UART3 ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_uart3_ack ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_maskack ( data - > irq , INTMSK_UART3 , SUBMSK_UART3 ) ;
2007-02-16 13:02:42 +01:00
}
static struct irq_chip s3c2443_irq_uart3 = {
2011-01-03 19:15:54 +09:00
. irq_mask = s3c2443_irq_uart3_mask ,
. irq_unmask = s3c2443_irq_uart3_unmask ,
. irq_ack = s3c2443_irq_uart3_ack ,
2007-02-16 13:02:42 +01:00
} ;
/* CAM sub interrupts */
static void s3c2443_irq_demux_cam ( unsigned int irq , struct irq_desc * desc )
{
s3c2443_irq_demux ( IRQ_S3C2440_CAM_C , 4 ) ;
}
# define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
# define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_cam_mask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_mask ( data - > irq , INTMSK_CAM , SUBMSK_CAM ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_cam_unmask ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_unmask ( data - > irq , INTMSK_CAM ) ;
2007-02-16 13:02:42 +01:00
}
2011-01-03 19:15:54 +09:00
static void s3c2443_irq_cam_ack ( struct irq_data * data )
2007-02-16 13:02:42 +01:00
{
2011-01-03 19:15:54 +09:00
s3c_irqsub_maskack ( data - > irq , INTMSK_CAM , SUBMSK_CAM ) ;
2007-02-16 13:02:42 +01:00
}
static struct irq_chip s3c2443_irq_cam = {
2011-01-03 19:15:54 +09:00
. irq_mask = s3c2443_irq_cam_mask ,
. irq_unmask = s3c2443_irq_cam_unmask ,
. irq_ack = s3c2443_irq_cam_ack ,
2007-02-16 13:02:42 +01:00
} ;
/* IRQ initialisation code */
static int __init s3c2443_add_sub ( unsigned int base ,
void ( * demux ) ( unsigned int ,
struct irq_desc * ) ,
struct irq_chip * chip ,
unsigned int start , unsigned int end )
{
unsigned int irqno ;
2011-03-24 13:35:09 +01:00
irq_set_chip_and_handler ( base , & s3c_irq_level_chip , handle_level_irq ) ;
2011-03-24 13:25:22 +01:00
irq_set_chained_handler ( base , demux ) ;
2007-02-16 13:02:42 +01:00
for ( irqno = start ; irqno < = end ; irqno + + ) {
2011-03-24 13:35:09 +01:00
irq_set_chip_and_handler ( irqno , chip , handle_level_irq ) ;
2007-02-16 12:12:31 +01:00
set_irq_flags ( irqno , IRQF_VALID ) ;
}
return 0 ;
}
2007-09-04 17:18:04 +01:00
static int __init s3c2443_irq_add ( struct sys_device * sysdev )
2007-02-16 13:02:42 +01:00
{
printk ( " S3C2443: IRQ Support \n " ) ;
s3c2443_add_sub ( IRQ_CAM , s3c2443_irq_demux_cam , & s3c2443_irq_cam ,
IRQ_S3C2440_CAM_C , IRQ_S3C2440_CAM_P ) ;
s3c2443_add_sub ( IRQ_LCD , s3c2443_irq_demux_lcd , & s3c2443_irq_lcd ,
IRQ_S3C2443_LCD1 , IRQ_S3C2443_LCD4 ) ;
s3c2443_add_sub ( IRQ_S3C2443_DMA , s3c2443_irq_demux_dma ,
& s3c2443_irq_dma , IRQ_S3C2443_DMA0 , IRQ_S3C2443_DMA5 ) ;
s3c2443_add_sub ( IRQ_S3C2443_UART3 , s3c2443_irq_demux_uart3 ,
& s3c2443_irq_uart3 ,
IRQ_S3C2443_RX3 , IRQ_S3C2443_ERR3 ) ;
s3c2443_add_sub ( IRQ_WDT , s3c2443_irq_demux_wdtac97 ,
& s3c2443_irq_wdtac97 ,
IRQ_S3C2443_WDT , IRQ_S3C2443_AC97 ) ;
return 0 ;
}
2007-02-16 12:12:31 +01:00
static struct sysdev_driver s3c2443_irq_driver = {
. add = s3c2443_irq_add ,
} ;
2007-09-04 17:18:04 +01:00
static int __init s3c2443_irq_init ( void )
2007-02-16 12:12:31 +01:00
{
return sysdev_driver_register ( & s3c2443_sysclass , & s3c2443_irq_driver ) ;
}
arch_initcall ( s3c2443_irq_init ) ;