[ARM] 3374/1: ep93xx: gpio interrupt support
Patch from Lennert Buytenhek Add GPIO interrupt support for the first 16 GPIO lines (port A and B.) Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
36c64af4e0
commit
bd20ff5793
|
@ -150,6 +150,26 @@ struct sys_timer ep93xx_timer = {
|
|||
/*************************************************************************
|
||||
* GPIO handling for EP93xx
|
||||
*************************************************************************/
|
||||
static unsigned char gpio_int_enable[2];
|
||||
static unsigned char gpio_int_type1[2];
|
||||
static unsigned char gpio_int_type2[2];
|
||||
|
||||
static void update_gpio_ab_int_params(int port)
|
||||
{
|
||||
if (port == 0) {
|
||||
__raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE);
|
||||
__raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2);
|
||||
__raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1);
|
||||
__raw_writeb(gpio_int_enable[0], EP93XX_GPIO_A_INT_ENABLE);
|
||||
} else if (port == 1) {
|
||||
__raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE);
|
||||
__raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2);
|
||||
__raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1);
|
||||
__raw_writeb(gpio_int_enable[1], EP93XX_GPIO_B_INT_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned char data_register_offset[8] = {
|
||||
0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40,
|
||||
};
|
||||
|
@ -169,6 +189,11 @@ void gpio_line_config(int line, int direction)
|
|||
|
||||
local_irq_save(flags);
|
||||
if (direction == GPIO_OUT) {
|
||||
if (line >= 0 && line < 16) {
|
||||
gpio_int_enable[line >> 3] &= ~(1 << (line & 7));
|
||||
update_gpio_ab_int_params(line >> 3);
|
||||
}
|
||||
|
||||
v = __raw_readb(data_direction_register);
|
||||
v |= 1 << (line & 7);
|
||||
__raw_writeb(v, data_direction_register);
|
||||
|
@ -217,10 +242,118 @@ EXPORT_SYMBOL(gpio_line_set);
|
|||
/*************************************************************************
|
||||
* EP93xx IRQ handling
|
||||
*************************************************************************/
|
||||
static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
|
||||
struct irqdesc *desc, struct pt_regs *regs)
|
||||
{
|
||||
unsigned char status;
|
||||
int i;
|
||||
|
||||
status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (status & (1 << i)) {
|
||||
desc = irq_desc + IRQ_EP93XX_GPIO(0) + i;
|
||||
desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc, regs);
|
||||
}
|
||||
}
|
||||
|
||||
status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (status & (1 << i)) {
|
||||
desc = irq_desc + IRQ_EP93XX_GPIO(8) + i;
|
||||
desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc, regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_ab_irq_mask_ack(unsigned int irq)
|
||||
{
|
||||
int line = irq - IRQ_EP93XX_GPIO(0);
|
||||
int port = line >> 3;
|
||||
|
||||
gpio_int_enable[port] &= ~(1 << (line & 7));
|
||||
update_gpio_ab_int_params(port);
|
||||
|
||||
if (line >> 3) {
|
||||
__raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
|
||||
} else {
|
||||
__raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK);
|
||||
}
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_ab_irq_mask(unsigned int irq)
|
||||
{
|
||||
int line = irq - IRQ_EP93XX_GPIO(0);
|
||||
int port = line >> 3;
|
||||
|
||||
gpio_int_enable[port] &= ~(1 << (line & 7));
|
||||
update_gpio_ab_int_params(port);
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_ab_irq_unmask(unsigned int irq)
|
||||
{
|
||||
int line = irq - IRQ_EP93XX_GPIO(0);
|
||||
int port = line >> 3;
|
||||
|
||||
gpio_int_enable[port] |= 1 << (line & 7);
|
||||
update_gpio_ab_int_params(port);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* gpio_int_type1 controls whether the interrupt is level (0) or
|
||||
* edge (1) triggered, while gpio_int_type2 controls whether it
|
||||
* triggers on low/falling (0) or high/rising (1).
|
||||
*/
|
||||
static int ep93xx_gpio_ab_irq_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
int port;
|
||||
int line;
|
||||
|
||||
line = irq - IRQ_EP93XX_GPIO(0);
|
||||
gpio_line_config(line, GPIO_IN);
|
||||
|
||||
port = line >> 3;
|
||||
line &= 7;
|
||||
|
||||
if (type & IRQT_RISING) {
|
||||
gpio_int_type1[port] |= 1 << line;
|
||||
gpio_int_type2[port] |= 1 << line;
|
||||
} else if (type & IRQT_FALLING) {
|
||||
gpio_int_type1[port] |= 1 << line;
|
||||
gpio_int_type2[port] &= ~(1 << line);
|
||||
} else if (type & IRQT_HIGH) {
|
||||
gpio_int_type1[port] &= ~(1 << line);
|
||||
gpio_int_type2[port] |= 1 << line;
|
||||
} else if (type & IRQT_LOW) {
|
||||
gpio_int_type1[port] &= ~(1 << line);
|
||||
gpio_int_type2[port] &= ~(1 << line);
|
||||
}
|
||||
update_gpio_ab_int_params(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irqchip ep93xx_gpio_ab_irq_chip = {
|
||||
.ack = ep93xx_gpio_ab_irq_mask_ack,
|
||||
.mask = ep93xx_gpio_ab_irq_mask,
|
||||
.unmask = ep93xx_gpio_ab_irq_unmask,
|
||||
.set_type = ep93xx_gpio_ab_irq_type,
|
||||
};
|
||||
|
||||
|
||||
void __init ep93xx_init_irq(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
|
||||
vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
|
||||
|
||||
for (irq = IRQ_EP93XX_GPIO(0) ; irq <= IRQ_EP93XX_GPIO(15); irq++) {
|
||||
set_irq_chip(irq, &ep93xx_gpio_ab_irq_chip);
|
||||
set_irq_handler(irq, do_level_IRQ);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -72,6 +72,16 @@
|
|||
|
||||
#define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000)
|
||||
#define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x))
|
||||
#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90)
|
||||
#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94)
|
||||
#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98)
|
||||
#define EP93XX_GPIO_A_INT_ENABLE EP93XX_GPIO_REG(0x9c)
|
||||
#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0)
|
||||
#define EP93XX_GPIO_B_INT_TYPE1 EP93XX_GPIO_REG(0xac)
|
||||
#define EP93XX_GPIO_B_INT_TYPE2 EP93XX_GPIO_REG(0xb0)
|
||||
#define EP93XX_GPIO_B_INT_ACK EP93XX_GPIO_REG(0xb4)
|
||||
#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8)
|
||||
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
|
||||
|
||||
#define EP93XX_AAC_BASE (EP93XX_APB_VIRT_BASE + 0x00080000)
|
||||
|
||||
|
|
|
@ -67,7 +67,9 @@
|
|||
#define IRQ_EP93XX_SAI 60
|
||||
#define EP93XX_VIC2_VALID_IRQ_MASK 0x1fffffff
|
||||
|
||||
#define NR_EP93XX_IRQS 64
|
||||
#define IRQ_EP93XX_GPIO(x) (64 + (x))
|
||||
|
||||
#define NR_EP93XX_IRQS IRQ_EP93XX_GPIO(16)
|
||||
|
||||
#define EP93XX_BOARD_IRQ(x) (NR_EP93XX_IRQS + (x))
|
||||
#define EP93XX_BOARD_IRQS 32
|
||||
|
|
Loading…
Reference in New Issue