浏览代码

[ARM] 4122/1: ep93xx: add support for GPIO port F interrupts

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Lennert Buytenhek 18 年之前
父节点
当前提交
4932e397be
共有 3 个文件被更改,包括 73 次插入30 次删除
  1. 62 28
      arch/arm/mach-ep93xx/core.c
  2. 5 0
      include/asm-arm/arch-ep93xx/ep93xx-regs.h
  3. 6 2
      include/asm-arm/arch-ep93xx/irqs.h

+ 62 - 28
arch/arm/mach-ep93xx/core.c

@@ -152,22 +152,29 @@ 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 unsigned char gpio_int_enable[3];
+static unsigned char gpio_int_type1[3];
+static unsigned char gpio_int_type2[3];
 
-static void update_gpio_ab_int_params(int port)
+static void update_gpio_int_params(int abf)
 {
-	if (port == 0) {
+	if (abf == 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) {
+	} else if (abf == 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);
+	} else if (abf == 2) {
+		__raw_writeb(0, EP93XX_GPIO_F_INT_ENABLE);
+		__raw_writeb(gpio_int_type2[2], EP93XX_GPIO_F_INT_TYPE2);
+		__raw_writeb(gpio_int_type1[2], EP93XX_GPIO_F_INT_TYPE1);
+		__raw_writeb(gpio_int_enable[2], EP93XX_GPIO_F_INT_ENABLE);
+	} else {
+		BUG();
 	}
 }
 
@@ -192,8 +199,13 @@ void gpio_line_config(int line, int direction)
 	local_irq_save(flags);
 	if (direction == GPIO_OUT) {
 		if (line >= 0 && line < 16) {
+			/* Port A/B.  */
 			gpio_int_enable[line >> 3] &= ~(1 << (line & 7));
-			update_gpio_ab_int_params(line >> 3);
+			update_gpio_int_params(line >> 3);
+		} else if (line >= 40 && line < 48) {
+			/* Port F.  */
+			gpio_int_enable[2] &= ~(1 << (line & 7));
+			update_gpio_int_params(2);
 		}
 
 		v = __raw_readb(data_direction_register);
@@ -244,8 +256,7 @@ EXPORT_SYMBOL(gpio_line_set);
 /*************************************************************************
  * EP93xx IRQ handling
  *************************************************************************/
-static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
-		struct irq_desc *desc)
+static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
 	unsigned char status;
 	int i;
@@ -267,37 +278,46 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
 	}
 }
 
-static void ep93xx_gpio_ab_irq_mask_ack(unsigned int irq)
+static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int gpio_irq = IRQ_EP93XX_GPIO(16) + (((irq + 1) & 7) ^ 4);
+
+	desc_handle_irq(gpio_irq, irq_desc + gpio_irq);
+}
+
+static void ep93xx_gpio_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);
+	update_gpio_int_params(port);
 
-	if (line >> 3) {
-		__raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
-	} else {
+	if (port == 0) {
 		__raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK);
+	} else if (port == 1) {
+		__raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
+	} else if (port == 2) {
+		__raw_writel(1 << (line & 7), EP93XX_GPIO_F_INT_ACK);
 	}
 }
 
-static void ep93xx_gpio_ab_irq_mask(unsigned int irq)
+static void ep93xx_gpio_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);
+	update_gpio_int_params(port);
 }
 
-static void ep93xx_gpio_ab_irq_unmask(unsigned int irq)
+static void ep93xx_gpio_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);
+	update_gpio_int_params(port);
 }
 
 
@@ -306,13 +326,17 @@ static void ep93xx_gpio_ab_irq_unmask(unsigned int irq)
  * 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)
+static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
 {
 	int port;
 	int line;
 
 	line = irq - IRQ_EP93XX_GPIO(0);
-	gpio_line_config(line, GPIO_IN);
+	if (line >= 0 && line < 16) {
+		gpio_line_config(line, GPIO_IN);
+	} else {
+		gpio_line_config(EP93XX_GPIO_LINE_F(line), GPIO_IN);
+	}
 
 	port = line >> 3;
 	line &= 7;
@@ -330,16 +354,17 @@ static int ep93xx_gpio_ab_irq_type(unsigned int irq, unsigned int type)
 		gpio_int_type1[port] &= ~(1 << line);
 		gpio_int_type2[port] &= ~(1 << line);
 	}
-	update_gpio_ab_int_params(port);
+	update_gpio_int_params(port);
 
 	return 0;
 }
 
-static struct irq_chip 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,
+static struct irq_chip ep93xx_gpio_irq_chip = {
+	.name		= "GPIO",
+	.ack		= ep93xx_gpio_irq_mask_ack,
+	.mask		= ep93xx_gpio_irq_mask,
+	.unmask		= ep93xx_gpio_irq_unmask,
+	.set_type	= ep93xx_gpio_irq_type,
 };
 
 
@@ -350,12 +375,21 @@ void __init ep93xx_init_irq(void)
 	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);
+	for (irq = IRQ_EP93XX_GPIO(0); irq <= IRQ_EP93XX_GPIO(23); irq++) {
+		set_irq_chip(irq, &ep93xx_gpio_irq_chip);
 		set_irq_handler(irq, handle_level_irq);
 		set_irq_flags(irq, IRQF_VALID);
 	}
+
 	set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler);
+	set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler);
 }
 
 

+ 5 - 0
include/asm-arm/arch-ep93xx/ep93xx-regs.h

@@ -73,6 +73,11 @@
 
 #define EP93XX_GPIO_BASE		(EP93XX_APB_VIRT_BASE + 0x00040000)
 #define EP93XX_GPIO_REG(x)		(EP93XX_GPIO_BASE + (x))
+#define EP93XX_GPIO_F_INT_TYPE1		EP93XX_GPIO_REG(0x4c)
+#define EP93XX_GPIO_F_INT_TYPE2		EP93XX_GPIO_REG(0x50)
+#define EP93XX_GPIO_F_INT_ACK		EP93XX_GPIO_REG(0x54)
+#define EP93XX_GPIO_F_INT_ENABLE	EP93XX_GPIO_REG(0x58)
+#define EP93XX_GPIO_F_INT_STATUS	EP93XX_GPIO_REG(0x5c)
 #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)

+ 6 - 2
include/asm-arm/arch-ep93xx/irqs.h

@@ -67,9 +67,13 @@
 #define IRQ_EP93XX_SAI			60
 #define EP93XX_VIC2_VALID_IRQ_MASK	0x1fffffff
 
-#define IRQ_EP93XX_GPIO(x)		(64 + (x))
+/*
+ * Map GPIO A0..A7 to irq 64..71, B0..B7 to 72..79, and
+ * F0..F7 to 80..87.
+ */
+#define IRQ_EP93XX_GPIO(x)		(64 + (((x) + (((x) >> 2) & 8)) & 0x1f))
 
-#define NR_EP93XX_IRQS			IRQ_EP93XX_GPIO(16)
+#define NR_EP93XX_IRQS			(64 + 24)
 
 #define EP93XX_BOARD_IRQ(x)		(NR_EP93XX_IRQS + (x))
 #define EP93XX_BOARD_IRQS		32