2007-11-26 04:11:58 -08:00
/* linux/arch/arm/mach-msm/irq.c
*
* Copyright ( C ) 2007 Google , Inc .
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* 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 .
*
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/ptrace.h>
# include <linux/timer.h>
# include <linux/irq.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2007-11-26 04:11:58 -08:00
2008-09-06 12:10:45 +01:00
# include <mach/hardware.h>
2007-11-26 04:11:58 -08:00
2008-08-05 16:14:15 +01:00
# include <mach/msm_iomap.h>
2007-11-26 04:11:58 -08:00
# define VIC_REG(off) (MSM_VIC_BASE + (off))
# define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */
# define VIC_INT_SELECT1 VIC_REG(0x0004) /* 1: FIQ, 0: IRQ */
# define VIC_INT_EN0 VIC_REG(0x0010)
# define VIC_INT_EN1 VIC_REG(0x0014)
# define VIC_INT_ENCLEAR0 VIC_REG(0x0020)
# define VIC_INT_ENCLEAR1 VIC_REG(0x0024)
# define VIC_INT_ENSET0 VIC_REG(0x0030)
# define VIC_INT_ENSET1 VIC_REG(0x0034)
# define VIC_INT_TYPE0 VIC_REG(0x0040) /* 1: EDGE, 0: LEVEL */
# define VIC_INT_TYPE1 VIC_REG(0x0044) /* 1: EDGE, 0: LEVEL */
# define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */
# define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */
# define VIC_NO_PEND_VAL VIC_REG(0x0060)
# define VIC_INT_MASTEREN VIC_REG(0x0064) /* 1: IRQ, 2: FIQ */
# define VIC_PROTECTION VIC_REG(0x006C) /* 1: ENABLE */
# define VIC_CONFIG VIC_REG(0x0068) /* 1: USE ARM1136 VIC */
# define VIC_IRQ_STATUS0 VIC_REG(0x0080)
# define VIC_IRQ_STATUS1 VIC_REG(0x0084)
# define VIC_FIQ_STATUS0 VIC_REG(0x0090)
# define VIC_FIQ_STATUS1 VIC_REG(0x0094)
# define VIC_RAW_STATUS0 VIC_REG(0x00A0)
# define VIC_RAW_STATUS1 VIC_REG(0x00A4)
# define VIC_INT_CLEAR0 VIC_REG(0x00B0)
# define VIC_INT_CLEAR1 VIC_REG(0x00B4)
# define VIC_SOFTINT0 VIC_REG(0x00C0)
# define VIC_SOFTINT1 VIC_REG(0x00C4)
# define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */
# define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */
# define VIC_IRQ_VEC_WR VIC_REG(0x00D8)
# define VIC_IRQ_IN_SERVICE VIC_REG(0x00E0)
# define VIC_IRQ_IN_STACK VIC_REG(0x00E4)
# define VIC_TEST_BUS_SEL VIC_REG(0x00E8)
# define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
# define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4))
2010-11-29 10:37:34 +01:00
static void msm_irq_ack ( struct irq_data * d )
2007-11-26 04:11:58 -08:00
{
2010-11-29 10:37:34 +01:00
void __iomem * reg = VIC_INT_CLEAR0 + ( ( d - > irq & 32 ) ? 4 : 0 ) ;
writel ( 1 < < ( d - > irq & 31 ) , reg ) ;
2007-11-26 04:11:58 -08:00
}
2010-11-29 10:37:34 +01:00
static void msm_irq_mask ( struct irq_data * d )
2007-11-26 04:11:58 -08:00
{
2010-11-29 10:37:34 +01:00
void __iomem * reg = VIC_INT_ENCLEAR0 + ( ( d - > irq & 32 ) ? 4 : 0 ) ;
writel ( 1 < < ( d - > irq & 31 ) , reg ) ;
2007-11-26 04:11:58 -08:00
}
2010-11-29 10:37:34 +01:00
static void msm_irq_unmask ( struct irq_data * d )
2007-11-26 04:11:58 -08:00
{
2010-11-29 10:37:34 +01:00
void __iomem * reg = VIC_INT_ENSET0 + ( ( d - > irq & 32 ) ? 4 : 0 ) ;
writel ( 1 < < ( d - > irq & 31 ) , reg ) ;
2007-11-26 04:11:58 -08:00
}
2010-11-29 10:37:34 +01:00
static int msm_irq_set_wake ( struct irq_data * d , unsigned int on )
2007-11-26 04:11:58 -08:00
{
return - EINVAL ;
}
2010-11-29 10:37:34 +01:00
static int msm_irq_set_type ( struct irq_data * d , unsigned int flow_type )
2007-11-26 04:11:58 -08:00
{
2010-11-29 10:37:34 +01:00
void __iomem * treg = VIC_INT_TYPE0 + ( ( d - > irq & 32 ) ? 4 : 0 ) ;
void __iomem * preg = VIC_INT_POLARITY0 + ( ( d - > irq & 32 ) ? 4 : 0 ) ;
int b = 1 < < ( d - > irq & 31 ) ;
2007-11-26 04:11:58 -08:00
if ( flow_type & ( IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW ) )
writel ( readl ( preg ) | b , preg ) ;
if ( flow_type & ( IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH ) )
writel ( readl ( preg ) & ( ~ b ) , preg ) ;
if ( flow_type & ( IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING ) ) {
writel ( readl ( treg ) | b , treg ) ;
2011-03-24 12:41:27 +01:00
__irq_set_handler_locked ( d - > irq , handle_edge_irq ) ;
2007-11-26 04:11:58 -08:00
}
if ( flow_type & ( IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW ) ) {
writel ( readl ( treg ) & ( ~ b ) , treg ) ;
2011-03-24 12:41:27 +01:00
__irq_set_handler_locked ( d - > irq , handle_level_irq ) ;
2007-11-26 04:11:58 -08:00
}
return 0 ;
}
static struct irq_chip msm_irq_chip = {
2010-11-29 10:37:34 +01:00
. name = " msm " ,
. irq_ack = msm_irq_ack ,
. irq_mask = msm_irq_mask ,
. irq_unmask = msm_irq_unmask ,
. irq_set_wake = msm_irq_set_wake ,
. irq_set_type = msm_irq_set_type ,
2007-11-26 04:11:58 -08:00
} ;
void __init msm_init_irq ( void )
{
unsigned n ;
/* select level interrupts */
writel ( 0 , VIC_INT_TYPE0 ) ;
writel ( 0 , VIC_INT_TYPE1 ) ;
/* select highlevel interrupts */
writel ( 0 , VIC_INT_POLARITY0 ) ;
writel ( 0 , VIC_INT_POLARITY1 ) ;
/* select IRQ for all INTs */
writel ( 0 , VIC_INT_SELECT0 ) ;
writel ( 0 , VIC_INT_SELECT1 ) ;
/* disable all INTs */
writel ( 0 , VIC_INT_EN0 ) ;
writel ( 0 , VIC_INT_EN1 ) ;
/* don't use 1136 vic */
writel ( 0 , VIC_CONFIG ) ;
/* enable interrupt controller */
writel ( 1 , VIC_INT_MASTEREN ) ;
for ( n = 0 ; n < NR_MSM_IRQS ; n + + ) {
2011-03-24 13:35:09 +01:00
irq_set_chip_and_handler ( n , & msm_irq_chip , handle_level_irq ) ;
2007-11-26 04:11:58 -08:00
set_irq_flags ( n , IRQF_VALID ) ;
}
}