123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- --- 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;
- @@ -235,6 +247,132 @@ 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 long stat = __raw_readl(base + AR71XX_GPIO_REG_INT_PENDING);
- + int bit_num;
- +
- + for_each_set_bit(bit_num, &stat, sizeof(stat) * BITS_PER_BYTE) {
- + unsigned long bit = BIT(bit_num);
- +
- + if (bit & gpio_both_edge) {
- + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_POLARITY) ^ bit,
- + base + AR71XX_GPIO_REG_INT_POLARITY);
- + }
- +
- + generic_handle_irq(ATH79_GPIO_IRQ(bit_num));
- + }
- +
- + 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_noprobe(irq);
- + }
- +
- + return 0;
- +}
- +
- void __init ath79_gpio_init(void)
- {
- int err;
- @@ -271,6 +409,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_irq(ATH79_MISC_IRQ(2), ath79_gpio_irq, 0, "ath79-gpio", NULL);
- }
-
- int gpio_get_value(unsigned gpio)
- @@ -293,14 +435,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,10 @@
- #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))
- +
- #include_next <irq.h>
-
- #endif /* __ASM_MACH_ATH79_IRQ_H */
|