[OpenWrt-Devel] [PATCH v2 4/8] ar71xx: add support to use gpio irqs

Günther Kelleter guenther.kelleter at devolo.de
Thu Jul 2 07:47:19 EDT 2015


Signed-off-by: Günther Kelleter <guenther.kelleter at devolo.de>
---
 .../739-MIPS-ath79-add-gpio-irq-support.patch      | 241 +++++++++++++++++++++
 1 file changed, 241 insertions(+)
 create mode 100644 target/linux/ar71xx/patches-3.18/739-MIPS-ath79-add-gpio-irq-support.patch

diff --git a/target/linux/ar71xx/patches-3.18/739-MIPS-ath79-add-gpio-irq-support.patch b/target/linux/ar71xx/patches-3.18/739-MIPS-ath79-add-gpio-irq-support.patch
new file mode 100644
index 0000000..0262d66
--- /dev/null
+++ b/target/linux/ar71xx/patches-3.18/739-MIPS-ath79-add-gpio-irq-support.patch
@@ -0,0 +1,241 @@
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -20,9 +20,14 @@
+ #include <linux/io.h>
+ #include <linux/ioport.h>
+ #include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++
++#include <linux/of.h>
+ 
+ #include <asm/mach-ath79/ar71xx_regs.h>
+ #include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/irq.h>
+ #include "common.h"
+ 
+ void __iomem *ath79_gpio_base;
+@@ -31,6 +36,13 @@ EXPORT_SYMBOL_GPL(ath79_gpio_base);
+ static unsigned long ath79_gpio_count;
+ static DEFINE_SPINLOCK(ath79_gpio_lock);
+ 
++/*
++ * gpio_both_edge is a bitmask of which gpio pins need to have
++ * the detect priority flipped from the interrupt handler to
++ * emulate IRQ_TYPE_EDGE_BOTH.
++ */
++static unsigned long gpio_both_edge = 0;
++
+ static void __ath79_gpio_set_value(unsigned gpio, int value)
+ {
+ 	void __iomem *base = ath79_gpio_base;
+@@ -209,6 +221,136 @@ void __init ath79_gpio_output_select(uns
+ 	spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+ }
+ 
++static int ath79_gpio_irq_type(struct irq_data *d, unsigned type)
++{
++	int offset = d->irq - ATH79_GPIO_IRQ_BASE;
++	void __iomem *base = ath79_gpio_base;
++	unsigned long flags;
++	unsigned long int_type;
++	unsigned long int_polarity;
++	unsigned long bit = (1 << offset);
++
++	spin_lock_irqsave(&ath79_gpio_lock, flags);
++
++	int_type = __raw_readl(base + AR71XX_GPIO_REG_INT_TYPE);
++	int_polarity = __raw_readl(base + AR71XX_GPIO_REG_INT_POLARITY);
++
++	gpio_both_edge &= ~bit;
++
++	switch (type) {
++	case IRQ_TYPE_EDGE_RISING:
++		int_type &= ~bit;
++		int_polarity |= bit;
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		int_type &= ~bit;
++		int_polarity &= ~bit;
++		break;
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		int_type |= bit;
++		int_polarity |= bit;
++		break;
++
++	case IRQ_TYPE_LEVEL_LOW:
++		int_type |= bit;
++		int_polarity &= ~bit;
++		break;
++
++	case IRQ_TYPE_EDGE_BOTH:
++		int_type |= bit;
++		/* set polarity based on current value */
++		if (gpio_get_value(offset)) {
++			int_polarity &= ~bit;
++		} else {
++			int_polarity |= bit;
++		}
++		/* flip this gpio in the interrupt handler */
++		gpio_both_edge |= bit;
++		break;
++
++	default:
++		spin_unlock_irqrestore(&ath79_gpio_lock, flags);
++		return -EINVAL;
++	}
++
++	__raw_writel(int_type, base + AR71XX_GPIO_REG_INT_TYPE);
++	__raw_writel(int_polarity, base + AR71XX_GPIO_REG_INT_POLARITY);
++
++	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_MODE) | (1 << offset),
++		     base + AR71XX_GPIO_REG_INT_MODE);
++
++	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_ENABLE) & ~(1 << offset),
++		     base + AR71XX_GPIO_REG_INT_ENABLE);
++
++	spin_unlock_irqrestore(&ath79_gpio_lock, flags);
++	return 0;
++}
++
++static void ath79_gpio_irq_enable(struct irq_data *d)
++{
++	int offset = d->irq - ATH79_GPIO_IRQ_BASE;
++	void __iomem *base = ath79_gpio_base;
++
++	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_ENABLE) | (1 << offset),
++		     base + AR71XX_GPIO_REG_INT_ENABLE);
++}
++
++static void ath79_gpio_irq_disable(struct irq_data *d)
++{
++	int offset = d->irq - ATH79_GPIO_IRQ_BASE;
++	void __iomem *base = ath79_gpio_base;
++
++	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_ENABLE) & ~(1 << offset),
++		     base + AR71XX_GPIO_REG_INT_ENABLE);
++}
++
++static struct irq_chip ath79_gpio_irqchip = {
++	.name = "GPIO",
++	.irq_enable = ath79_gpio_irq_enable,
++	.irq_disable = ath79_gpio_irq_disable,
++	.irq_set_type = ath79_gpio_irq_type,
++};
++
++static irqreturn_t ath79_gpio_irq(int irq, void *dev)
++{
++	void __iomem *base = ath79_gpio_base;
++	unsigned int stat = __raw_readl(base + AR71XX_GPIO_REG_INT_PENDING);
++
++	int irq_base = ATH79_GPIO_IRQ_BASE;
++
++	while (stat) {
++		int bit_num = __ffs(stat);
++		unsigned long bit = (1<<bit_num);
++
++		if (bit & gpio_both_edge) {
++			__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_POLARITY) ^ bit,
++				base + AR71XX_GPIO_REG_INT_POLARITY);
++		}
++
++		handle_nested_irq(irq_base + bit_num);
++		stat &= ~bit;
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int __init ath79_gpio_irq_init(struct gpio_chip *chip)
++{
++	int irq;
++	int irq_base = ATH79_GPIO_IRQ_BASE;
++
++	for (irq = irq_base; irq < irq_base + chip->ngpio; irq++) {
++		irq_set_chip_data(irq, chip);
++		irq_set_chip_and_handler(irq, &ath79_gpio_irqchip, handle_simple_irq);
++		irq_set_nested_thread(irq, 1);
++		irq_set_noprobe(irq);
++	}
++
++	return 0;
++}
++
+ void __init ath79_gpio_init(void)
+ {
+ 	int err;
+@@ -245,6 +387,10 @@ void __init ath79_gpio_init(void)
+ 	err = gpiochip_add(&ath79_gpio_chip);
+ 	if (err)
+ 		panic("cannot add AR71xx GPIO chip, error=%d", err);
++
++	ath79_gpio_irq_init(&ath79_gpio_chip);
++
++	request_threaded_irq(ATH79_MISC_IRQ_GPIO, NULL, ath79_gpio_irq, IRQF_ONESHOT, "ath79-gpio", NULL);
+ }
+ 
+ int gpio_get_value(unsigned gpio)
+@@ -267,14 +413,22 @@ EXPORT_SYMBOL(gpio_set_value);
+ 
+ int gpio_to_irq(unsigned gpio)
+ {
+-	/* FIXME */
+-	return -EINVAL;
++	if (gpio > ath79_gpio_count) {
++		return -EINVAL;
++	}
++
++	return ATH79_GPIO_IRQ_BASE + gpio;
+ }
+ EXPORT_SYMBOL(gpio_to_irq);
+ 
+ int irq_to_gpio(unsigned irq)
+ {
+-	/* FIXME */
+-	return -EINVAL;
++	unsigned gpio = irq - ATH79_GPIO_IRQ_BASE;
++
++	if (gpio > ath79_gpio_count) {
++		return -EINVAL;
++	}
++
++	return gpio;
+ }
+ EXPORT_SYMBOL(irq_to_gpio);
+--- a/arch/mips/include/asm/mach-ath79/irq.h
++++ b/arch/mips/include/asm/mach-ath79/irq.h
+@@ -10,7 +10,7 @@
+ #define __ASM_MACH_ATH79_IRQ_H
+ 
+ #define MIPS_CPU_IRQ_BASE	0
+-#define NR_IRQS			51
++#define NR_IRQS			83
+ 
+ #define ATH79_CPU_IRQ(_x)	(MIPS_CPU_IRQ_BASE + (_x))
+ 
+@@ -30,6 +30,23 @@
+ #define ATH79_IP3_IRQ_COUNT     3
+ #define ATH79_IP3_IRQ(_x)       (ATH79_IP3_IRQ_BASE + (_x))
+ 
++#define ATH79_GPIO_IRQ_BASE	(ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT)
++#define ATH79_GPIO_IRQ_COUNT	32
++#define ATH79_GPIO_IRQ(_x)	(ATH79_GPIO_IRQ_BASE + (_x))
++
++#define ATH79_MISC_IRQ_TIMER	(ATH79_MISC_IRQ_BASE + 0)
++#define ATH79_MISC_IRQ_ERROR	(ATH79_MISC_IRQ_BASE + 1)
++#define ATH79_MISC_IRQ_GPIO	(ATH79_MISC_IRQ_BASE + 2)
++#define ATH79_MISC_IRQ_UART	(ATH79_MISC_IRQ_BASE + 3)
++#define ATH79_MISC_IRQ_WDOG	(ATH79_MISC_IRQ_BASE + 4)
++#define ATH79_MISC_IRQ_PERFC	(ATH79_MISC_IRQ_BASE + 5)
++#define ATH79_MISC_IRQ_OHCI	(ATH79_MISC_IRQ_BASE + 6)
++#define ATH79_MISC_IRQ_DMA	(ATH79_MISC_IRQ_BASE + 7)
++#define ATH79_MISC_IRQ_TIMER2	(ATH79_MISC_IRQ_BASE + 8)
++#define ATH79_MISC_IRQ_TIMER3	(ATH79_MISC_IRQ_BASE + 9)
++#define ATH79_MISC_IRQ_TIMER4	(ATH79_MISC_IRQ_BASE + 10)
++#define ATH79_MISC_IRQ_ETHSW	(ATH79_MISC_IRQ_BASE + 12)
++
+ #include_next <irq.h>
+ 
+ #endif /* __ASM_MACH_ATH79_IRQ_H */
-- 
2.4.4.88.gac2ab0d
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list