[PATCH 2/6] gpiolib: override irq_request/release_resources hooks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Hans Verkuil <hans.verkuil@xxxxxxxxx>

Rather than completely replacing any existing irq_request/release_resources
irq_chip callbacks, remember the driver's version and call it from our
override.

Two drivers that select GPIOLIB_IRQCHIP and set these callbacks had to
be changed, otherwise you would get into an infinite loop.

Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>
Cc: Patrice Chotard <patrice.chotard@xxxxxx>
Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Cc: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx>
---
 drivers/gpio/gpiolib.c                | 60 ++++++++++++++++-----------
 drivers/pinctrl/intel/pinctrl-intel.c | 32 --------------
 drivers/pinctrl/pinctrl-st.c          | 11 +----
 include/linux/gpio/driver.h           | 14 +++++++
 4 files changed, 50 insertions(+), 67 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index cbab0e744de0..d2c1e2cccc65 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1815,17 +1815,40 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 static int gpiochip_irq_reqres(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	int ret;
 
-	return gpiochip_reqres_irq(chip, d->hwirq);
+	ret = gpiochip_reqres_irq(chip, d->hwirq);
+	if (ret || !chip->irq.irq_reqres)
+		return ret;
+	ret = chip->irq.irq_reqres(d);
+	if (ret)
+		gpiochip_relres_irq(chip, d->hwirq);
+	return ret;
 }
 
 static void gpiochip_irq_relres(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
+	if (chip->irq.irq_relres)
+		chip->irq.irq_relres(d);
 	gpiochip_relres_irq(chip, d->hwirq);
 }
 
+static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
+{
+	struct irq_chip *irqchip = gpiochip->irq.chip;
+
+	if (WARN_ON(irqchip->irq_request_resources == gpiochip_irq_reqres))
+		return;
+
+	gpiochip->irq.irq_reqres = irqchip->irq_request_resources;
+	gpiochip->irq.irq_relres = irqchip->irq_release_resources;
+
+	irqchip->irq_request_resources = gpiochip_irq_reqres;
+	irqchip->irq_release_resources = gpiochip_irq_relres;
+}
+
 /**
  * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
  * @gpiochip: the GPIO chip to add the IRQ chip to
@@ -1884,16 +1907,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
 	if (!gpiochip->irq.domain)
 		return -EINVAL;
 
-	/*
-	 * It is possible for a driver to override this, but only if the
-	 * alternative functions are both implemented.
-	 */
-	if (!irqchip->irq_request_resources &&
-	    !irqchip->irq_release_resources) {
-		irqchip->irq_request_resources = gpiochip_irq_reqres;
-		irqchip->irq_release_resources = gpiochip_irq_relres;
-	}
-
 	if (gpiochip->irq.parent_handler) {
 		void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
 
@@ -1909,6 +1922,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
 		}
 	}
 
+	gpiochip_set_irq_hooks(gpiochip);
+
 	acpi_gpiochip_request_interrupts(gpiochip);
 
 	return 0;
@@ -1922,11 +1937,12 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
  */
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 {
+	struct irq_chip *irqchip = gpiochip->irq.chip;
 	unsigned int offset;
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
-	if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
+	if (irqchip && gpiochip->irq.parent_handler) {
 		struct gpio_irq_chip *irq = &gpiochip->irq;
 		unsigned int i;
 
@@ -1950,11 +1966,13 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_domain_remove(gpiochip->irq.domain);
 	}
 
-	if (gpiochip->irq.chip) {
-		gpiochip->irq.chip->irq_request_resources = NULL;
-		gpiochip->irq.chip->irq_release_resources = NULL;
-		gpiochip->irq.chip = NULL;
+	if (irqchip && irqchip->irq_request_resources == gpiochip_irq_reqres) {
+		irqchip->irq_request_resources = gpiochip->irq.irq_reqres;
+		irqchip->irq_release_resources = gpiochip->irq.irq_relres;
 	}
+	gpiochip->irq.irq_reqres = NULL;
+	gpiochip->irq.irq_relres = NULL;
+	gpiochip->irq.chip = NULL;
 
 	gpiochip_irqchip_free_valid_mask(gpiochip);
 }
@@ -2043,15 +2061,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 		return -EINVAL;
 	}
 
-	/*
-	 * It is possible for a driver to override this, but only if the
-	 * alternative functions are both implemented.
-	 */
-	if (!irqchip->irq_request_resources &&
-	    !irqchip->irq_release_resources) {
-		irqchip->irq_request_resources = gpiochip_irq_reqres;
-		irqchip->irq_release_resources = gpiochip_irq_relres;
-	}
+	gpiochip_set_irq_hooks(gpiochip);
 
 	acpi_gpiochip_request_interrupts(gpiochip);
 
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 62b009b27eda..3d0bd7b99725 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -872,36 +872,6 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset,
 	return -EINVAL;
 }
 
-static int intel_gpio_irq_reqres(struct irq_data *d)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
-	int pin;
-	int ret;
-
-	pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
-	if (pin >= 0) {
-		ret = gpiochip_lock_as_irq(gc, pin);
-		if (ret) {
-			dev_err(pctrl->dev, "unable to lock HW IRQ %d for IRQ\n",
-				pin);
-			return ret;
-		}
-	}
-	return 0;
-}
-
-static void intel_gpio_irq_relres(struct irq_data *d)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
-	int pin;
-
-	pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
-	if (pin >= 0)
-		gpiochip_unlock_as_irq(gc, pin);
-}
-
 static void intel_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -1117,8 +1087,6 @@ static irqreturn_t intel_gpio_irq(int irq, void *data)
 
 static struct irq_chip intel_gpio_irqchip = {
 	.name = "intel-gpio",
-	.irq_request_resources = intel_gpio_irq_reqres,
-	.irq_release_resources = intel_gpio_irq_relres,
 	.irq_enable = intel_gpio_irq_enable,
 	.irq_ack = intel_gpio_irq_ack,
 	.irq_mask = intel_gpio_irq_mask,
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 0966bb0bf71f..02a45bcd79c1 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1290,15 +1290,7 @@ static int st_gpio_irq_request_resources(struct irq_data *d)
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 
 	st_gpio_direction_input(gc, d->hwirq);
-
-	return gpiochip_lock_as_irq(gc, d->hwirq);
-}
-
-static void st_gpio_irq_release_resources(struct irq_data *d)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-
-	gpiochip_unlock_as_irq(gc, d->hwirq);
+	return 0;
 }
 
 static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
@@ -1456,7 +1448,6 @@ static const struct gpio_chip st_gpio_template = {
 static struct irq_chip st_gpio_irqchip = {
 	.name			= "GPIO",
 	.irq_request_resources	= st_gpio_irq_request_resources,
-	.irq_release_resources	= st_gpio_irq_release_resources,
 	.irq_disable		= st_gpio_irq_mask,
 	.irq_mask		= st_gpio_irq_mask,
 	.irq_unmask		= st_gpio_irq_unmask,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 380251955ad1..b445b083e568 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -138,6 +138,20 @@ struct gpio_irq_chip {
 	 * will allocate and map all IRQs during initialization.
 	 */
 	unsigned int first;
+
+	/**
+	 * @irq_reqres:
+	 *
+	 * Store old irq_chip irq_request_resources callback
+	 */
+	int		(*irq_reqres)(struct irq_data *d);
+
+	/**
+	 * @irq_relres:
+	 *
+	 * Store old irq_chip irq_release_resources callback
+	 */
+	void		(*irq_relres)(struct irq_data *d);
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
-- 
2.18.0




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux