aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ep93xx/gpio.c
diff options
context:
space:
mode:
authorHartley Sweeten <hartleys@visionengravers.com>2010-02-23 15:41:17 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-02-24 16:08:36 -0500
commitd056ab78558c03e6d31c031f7b83f0cb10bee7d4 (patch)
tree7ea0c3f75d43986031c352550190bc3bc4f4b7fa /arch/arm/mach-ep93xx/gpio.c
parentba7c6a3bccd25abd3c19d3655ecb1cc4d258271b (diff)
ARM: 5954/1: ep93xx: move gpio interrupt support to gpio.c
The GPIO support in core.c handles the interrupt support for GPIO ports A, B, and F. The gpiolib implementation in gpio.c needs to access the function ep93xx_gpio_int_mask when a gpio pin is made an output and ep93xx_gpio_update_int_params in order to update the registers. Moving this support from core.c to gpio.c allows making the two functions static. It also keeps all the GPIO handling together in one file. Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com> Acked-by: Ryan Mallon <ryan@bluewatersys.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ep93xx/gpio.c')
-rw-r--r--arch/arm/mach-ep93xx/gpio.c235
1 files changed, 231 insertions, 4 deletions
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c
index 1ea8871e03a9..cc377ae8c428 100644
--- a/arch/arm/mach-ep93xx/gpio.c
+++ b/arch/arm/mach-ep93xx/gpio.c
@@ -13,6 +13,8 @@
13 * published by the Free Software Foundation. 13 * published by the Free Software Foundation.
14 */ 14 */
15 15
16#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
17
16#include <linux/init.h> 18#include <linux/init.h>
17#include <linux/module.h> 19#include <linux/module.h>
18#include <linux/seq_file.h> 20#include <linux/seq_file.h>
@@ -22,6 +24,235 @@
22 24
23#include <mach/hardware.h> 25#include <mach/hardware.h>
24 26
27/*************************************************************************
28 * GPIO handling for EP93xx
29 *************************************************************************/
30static unsigned char gpio_int_unmasked[3];
31static unsigned char gpio_int_enabled[3];
32static unsigned char gpio_int_type1[3];
33static unsigned char gpio_int_type2[3];
34static unsigned char gpio_int_debounce[3];
35
36/* Port ordering is: A B F */
37static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c };
38static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 };
39static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 };
40static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 };
41static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 };
42
43void 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
59void ep93xx_gpio_int_mask(unsigned line)
60{
61 gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
62}
63
64void ep93xx_gpio_int_debounce(unsigned int irq, int 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}
78EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
79
80static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
81{
82 unsigned char status;
83 int i;
84
85 status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
86 for (i = 0; i < 8; i++) {
87 if (status & (1 << i)) {
88 int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
89 generic_handle_irq(gpio_irq);
90 }
91 }
92
93 status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
94 for (i = 0; i < 8; i++) {
95 if (status & (1 << i)) {
96 int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
97 generic_handle_irq(gpio_irq);
98 }
99 }
100}
101
102static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
103{
104 /*
105 * map discontiguous hw irq range to continous sw irq range:
106 *
107 * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
108 */
109 int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
110 int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
111
112 generic_handle_irq(gpio_irq);
113}
114
115static void ep93xx_gpio_irq_ack(unsigned int irq)
116{
117 int line = irq_to_gpio(irq);
118 int port = line >> 3;
119 int port_mask = 1 << (line & 7);
120
121 if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
122 gpio_int_type2[port] ^= port_mask; /* switch edge direction */
123 ep93xx_gpio_update_int_params(port);
124 }
125
126 __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
127}
128
129static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
130{
131 int line = irq_to_gpio(irq);
132 int port = line >> 3;
133 int port_mask = 1 << (line & 7);
134
135 if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
136 gpio_int_type2[port] ^= port_mask; /* switch edge direction */
137
138 gpio_int_unmasked[port] &= ~port_mask;
139 ep93xx_gpio_update_int_params(port);
140
141 __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
142}
143
144static void ep93xx_gpio_irq_mask(unsigned int irq)
145{
146 int line = irq_to_gpio(irq);
147 int port = line >> 3;
148
149 gpio_int_unmasked[port] &= ~(1 << (line & 7));
150 ep93xx_gpio_update_int_params(port);
151}
152
153static void ep93xx_gpio_irq_unmask(unsigned int irq)
154{
155 int line = irq_to_gpio(irq);
156 int port = line >> 3;
157
158 gpio_int_unmasked[port] |= 1 << (line & 7);
159 ep93xx_gpio_update_int_params(port);
160}
161
162/*
163 * gpio_int_type1 controls whether the interrupt is level (0) or
164 * edge (1) triggered, while gpio_int_type2 controls whether it
165 * triggers on low/falling (0) or high/rising (1).
166 */
167static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
168{
169 struct irq_desc *desc = irq_desc + irq;
170 const int gpio = irq_to_gpio(irq);
171 const int port = gpio >> 3;
172 const int port_mask = 1 << (gpio & 7);
173
174 gpio_direction_input(gpio);
175
176 switch (type) {
177 case IRQ_TYPE_EDGE_RISING:
178 gpio_int_type1[port] |= port_mask;
179 gpio_int_type2[port] |= port_mask;
180 desc->handle_irq = handle_edge_irq;
181 break;
182 case IRQ_TYPE_EDGE_FALLING:
183 gpio_int_type1[port] |= port_mask;
184 gpio_int_type2[port] &= ~port_mask;
185 desc->handle_irq = handle_edge_irq;
186 break;
187 case IRQ_TYPE_LEVEL_HIGH:
188 gpio_int_type1[port] &= ~port_mask;
189 gpio_int_type2[port] |= port_mask;
190 desc->handle_irq = handle_level_irq;
191 break;
192 case IRQ_TYPE_LEVEL_LOW:
193 gpio_int_type1[port] &= ~port_mask;
194 gpio_int_type2[port] &= ~port_mask;
195 desc->handle_irq = handle_level_irq;
196 break;
197 case IRQ_TYPE_EDGE_BOTH:
198 gpio_int_type1[port] |= port_mask;
199 /* set initial polarity based on current input level */
200 if (gpio_get_value(gpio))
201 gpio_int_type2[port] &= ~port_mask; /* falling */
202 else
203 gpio_int_type2[port] |= port_mask; /* rising */
204 desc->handle_irq = handle_edge_irq;
205 break;
206 default:
207 pr_err("failed to set irq type %d for gpio %d\n", type, gpio);
208 return -EINVAL;
209 }
210
211 gpio_int_enabled[port] |= port_mask;
212
213 desc->status &= ~IRQ_TYPE_SENSE_MASK;
214 desc->status |= type & IRQ_TYPE_SENSE_MASK;
215
216 ep93xx_gpio_update_int_params(port);
217
218 return 0;
219}
220
221static struct irq_chip ep93xx_gpio_irq_chip = {
222 .name = "GPIO",
223 .ack = ep93xx_gpio_irq_ack,
224 .mask_ack = ep93xx_gpio_irq_mask_ack,
225 .mask = ep93xx_gpio_irq_mask,
226 .unmask = ep93xx_gpio_irq_unmask,
227 .set_type = ep93xx_gpio_irq_type,
228};
229
230void __init ep93xx_gpio_init_irq(void)
231{
232 int gpio_irq;
233
234 for (gpio_irq = gpio_to_irq(0);
235 gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
236 set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip);
237 set_irq_handler(gpio_irq, handle_level_irq);
238 set_irq_flags(gpio_irq, IRQF_VALID);
239 }
240
241 set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
242 set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler);
243 set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler);
244 set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler);
245 set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler);
246 set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler);
247 set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler);
248 set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler);
249 set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler);
250}
251
252
253/*************************************************************************
254 * gpiolib interface for EP93xx on-chip GPIOs
255 *************************************************************************/
25struct ep93xx_gpio_chip { 256struct ep93xx_gpio_chip {
26 struct gpio_chip chip; 257 struct gpio_chip chip;
27 258
@@ -31,10 +262,6 @@ struct ep93xx_gpio_chip {
31 262
32#define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip) 263#define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip)
33 264
34/* From core.c */
35extern void ep93xx_gpio_int_mask(unsigned line);
36extern void ep93xx_gpio_update_int_params(unsigned port);
37
38static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 265static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
39{ 266{
40 struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); 267 struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);