aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-pxa
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2011-09-28 04:10:54 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-10-01 18:41:41 -0400
commit354bf8010ffea1ca5accd9fae26b7373df96bcb7 (patch)
tree80bcb552771d44e9974de2a89b5b40213cef7e44 /arch/arm/plat-pxa
parentbd5f12a24766c1f299def0a78b008d4746f528f2 (diff)
ARM: 7103/1: plat-pxa: move PXA GPIO driver to GPIO subsystem
As per example from the other ARM boards, push the PXA GPIO driver down to the GPIO subsystem so it can be consolidated. Acked-by: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-pxa')
-rw-r--r--arch/arm/plat-pxa/Makefile1
-rw-r--r--arch/arm/plat-pxa/gpio.c336
2 files changed, 0 insertions, 337 deletions
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 3aca5ba0f876..f302d048392d 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -4,7 +4,6 @@
4 4
5obj-y := dma.o 5obj-y := dma.o
6 6
7obj-$(CONFIG_GENERIC_GPIO) += gpio.o
8obj-$(CONFIG_PXA3xx) += mfp.o 7obj-$(CONFIG_PXA3xx) += mfp.o
9obj-$(CONFIG_PXA95x) += mfp.o 8obj-$(CONFIG_PXA95x) += mfp.o
10obj-$(CONFIG_ARCH_MMP) += mfp.o 9obj-$(CONFIG_ARCH_MMP) += mfp.o
diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c
deleted file mode 100644
index 5d6a86bfc68d..000000000000
--- a/arch/arm/plat-pxa/gpio.c
+++ /dev/null
@@ -1,336 +0,0 @@
1/*
2 * linux/arch/arm/plat-pxa/gpio.c
3 *
4 * Generic PXA GPIO handling
5 *
6 * Author: Nicolas Pitre
7 * Created: Jun 15, 2001
8 * Copyright: MontaVista Software Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14#include <linux/gpio.h>
15#include <linux/init.h>
16#include <linux/irq.h>
17#include <linux/io.h>
18#include <linux/syscore_ops.h>
19#include <linux/slab.h>
20
21int pxa_last_gpio;
22
23struct pxa_gpio_chip {
24 struct gpio_chip chip;
25 void __iomem *regbase;
26 char label[10];
27
28 unsigned long irq_mask;
29 unsigned long irq_edge_rise;
30 unsigned long irq_edge_fall;
31
32#ifdef CONFIG_PM
33 unsigned long saved_gplr;
34 unsigned long saved_gpdr;
35 unsigned long saved_grer;
36 unsigned long saved_gfer;
37#endif
38};
39
40static DEFINE_SPINLOCK(gpio_lock);
41static struct pxa_gpio_chip *pxa_gpio_chips;
42
43#define for_each_gpio_chip(i, c) \
44 for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
45
46static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
47{
48 return container_of(c, struct pxa_gpio_chip, chip)->regbase;
49}
50
51static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
52{
53 return &pxa_gpio_chips[gpio_to_bank(gpio)];
54}
55
56static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
57{
58 void __iomem *base = gpio_chip_base(chip);
59 uint32_t value, mask = 1 << offset;
60 unsigned long flags;
61
62 spin_lock_irqsave(&gpio_lock, flags);
63
64 value = __raw_readl(base + GPDR_OFFSET);
65 if (__gpio_is_inverted(chip->base + offset))
66 value |= mask;
67 else
68 value &= ~mask;
69 __raw_writel(value, base + GPDR_OFFSET);
70
71 spin_unlock_irqrestore(&gpio_lock, flags);
72 return 0;
73}
74
75static int pxa_gpio_direction_output(struct gpio_chip *chip,
76 unsigned offset, int value)
77{
78 void __iomem *base = gpio_chip_base(chip);
79 uint32_t tmp, mask = 1 << offset;
80 unsigned long flags;
81
82 __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
83
84 spin_lock_irqsave(&gpio_lock, flags);
85
86 tmp = __raw_readl(base + GPDR_OFFSET);
87 if (__gpio_is_inverted(chip->base + offset))
88 tmp &= ~mask;
89 else
90 tmp |= mask;
91 __raw_writel(tmp, base + GPDR_OFFSET);
92
93 spin_unlock_irqrestore(&gpio_lock, flags);
94 return 0;
95}
96
97static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
98{
99 return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset);
100}
101
102static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
103{
104 __raw_writel(1 << offset, gpio_chip_base(chip) +
105 (value ? GPSR_OFFSET : GPCR_OFFSET));
106}
107
108static int __init pxa_init_gpio_chip(int gpio_end)
109{
110 int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
111 struct pxa_gpio_chip *chips;
112
113 chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
114 if (chips == NULL) {
115 pr_err("%s: failed to allocate GPIO chips\n", __func__);
116 return -ENOMEM;
117 }
118
119 for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
120 struct gpio_chip *c = &chips[i].chip;
121
122 sprintf(chips[i].label, "gpio-%d", i);
123 chips[i].regbase = (void __iomem *)GPIO_BANK(i);
124
125 c->base = gpio;
126 c->label = chips[i].label;
127
128 c->direction_input = pxa_gpio_direction_input;
129 c->direction_output = pxa_gpio_direction_output;
130 c->get = pxa_gpio_get;
131 c->set = pxa_gpio_set;
132
133 /* number of GPIOs on last bank may be less than 32 */
134 c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
135 gpiochip_add(c);
136 }
137 pxa_gpio_chips = chips;
138 return 0;
139}
140
141/* Update only those GRERx and GFERx edge detection register bits if those
142 * bits are set in c->irq_mask
143 */
144static inline void update_edge_detect(struct pxa_gpio_chip *c)
145{
146 uint32_t grer, gfer;
147
148 grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask;
149 gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask;
150 grer |= c->irq_edge_rise & c->irq_mask;
151 gfer |= c->irq_edge_fall & c->irq_mask;
152 __raw_writel(grer, c->regbase + GRER_OFFSET);
153 __raw_writel(gfer, c->regbase + GFER_OFFSET);
154}
155
156static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
157{
158 struct pxa_gpio_chip *c;
159 int gpio = irq_to_gpio(d->irq);
160 unsigned long gpdr, mask = GPIO_bit(gpio);
161
162 c = gpio_to_pxachip(gpio);
163
164 if (type == IRQ_TYPE_PROBE) {
165 /* Don't mess with enabled GPIOs using preconfigured edges or
166 * GPIOs set to alternate function or to output during probe
167 */
168 if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
169 return 0;
170
171 if (__gpio_is_occupied(gpio))
172 return 0;
173
174 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
175 }
176
177 gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
178
179 if (__gpio_is_inverted(gpio))
180 __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET);
181 else
182 __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET);
183
184 if (type & IRQ_TYPE_EDGE_RISING)
185 c->irq_edge_rise |= mask;
186 else
187 c->irq_edge_rise &= ~mask;
188
189 if (type & IRQ_TYPE_EDGE_FALLING)
190 c->irq_edge_fall |= mask;
191 else
192 c->irq_edge_fall &= ~mask;
193
194 update_edge_detect(c);
195
196 pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio,
197 ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""),
198 ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : ""));
199 return 0;
200}
201
202static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
203{
204 struct pxa_gpio_chip *c;
205 int loop, gpio, gpio_base, n;
206 unsigned long gedr;
207
208 do {
209 loop = 0;
210 for_each_gpio_chip(gpio, c) {
211 gpio_base = c->chip.base;
212
213 gedr = __raw_readl(c->regbase + GEDR_OFFSET);
214 gedr = gedr & c->irq_mask;
215 __raw_writel(gedr, c->regbase + GEDR_OFFSET);
216
217 n = find_first_bit(&gedr, BITS_PER_LONG);
218 while (n < BITS_PER_LONG) {
219 loop = 1;
220
221 generic_handle_irq(gpio_to_irq(gpio_base + n));
222 n = find_next_bit(&gedr, BITS_PER_LONG, n + 1);
223 }
224 }
225 } while (loop);
226}
227
228static void pxa_ack_muxed_gpio(struct irq_data *d)
229{
230 int gpio = irq_to_gpio(d->irq);
231 struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
232
233 __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
234}
235
236static void pxa_mask_muxed_gpio(struct irq_data *d)
237{
238 int gpio = irq_to_gpio(d->irq);
239 struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
240 uint32_t grer, gfer;
241
242 c->irq_mask &= ~GPIO_bit(gpio);
243
244 grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
245 gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
246 __raw_writel(grer, c->regbase + GRER_OFFSET);
247 __raw_writel(gfer, c->regbase + GFER_OFFSET);
248}
249
250static void pxa_unmask_muxed_gpio(struct irq_data *d)
251{
252 int gpio = irq_to_gpio(d->irq);
253 struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
254
255 c->irq_mask |= GPIO_bit(gpio);
256 update_edge_detect(c);
257}
258
259static struct irq_chip pxa_muxed_gpio_chip = {
260 .name = "GPIO",
261 .irq_ack = pxa_ack_muxed_gpio,
262 .irq_mask = pxa_mask_muxed_gpio,
263 .irq_unmask = pxa_unmask_muxed_gpio,
264 .irq_set_type = pxa_gpio_irq_type,
265};
266
267void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
268{
269 struct pxa_gpio_chip *c;
270 int gpio, irq;
271
272 pxa_last_gpio = end;
273
274 /* Initialize GPIO chips */
275 pxa_init_gpio_chip(end);
276
277 /* clear all GPIO edge detects */
278 for_each_gpio_chip(gpio, c) {
279 __raw_writel(0, c->regbase + GFER_OFFSET);
280 __raw_writel(0, c->regbase + GRER_OFFSET);
281 __raw_writel(~0,c->regbase + GEDR_OFFSET);
282 }
283
284 for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) {
285 irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
286 handle_edge_irq);
287 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
288 }
289
290 /* Install handler for GPIO>=2 edge detect interrupts */
291 irq_set_chained_handler(mux_irq, pxa_gpio_demux_handler);
292 pxa_muxed_gpio_chip.irq_set_wake = fn;
293}
294
295#ifdef CONFIG_PM
296static int pxa_gpio_suspend(void)
297{
298 struct pxa_gpio_chip *c;
299 int gpio;
300
301 for_each_gpio_chip(gpio, c) {
302 c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET);
303 c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
304 c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET);
305 c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET);
306
307 /* Clear GPIO transition detect bits */
308 __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET);
309 }
310 return 0;
311}
312
313static void pxa_gpio_resume(void)
314{
315 struct pxa_gpio_chip *c;
316 int gpio;
317
318 for_each_gpio_chip(gpio, c) {
319 /* restore level with set/clear */
320 __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET);
321 __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET);
322
323 __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET);
324 __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET);
325 __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET);
326 }
327}
328#else
329#define pxa_gpio_suspend NULL
330#define pxa_gpio_resume NULL
331#endif
332
333struct syscore_ops pxa_gpio_syscore_ops = {
334 .suspend = pxa_gpio_suspend,
335 .resume = pxa_gpio_resume,
336};