d7e8e88cc9a91604b2ec8a7b74dd82db7f4ffd28
[openwrt.git] / target / linux / cns21xx / patches-3.3 / 005-arm-add-fa-gpio-driver.patch
1 --- /dev/null
2 +++ b/arch/arm/plat-fa/gpio.c
3 @@ -0,0 +1,283 @@
4 +/*
5 + * Gpiochip and interrupt routines for Faraday FA526 based SoCs
6 + *
7 + * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
8 + * Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
9 + *
10 + * Based on plat-mxc/gpio.c:
11 + *  MXC GPIO supchip. (c) 2008 Daniel Mack <daniel@caiaq.de>
12 + *  Copyright 2008 Juergen Beisert, kernel@pengutronix.de
13 + *
14 + * This program is free software; you can redistribute it and/or modify
15 + * it under the terms of the GNU General Public License as published by
16 + * the Free Software Foundation; either version 2 of the License, or
17 + * (at your option) any later version.
18 + */
19 +
20 +#include <linux/spinlock.h>
21 +
22 +#include <plat/gpio.h>
23 +
24 +#define GPIO_DATA_OUT          0x0
25 +#define GPIO_DATA_IN           0x4
26 +#define GPIO_DIR               0x8
27 +#define GPIO_DATA_SET          0x10
28 +#define GPIO_DATA_CLR          0x14
29 +#define GPIO_PULL_EN           0x18
30 +#define GPIO_PULL_TYPE         0x1C
31 +#define GPIO_INT_EN            0x20
32 +#define GPIO_INT_STAT          0x24
33 +#define GPIO_INT_MASK          0x2C
34 +#define GPIO_INT_CLR           0x30
35 +#define GPIO_INT_TYPE          0x34
36 +#define GPIO_INT_BOTH_EDGE     0x38
37 +#define GPIO_INT_LEVEL         0x3C
38 +#define GPIO_DEBOUNCE_EN       0x40
39 +#define GPIO_DEBOUNCE_PRESCALE 0x44
40 +
41 +#define GPIO_REGS_SIZE         0x48
42 +
43 +static DEFINE_SPINLOCK(fa_gpio_lock);
44 +
45 +static inline struct fa_gpio_chip *to_fgc(struct gpio_chip *chip)
46 +{
47 +       return container_of(chip, struct fa_gpio_chip, gpio_chip);
48 +}
49 +
50 +static void _fa_gpio_irq_setenable(struct irq_data *d, int enable)
51 +{
52 +       struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
53 +       void __iomem *base = fgc->mem_base;
54 +       unsigned int gpio = d->irq - fgc->irq_base;
55 +       unsigned int reg;
56 +
57 +       reg = __raw_readl(base + GPIO_INT_EN);
58 +       reg = (reg & (~(1 << gpio))) | (!!enable << gpio);
59 +       __raw_writel(reg, base + GPIO_INT_EN);
60 +}
61 +
62 +static void fa_gpio_irq_ack(struct irq_data *d)
63 +{
64 +       struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
65 +       unsigned int gpio = d->irq - fgc->irq_base;
66 +
67 +       __raw_writel(1 << gpio, fgc->mem_base + GPIO_INT_CLR);
68 +}
69 +
70 +static void fa_gpio_irq_mask(struct irq_data *d)
71 +{
72 +       _fa_gpio_irq_setenable(d, 0);
73 +}
74 +
75 +static void fa_gpio_irq_unmask(struct irq_data *d)
76 +{
77 +       _fa_gpio_irq_setenable(d, 1);
78 +}
79 +
80 +static int fa_gpio_irq_set_type(struct irq_data *d, unsigned int type)
81 +{
82 +       struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
83 +       void __iomem *base = fgc->mem_base;
84 +       unsigned int gpio = d->irq - fgc->irq_base;
85 +       unsigned int gpio_mask = 1 << gpio;
86 +       unsigned int reg_both, reg_level, reg_type;
87 +
88 +       reg_type = __raw_readl(base + GPIO_INT_TYPE);
89 +       reg_level = __raw_readl(base + GPIO_INT_LEVEL);
90 +       reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
91 +
92 +       switch (type) {
93 +       case IRQ_TYPE_EDGE_BOTH:
94 +               reg_type &= ~gpio_mask;
95 +               reg_both |= gpio_mask;
96 +               break;
97 +       case IRQ_TYPE_EDGE_RISING:
98 +               reg_type &= ~gpio_mask;
99 +               reg_both &= ~gpio_mask;
100 +               reg_level &= ~gpio_mask;
101 +               break;
102 +       case IRQ_TYPE_EDGE_FALLING:
103 +               reg_type &= ~gpio_mask;
104 +               reg_both &= ~gpio_mask;
105 +               reg_level |= gpio_mask;
106 +               break;
107 +       case IRQ_TYPE_LEVEL_HIGH:
108 +               reg_type |= gpio_mask;
109 +               reg_level &= ~gpio_mask;
110 +               break;
111 +       case IRQ_TYPE_LEVEL_LOW:
112 +               reg_type |= gpio_mask;
113 +               reg_level |= gpio_mask;
114 +               break;
115 +       default:
116 +               return -EINVAL;
117 +       }
118 +
119 +       __raw_writel(reg_type, base + GPIO_INT_TYPE);
120 +       __raw_writel(reg_level, base + GPIO_INT_LEVEL);
121 +       __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
122 +
123 +       fa_gpio_irq_ack(d);
124 +
125 +       return 0;
126 +}
127 +
128 +static void fa_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
129 +{
130 +       struct fa_gpio_data *data = irq_get_handler_data(irq);
131 +       unsigned int chip;
132 +
133 +       for (chip = 0; chip < data->nchips; chip++) {
134 +               struct fa_gpio_chip *fgc = &data->chips[chip];
135 +               unsigned int status;
136 +               unsigned int i;
137 +
138 +               status = __raw_readl(fgc->mem_base + GPIO_INT_STAT);
139 +               for (i = fgc->irq_base; status != 0; status >>= 1, i++) {
140 +                       if ((status & 1) == 0)
141 +                               continue;
142 +
143 +                       BUG_ON(!(irq_desc[i].handle_irq));
144 +                       irq_desc[i].handle_irq(i, &irq_desc[i]);
145 +               }
146 +       }
147 +}
148 +
149 +static struct irq_chip fa_gpio_irq_chip = {
150 +       .name           = "GPIO",
151 +       .irq_ack        = fa_gpio_irq_ack,
152 +       .irq_mask       = fa_gpio_irq_mask,
153 +       .irq_unmask     = fa_gpio_irq_unmask,
154 +       .irq_set_type   = fa_gpio_irq_set_type,
155 +};
156 +
157 +static void _fa_gpio_set_direction(struct fa_gpio_chip *fgc, unsigned offset,
158 +                                  int is_output)
159 +{
160 +       unsigned int reg;
161 +
162 +       reg = __raw_readl(fgc->mem_base + GPIO_DIR);
163 +       if (is_output)
164 +               reg |= 1 << offset;
165 +       else
166 +               reg &= ~(1 << offset);
167 +       __raw_writel(reg, fgc->mem_base + GPIO_DIR);
168 +}
169 +
170 +static void _fa_gpio_set(struct fa_gpio_chip *fgc, unsigned offset, int value)
171 +{
172 +       if (value)
173 +               __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_SET);
174 +       else
175 +               __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_CLR);
176 +}
177 +
178 +static void fa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
179 +{
180 +       struct fa_gpio_chip *fgc = to_fgc(chip);
181 +
182 +       _fa_gpio_set(fgc, offset, value);
183 +}
184 +
185 +static int fa_gpio_get(struct gpio_chip *chip, unsigned offset)
186 +{
187 +       struct fa_gpio_chip *fgc = to_fgc(chip);
188 +
189 +       return (__raw_readl(fgc->mem_base + GPIO_DATA_IN) >> offset) & 1;
190 +}
191 +
192 +static int fa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
193 +{
194 +       struct fa_gpio_chip *fgc = to_fgc(chip);
195 +
196 +       return fgc->irq_base + offset;
197 +}
198 +
199 +static int fa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
200 +{
201 +       struct fa_gpio_chip *fgc = to_fgc(chip);
202 +       unsigned long flags;
203 +
204 +       spin_lock_irqsave(&fa_gpio_lock, flags);
205 +
206 +       _fa_gpio_set_direction(fgc, offset, 0);
207 +
208 +       spin_unlock_irqrestore(&fa_gpio_lock, flags);
209 +
210 +       return 0;
211 +}
212 +
213 +static int fa_gpio_direction_output(struct gpio_chip *chip,
214 +                                   unsigned offset,
215 +                                   int value)
216 +{
217 +       struct fa_gpio_chip *fgc = to_fgc(chip);
218 +       unsigned long flags;
219 +
220 +       spin_lock_irqsave(&fa_gpio_lock, flags);
221 +
222 +       _fa_gpio_set(fgc, offset, value);
223 +       _fa_gpio_set_direction(fgc, offset, 1);
224 +
225 +       spin_unlock_irqrestore(&fa_gpio_lock, flags);
226 +
227 +       return 0;
228 +}
229 +
230 +static int fa_gpio_init_chip(struct fa_gpio_chip *fgc)
231 +{
232 +       void __iomem *mem_base;
233 +       unsigned int i;
234 +       int err;
235 +
236 +       mem_base = ioremap(fgc->map_base, GPIO_REGS_SIZE);
237 +       if (!mem_base)
238 +               return -ENXIO;
239 +
240 +       fgc->mem_base = mem_base;
241 +
242 +       fgc->gpio_chip.direction_input = fa_gpio_direction_input;
243 +       fgc->gpio_chip.direction_output = fa_gpio_direction_output;
244 +       fgc->gpio_chip.get = fa_gpio_get;
245 +       fgc->gpio_chip.set = fa_gpio_set;
246 +       fgc->gpio_chip.to_irq = fa_gpio_to_irq;
247 +
248 +       /* disable, unmask and clear all interrupts */
249 +       __raw_writel(0x0, mem_base + GPIO_INT_EN);
250 +       __raw_writel(0x0, mem_base + GPIO_INT_MASK);
251 +       __raw_writel(~0x0, mem_base + GPIO_INT_CLR);
252 +
253 +       for (i = fgc->irq_base;
254 +            i < fgc->irq_base + fgc->gpio_chip.ngpio; i++) {
255 +               irq_set_chip(i, &fa_gpio_irq_chip);
256 +               irq_set_chip_data(i, fgc);
257 +               irq_set_handler(i, handle_edge_irq);
258 +               set_irq_flags(i, IRQF_VALID);
259 +       }
260 +
261 +       err = gpiochip_add(&fgc->gpio_chip);
262 +       if (err)
263 +               goto unmap;
264 +
265 +       return 0;
266 +
267 + unmap:
268 +       iounmap(fgc->mem_base);
269 +       return err;
270 +}
271 +
272 +void __init fa_gpio_init(struct fa_gpio_data *data)
273 +{
274 +       unsigned int i;
275 +
276 +       for (i = 0; i < data->nchips; i++) {
277 +               int err;
278 +
279 +               err = fa_gpio_init_chip(&data->chips[i]);
280 +               if (WARN(err, "GPIO init failed\n"))
281 +                       return;
282 +       }
283 +
284 +       irq_set_chained_handler(data->irq, fa_gpio_irq_handler);
285 +       irq_set_handler_data(data->irq, data);
286 +}
287 --- /dev/null
288 +++ b/arch/arm/plat-fa/include/plat/gpio.h
289 @@ -0,0 +1,33 @@
290 +/*
291 + *  Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
292 + *
293 + *  This file is free software; you can redistribute it and/or modify
294 + *  it under the terms of the GNU General Public License, Version 2, as
295 + *  published by the Free Software Foundation.
296 + */
297 +
298 +#ifndef _FA_GPIO_H
299 +#define _FA_GPIO_H
300 +
301 +#include <linux/init.h>
302 +#include <linux/gpio.h>
303 +#include <linux/irq.h>
304 +#include <linux/io.h>
305 +
306 +struct fa_gpio_chip {
307 +       struct gpio_chip        gpio_chip;
308 +       unsigned int            map_base;
309 +       unsigned int            irq_base;
310 +
311 +       void __iomem            *mem_base;
312 +};
313 +
314 +struct fa_gpio_data {
315 +       struct fa_gpio_chip     *chips;
316 +       unsigned int            nchips;
317 +       unsigned int            irq;
318 +};
319 +
320 +void __init fa_gpio_init(struct fa_gpio_data *data);
321 +
322 +#endif /* _FA_GPIO_H */
323 --- a/arch/arm/plat-fa/Kconfig
324 +++ b/arch/arm/plat-fa/Kconfig
325 @@ -1,5 +1,8 @@
326  if PLAT_FA
327  
328 +config PLAT_FA_GPIO
329 +       def_bool n
330 +
331  config PLAT_FA_TIME
332         def_bool n
333  
334 --- a/arch/arm/plat-fa/Makefile
335 +++ b/arch/arm/plat-fa/Makefile
336 @@ -4,6 +4,7 @@
337  
338  obj-y :=
339  
340 +obj-$(CONFIG_PLAT_FA_GPIO)     += gpio.o
341  obj-$(CONFIG_PLAT_FA_TIME)     += time.o
342  
343  obj-m :=