diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2012-06-12 21:04:03 -0400 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2012-07-01 09:57:22 -0400 |
commit | 1ab7ef158dfbaf6314b6660a3e3fb037cba2a1ca (patch) | |
tree | 185ffbcf9922139023bcc282ac37b2626a79facb /drivers/gpio/gpio-mxc.c | |
parent | 438196c371cb32f0eacaf2a44166d9a0cf37c4a8 (diff) |
gpio/mxc: move irq_domain_add_legacy call into gpio driver
Move irq_domain_add_legacy call from imx*-dt.c into gpio driver and
have the gpio driver adopt irqdomain support for both DT and non-DT
boot.
With all imx platform code converted from static gpio irq number
computation to use run-time gpio_to_irq call, we can now use
irq_alloc_descs and irqdomain support to dynamically get irq_base
and have the mapping between gpio and irq number available without
using virtual_irq_start and MXC_GPIO_IRQ_START.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-mxc.c')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 56 |
1 files changed, 32 insertions, 24 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c337143b18f8..e5db670d0002 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,8 +34,6 @@ | |||
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 */ |
@@ -61,7 +60,7 @@ struct mxc_gpio_port { | |||
61 | void __iomem *base; | 60 | void __iomem *base; |
62 | int irq; | 61 | int irq; |
63 | int irq_high; | 62 | int irq_high; |
64 | int virtual_irq_start; | 63 | struct irq_domain *domain; |
65 | struct bgpio_chip bgc; | 64 | struct bgpio_chip bgc; |
66 | u32 both_edges; | 65 | u32 both_edges; |
67 | }; | 66 | }; |
@@ -144,14 +143,15 @@ static LIST_HEAD(mxc_gpio_ports); | |||
144 | 143 | ||
145 | static int gpio_set_irq_type(struct irq_data *d, u32 type) | 144 | static int gpio_set_irq_type(struct irq_data *d, u32 type) |
146 | { | 145 | { |
147 | u32 gpio = irq_to_gpio(d->irq); | ||
148 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | 146 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
149 | struct mxc_gpio_port *port = gc->private; | 147 | struct mxc_gpio_port *port = gc->private; |
150 | u32 bit, val; | 148 | u32 bit, val; |
149 | u32 gpio_idx = d->hwirq; | ||
150 | u32 gpio = port->bgc.gc.base + gpio_idx; | ||
151 | int edge; | 151 | int edge; |
152 | void __iomem *reg = port->base; | 152 | void __iomem *reg = port->base; |
153 | 153 | ||
154 | port->both_edges &= ~(1 << (gpio & 31)); | 154 | port->both_edges &= ~(1 << gpio_idx); |
155 | switch (type) { | 155 | switch (type) { |
156 | case IRQ_TYPE_EDGE_RISING: | 156 | case IRQ_TYPE_EDGE_RISING: |
157 | edge = GPIO_INT_RISE_EDGE; | 157 | edge = GPIO_INT_RISE_EDGE; |
@@ -168,7 +168,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) | |||
168 | edge = GPIO_INT_HIGH_LEV; | 168 | edge = GPIO_INT_HIGH_LEV; |
169 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | 169 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); |
170 | } | 170 | } |
171 | port->both_edges |= 1 << (gpio & 31); | 171 | port->both_edges |= 1 << gpio_idx; |
172 | break; | 172 | break; |
173 | case IRQ_TYPE_LEVEL_LOW: | 173 | case IRQ_TYPE_LEVEL_LOW: |
174 | edge = GPIO_INT_LOW_LEV; | 174 | edge = GPIO_INT_LOW_LEV; |
@@ -180,11 +180,11 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) | |||
180 | return -EINVAL; | 180 | return -EINVAL; |
181 | } | 181 | } |
182 | 182 | ||
183 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | 183 | reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* ICR1 or ICR2 */ |
184 | bit = gpio & 0xf; | 184 | bit = gpio_idx & 0xf; |
185 | val = readl(reg) & ~(0x3 << (bit << 1)); | 185 | val = readl(reg) & ~(0x3 << (bit << 1)); |
186 | writel(val | (edge << (bit << 1)), reg); | 186 | writel(val | (edge << (bit << 1)), reg); |
187 | writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); | 187 | writel(1 << gpio_idx, port->base + GPIO_ISR); |
188 | 188 | ||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
@@ -217,15 +217,13 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) | |||
217 | /* handle 32 interrupts in one status register */ | 217 | /* handle 32 interrupts in one status register */ |
218 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) | 218 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) |
219 | { | 219 | { |
220 | u32 gpio_irq_no_base = port->virtual_irq_start; | ||
221 | |||
222 | while (irq_stat != 0) { | 220 | while (irq_stat != 0) { |
223 | int irqoffset = fls(irq_stat) - 1; | 221 | int irqoffset = fls(irq_stat) - 1; |
224 | 222 | ||
225 | if (port->both_edges & (1 << irqoffset)) | 223 | if (port->both_edges & (1 << irqoffset)) |
226 | mxc_flip_edge(port, irqoffset); | 224 | mxc_flip_edge(port, irqoffset); |
227 | 225 | ||
228 | generic_handle_irq(gpio_irq_no_base + irqoffset); | 226 | generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); |
229 | 227 | ||
230 | irq_stat &= ~(1 << irqoffset); | 228 | irq_stat &= ~(1 << irqoffset); |
231 | } | 229 | } |
@@ -276,10 +274,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) | |||
276 | */ | 274 | */ |
277 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) | 275 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) |
278 | { | 276 | { |
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); | 277 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
282 | struct mxc_gpio_port *port = gc->private; | 278 | struct mxc_gpio_port *port = gc->private; |
279 | u32 gpio_idx = d->hwirq; | ||
283 | 280 | ||
284 | if (enable) { | 281 | if (enable) { |
285 | if (port->irq_high && (gpio_idx >= 16)) | 282 | if (port->irq_high && (gpio_idx >= 16)) |
@@ -296,12 +293,12 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) | |||
296 | return 0; | 293 | return 0; |
297 | } | 294 | } |
298 | 295 | ||
299 | static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port) | 296 | static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) |
300 | { | 297 | { |
301 | struct irq_chip_generic *gc; | 298 | struct irq_chip_generic *gc; |
302 | struct irq_chip_type *ct; | 299 | struct irq_chip_type *ct; |
303 | 300 | ||
304 | gc = irq_alloc_generic_chip("gpio-mxc", 1, port->virtual_irq_start, | 301 | gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, |
305 | port->base, handle_level_irq); | 302 | port->base, handle_level_irq); |
306 | gc->private = port; | 303 | gc->private = port; |
307 | 304 | ||
@@ -352,7 +349,7 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | |||
352 | struct mxc_gpio_port *port = | 349 | struct mxc_gpio_port *port = |
353 | container_of(bgc, struct mxc_gpio_port, bgc); | 350 | container_of(bgc, struct mxc_gpio_port, bgc); |
354 | 351 | ||
355 | return port->virtual_irq_start + offset; | 352 | return irq_find_mapping(port->domain, offset); |
356 | } | 353 | } |
357 | 354 | ||
358 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) | 355 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) |
@@ -360,6 +357,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) | |||
360 | struct device_node *np = pdev->dev.of_node; | 357 | struct device_node *np = pdev->dev.of_node; |
361 | struct mxc_gpio_port *port; | 358 | struct mxc_gpio_port *port; |
362 | struct resource *iores; | 359 | struct resource *iores; |
360 | int irq_base; | ||
363 | int err; | 361 | int err; |
364 | 362 | ||
365 | mxc_gpio_get_hw(pdev); | 363 | mxc_gpio_get_hw(pdev); |
@@ -430,20 +428,30 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) | |||
430 | if (err) | 428 | if (err) |
431 | goto out_bgpio_remove; | 429 | goto out_bgpio_remove; |
432 | 430 | ||
433 | /* | 431 | irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); |
434 | * In dt case, we use gpio number range dynamically | 432 | if (irq_base < 0) { |
435 | * allocated by gpio core. | 433 | err = irq_base; |
436 | */ | 434 | goto out_gpiochip_remove; |
437 | port->virtual_irq_start = MXC_GPIO_IRQ_START + (np ? port->bgc.gc.base : | 435 | } |
438 | pdev->id * 32); | 436 | |
437 | port->domain = irq_domain_add_legacy(np, 32, irq_base, 0, | ||
438 | &irq_domain_simple_ops, NULL); | ||
439 | if (!port->domain) { | ||
440 | err = -ENODEV; | ||
441 | goto out_irqdesc_free; | ||
442 | } | ||
439 | 443 | ||
440 | /* gpio-mxc can be a generic irq chip */ | 444 | /* gpio-mxc can be a generic irq chip */ |
441 | mxc_gpio_init_gc(port); | 445 | mxc_gpio_init_gc(port, irq_base); |
442 | 446 | ||
443 | list_add_tail(&port->node, &mxc_gpio_ports); | 447 | list_add_tail(&port->node, &mxc_gpio_ports); |
444 | 448 | ||
445 | return 0; | 449 | return 0; |
446 | 450 | ||
451 | out_irqdesc_free: | ||
452 | irq_free_descs(irq_base, 32); | ||
453 | out_gpiochip_remove: | ||
454 | WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); | ||
447 | out_bgpio_remove: | 455 | out_bgpio_remove: |
448 | bgpio_remove(&port->bgc); | 456 | bgpio_remove(&port->bgc); |
449 | out_iounmap: | 457 | out_iounmap: |