2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-05-12 00:01:28 +04:00
/*
* arch / arm / mach - ks8695 / irq . c
*
* Copyright ( C ) 2006 Ben Dooks < ben @ simtec . co . uk >
* Copyright ( C ) 2006 Simtec Electronics
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
2011-12-22 04:26:03 +04:00
# include <linux/device.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2007-05-12 00:01:28 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2007-05-12 00:01:28 +04:00
# include <asm/irq.h>
# include <asm/mach/irq.h>
2008-08-05 19:14:15 +04:00
# include <mach/regs-irq.h>
# include <mach/regs-gpio.h>
2007-05-12 00:01:28 +04:00
2010-11-29 12:34:14 +03:00
static void ks8695_irq_mask ( struct irq_data * d )
2007-05-12 00:01:28 +04:00
{
unsigned long inten ;
inten = __raw_readl ( KS8695_IRQ_VA + KS8695_INTEN ) ;
2010-11-29 12:34:14 +03:00
inten & = ~ ( 1 < < d - > irq ) ;
2007-05-12 00:01:28 +04:00
__raw_writel ( inten , KS8695_IRQ_VA + KS8695_INTEN ) ;
}
2010-11-29 12:34:14 +03:00
static void ks8695_irq_unmask ( struct irq_data * d )
2007-05-12 00:01:28 +04:00
{
unsigned long inten ;
inten = __raw_readl ( KS8695_IRQ_VA + KS8695_INTEN ) ;
2010-11-29 12:34:14 +03:00
inten | = ( 1 < < d - > irq ) ;
2007-05-12 00:01:28 +04:00
__raw_writel ( inten , KS8695_IRQ_VA + KS8695_INTEN ) ;
}
2010-11-29 12:34:14 +03:00
static void ks8695_irq_ack ( struct irq_data * d )
2007-05-12 00:01:28 +04:00
{
2010-11-29 12:34:14 +03:00
__raw_writel ( ( 1 < < d - > irq ) , KS8695_IRQ_VA + KS8695_INTST ) ;
2007-05-12 00:01:28 +04:00
}
static struct irq_chip ks8695_irq_level_chip ;
static struct irq_chip ks8695_irq_edge_chip ;
2010-11-29 12:34:14 +03:00
static int ks8695_irq_set_type ( struct irq_data * d , unsigned int type )
2007-05-12 00:01:28 +04:00
{
unsigned long ctrl , mode ;
unsigned short level_triggered = 0 ;
ctrl = __raw_readl ( KS8695_GPIO_VA + KS8695_IOPC ) ;
switch ( type ) {
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_LEVEL_HIGH :
2007-05-12 00:01:28 +04:00
mode = IOPC_TM_HIGH ;
level_triggered = 1 ;
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_LEVEL_LOW :
2007-05-12 00:01:28 +04:00
mode = IOPC_TM_LOW ;
level_triggered = 1 ;
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_RISING :
2007-05-12 00:01:28 +04:00
mode = IOPC_TM_RISING ;
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_FALLING :
2007-05-12 00:01:28 +04:00
mode = IOPC_TM_FALLING ;
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_BOTH :
2007-05-12 00:01:28 +04:00
mode = IOPC_TM_EDGE ;
break ;
default :
return - EINVAL ;
}
2010-11-29 12:34:14 +03:00
switch ( d - > irq ) {
2007-05-12 00:01:28 +04:00
case KS8695_IRQ_EXTERN0 :
ctrl & = ~ IOPC_IOEINT0TM ;
ctrl | = IOPC_IOEINT0_MODE ( mode ) ;
break ;
case KS8695_IRQ_EXTERN1 :
ctrl & = ~ IOPC_IOEINT1TM ;
ctrl | = IOPC_IOEINT1_MODE ( mode ) ;
break ;
case KS8695_IRQ_EXTERN2 :
ctrl & = ~ IOPC_IOEINT2TM ;
ctrl | = IOPC_IOEINT2_MODE ( mode ) ;
break ;
case KS8695_IRQ_EXTERN3 :
ctrl & = ~ IOPC_IOEINT3TM ;
ctrl | = IOPC_IOEINT3_MODE ( mode ) ;
break ;
default :
return - EINVAL ;
}
if ( level_triggered ) {
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( d - > irq , & ks8695_irq_level_chip ,
handle_level_irq ) ;
2007-05-12 00:01:28 +04:00
}
else {
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( d - > irq , & ks8695_irq_edge_chip ,
handle_edge_irq ) ;
2007-05-12 00:01:28 +04:00
}
__raw_writel ( ctrl , KS8695_GPIO_VA + KS8695_IOPC ) ;
return 0 ;
}
static struct irq_chip ks8695_irq_level_chip = {
2010-11-29 12:34:14 +03:00
. irq_ack = ks8695_irq_mask ,
. irq_mask = ks8695_irq_mask ,
. irq_unmask = ks8695_irq_unmask ,
. irq_set_type = ks8695_irq_set_type ,
2007-05-12 00:01:28 +04:00
} ;
static struct irq_chip ks8695_irq_edge_chip = {
2010-11-29 12:34:14 +03:00
. irq_ack = ks8695_irq_ack ,
. irq_mask = ks8695_irq_mask ,
. irq_unmask = ks8695_irq_unmask ,
. irq_set_type = ks8695_irq_set_type ,
2007-05-12 00:01:28 +04:00
} ;
void __init ks8695_init_irq ( void )
{
unsigned int irq ;
/* Disable all interrupts initially */
__raw_writel ( 0 , KS8695_IRQ_VA + KS8695_INTMC ) ;
__raw_writel ( 0 , KS8695_IRQ_VA + KS8695_INTEN ) ;
for ( irq = 0 ; irq < NR_IRQS ; irq + + ) {
switch ( irq ) {
/* Level-triggered interrupts */
case KS8695_IRQ_BUS_ERROR :
case KS8695_IRQ_UART_MODEM_STATUS :
case KS8695_IRQ_UART_LINE_STATUS :
case KS8695_IRQ_UART_RX :
case KS8695_IRQ_COMM_TX :
case KS8695_IRQ_COMM_RX :
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( irq ,
& ks8695_irq_level_chip ,
handle_level_irq ) ;
2007-05-12 00:01:28 +04:00
break ;
/* Edge-triggered interrupts */
default :
2010-11-29 12:34:14 +03:00
/* clear pending bit */
ks8695_irq_ack ( irq_get_irq_data ( irq ) ) ;
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( irq ,
& ks8695_irq_edge_chip ,
handle_edge_irq ) ;
2007-05-12 00:01:28 +04:00
}
2015-07-27 23:55:13 +03:00
irq_clear_status_flags ( irq , IRQ_NOREQUEST ) ;
2007-05-12 00:01:28 +04:00
}
}