diff options
-rw-r--r-- | drivers/gpio/gpio-stmpe.c | 78 |
1 files changed, 47 insertions, 31 deletions
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 522c90ee96e..3e1d39895ce 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/mfd/stmpe.h> @@ -29,6 +30,7 @@ struct stmpe_gpio { struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; + struct irq_domain *domain; int irq_base; unsigned norequest_mask; @@ -104,7 +106,7 @@ static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); - return stmpe_gpio->irq_base + offset; + return irq_create_mapping(stmpe_gpio->domain, offset); } static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -133,7 +135,7 @@ static struct gpio_chip template_chip = { static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - stmpe_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -200,7 +202,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) static void stmpe_gpio_irq_mask(struct irq_data *d) { struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - stmpe_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -210,7 +212,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d) static void stmpe_gpio_irq_unmask(struct irq_data *d) { struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - stmpe_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -252,8 +254,9 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; + int virq = irq_find_mapping(stmpe_gpio->domain, line); - handle_nested_irq(stmpe_gpio->irq_base + line); + handle_nested_irq(virq); stat &= ~(1 << bit); } @@ -268,38 +271,55 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) +int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - int base = stmpe_gpio->irq_base; - int irq; + struct stmpe_gpio *stmpe_gpio = d->host_data; + + if (!stmpe_gpio) + return -EINVAL; - for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { - irq_set_chip_data(irq, stmpe_gpio); - irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); + irq_set_chip_data(hwirq, stmpe_gpio); + irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, + handle_simple_irq); + irq_set_nested_thread(hwirq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(hwirq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(hwirq); #endif - } return 0; } -static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio) +void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) { - int base = stmpe_gpio->irq_base; - int irq; - - for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { #ifdef CONFIG_ARM - set_irq_flags(irq, 0); + set_irq_flags(virq, 0); #endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { + .unmap = stmpe_gpio_irq_unmap, + .map = stmpe_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) +{ + int base = stmpe_gpio->irq_base; + + stmpe_gpio->domain = irq_domain_add_simple(NULL, + stmpe_gpio->chip.ngpio, base, + &stmpe_gpio_irq_simple_ops, stmpe_gpio); + if (!stmpe_gpio->domain) { + dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); + return -ENOSYS; } + + return 0; } static int __devinit stmpe_gpio_probe(struct platform_device *pdev) @@ -354,7 +374,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_removeirq; + goto out_disable; } } @@ -374,9 +394,6 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) out_freeirq: if (irq >= 0) free_irq(irq, stmpe_gpio); -out_removeirq: - if (irq >= 0) - stmpe_gpio_irq_remove(stmpe_gpio); out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); out_free: @@ -404,10 +421,9 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev) stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - if (irq >= 0) { + if (irq >= 0) free_irq(irq, stmpe_gpio); - stmpe_gpio_irq_remove(stmpe_gpio); - } + platform_set_drvdata(pdev, NULL); kfree(stmpe_gpio); |