diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2011-06-05 12:07:54 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-06-06 12:01:19 -0400 |
commit | d37a65bb4663bde7cf3dbc51aec7f264fa4d0ebf (patch) | |
tree | 5cea55304a0c2863273299209c7edd6518617377 /drivers/gpio/gpio-mxc.c | |
parent | 8d7cf8370d5fb75a3265408dceb1d6173eebfafd (diff) |
gpio/mxc: Move Freescale MXC gpio driver to drivers/gpio
GPIO drivers are getting moved to drivers/gpio for cleanup and
consolidation. This patch moves the plat-mxc driver. Follow up
patches will clean it up and make it a fine upstanding gpio driver.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio/gpio-mxc.c')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c new file mode 100644 index 000000000000..6cd6d7f686f6 --- /dev/null +++ b/drivers/gpio/gpio-mxc.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de> | ||
3 | * Copyright 2008 Juergen Beisert, kernel@pengutronix.de | ||
4 | * | ||
5 | * Based on code from Freescale, | ||
6 | * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/gpio.h> | ||
27 | #include <mach/hardware.h> | ||
28 | #include <asm-generic/bug.h> | ||
29 | |||
30 | static struct mxc_gpio_port *mxc_gpio_ports; | ||
31 | static int gpio_table_size; | ||
32 | |||
33 | #define cpu_is_mx1_mx2() (cpu_is_mx1() || cpu_is_mx2()) | ||
34 | |||
35 | #define GPIO_DR (cpu_is_mx1_mx2() ? 0x1c : 0x00) | ||
36 | #define GPIO_GDIR (cpu_is_mx1_mx2() ? 0x00 : 0x04) | ||
37 | #define GPIO_PSR (cpu_is_mx1_mx2() ? 0x24 : 0x08) | ||
38 | #define GPIO_ICR1 (cpu_is_mx1_mx2() ? 0x28 : 0x0C) | ||
39 | #define GPIO_ICR2 (cpu_is_mx1_mx2() ? 0x2C : 0x10) | ||
40 | #define GPIO_IMR (cpu_is_mx1_mx2() ? 0x30 : 0x14) | ||
41 | #define GPIO_ISR (cpu_is_mx1_mx2() ? 0x34 : 0x18) | ||
42 | |||
43 | #define GPIO_INT_LOW_LEV (cpu_is_mx1_mx2() ? 0x3 : 0x0) | ||
44 | #define GPIO_INT_HIGH_LEV (cpu_is_mx1_mx2() ? 0x2 : 0x1) | ||
45 | #define GPIO_INT_RISE_EDGE (cpu_is_mx1_mx2() ? 0x0 : 0x2) | ||
46 | #define GPIO_INT_FALL_EDGE (cpu_is_mx1_mx2() ? 0x1 : 0x3) | ||
47 | #define GPIO_INT_NONE 0x4 | ||
48 | |||
49 | /* Note: This driver assumes 32 GPIOs are handled in one register */ | ||
50 | |||
51 | static void _clear_gpio_irqstatus(struct mxc_gpio_port *port, u32 index) | ||
52 | { | ||
53 | __raw_writel(1 << index, port->base + GPIO_ISR); | ||
54 | } | ||
55 | |||
56 | static void _set_gpio_irqenable(struct mxc_gpio_port *port, u32 index, | ||
57 | int enable) | ||
58 | { | ||
59 | u32 l; | ||
60 | |||
61 | l = __raw_readl(port->base + GPIO_IMR); | ||
62 | l = (l & (~(1 << index))) | (!!enable << index); | ||
63 | __raw_writel(l, port->base + GPIO_IMR); | ||
64 | } | ||
65 | |||
66 | static void gpio_ack_irq(struct irq_data *d) | ||
67 | { | ||
68 | u32 gpio = irq_to_gpio(d->irq); | ||
69 | _clear_gpio_irqstatus(&mxc_gpio_ports[gpio / 32], gpio & 0x1f); | ||
70 | } | ||
71 | |||
72 | static void gpio_mask_irq(struct irq_data *d) | ||
73 | { | ||
74 | u32 gpio = irq_to_gpio(d->irq); | ||
75 | _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 0); | ||
76 | } | ||
77 | |||
78 | static void gpio_unmask_irq(struct irq_data *d) | ||
79 | { | ||
80 | u32 gpio = irq_to_gpio(d->irq); | ||
81 | _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1); | ||
82 | } | ||
83 | |||
84 | static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset); | ||
85 | |||
86 | static int gpio_set_irq_type(struct irq_data *d, u32 type) | ||
87 | { | ||
88 | u32 gpio = irq_to_gpio(d->irq); | ||
89 | struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32]; | ||
90 | u32 bit, val; | ||
91 | int edge; | ||
92 | void __iomem *reg = port->base; | ||
93 | |||
94 | port->both_edges &= ~(1 << (gpio & 31)); | ||
95 | switch (type) { | ||
96 | case IRQ_TYPE_EDGE_RISING: | ||
97 | edge = GPIO_INT_RISE_EDGE; | ||
98 | break; | ||
99 | case IRQ_TYPE_EDGE_FALLING: | ||
100 | edge = GPIO_INT_FALL_EDGE; | ||
101 | break; | ||
102 | case IRQ_TYPE_EDGE_BOTH: | ||
103 | val = mxc_gpio_get(&port->chip, gpio & 31); | ||
104 | if (val) { | ||
105 | edge = GPIO_INT_LOW_LEV; | ||
106 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
107 | } else { | ||
108 | edge = GPIO_INT_HIGH_LEV; | ||
109 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | ||
110 | } | ||
111 | port->both_edges |= 1 << (gpio & 31); | ||
112 | break; | ||
113 | case IRQ_TYPE_LEVEL_LOW: | ||
114 | edge = GPIO_INT_LOW_LEV; | ||
115 | break; | ||
116 | case IRQ_TYPE_LEVEL_HIGH: | ||
117 | edge = GPIO_INT_HIGH_LEV; | ||
118 | break; | ||
119 | default: | ||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | ||
124 | bit = gpio & 0xf; | ||
125 | val = __raw_readl(reg) & ~(0x3 << (bit << 1)); | ||
126 | __raw_writel(val | (edge << (bit << 1)), reg); | ||
127 | _clear_gpio_irqstatus(port, gpio & 0x1f); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) | ||
133 | { | ||
134 | void __iomem *reg = port->base; | ||
135 | u32 bit, val; | ||
136 | int edge; | ||
137 | |||
138 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | ||
139 | bit = gpio & 0xf; | ||
140 | val = __raw_readl(reg); | ||
141 | edge = (val >> (bit << 1)) & 3; | ||
142 | val &= ~(0x3 << (bit << 1)); | ||
143 | if (edge == GPIO_INT_HIGH_LEV) { | ||
144 | edge = GPIO_INT_LOW_LEV; | ||
145 | pr_debug("mxc: switch GPIO %d to low trigger\n", gpio); | ||
146 | } else if (edge == GPIO_INT_LOW_LEV) { | ||
147 | edge = GPIO_INT_HIGH_LEV; | ||
148 | pr_debug("mxc: switch GPIO %d to high trigger\n", gpio); | ||
149 | } else { | ||
150 | pr_err("mxc: invalid configuration for GPIO %d: %x\n", | ||
151 | gpio, edge); | ||
152 | return; | ||
153 | } | ||
154 | __raw_writel(val | (edge << (bit << 1)), reg); | ||
155 | } | ||
156 | |||
157 | /* handle 32 interrupts in one status register */ | ||
158 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) | ||
159 | { | ||
160 | u32 gpio_irq_no_base = port->virtual_irq_start; | ||
161 | |||
162 | while (irq_stat != 0) { | ||
163 | int irqoffset = fls(irq_stat) - 1; | ||
164 | |||
165 | if (port->both_edges & (1 << irqoffset)) | ||
166 | mxc_flip_edge(port, irqoffset); | ||
167 | |||
168 | generic_handle_irq(gpio_irq_no_base + irqoffset); | ||
169 | |||
170 | irq_stat &= ~(1 << irqoffset); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /* MX1 and MX3 has one interrupt *per* gpio port */ | ||
175 | static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) | ||
176 | { | ||
177 | u32 irq_stat; | ||
178 | struct mxc_gpio_port *port = irq_get_handler_data(irq); | ||
179 | |||
180 | irq_stat = __raw_readl(port->base + GPIO_ISR) & | ||
181 | __raw_readl(port->base + GPIO_IMR); | ||
182 | |||
183 | mxc_gpio_irq_handler(port, irq_stat); | ||
184 | } | ||
185 | |||
186 | /* MX2 has one interrupt *for all* gpio ports */ | ||
187 | static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) | ||
188 | { | ||
189 | int i; | ||
190 | u32 irq_msk, irq_stat; | ||
191 | struct mxc_gpio_port *port = irq_get_handler_data(irq); | ||
192 | |||
193 | /* walk through all interrupt status registers */ | ||
194 | for (i = 0; i < gpio_table_size; i++) { | ||
195 | irq_msk = __raw_readl(port[i].base + GPIO_IMR); | ||
196 | if (!irq_msk) | ||
197 | continue; | ||
198 | |||
199 | irq_stat = __raw_readl(port[i].base + GPIO_ISR) & irq_msk; | ||
200 | if (irq_stat) | ||
201 | mxc_gpio_irq_handler(&port[i], irq_stat); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Set interrupt number "irq" in the GPIO as a wake-up source. | ||
207 | * While system is running, all registered GPIO interrupts need to have | ||
208 | * wake-up enabled. When system is suspended, only selected GPIO interrupts | ||
209 | * need to have wake-up enabled. | ||
210 | * @param irq interrupt source number | ||
211 | * @param enable enable as wake-up if equal to non-zero | ||
212 | * @return This function returns 0 on success. | ||
213 | */ | ||
214 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) | ||
215 | { | ||
216 | u32 gpio = irq_to_gpio(d->irq); | ||
217 | u32 gpio_idx = gpio & 0x1F; | ||
218 | struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32]; | ||
219 | |||
220 | if (enable) { | ||
221 | if (port->irq_high && (gpio_idx >= 16)) | ||
222 | enable_irq_wake(port->irq_high); | ||
223 | else | ||
224 | enable_irq_wake(port->irq); | ||
225 | } else { | ||
226 | if (port->irq_high && (gpio_idx >= 16)) | ||
227 | disable_irq_wake(port->irq_high); | ||
228 | else | ||
229 | disable_irq_wake(port->irq); | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static struct irq_chip gpio_irq_chip = { | ||
236 | .name = "GPIO", | ||
237 | .irq_ack = gpio_ack_irq, | ||
238 | .irq_mask = gpio_mask_irq, | ||
239 | .irq_unmask = gpio_unmask_irq, | ||
240 | .irq_set_type = gpio_set_irq_type, | ||
241 | .irq_set_wake = gpio_set_wake_irq, | ||
242 | }; | ||
243 | |||
244 | static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, | ||
245 | int dir) | ||
246 | { | ||
247 | struct mxc_gpio_port *port = | ||
248 | container_of(chip, struct mxc_gpio_port, chip); | ||
249 | u32 l; | ||
250 | unsigned long flags; | ||
251 | |||
252 | spin_lock_irqsave(&port->lock, flags); | ||
253 | l = __raw_readl(port->base + GPIO_GDIR); | ||
254 | if (dir) | ||
255 | l |= 1 << offset; | ||
256 | else | ||
257 | l &= ~(1 << offset); | ||
258 | __raw_writel(l, port->base + GPIO_GDIR); | ||
259 | spin_unlock_irqrestore(&port->lock, flags); | ||
260 | } | ||
261 | |||
262 | static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
263 | { | ||
264 | struct mxc_gpio_port *port = | ||
265 | container_of(chip, struct mxc_gpio_port, chip); | ||
266 | void __iomem *reg = port->base + GPIO_DR; | ||
267 | u32 l; | ||
268 | unsigned long flags; | ||
269 | |||
270 | spin_lock_irqsave(&port->lock, flags); | ||
271 | l = (__raw_readl(reg) & (~(1 << offset))) | (!!value << offset); | ||
272 | __raw_writel(l, reg); | ||
273 | spin_unlock_irqrestore(&port->lock, flags); | ||
274 | } | ||
275 | |||
276 | static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
277 | { | ||
278 | struct mxc_gpio_port *port = | ||
279 | container_of(chip, struct mxc_gpio_port, chip); | ||
280 | |||
281 | return (__raw_readl(port->base + GPIO_PSR) >> offset) & 1; | ||
282 | } | ||
283 | |||
284 | static int mxc_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
285 | { | ||
286 | _set_gpio_direction(chip, offset, 0); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int mxc_gpio_direction_output(struct gpio_chip *chip, | ||
291 | unsigned offset, int value) | ||
292 | { | ||
293 | mxc_gpio_set(chip, offset, value); | ||
294 | _set_gpio_direction(chip, offset, 1); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * This lock class tells lockdep that GPIO irqs are in a different | ||
300 | * category than their parents, so it won't report false recursion. | ||
301 | */ | ||
302 | static struct lock_class_key gpio_lock_class; | ||
303 | |||
304 | int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) | ||
305 | { | ||
306 | int i, j; | ||
307 | |||
308 | /* save for local usage */ | ||
309 | mxc_gpio_ports = port; | ||
310 | gpio_table_size = cnt; | ||
311 | |||
312 | printk(KERN_INFO "MXC GPIO hardware\n"); | ||
313 | |||
314 | for (i = 0; i < cnt; i++) { | ||
315 | /* disable the interrupt and clear the status */ | ||
316 | __raw_writel(0, port[i].base + GPIO_IMR); | ||
317 | __raw_writel(~0, port[i].base + GPIO_ISR); | ||
318 | for (j = port[i].virtual_irq_start; | ||
319 | j < port[i].virtual_irq_start + 32; j++) { | ||
320 | irq_set_lockdep_class(j, &gpio_lock_class); | ||
321 | irq_set_chip_and_handler(j, &gpio_irq_chip, | ||
322 | handle_level_irq); | ||
323 | set_irq_flags(j, IRQF_VALID); | ||
324 | } | ||
325 | |||
326 | /* register gpio chip */ | ||
327 | port[i].chip.direction_input = mxc_gpio_direction_input; | ||
328 | port[i].chip.direction_output = mxc_gpio_direction_output; | ||
329 | port[i].chip.get = mxc_gpio_get; | ||
330 | port[i].chip.set = mxc_gpio_set; | ||
331 | port[i].chip.base = i * 32; | ||
332 | port[i].chip.ngpio = 32; | ||
333 | |||
334 | spin_lock_init(&port[i].lock); | ||
335 | |||
336 | /* its a serious configuration bug when it fails */ | ||
337 | BUG_ON( gpiochip_add(&port[i].chip) < 0 ); | ||
338 | |||
339 | if (cpu_is_mx1() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51()) { | ||
340 | /* setup one handler for each entry */ | ||
341 | irq_set_chained_handler(port[i].irq, | ||
342 | mx3_gpio_irq_handler); | ||
343 | irq_set_handler_data(port[i].irq, &port[i]); | ||
344 | if (port[i].irq_high) { | ||
345 | /* setup handler for GPIO 16 to 31 */ | ||
346 | irq_set_chained_handler(port[i].irq_high, | ||
347 | mx3_gpio_irq_handler); | ||
348 | irq_set_handler_data(port[i].irq_high, | ||
349 | &port[i]); | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | |||
354 | if (cpu_is_mx2()) { | ||
355 | /* setup one handler for all GPIO interrupts */ | ||
356 | irq_set_chained_handler(port[0].irq, mx2_gpio_irq_handler); | ||
357 | irq_set_handler_data(port[0].irq, port); | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | } | ||