diff options
Diffstat (limited to 'arch/arm/mach-ep93xx/gpio.c')
-rw-r--r-- | arch/arm/mach-ep93xx/gpio.c | 410 |
1 files changed, 0 insertions, 410 deletions
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c deleted file mode 100644 index 415dce37b88..00000000000 --- a/arch/arm/mach-ep93xx/gpio.c +++ /dev/null | |||
@@ -1,410 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-ep93xx/gpio.c | ||
3 | * | ||
4 | * Generic EP93xx GPIO handling | ||
5 | * | ||
6 | * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com> | ||
7 | * | ||
8 | * Based on code originally from: | ||
9 | * linux/arch/arm/mach-ep93xx/core.c | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/irq.h> | ||
24 | |||
25 | #include <mach/hardware.h> | ||
26 | |||
27 | /************************************************************************* | ||
28 | * Interrupt handling for EP93xx on-chip GPIOs | ||
29 | *************************************************************************/ | ||
30 | static unsigned char gpio_int_unmasked[3]; | ||
31 | static unsigned char gpio_int_enabled[3]; | ||
32 | static unsigned char gpio_int_type1[3]; | ||
33 | static unsigned char gpio_int_type2[3]; | ||
34 | static unsigned char gpio_int_debounce[3]; | ||
35 | |||
36 | /* Port ordering is: A B F */ | ||
37 | static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c }; | ||
38 | static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 }; | ||
39 | static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 }; | ||
40 | static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 }; | ||
41 | static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 }; | ||
42 | |||
43 | static void ep93xx_gpio_update_int_params(unsigned port) | ||
44 | { | ||
45 | BUG_ON(port > 2); | ||
46 | |||
47 | __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); | ||
48 | |||
49 | __raw_writeb(gpio_int_type2[port], | ||
50 | EP93XX_GPIO_REG(int_type2_register_offset[port])); | ||
51 | |||
52 | __raw_writeb(gpio_int_type1[port], | ||
53 | EP93XX_GPIO_REG(int_type1_register_offset[port])); | ||
54 | |||
55 | __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], | ||
56 | EP93XX_GPIO_REG(int_en_register_offset[port])); | ||
57 | } | ||
58 | |||
59 | static inline void ep93xx_gpio_int_mask(unsigned line) | ||
60 | { | ||
61 | gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); | ||
62 | } | ||
63 | |||
64 | static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) | ||
65 | { | ||
66 | int line = irq_to_gpio(irq); | ||
67 | int port = line >> 3; | ||
68 | int port_mask = 1 << (line & 7); | ||
69 | |||
70 | if (enable) | ||
71 | gpio_int_debounce[port] |= port_mask; | ||
72 | else | ||
73 | gpio_int_debounce[port] &= ~port_mask; | ||
74 | |||
75 | __raw_writeb(gpio_int_debounce[port], | ||
76 | EP93XX_GPIO_REG(int_debounce_register_offset[port])); | ||
77 | } | ||
78 | |||
79 | static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
80 | { | ||
81 | unsigned char status; | ||
82 | int i; | ||
83 | |||
84 | status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); | ||
85 | for (i = 0; i < 8; i++) { | ||
86 | if (status & (1 << i)) { | ||
87 | int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; | ||
88 | generic_handle_irq(gpio_irq); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); | ||
93 | for (i = 0; i < 8; i++) { | ||
94 | if (status & (1 << i)) { | ||
95 | int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; | ||
96 | generic_handle_irq(gpio_irq); | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
102 | { | ||
103 | /* | ||
104 | * map discontiguous hw irq range to continuous sw irq range: | ||
105 | * | ||
106 | * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) | ||
107 | */ | ||
108 | int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ | ||
109 | int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; | ||
110 | |||
111 | generic_handle_irq(gpio_irq); | ||
112 | } | ||
113 | |||
114 | static void ep93xx_gpio_irq_ack(struct irq_data *d) | ||
115 | { | ||
116 | int line = irq_to_gpio(d->irq); | ||
117 | int port = line >> 3; | ||
118 | int port_mask = 1 << (line & 7); | ||
119 | |||
120 | if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { | ||
121 | gpio_int_type2[port] ^= port_mask; /* switch edge direction */ | ||
122 | ep93xx_gpio_update_int_params(port); | ||
123 | } | ||
124 | |||
125 | __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); | ||
126 | } | ||
127 | |||
128 | static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) | ||
129 | { | ||
130 | int line = irq_to_gpio(d->irq); | ||
131 | int port = line >> 3; | ||
132 | int port_mask = 1 << (line & 7); | ||
133 | |||
134 | if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) | ||
135 | gpio_int_type2[port] ^= port_mask; /* switch edge direction */ | ||
136 | |||
137 | gpio_int_unmasked[port] &= ~port_mask; | ||
138 | ep93xx_gpio_update_int_params(port); | ||
139 | |||
140 | __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); | ||
141 | } | ||
142 | |||
143 | static void ep93xx_gpio_irq_mask(struct irq_data *d) | ||
144 | { | ||
145 | int line = irq_to_gpio(d->irq); | ||
146 | int port = line >> 3; | ||
147 | |||
148 | gpio_int_unmasked[port] &= ~(1 << (line & 7)); | ||
149 | ep93xx_gpio_update_int_params(port); | ||
150 | } | ||
151 | |||
152 | static void ep93xx_gpio_irq_unmask(struct irq_data *d) | ||
153 | { | ||
154 | int line = irq_to_gpio(d->irq); | ||
155 | int port = line >> 3; | ||
156 | |||
157 | gpio_int_unmasked[port] |= 1 << (line & 7); | ||
158 | ep93xx_gpio_update_int_params(port); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * gpio_int_type1 controls whether the interrupt is level (0) or | ||
163 | * edge (1) triggered, while gpio_int_type2 controls whether it | ||
164 | * triggers on low/falling (0) or high/rising (1). | ||
165 | */ | ||
166 | static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) | ||
167 | { | ||
168 | const int gpio = irq_to_gpio(d->irq); | ||
169 | const int port = gpio >> 3; | ||
170 | const int port_mask = 1 << (gpio & 7); | ||
171 | irq_flow_handler_t handler; | ||
172 | |||
173 | gpio_direction_input(gpio); | ||
174 | |||
175 | switch (type) { | ||
176 | case IRQ_TYPE_EDGE_RISING: | ||
177 | gpio_int_type1[port] |= port_mask; | ||
178 | gpio_int_type2[port] |= port_mask; | ||
179 | handler = handle_edge_irq; | ||
180 | break; | ||
181 | case IRQ_TYPE_EDGE_FALLING: | ||
182 | gpio_int_type1[port] |= port_mask; | ||
183 | gpio_int_type2[port] &= ~port_mask; | ||
184 | handler = handle_edge_irq; | ||
185 | break; | ||
186 | case IRQ_TYPE_LEVEL_HIGH: | ||
187 | gpio_int_type1[port] &= ~port_mask; | ||
188 | gpio_int_type2[port] |= port_mask; | ||
189 | handler = handle_level_irq; | ||
190 | break; | ||
191 | case IRQ_TYPE_LEVEL_LOW: | ||
192 | gpio_int_type1[port] &= ~port_mask; | ||
193 | gpio_int_type2[port] &= ~port_mask; | ||
194 | handler = handle_level_irq; | ||
195 | break; | ||
196 | case IRQ_TYPE_EDGE_BOTH: | ||
197 | gpio_int_type1[port] |= port_mask; | ||
198 | /* set initial polarity based on current input level */ | ||
199 | if (gpio_get_value(gpio)) | ||
200 | gpio_int_type2[port] &= ~port_mask; /* falling */ | ||
201 | else | ||
202 | gpio_int_type2[port] |= port_mask; /* rising */ | ||
203 | handler = handle_edge_irq; | ||
204 | break; | ||
205 | default: | ||
206 | pr_err("failed to set irq type %d for gpio %d\n", type, gpio); | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | |||
210 | __irq_set_handler_locked(d->irq, handler); | ||
211 | |||
212 | gpio_int_enabled[port] |= port_mask; | ||
213 | |||
214 | ep93xx_gpio_update_int_params(port); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static struct irq_chip ep93xx_gpio_irq_chip = { | ||
220 | .name = "GPIO", | ||
221 | .irq_ack = ep93xx_gpio_irq_ack, | ||
222 | .irq_mask_ack = ep93xx_gpio_irq_mask_ack, | ||
223 | .irq_mask = ep93xx_gpio_irq_mask, | ||
224 | .irq_unmask = ep93xx_gpio_irq_unmask, | ||
225 | .irq_set_type = ep93xx_gpio_irq_type, | ||
226 | }; | ||
227 | |||
228 | void __init ep93xx_gpio_init_irq(void) | ||
229 | { | ||
230 | int gpio_irq; | ||
231 | |||
232 | for (gpio_irq = gpio_to_irq(0); | ||
233 | gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { | ||
234 | irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, | ||
235 | handle_level_irq); | ||
236 | set_irq_flags(gpio_irq, IRQF_VALID); | ||
237 | } | ||
238 | |||
239 | irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, | ||
240 | ep93xx_gpio_ab_irq_handler); | ||
241 | irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX, | ||
242 | ep93xx_gpio_f_irq_handler); | ||
243 | irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX, | ||
244 | ep93xx_gpio_f_irq_handler); | ||
245 | irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX, | ||
246 | ep93xx_gpio_f_irq_handler); | ||
247 | irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX, | ||
248 | ep93xx_gpio_f_irq_handler); | ||
249 | irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX, | ||
250 | ep93xx_gpio_f_irq_handler); | ||
251 | irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX, | ||
252 | ep93xx_gpio_f_irq_handler); | ||
253 | irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX, | ||
254 | ep93xx_gpio_f_irq_handler); | ||
255 | irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX, | ||
256 | ep93xx_gpio_f_irq_handler); | ||
257 | } | ||
258 | |||
259 | |||
260 | /************************************************************************* | ||
261 | * gpiolib interface for EP93xx on-chip GPIOs | ||
262 | *************************************************************************/ | ||
263 | struct ep93xx_gpio_chip { | ||
264 | struct gpio_chip chip; | ||
265 | |||
266 | void __iomem *data_reg; | ||
267 | void __iomem *data_dir_reg; | ||
268 | }; | ||
269 | |||
270 | #define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip) | ||
271 | |||
272 | static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
273 | { | ||
274 | struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); | ||
275 | unsigned long flags; | ||
276 | u8 v; | ||
277 | |||
278 | local_irq_save(flags); | ||
279 | v = __raw_readb(ep93xx_chip->data_dir_reg); | ||
280 | v &= ~(1 << offset); | ||
281 | __raw_writeb(v, ep93xx_chip->data_dir_reg); | ||
282 | local_irq_restore(flags); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int ep93xx_gpio_direction_output(struct gpio_chip *chip, | ||
288 | unsigned offset, int val) | ||
289 | { | ||
290 | struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); | ||
291 | unsigned long flags; | ||
292 | int line; | ||
293 | u8 v; | ||
294 | |||
295 | local_irq_save(flags); | ||
296 | |||
297 | /* Set the value */ | ||
298 | v = __raw_readb(ep93xx_chip->data_reg); | ||
299 | if (val) | ||
300 | v |= (1 << offset); | ||
301 | else | ||
302 | v &= ~(1 << offset); | ||
303 | __raw_writeb(v, ep93xx_chip->data_reg); | ||
304 | |||
305 | /* Drive as an output */ | ||
306 | line = chip->base + offset; | ||
307 | if (line <= EP93XX_GPIO_LINE_MAX_IRQ) { | ||
308 | /* Ports A/B/F */ | ||
309 | ep93xx_gpio_int_mask(line); | ||
310 | ep93xx_gpio_update_int_params(line >> 3); | ||
311 | } | ||
312 | |||
313 | v = __raw_readb(ep93xx_chip->data_dir_reg); | ||
314 | v |= (1 << offset); | ||
315 | __raw_writeb(v, ep93xx_chip->data_dir_reg); | ||
316 | |||
317 | local_irq_restore(flags); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int ep93xx_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
323 | { | ||
324 | struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); | ||
325 | |||
326 | return !!(__raw_readb(ep93xx_chip->data_reg) & (1 << offset)); | ||
327 | } | ||
328 | |||
329 | static void ep93xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
330 | { | ||
331 | struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); | ||
332 | unsigned long flags; | ||
333 | u8 v; | ||
334 | |||
335 | local_irq_save(flags); | ||
336 | v = __raw_readb(ep93xx_chip->data_reg); | ||
337 | if (val) | ||
338 | v |= (1 << offset); | ||
339 | else | ||
340 | v &= ~(1 << offset); | ||
341 | __raw_writeb(v, ep93xx_chip->data_reg); | ||
342 | local_irq_restore(flags); | ||
343 | } | ||
344 | |||
345 | static int ep93xx_gpio_set_debounce(struct gpio_chip *chip, | ||
346 | unsigned offset, unsigned debounce) | ||
347 | { | ||
348 | int gpio = chip->base + offset; | ||
349 | int irq = gpio_to_irq(gpio); | ||
350 | |||
351 | if (irq < 0) | ||
352 | return -EINVAL; | ||
353 | |||
354 | ep93xx_gpio_int_debounce(irq, debounce ? true : false); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | #define EP93XX_GPIO_BANK(name, dr, ddr, base_gpio) \ | ||
360 | { \ | ||
361 | .chip = { \ | ||
362 | .label = name, \ | ||
363 | .direction_input = ep93xx_gpio_direction_input, \ | ||
364 | .direction_output = ep93xx_gpio_direction_output, \ | ||
365 | .get = ep93xx_gpio_get, \ | ||
366 | .set = ep93xx_gpio_set, \ | ||
367 | .base = base_gpio, \ | ||
368 | .ngpio = 8, \ | ||
369 | }, \ | ||
370 | .data_reg = EP93XX_GPIO_REG(dr), \ | ||
371 | .data_dir_reg = EP93XX_GPIO_REG(ddr), \ | ||
372 | } | ||
373 | |||
374 | static struct ep93xx_gpio_chip ep93xx_gpio_banks[] = { | ||
375 | EP93XX_GPIO_BANK("A", 0x00, 0x10, 0), | ||
376 | EP93XX_GPIO_BANK("B", 0x04, 0x14, 8), | ||
377 | EP93XX_GPIO_BANK("C", 0x08, 0x18, 40), | ||
378 | EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24), | ||
379 | EP93XX_GPIO_BANK("E", 0x20, 0x24, 32), | ||
380 | EP93XX_GPIO_BANK("F", 0x30, 0x34, 16), | ||
381 | EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48), | ||
382 | EP93XX_GPIO_BANK("H", 0x40, 0x44, 56), | ||
383 | }; | ||
384 | |||
385 | void __init ep93xx_gpio_init(void) | ||
386 | { | ||
387 | int i; | ||
388 | |||
389 | /* Set Ports C, D, E, G, and H for GPIO use */ | ||
390 | ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | | ||
391 | EP93XX_SYSCON_DEVCFG_GONK | | ||
392 | EP93XX_SYSCON_DEVCFG_EONIDE | | ||
393 | EP93XX_SYSCON_DEVCFG_GONIDE | | ||
394 | EP93XX_SYSCON_DEVCFG_HONIDE); | ||
395 | |||
396 | for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { | ||
397 | struct gpio_chip *chip = &ep93xx_gpio_banks[i].chip; | ||
398 | |||
399 | /* | ||
400 | * Ports A, B, and F support input debouncing when | ||
401 | * used as interrupts. | ||
402 | */ | ||
403 | if (!strcmp(chip->label, "A") || | ||
404 | !strcmp(chip->label, "B") || | ||
405 | !strcmp(chip->label, "F")) | ||
406 | chip->set_debounce = ep93xx_gpio_set_debounce; | ||
407 | |||
408 | gpiochip_add(chip); | ||
409 | } | ||
410 | } | ||