gpio: zynq: Wakeup gpio controller when it is used as IRQ controller

Message ID 1549861628-12220-1-git-send-email-shubhrajyoti.datta@gmail.com
State New
Headers show
Series
  • gpio: zynq: Wakeup gpio controller when it is used as IRQ controller
Related show

Commit Message

Shubhrajyoti Datta Feb. 11, 2019, 5:07 a.m.
From: Borsodi Petr <Petr.Borsodi@i.cz>

There is a problem with GPIO driver when used as IRQ controller.
It is not working because the module is sleeping (clock is disabled).
The patch enables clocks when IP is used as IRQ controller.

Signed-off-by: Borsodi Petr <Petr.Borsodi@i.cz>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
---

 drivers/gpio/gpio-zynq.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

Comments

Thomas Petazzoni Feb. 11, 2019, 7:53 a.m. | #1
Hello,

On Mon, 11 Feb 2019 10:37:08 +0530
<shubhrajyoti.datta@gmail.com> wrote:

> From: Borsodi Petr <Petr.Borsodi@i.cz>
> 
> There is a problem with GPIO driver when used as IRQ controller.
> It is not working because the module is sleeping (clock is disabled).
> The patch enables clocks when IP is used as IRQ controller.
> 
> Signed-off-by: Borsodi Petr <Petr.Borsodi@i.cz>
> Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>

I sent another similar patch a few days ago:

  https://www.spinics.net/lists/linux-gpio/msg36472.html

Except that I re-use the existing gpiochip_reqres_irq() and
gpiochip_relres_irq() functions instead of duplicating them.

Best regards,

Thomas
Shubhrajyoti Datta Feb. 11, 2019, 1:40 p.m. | #2
On Mon, Feb 11, 2019 at 1:23 PM Thomas Petazzoni
<thomas.petazzoni@bootlin.com> wrote:
>
> Hello,
>
> On Mon, 11 Feb 2019 10:37:08 +0530
> <shubhrajyoti.datta@gmail.com> wrote:
>
> > From: Borsodi Petr <Petr.Borsodi@i.cz>
> >
> > There is a problem with GPIO driver when used as IRQ controller.
> > It is not working because the module is sleeping (clock is disabled).
> > The patch enables clocks when IP is used as IRQ controller.
> >
> > Signed-off-by: Borsodi Petr <Petr.Borsodi@i.cz>
> > Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
>
> I sent another similar patch a few days ago:
>
>   https://www.spinics.net/lists/linux-gpio/msg36472.html
>
> Except that I re-use the existing gpiochip_reqres_irq() and
> gpiochip_relres_irq() functions instead of duplicating them.
>
Thanks  looks to be a better approach.
> Best regards,
>
> Thomas
> --
> Thomas Petazzoni, CTO, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

Patch

diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index a7df6b2..ce40fbd 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -11,6 +11,7 @@ 
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 #include <linux/gpio/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -21,6 +22,8 @@ 
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 
+#include "gpiolib.h"
+
 #define DRIVER_NAME "zynq-gpio"
 
 /* Maximum banks */
@@ -569,6 +572,38 @@  static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
 	return 0;
 }
 
+static int zynq_gpio_irq_request_resources(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	int ret;
+
+	if (!try_module_get(chip->gpiodev->owner))
+		return -ENODEV;
+
+	ret = pm_runtime_get_sync(chip->parent);
+	if (ret < 0) {
+		module_put(chip->gpiodev->owner);
+		return ret;
+	}
+
+	if (gpiochip_lock_as_irq(chip, d->hwirq)) {
+		chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq);
+		pm_runtime_put(chip->parent);
+		module_put(chip->gpiodev->owner);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void zynq_gpio_irq_release_resources(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+	gpiochip_unlock_as_irq(chip, d->hwirq);
+	pm_runtime_put(chip->parent);
+	module_put(chip->gpiodev->owner);
+}
+
 /* irq chip descriptor */
 static struct irq_chip zynq_gpio_level_irqchip = {
 	.name		= DRIVER_NAME,
@@ -578,6 +613,8 @@  static struct irq_chip zynq_gpio_level_irqchip = {
 	.irq_unmask	= zynq_gpio_irq_unmask,
 	.irq_set_type	= zynq_gpio_set_irq_type,
 	.irq_set_wake	= zynq_gpio_set_wake,
+	.irq_request_resources = zynq_gpio_irq_request_resources,
+	.irq_release_resources = zynq_gpio_irq_release_resources,
 	.flags		= IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
 			  IRQCHIP_MASK_ON_SUSPEND,
 };
@@ -590,6 +627,8 @@  static struct irq_chip zynq_gpio_edge_irqchip = {
 	.irq_unmask	= zynq_gpio_irq_unmask,
 	.irq_set_type	= zynq_gpio_set_irq_type,
 	.irq_set_wake	= zynq_gpio_set_wake,
+	.irq_request_resources = zynq_gpio_irq_request_resources,
+	.irq_release_resources = zynq_gpio_irq_release_resources,
 	.flags		= IRQCHIP_MASK_ON_SUSPEND,
 };