diff options
Diffstat (limited to 'drivers/gpio/gpio-mxc.c')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 136 |
1 files changed, 94 insertions, 42 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c337143b18f8..80f44bb64a87 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | #include <linux/irqdomain.h> | ||
26 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
@@ -33,12 +34,11 @@ | |||
33 | #include <asm-generic/bug.h> | 34 | #include <asm-generic/bug.h> |
34 | #include <asm/mach/irq.h> | 35 | #include <asm/mach/irq.h> |
35 | 36 | ||
36 | #define irq_to_gpio(irq) ((irq) - MXC_GPIO_IRQ_START) | ||
37 | |||
38 | enum mxc_gpio_hwtype { | 37 | enum mxc_gpio_hwtype { |
39 | IMX1_GPIO, /* runs on i.mx1 */ | 38 | IMX1_GPIO, /* runs on i.mx1 */ |
40 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ | 39 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ |
41 | IMX31_GPIO, /* runs on all other i.mx */ | 40 | IMX31_GPIO, /* runs on i.mx31 */ |
41 | IMX35_GPIO, /* runs on all other i.mx */ | ||
42 | }; | 42 | }; |
43 | 43 | ||
44 | /* device type dependent stuff */ | 44 | /* device type dependent stuff */ |
@@ -50,6 +50,7 @@ struct mxc_gpio_hwdata { | |||
50 | unsigned icr2_reg; | 50 | unsigned icr2_reg; |
51 | unsigned imr_reg; | 51 | unsigned imr_reg; |
52 | unsigned isr_reg; | 52 | unsigned isr_reg; |
53 | int edge_sel_reg; | ||
53 | unsigned low_level; | 54 | unsigned low_level; |
54 | unsigned high_level; | 55 | unsigned high_level; |
55 | unsigned rise_edge; | 56 | unsigned rise_edge; |
@@ -61,7 +62,7 @@ struct mxc_gpio_port { | |||
61 | void __iomem *base; | 62 | void __iomem *base; |
62 | int irq; | 63 | int irq; |
63 | int irq_high; | 64 | int irq_high; |
64 | int virtual_irq_start; | 65 | struct irq_domain *domain; |
65 | struct bgpio_chip bgc; | 66 | struct bgpio_chip bgc; |
66 | u32 both_edges; | 67 | u32 both_edges; |
67 | }; | 68 | }; |
@@ -74,6 +75,7 @@ static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { | |||
74 | .icr2_reg = 0x2c, | 75 | .icr2_reg = 0x2c, |
75 | .imr_reg = 0x30, | 76 | .imr_reg = 0x30, |
76 | .isr_reg = 0x34, | 77 | .isr_reg = 0x34, |
78 | .edge_sel_reg = -EINVAL, | ||
77 | .low_level = 0x03, | 79 | .low_level = 0x03, |
78 | .high_level = 0x02, | 80 | .high_level = 0x02, |
79 | .rise_edge = 0x00, | 81 | .rise_edge = 0x00, |
@@ -88,6 +90,22 @@ static struct mxc_gpio_hwdata imx31_gpio_hwdata = { | |||
88 | .icr2_reg = 0x10, | 90 | .icr2_reg = 0x10, |
89 | .imr_reg = 0x14, | 91 | .imr_reg = 0x14, |
90 | .isr_reg = 0x18, | 92 | .isr_reg = 0x18, |
93 | .edge_sel_reg = -EINVAL, | ||
94 | .low_level = 0x00, | ||
95 | .high_level = 0x01, | ||
96 | .rise_edge = 0x02, | ||
97 | .fall_edge = 0x03, | ||
98 | }; | ||
99 | |||
100 | static struct mxc_gpio_hwdata imx35_gpio_hwdata = { | ||
101 | .dr_reg = 0x00, | ||
102 | .gdir_reg = 0x04, | ||
103 | .psr_reg = 0x08, | ||
104 | .icr1_reg = 0x0c, | ||
105 | .icr2_reg = 0x10, | ||
106 | .imr_reg = 0x14, | ||
107 | .isr_reg = 0x18, | ||
108 | .edge_sel_reg = 0x1c, | ||
91 | .low_level = 0x00, | 109 | .low_level = 0x00, |
92 | .high_level = 0x01, | 110 | .high_level = 0x01, |
93 | .rise_edge = 0x02, | 111 | .rise_edge = 0x02, |
@@ -104,12 +122,13 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata; | |||
104 | #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) | 122 | #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) |
105 | #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) | 123 | #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) |
106 | #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) | 124 | #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) |
125 | #define GPIO_EDGE_SEL (mxc_gpio_hwdata->edge_sel_reg) | ||
107 | 126 | ||
108 | #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) | 127 | #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) |
109 | #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) | 128 | #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) |
110 | #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) | 129 | #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) |
111 | #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) | 130 | #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) |
112 | #define GPIO_INT_NONE 0x4 | 131 | #define GPIO_INT_BOTH_EDGES 0x4 |
113 | 132 | ||
114 | static struct platform_device_id mxc_gpio_devtype[] = { | 133 | static struct platform_device_id mxc_gpio_devtype[] = { |
115 | { | 134 | { |
@@ -122,6 +141,9 @@ static struct platform_device_id mxc_gpio_devtype[] = { | |||
122 | .name = "imx31-gpio", | 141 | .name = "imx31-gpio", |
123 | .driver_data = IMX31_GPIO, | 142 | .driver_data = IMX31_GPIO, |
124 | }, { | 143 | }, { |
144 | .name = "imx35-gpio", | ||
145 | .driver_data = IMX35_GPIO, | ||
146 | }, { | ||
125 | /* sentinel */ | 147 | /* sentinel */ |
126 | } | 148 | } |
127 | }; | 149 | }; |
@@ -130,6 +152,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { | |||
130 | { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, | 152 | { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, |
131 | { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, | 153 | { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, |
132 | { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, | 154 | { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, |
155 | { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, | ||
133 | { /* sentinel */ } | 156 | { /* sentinel */ } |
134 | }; | 157 | }; |
135 | 158 | ||
@@ -144,14 +167,15 @@ static LIST_HEAD(mxc_gpio_ports); | |||
144 | 167 | ||
145 | static int gpio_set_irq_type(struct irq_data *d, u32 type) | 168 | static int gpio_set_irq_type(struct irq_data *d, u32 type) |
146 | { | 169 | { |
147 | u32 gpio = irq_to_gpio(d->irq); | ||
148 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | 170 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
149 | struct mxc_gpio_port *port = gc->private; | 171 | struct mxc_gpio_port *port = gc->private; |
150 | u32 bit, val; | 172 | u32 bit, val; |
173 | u32 gpio_idx = d->hwirq; | ||
174 | u32 gpio = port->bgc.gc.base + gpio_idx; | ||
151 | int edge; | 175 | int edge; |
152 | void __iomem *reg = port->base; | 176 | void __iomem *reg = port->base; |
153 | 177 | ||
154 | port->both_edges &= ~(1 << (gpio & 31)); | 178 | port->both_edges &= ~(1 << gpio_idx); |
155 | switch (type) { | 179 | switch (type) { |
156 | case IRQ_TYPE_EDGE_RISING: | 180 | case IRQ_TYPE_EDGE_RISING: |
157 | edge = GPIO_INT_RISE_EDGE; | 181 | edge = GPIO_INT_RISE_EDGE; |
@@ -160,15 +184,19 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) | |||
160 | edge = GPIO_INT_FALL_EDGE; | 184 | edge = GPIO_INT_FALL_EDGE; |
161 | break; | 185 | break; |
162 | case IRQ_TYPE_EDGE_BOTH: | 186 | case IRQ_TYPE_EDGE_BOTH: |
163 | val = gpio_get_value(gpio); | 187 | if (GPIO_EDGE_SEL >= 0) { |
164 | if (val) { | 188 | edge = GPIO_INT_BOTH_EDGES; |
165 | edge = GPIO_INT_LOW_LEV; | ||
166 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
167 | } else { | 189 | } else { |
168 | edge = GPIO_INT_HIGH_LEV; | 190 | val = gpio_get_value(gpio); |
169 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | 191 | if (val) { |
192 | edge = GPIO_INT_LOW_LEV; | ||
193 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
194 | } else { | ||
195 | edge = GPIO_INT_HIGH_LEV; | ||
196 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | ||
197 | } | ||
198 | port->both_edges |= 1 << gpio_idx; | ||
170 | } | 199 | } |
171 | port->both_edges |= 1 << (gpio & 31); | ||
172 | break; | 200 | break; |
173 | case IRQ_TYPE_LEVEL_LOW: | 201 | case IRQ_TYPE_LEVEL_LOW: |
174 | edge = GPIO_INT_LOW_LEV; | 202 | edge = GPIO_INT_LOW_LEV; |
@@ -180,11 +208,24 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) | |||
180 | return -EINVAL; | 208 | return -EINVAL; |
181 | } | 209 | } |
182 | 210 | ||
183 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | 211 | if (GPIO_EDGE_SEL >= 0) { |
184 | bit = gpio & 0xf; | 212 | val = readl(port->base + GPIO_EDGE_SEL); |
185 | val = readl(reg) & ~(0x3 << (bit << 1)); | 213 | if (edge == GPIO_INT_BOTH_EDGES) |
186 | writel(val | (edge << (bit << 1)), reg); | 214 | writel(val | (1 << gpio_idx), |
187 | writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); | 215 | port->base + GPIO_EDGE_SEL); |
216 | else | ||
217 | writel(val & ~(1 << gpio_idx), | ||
218 | port->base + GPIO_EDGE_SEL); | ||
219 | } | ||
220 | |||
221 | if (edge != GPIO_INT_BOTH_EDGES) { | ||
222 | reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ | ||
223 | bit = gpio_idx & 0xf; | ||
224 | val = readl(reg) & ~(0x3 << (bit << 1)); | ||
225 | writel(val | (edge << (bit << 1)), reg); | ||
226 | } | ||
227 | |||
228 | writel(1 << gpio_idx, port->base + GPIO_ISR); | ||
188 | 229 | ||
189 | return 0; | 230 | return 0; |
190 | } | 231 | } |
@@ -217,15 +258,13 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) | |||
217 | /* handle 32 interrupts in one status register */ | 258 | /* handle 32 interrupts in one status register */ |
218 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) | 259 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) |
219 | { | 260 | { |
220 | u32 gpio_irq_no_base = port->virtual_irq_start; | ||
221 | |||
222 | while (irq_stat != 0) { | 261 | while (irq_stat != 0) { |
223 | int irqoffset = fls(irq_stat) - 1; | 262 | int irqoffset = fls(irq_stat) - 1; |
224 | 263 | ||
225 | if (port->both_edges & (1 << irqoffset)) | 264 | if (port->both_edges & (1 << irqoffset)) |
226 | mxc_flip_edge(port, irqoffset); | 265 | mxc_flip_edge(port, irqoffset); |
227 | 266 | ||
228 | generic_handle_irq(gpio_irq_no_base + irqoffset); | 267 | generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); |
229 | 268 | ||
230 | irq_stat &= ~(1 << irqoffset); | 269 | irq_stat &= ~(1 << irqoffset); |
231 | } | 270 | } |
@@ -276,10 +315,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) | |||
276 | */ | 315 | */ |
277 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) | 316 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) |
278 | { | 317 | { |
279 | u32 gpio = irq_to_gpio(d->irq); | ||
280 | u32 gpio_idx = gpio & 0x1F; | ||
281 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | 318 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
282 | struct mxc_gpio_port *port = gc->private; | 319 | struct mxc_gpio_port *port = gc->private; |
320 | u32 gpio_idx = d->hwirq; | ||
283 | 321 | ||
284 | if (enable) { | 322 | if (enable) { |
285 | if (port->irq_high && (gpio_idx >= 16)) | 323 | if (port->irq_high && (gpio_idx >= 16)) |
@@ -296,12 +334,12 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) | |||
296 | return 0; | 334 | return 0; |
297 | } | 335 | } |
298 | 336 | ||
299 | static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port) | 337 | static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) |
300 | { | 338 | { |
301 | struct irq_chip_generic *gc; | 339 | struct irq_chip_generic *gc; |
302 | struct irq_chip_type *ct; | 340 | struct irq_chip_type *ct; |
303 | 341 | ||
304 | gc = irq_alloc_generic_chip("gpio-mxc", 1, port->virtual_irq_start, | 342 | gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, |
305 | port->base, handle_level_irq); | 343 | port->base, handle_level_irq); |
306 | gc->private = port; | 344 | gc->private = port; |
307 | 345 | ||
@@ -338,7 +376,9 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) | |||
338 | return; | 376 | return; |
339 | } | 377 | } |
340 | 378 | ||
341 | if (hwtype == IMX31_GPIO) | 379 | if (hwtype == IMX35_GPIO) |
380 | mxc_gpio_hwdata = &imx35_gpio_hwdata; | ||
381 | else if (hwtype == IMX31_GPIO) | ||
342 | mxc_gpio_hwdata = &imx31_gpio_hwdata; | 382 | mxc_gpio_hwdata = &imx31_gpio_hwdata; |
343 | else | 383 | else |
344 | mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; | 384 | mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; |
@@ -352,7 +392,7 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | |||
352 | struct mxc_gpio_port *port = | 392 | struct mxc_gpio_port *port = |
353 | container_of(bgc, struct mxc_gpio_port, bgc); | 393 | container_of(bgc, struct mxc_gpio_port, bgc); |
354 | 394 | ||
355 | return port->virtual_irq_start + offset; | 395 | return irq_find_mapping(port->domain, offset); |
356 | } | 396 | } |
357 | 397 | ||
358 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) | 398 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) |
@@ -360,6 +400,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) | |||
360 | struct device_node *np = pdev->dev.of_node; | 400 | struct device_node *np = pdev->dev.of_node; |
361 | struct mxc_gpio_port *port; | 401 | struct mxc_gpio_port *port; |
362 | struct resource *iores; | 402 | struct resource *iores; |
403 | int irq_base; | ||
363 | int err; | 404 | int err; |
364 | 405 | ||
365 | mxc_gpio_get_hw(pdev); | 406 | mxc_gpio_get_hw(pdev); |
@@ -398,10 +439,12 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) | |||
398 | writel(~0, port->base + GPIO_ISR); | 439 | writel(~0, port->base + GPIO_ISR); |
399 | 440 | ||
400 | if (mxc_gpio_hwtype == IMX21_GPIO) { | 441 | if (mxc_gpio_hwtype == IMX21_GPIO) { |
401 | /* setup one handler for all GPIO interrupts */ | 442 | /* |
402 | if (pdev->id == 0) | 443 | * Setup one handler for all GPIO interrupts. Actually setting |
403 | irq_set_chained_handler(port->irq, | 444 | * the handler is needed only once, but doing it for every port |
404 | mx2_gpio_irq_handler); | 445 | * is more robust and easier. |
446 | */ | ||
447 | irq_set_chained_handler(port->irq, mx2_gpio_irq_handler); | ||
405 | } else { | 448 | } else { |
406 | /* setup one handler for each entry */ | 449 | /* setup one handler for each entry */ |
407 | irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); | 450 | irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); |
@@ -422,28 +465,37 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) | |||
422 | goto out_iounmap; | 465 | goto out_iounmap; |
423 | 466 | ||
424 | port->bgc.gc.to_irq = mxc_gpio_to_irq; | 467 | port->bgc.gc.to_irq = mxc_gpio_to_irq; |
425 | port->bgc.gc.base = pdev->id * 32; | 468 | port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : |
426 | port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); | 469 | pdev->id * 32; |
427 | port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); | ||
428 | 470 | ||
429 | err = gpiochip_add(&port->bgc.gc); | 471 | err = gpiochip_add(&port->bgc.gc); |
430 | if (err) | 472 | if (err) |
431 | goto out_bgpio_remove; | 473 | goto out_bgpio_remove; |
432 | 474 | ||
433 | /* | 475 | irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); |
434 | * In dt case, we use gpio number range dynamically | 476 | if (irq_base < 0) { |
435 | * allocated by gpio core. | 477 | err = irq_base; |
436 | */ | 478 | goto out_gpiochip_remove; |
437 | port->virtual_irq_start = MXC_GPIO_IRQ_START + (np ? port->bgc.gc.base : | 479 | } |
438 | pdev->id * 32); | 480 | |
481 | port->domain = irq_domain_add_legacy(np, 32, irq_base, 0, | ||
482 | &irq_domain_simple_ops, NULL); | ||
483 | if (!port->domain) { | ||
484 | err = -ENODEV; | ||
485 | goto out_irqdesc_free; | ||
486 | } | ||
439 | 487 | ||
440 | /* gpio-mxc can be a generic irq chip */ | 488 | /* gpio-mxc can be a generic irq chip */ |
441 | mxc_gpio_init_gc(port); | 489 | mxc_gpio_init_gc(port, irq_base); |
442 | 490 | ||
443 | list_add_tail(&port->node, &mxc_gpio_ports); | 491 | list_add_tail(&port->node, &mxc_gpio_ports); |
444 | 492 | ||
445 | return 0; | 493 | return 0; |
446 | 494 | ||
495 | out_irqdesc_free: | ||
496 | irq_free_descs(irq_base, 32); | ||
497 | out_gpiochip_remove: | ||
498 | WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); | ||
447 | out_bgpio_remove: | 499 | out_bgpio_remove: |
448 | bgpio_remove(&port->bgc); | 500 | bgpio_remove(&port->bgc); |
449 | out_iounmap: | 501 | out_iounmap: |