ar71xx: Add support for ath79_gpio_function_* on QCA955X
[openwrt.git] / target / linux / ar71xx / patches-4.1 / 633-MIPS-ath79-add-gpio-irq-support.patch
1 --- a/arch/mips/ath79/gpio.c
2 +++ b/arch/mips/ath79/gpio.c
3 @@ -20,9 +20,14 @@
4  #include <linux/io.h>
5  #include <linux/ioport.h>
6  #include <linux/gpio.h>
7 +#include <linux/irq.h>
8 +#include <linux/interrupt.h>
9 +
10 +#include <linux/of.h>
11  
12  #include <asm/mach-ath79/ar71xx_regs.h>
13  #include <asm/mach-ath79/ath79.h>
14 +#include <asm/mach-ath79/irq.h>
15  #include "common.h"
16  
17  void __iomem *ath79_gpio_base;
18 @@ -31,6 +36,13 @@ EXPORT_SYMBOL_GPL(ath79_gpio_base);
19  static unsigned long ath79_gpio_count;
20  static DEFINE_SPINLOCK(ath79_gpio_lock);
21  
22 +/*
23 + * gpio_both_edge is a bitmask of which gpio pins need to have
24 + * the detect priority flipped from the interrupt handler to
25 + * emulate IRQ_TYPE_EDGE_BOTH.
26 + */
27 +static unsigned long gpio_both_edge = 0;
28 +
29  static void __ath79_gpio_set_value(unsigned gpio, int value)
30  {
31         void __iomem *base = ath79_gpio_base;
32 @@ -235,6 +247,132 @@ void __init ath79_gpio_output_select(uns
33         spin_unlock_irqrestore(&ath79_gpio_lock, flags);
34  }
35  
36 +static int ath79_gpio_irq_type(struct irq_data *d, unsigned type)
37 +{
38 +       int offset = d->irq - ATH79_GPIO_IRQ_BASE;
39 +       void __iomem *base = ath79_gpio_base;
40 +       unsigned long flags;
41 +       unsigned long int_type;
42 +       unsigned long int_polarity;
43 +       unsigned long bit = (1 << offset);
44 +
45 +       spin_lock_irqsave(&ath79_gpio_lock, flags);
46 +
47 +       int_type = __raw_readl(base + AR71XX_GPIO_REG_INT_TYPE);
48 +       int_polarity = __raw_readl(base + AR71XX_GPIO_REG_INT_POLARITY);
49 +
50 +       gpio_both_edge &= ~bit;
51 +
52 +       switch (type) {
53 +       case IRQ_TYPE_EDGE_RISING:
54 +               int_type &= ~bit;
55 +               int_polarity |= bit;
56 +               break;
57 +
58 +       case IRQ_TYPE_EDGE_FALLING:
59 +               int_type &= ~bit;
60 +               int_polarity &= ~bit;
61 +               break;
62 +
63 +       case IRQ_TYPE_LEVEL_HIGH:
64 +               int_type |= bit;
65 +               int_polarity |= bit;
66 +               break;
67 +
68 +       case IRQ_TYPE_LEVEL_LOW:
69 +               int_type |= bit;
70 +               int_polarity &= ~bit;
71 +               break;
72 +
73 +       case IRQ_TYPE_EDGE_BOTH:
74 +               int_type |= bit;
75 +               /* set polarity based on current value */
76 +               if (gpio_get_value(offset)) {
77 +                       int_polarity &= ~bit;
78 +               } else {
79 +                       int_polarity |= bit;
80 +               }
81 +               /* flip this gpio in the interrupt handler */
82 +               gpio_both_edge |= bit;
83 +               break;
84 +
85 +       default:
86 +               spin_unlock_irqrestore(&ath79_gpio_lock, flags);
87 +               return -EINVAL;
88 +       }
89 +
90 +       __raw_writel(int_type, base + AR71XX_GPIO_REG_INT_TYPE);
91 +       __raw_writel(int_polarity, base + AR71XX_GPIO_REG_INT_POLARITY);
92 +
93 +       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_MODE) | (1 << offset),
94 +                    base + AR71XX_GPIO_REG_INT_MODE);
95 +
96 +       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_ENABLE) & ~(1 << offset),
97 +                    base + AR71XX_GPIO_REG_INT_ENABLE);
98 +
99 +       spin_unlock_irqrestore(&ath79_gpio_lock, flags);
100 +       return 0;
101 +}
102 +
103 +static void ath79_gpio_irq_enable(struct irq_data *d)
104 +{
105 +       int offset = d->irq - ATH79_GPIO_IRQ_BASE;
106 +       void __iomem *base = ath79_gpio_base;
107 +
108 +       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_ENABLE) | (1 << offset),
109 +                    base + AR71XX_GPIO_REG_INT_ENABLE);
110 +}
111 +
112 +static void ath79_gpio_irq_disable(struct irq_data *d)
113 +{
114 +       int offset = d->irq - ATH79_GPIO_IRQ_BASE;
115 +       void __iomem *base = ath79_gpio_base;
116 +
117 +       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_ENABLE) & ~(1 << offset),
118 +                    base + AR71XX_GPIO_REG_INT_ENABLE);
119 +}
120 +
121 +static struct irq_chip ath79_gpio_irqchip = {
122 +       .name = "GPIO",
123 +       .irq_enable = ath79_gpio_irq_enable,
124 +       .irq_disable = ath79_gpio_irq_disable,
125 +       .irq_set_type = ath79_gpio_irq_type,
126 +};
127 +
128 +static irqreturn_t ath79_gpio_irq(int irq, void *dev)
129 +{
130 +       void __iomem *base = ath79_gpio_base;
131 +       unsigned long stat = __raw_readl(base + AR71XX_GPIO_REG_INT_PENDING);
132 +       int bit_num;
133 +
134 +       for_each_set_bit(bit_num, &stat, sizeof(stat) * BITS_PER_BYTE) {
135 +               unsigned long bit = BIT(bit_num);
136 +
137 +               if (bit & gpio_both_edge) {
138 +                       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_INT_POLARITY) ^ bit,
139 +                               base + AR71XX_GPIO_REG_INT_POLARITY);
140 +               }
141 +
142 +               generic_handle_irq(ATH79_GPIO_IRQ(bit_num));
143 +       }
144 +
145 +       return IRQ_HANDLED;
146 +}
147 +
148 +static int __init ath79_gpio_irq_init(struct gpio_chip *chip)
149 +{
150 +       int irq;
151 +       int irq_base = ATH79_GPIO_IRQ_BASE;
152 +
153 +       for (irq = irq_base; irq < irq_base + chip->ngpio; irq++) {
154 +               irq_set_chip_data(irq, chip);
155 +               irq_set_chip_and_handler(irq, &ath79_gpio_irqchip, handle_simple_irq);
156 +               irq_set_noprobe(irq);
157 +       }
158 +
159 +       return 0;
160 +}
161 +
162  void __init ath79_gpio_init(void)
163  {
164         int err;
165 @@ -271,6 +409,10 @@ void __init ath79_gpio_init(void)
166         err = gpiochip_add(&ath79_gpio_chip);
167         if (err)
168                 panic("cannot add AR71xx GPIO chip, error=%d", err);
169 +
170 +       ath79_gpio_irq_init(&ath79_gpio_chip);
171 +
172 +       request_irq(ATH79_MISC_IRQ(2), ath79_gpio_irq, 0, "ath79-gpio", NULL);
173  }
174  
175  int gpio_get_value(unsigned gpio)
176 @@ -293,14 +435,22 @@ EXPORT_SYMBOL(gpio_set_value);
177  
178  int gpio_to_irq(unsigned gpio)
179  {
180 -       /* FIXME */
181 -       return -EINVAL;
182 +       if (gpio > ath79_gpio_count) {
183 +               return -EINVAL;
184 +       }
185 +
186 +       return ATH79_GPIO_IRQ_BASE + gpio;
187  }
188  EXPORT_SYMBOL(gpio_to_irq);
189  
190  int irq_to_gpio(unsigned irq)
191  {
192 -       /* FIXME */
193 -       return -EINVAL;
194 +       unsigned gpio = irq - ATH79_GPIO_IRQ_BASE;
195 +
196 +       if (gpio > ath79_gpio_count) {
197 +               return -EINVAL;
198 +       }
199 +
200 +       return gpio;
201  }
202  EXPORT_SYMBOL(irq_to_gpio);
203 --- a/arch/mips/include/asm/mach-ath79/irq.h
204 +++ b/arch/mips/include/asm/mach-ath79/irq.h
205 @@ -10,7 +10,7 @@
206  #define __ASM_MACH_ATH79_IRQ_H
207  
208  #define MIPS_CPU_IRQ_BASE      0
209 -#define NR_IRQS                        51
210 +#define NR_IRQS                        83
211  
212  #define ATH79_CPU_IRQ(_x)      (MIPS_CPU_IRQ_BASE + (_x))
213  
214 @@ -30,6 +30,10 @@
215  #define ATH79_IP3_IRQ_COUNT     3
216  #define ATH79_IP3_IRQ(_x)       (ATH79_IP3_IRQ_BASE + (_x))
217  
218 +#define ATH79_GPIO_IRQ_BASE    (ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT)
219 +#define ATH79_GPIO_IRQ_COUNT   32
220 +#define ATH79_GPIO_IRQ(_x)     (ATH79_GPIO_IRQ_BASE + (_x))
221 +
222  #include_next <irq.h>
223  
224  #endif /* __ASM_MACH_ATH79_IRQ_H */