|
@@ -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);
|
|
|
|