aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2018-09-08 11:23:17 +0200
committerLinus Walleij <linus.walleij@linaro.org>2018-09-10 08:56:38 +0200
commit461c1a7d4733d1dfd5c47b040cf32a5e7eefbc6c (patch)
treebf21a1669e7b6c9e30cae1e427aeed2c4daa7d75 /drivers/gpio/gpiolib.c
parentgpiolib: add flag to indicate if the irq is disabled (diff)
downloadlinux-dev-461c1a7d4733d1dfd5c47b040cf32a5e7eefbc6c.tar.xz
linux-dev-461c1a7d4733d1dfd5c47b040cf32a5e7eefbc6c.zip
gpiolib: override irq_enable/disable
When using the gpiolib irqchip helpers install irq_enable/disable hooks for the irqchip to ensure that gpiolib knows when the irq is enabled or disabled, allowing drivers to disable the irq and then use it as an output pin, and later switch the direction to input and re-enable the irq. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e52fa72f13d7..efce534a269b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1826,6 +1826,28 @@ static void gpiochip_irq_relres(struct irq_data *d)
gpiochip_relres_irq(chip, d->hwirq);
}
+static void gpiochip_irq_enable(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ gpiochip_enable_irq(chip, d->hwirq);
+ if (chip->irq.irq_enable)
+ chip->irq.irq_enable(d);
+ else
+ chip->irq.chip->irq_unmask(d);
+}
+
+static void gpiochip_irq_disable(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ if (chip->irq.irq_disable)
+ chip->irq.irq_disable(d);
+ else
+ chip->irq.chip->irq_mask(d);
+ gpiochip_disable_irq(chip, d->hwirq);
+}
+
static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
{
struct irq_chip *irqchip = gpiochip->irq.chip;
@@ -1835,6 +1857,12 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
irqchip->irq_request_resources = gpiochip_irq_reqres;
irqchip->irq_release_resources = gpiochip_irq_relres;
}
+ if (WARN_ON(gpiochip->irq.irq_enable))
+ return;
+ gpiochip->irq.irq_enable = irqchip->irq_enable;
+ gpiochip->irq.irq_disable = irqchip->irq_disable;
+ irqchip->irq_enable = gpiochip_irq_enable;
+ irqchip->irq_disable = gpiochip_irq_disable;
}
/**
@@ -1954,11 +1982,18 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
irq_domain_remove(gpiochip->irq.domain);
}
- if (irqchip &&
- irqchip->irq_request_resources == gpiochip_irq_reqres) {
- irqchip->irq_request_resources = NULL;
- irqchip->irq_release_resources = NULL;
+ if (irqchip) {
+ if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
+ irqchip->irq_request_resources = NULL;
+ irqchip->irq_release_resources = NULL;
+ }
+ if (irqchip->irq_enable == gpiochip_irq_enable) {
+ irqchip->irq_enable = gpiochip->irq.irq_enable;
+ irqchip->irq_disable = gpiochip->irq.irq_disable;
+ }
}
+ gpiochip->irq.irq_enable = NULL;
+ gpiochip->irq.irq_disable = NULL;
gpiochip->irq.chip = NULL;
gpiochip_irqchip_free_valid_mask(gpiochip);