diff options
Diffstat (limited to 'drivers/gpio/gpio-mxc.c')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c new file mode 100644 index 00000000000..4340acae3bd --- /dev/null +++ b/drivers/gpio/gpio-mxc.c | |||
@@ -0,0 +1,460 @@ | |||
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 <linux/platform_device.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/basic_mmio_gpio.h> | ||
30 | #include <linux/of.h> | ||
31 | #include <linux/of_device.h> | ||
32 | #include <asm-generic/bug.h> | ||
33 | |||
34 | enum mxc_gpio_hwtype { | ||
35 | IMX1_GPIO, /* runs on i.mx1 */ | ||
36 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ | ||
37 | IMX31_GPIO, /* runs on all other i.mx */ | ||
38 | }; | ||
39 | |||
40 | /* device type dependent stuff */ | ||
41 | struct mxc_gpio_hwdata { | ||
42 | unsigned dr_reg; | ||
43 | unsigned gdir_reg; | ||
44 | unsigned psr_reg; | ||
45 | unsigned icr1_reg; | ||
46 | unsigned icr2_reg; | ||
47 | unsigned imr_reg; | ||
48 | unsigned isr_reg; | ||
49 | unsigned low_level; | ||
50 | unsigned high_level; | ||
51 | unsigned rise_edge; | ||
52 | unsigned fall_edge; | ||
53 | }; | ||
54 | |||
55 | struct mxc_gpio_port { | ||
56 | struct list_head node; | ||
57 | void __iomem *base; | ||
58 | int irq; | ||
59 | int irq_high; | ||
60 | int virtual_irq_start; | ||
61 | struct bgpio_chip bgc; | ||
62 | u32 both_edges; | ||
63 | }; | ||
64 | |||
65 | static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { | ||
66 | .dr_reg = 0x1c, | ||
67 | .gdir_reg = 0x00, | ||
68 | .psr_reg = 0x24, | ||
69 | .icr1_reg = 0x28, | ||
70 | .icr2_reg = 0x2c, | ||
71 | .imr_reg = 0x30, | ||
72 | .isr_reg = 0x34, | ||
73 | .low_level = 0x03, | ||
74 | .high_level = 0x02, | ||
75 | .rise_edge = 0x00, | ||
76 | .fall_edge = 0x01, | ||
77 | }; | ||
78 | |||
79 | static struct mxc_gpio_hwdata imx31_gpio_hwdata = { | ||
80 | .dr_reg = 0x00, | ||
81 | .gdir_reg = 0x04, | ||
82 | .psr_reg = 0x08, | ||
83 | .icr1_reg = 0x0c, | ||
84 | .icr2_reg = 0x10, | ||
85 | .imr_reg = 0x14, | ||
86 | .isr_reg = 0x18, | ||
87 | .low_level = 0x00, | ||
88 | .high_level = 0x01, | ||
89 | .rise_edge = 0x02, | ||
90 | .fall_edge = 0x03, | ||
91 | }; | ||
92 | |||
93 | static enum mxc_gpio_hwtype mxc_gpio_hwtype; | ||
94 | static struct mxc_gpio_hwdata *mxc_gpio_hwdata; | ||
95 | |||
96 | #define GPIO_DR (mxc_gpio_hwdata->dr_reg) | ||
97 | #define GPIO_GDIR (mxc_gpio_hwdata->gdir_reg) | ||
98 | #define GPIO_PSR (mxc_gpio_hwdata->psr_reg) | ||
99 | #define GPIO_ICR1 (mxc_gpio_hwdata->icr1_reg) | ||
100 | #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) | ||
101 | #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) | ||
102 | #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) | ||
103 | |||
104 | #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) | ||
105 | #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) | ||
106 | #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) | ||
107 | #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) | ||
108 | #define GPIO_INT_NONE 0x4 | ||
109 | |||
110 | static struct platform_device_id mxc_gpio_devtype[] = { | ||
111 | { | ||
112 | .name = "imx1-gpio", | ||
113 | .driver_data = IMX1_GPIO, | ||
114 | }, { | ||
115 | .name = "imx21-gpio", | ||
116 | .driver_data = IMX21_GPIO, | ||
117 | }, { | ||
118 | .name = "imx31-gpio", | ||
119 | .driver_data = IMX31_GPIO, | ||
120 | }, { | ||
121 | /* sentinel */ | ||
122 | } | ||
123 | }; | ||
124 | |||
125 | static const struct of_device_id mxc_gpio_dt_ids[] = { | ||
126 | { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, | ||
127 | { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, | ||
128 | { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, | ||
129 | { /* sentinel */ } | ||
130 | }; | ||
131 | |||
132 | /* | ||
133 | * MX2 has one interrupt *for all* gpio ports. The list is used | ||
134 | * to save the references to all ports, so that mx2_gpio_irq_handler | ||
135 | * can walk through all interrupt status registers. | ||
136 | */ | ||
137 | static LIST_HEAD(mxc_gpio_ports); | ||
138 | |||
139 | /* Note: This driver assumes 32 GPIOs are handled in one register */ | ||
140 | |||
141 | static int gpio_set_irq_type(struct irq_data *d, u32 type) | ||
142 | { | ||
143 | u32 gpio = irq_to_gpio(d->irq); | ||
144 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
145 | struct mxc_gpio_port *port = gc->private; | ||
146 | u32 bit, val; | ||
147 | int edge; | ||
148 | void __iomem *reg = port->base; | ||
149 | |||
150 | port->both_edges &= ~(1 << (gpio & 31)); | ||
151 | switch (type) { | ||
152 | case IRQ_TYPE_EDGE_RISING: | ||
153 | edge = GPIO_INT_RISE_EDGE; | ||
154 | break; | ||
155 | case IRQ_TYPE_EDGE_FALLING: | ||
156 | edge = GPIO_INT_FALL_EDGE; | ||
157 | break; | ||
158 | case IRQ_TYPE_EDGE_BOTH: | ||
159 | val = gpio_get_value(gpio); | ||
160 | if (val) { | ||
161 | edge = GPIO_INT_LOW_LEV; | ||
162 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
163 | } else { | ||
164 | edge = GPIO_INT_HIGH_LEV; | ||
165 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | ||
166 | } | ||
167 | port->both_edges |= 1 << (gpio & 31); | ||
168 | break; | ||
169 | case IRQ_TYPE_LEVEL_LOW: | ||
170 | edge = GPIO_INT_LOW_LEV; | ||
171 | break; | ||
172 | case IRQ_TYPE_LEVEL_HIGH: | ||
173 | edge = GPIO_INT_HIGH_LEV; | ||
174 | break; | ||
175 | default: | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | ||
180 | bit = gpio & 0xf; | ||
181 | val = readl(reg) & ~(0x3 << (bit << 1)); | ||
182 | writel(val | (edge << (bit << 1)), reg); | ||
183 | writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) | ||
189 | { | ||
190 | void __iomem *reg = port->base; | ||
191 | u32 bit, val; | ||
192 | int edge; | ||
193 | |||
194 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | ||
195 | bit = gpio & 0xf; | ||
196 | val = readl(reg); | ||
197 | edge = (val >> (bit << 1)) & 3; | ||
198 | val &= ~(0x3 << (bit << 1)); | ||
199 | if (edge == GPIO_INT_HIGH_LEV) { | ||
200 | edge = GPIO_INT_LOW_LEV; | ||
201 | pr_debug("mxc: switch GPIO %d to low trigger\n", gpio); | ||
202 | } else if (edge == GPIO_INT_LOW_LEV) { | ||
203 | edge = GPIO_INT_HIGH_LEV; | ||
204 | pr_debug("mxc: switch GPIO %d to high trigger\n", gpio); | ||
205 | } else { | ||
206 | pr_err("mxc: invalid configuration for GPIO %d: %x\n", | ||
207 | gpio, edge); | ||
208 | return; | ||
209 | } | ||
210 | writel(val | (edge << (bit << 1)), reg); | ||
211 | } | ||
212 | |||
213 | /* handle 32 interrupts in one status register */ | ||
214 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) | ||
215 | { | ||
216 | u32 gpio_irq_no_base = port->virtual_irq_start; | ||
217 | |||
218 | while (irq_stat != 0) { | ||
219 | int irqoffset = fls(irq_stat) - 1; | ||
220 | |||
221 | if (port->both_edges & (1 << irqoffset)) | ||
222 | mxc_flip_edge(port, irqoffset); | ||
223 | |||
224 | generic_handle_irq(gpio_irq_no_base + irqoffset); | ||
225 | |||
226 | irq_stat &= ~(1 << irqoffset); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /* MX1 and MX3 has one interrupt *per* gpio port */ | ||
231 | static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) | ||
232 | { | ||
233 | u32 irq_stat; | ||
234 | struct mxc_gpio_port *port = irq_get_handler_data(irq); | ||
235 | |||
236 | irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR); | ||
237 | |||
238 | mxc_gpio_irq_handler(port, irq_stat); | ||
239 | } | ||
240 | |||
241 | /* MX2 has one interrupt *for all* gpio ports */ | ||
242 | static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) | ||
243 | { | ||
244 | u32 irq_msk, irq_stat; | ||
245 | struct mxc_gpio_port *port; | ||
246 | |||
247 | /* walk through all interrupt status registers */ | ||
248 | list_for_each_entry(port, &mxc_gpio_ports, node) { | ||
249 | irq_msk = readl(port->base + GPIO_IMR); | ||
250 | if (!irq_msk) | ||
251 | continue; | ||
252 | |||
253 | irq_stat = readl(port->base + GPIO_ISR) & irq_msk; | ||
254 | if (irq_stat) | ||
255 | mxc_gpio_irq_handler(port, irq_stat); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Set interrupt number "irq" in the GPIO as a wake-up source. | ||
261 | * While system is running, all registered GPIO interrupts need to have | ||
262 | * wake-up enabled. When system is suspended, only selected GPIO interrupts | ||
263 | * need to have wake-up enabled. | ||
264 | * @param irq interrupt source number | ||
265 | * @param enable enable as wake-up if equal to non-zero | ||
266 | * @return This function returns 0 on success. | ||
267 | */ | ||
268 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) | ||
269 | { | ||
270 | u32 gpio = irq_to_gpio(d->irq); | ||
271 | u32 gpio_idx = gpio & 0x1F; | ||
272 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
273 | struct mxc_gpio_port *port = gc->private; | ||
274 | |||
275 | if (enable) { | ||
276 | if (port->irq_high && (gpio_idx >= 16)) | ||
277 | enable_irq_wake(port->irq_high); | ||
278 | else | ||
279 | enable_irq_wake(port->irq); | ||
280 | } else { | ||
281 | if (port->irq_high && (gpio_idx >= 16)) | ||
282 | disable_irq_wake(port->irq_high); | ||
283 | else | ||
284 | disable_irq_wake(port->irq); | ||
285 | } | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port) | ||
291 | { | ||
292 | struct irq_chip_generic *gc; | ||
293 | struct irq_chip_type *ct; | ||
294 | |||
295 | gc = irq_alloc_generic_chip("gpio-mxc", 1, port->virtual_irq_start, | ||
296 | port->base, handle_level_irq); | ||
297 | gc->private = port; | ||
298 | |||
299 | ct = gc->chip_types; | ||
300 | ct->chip.irq_ack = irq_gc_ack_set_bit; | ||
301 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||
302 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||
303 | ct->chip.irq_set_type = gpio_set_irq_type; | ||
304 | ct->chip.irq_set_wake = gpio_set_wake_irq; | ||
305 | ct->regs.ack = GPIO_ISR; | ||
306 | ct->regs.mask = GPIO_IMR; | ||
307 | |||
308 | irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, | ||
309 | IRQ_NOREQUEST, 0); | ||
310 | } | ||
311 | |||
312 | static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) | ||
313 | { | ||
314 | const struct of_device_id *of_id = | ||
315 | of_match_device(mxc_gpio_dt_ids, &pdev->dev); | ||
316 | enum mxc_gpio_hwtype hwtype; | ||
317 | |||
318 | if (of_id) | ||
319 | pdev->id_entry = of_id->data; | ||
320 | hwtype = pdev->id_entry->driver_data; | ||
321 | |||
322 | if (mxc_gpio_hwtype) { | ||
323 | /* | ||
324 | * The driver works with a reasonable presupposition, | ||
325 | * that is all gpio ports must be the same type when | ||
326 | * running on one soc. | ||
327 | */ | ||
328 | BUG_ON(mxc_gpio_hwtype != hwtype); | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | if (hwtype == IMX31_GPIO) | ||
333 | mxc_gpio_hwdata = &imx31_gpio_hwdata; | ||
334 | else | ||
335 | mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; | ||
336 | |||
337 | mxc_gpio_hwtype = hwtype; | ||
338 | } | ||
339 | |||
340 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) | ||
341 | { | ||
342 | struct device_node *np = pdev->dev.of_node; | ||
343 | struct mxc_gpio_port *port; | ||
344 | struct resource *iores; | ||
345 | int err; | ||
346 | |||
347 | mxc_gpio_get_hw(pdev); | ||
348 | |||
349 | port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL); | ||
350 | if (!port) | ||
351 | return -ENOMEM; | ||
352 | |||
353 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
354 | if (!iores) { | ||
355 | err = -ENODEV; | ||
356 | goto out_kfree; | ||
357 | } | ||
358 | |||
359 | if (!request_mem_region(iores->start, resource_size(iores), | ||
360 | pdev->name)) { | ||
361 | err = -EBUSY; | ||
362 | goto out_kfree; | ||
363 | } | ||
364 | |||
365 | port->base = ioremap(iores->start, resource_size(iores)); | ||
366 | if (!port->base) { | ||
367 | err = -ENOMEM; | ||
368 | goto out_release_mem; | ||
369 | } | ||
370 | |||
371 | port->irq_high = platform_get_irq(pdev, 1); | ||
372 | port->irq = platform_get_irq(pdev, 0); | ||
373 | if (port->irq < 0) { | ||
374 | err = -EINVAL; | ||
375 | goto out_iounmap; | ||
376 | } | ||
377 | |||
378 | /* disable the interrupt and clear the status */ | ||
379 | writel(0, port->base + GPIO_IMR); | ||
380 | writel(~0, port->base + GPIO_ISR); | ||
381 | |||
382 | if (mxc_gpio_hwtype == IMX21_GPIO) { | ||
383 | /* setup one handler for all GPIO interrupts */ | ||
384 | if (pdev->id == 0) | ||
385 | irq_set_chained_handler(port->irq, | ||
386 | mx2_gpio_irq_handler); | ||
387 | } else { | ||
388 | /* setup one handler for each entry */ | ||
389 | irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); | ||
390 | irq_set_handler_data(port->irq, port); | ||
391 | if (port->irq_high > 0) { | ||
392 | /* setup handler for GPIO 16 to 31 */ | ||
393 | irq_set_chained_handler(port->irq_high, | ||
394 | mx3_gpio_irq_handler); | ||
395 | irq_set_handler_data(port->irq_high, port); | ||
396 | } | ||
397 | } | ||
398 | |||
399 | err = bgpio_init(&port->bgc, &pdev->dev, 4, | ||
400 | port->base + GPIO_PSR, | ||
401 | port->base + GPIO_DR, NULL, | ||
402 | port->base + GPIO_GDIR, NULL, false); | ||
403 | if (err) | ||
404 | goto out_iounmap; | ||
405 | |||
406 | port->bgc.gc.base = pdev->id * 32; | ||
407 | port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); | ||
408 | port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); | ||
409 | |||
410 | err = gpiochip_add(&port->bgc.gc); | ||
411 | if (err) | ||
412 | goto out_bgpio_remove; | ||
413 | |||
414 | /* | ||
415 | * In dt case, we use gpio number range dynamically | ||
416 | * allocated by gpio core. | ||
417 | */ | ||
418 | port->virtual_irq_start = MXC_GPIO_IRQ_START + (np ? port->bgc.gc.base : | ||
419 | pdev->id * 32); | ||
420 | |||
421 | /* gpio-mxc can be a generic irq chip */ | ||
422 | mxc_gpio_init_gc(port); | ||
423 | |||
424 | list_add_tail(&port->node, &mxc_gpio_ports); | ||
425 | |||
426 | return 0; | ||
427 | |||
428 | out_bgpio_remove: | ||
429 | bgpio_remove(&port->bgc); | ||
430 | out_iounmap: | ||
431 | iounmap(port->base); | ||
432 | out_release_mem: | ||
433 | release_mem_region(iores->start, resource_size(iores)); | ||
434 | out_kfree: | ||
435 | kfree(port); | ||
436 | dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); | ||
437 | return err; | ||
438 | } | ||
439 | |||
440 | static struct platform_driver mxc_gpio_driver = { | ||
441 | .driver = { | ||
442 | .name = "gpio-mxc", | ||
443 | .owner = THIS_MODULE, | ||
444 | .of_match_table = mxc_gpio_dt_ids, | ||
445 | }, | ||
446 | .probe = mxc_gpio_probe, | ||
447 | .id_table = mxc_gpio_devtype, | ||
448 | }; | ||
449 | |||
450 | static int __init gpio_mxc_init(void) | ||
451 | { | ||
452 | return platform_driver_register(&mxc_gpio_driver); | ||
453 | } | ||
454 | postcore_initcall(gpio_mxc_init); | ||
455 | |||
456 | MODULE_AUTHOR("Freescale Semiconductor, " | ||
457 | "Daniel Mack <danielncaiaq.de>, " | ||
458 | "Juergen Beisert <kernel@pengutronix.de>"); | ||
459 | MODULE_DESCRIPTION("Freescale MXC GPIO"); | ||
460 | MODULE_LICENSE("GPL"); | ||