diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2012-10-17 18:31:20 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-11-11 19:06:02 +0100 |
commit | a6c45b99a658521291cfb66ecf035cc58b38f206 (patch) | |
tree | 965842ac249c2b786c54d0fab12008276f419121 /drivers/pinctrl/pinctrl-coh901.c | |
parent | d4a31ee8997b2fbd82837182363cf8fa84abf347 (diff) |
pinctrl/coh901: use irqdomain, allocate irqdescs
This switches the COH 901 pinctrl driver to allocate its GPIO
IRQs dynamically, and start to use a linear irqdomain to map
from the hardware IRQs.
This way we can cut away the complex allocation of IRQ numbers
from the <mach/irqs.h> file.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinctrl-coh901.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-coh901.c | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index b446c964121..152efae3df8 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/io.h> +#include <linux/irqdomain.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/platform_device.h> @@ -67,7 +68,6 @@ struct u300_gpio { struct resource *memres; void __iomem *base; struct device *dev; - int irq_base; u32 stride; /* Register offsets */ u32 pcr; @@ -83,6 +83,7 @@ struct u300_gpio_port { struct list_head node; struct u300_gpio *gpio; char name[8]; + struct irq_domain *domain; int irq; int number; u8 toggle_edge_mode; @@ -314,10 +315,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct u300_gpio *gpio = to_u300_gpio(chip); - int retirq = gpio->irq_base + offset; + int portno = offset >> 3; + struct u300_gpio_port *port = NULL; + struct list_head *p; + int retirq; - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, - retirq); + list_for_each(p, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + if (port->number == portno) + break; + } + if (port == NULL) { + dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", + offset); + return -EINVAL; + } + + /* + * The local hwirqs on the port are the lower three bits, there + * are exactly 8 IRQs per port since they are 8-bit + */ + retirq = irq_find_mapping(port->domain, (offset & 0x7)); + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", + offset, retirq, port->number); return retirq; } @@ -467,7 +488,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -503,10 +524,12 @@ static void u300_gpio_irq_enable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; + dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", + d->hwirq, port->name, offset); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -517,7 +540,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; @@ -555,8 +578,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = gpio->irq_base + (port->number << 3) - + irqoffset; + int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", @@ -631,6 +653,8 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio) list_for_each_safe(p, n, &gpio->port_list) { port = list_entry(p, struct u300_gpio_port, node); list_del(&port->node); + if (port->domain) + irq_domain_remove(port->domain); kfree(port); } } @@ -653,7 +677,6 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; - gpio->irq_base = plat->gpio_irq_base; gpio->chip.dev = &pdev->dev; gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; @@ -732,18 +755,26 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq_byname(pdev, port->name); - dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, port->name); + port->domain = irq_domain_add_linear(pdev->dev.of_node, + U300_GPIO_PINS_PER_PORT, + &irq_domain_simple_ops, + port); + if (!port->domain) + goto err_no_domain; + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); irq_set_handler_data(port->irq, port); /* For each GPIO pin set the unique IRQ handler */ for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = gpio->irq_base + (portno << 3) + i; + int irqno = irq_create_mapping(port->domain, i); - dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", - irqno, port->name); + dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", + gpio->chip.base + (port->number << 3) + i, + port->name, irqno); irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, handle_simple_irq); set_irq_flags(irqno, IRQF_VALID); @@ -776,6 +807,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev) err_no_pinctrl: err = gpiochip_remove(&gpio->chip); err_no_chip: +err_no_domain: err_no_port: u300_gpio_free_ports(gpio); iounmap(gpio->base); |