Commit c2df3de0 authored by Thomas Petazzoni's avatar Thomas Petazzoni Committed by Linus Walleij

gpio: zynq: properly support runtime PM for GPIO used as interrupts

The Zynq GPIO driver currently implements runtime PM by:

 - Enabling runtime PM support in ->probe() and letting the runtime PM
   reference counter drop to zero at the end of ->probe().

 - Increasing the runtime PM reference counter in ->request() and
   decreasing it in ->free().

However, the latter is not sufficient: when a GPIO is used as an
interrupt, ->request() and ->free() are not called. Due to this, the
runtime PM counter remains to zero when the only GPIOs in use are used
as interrupts, causing them to simply not work.

To address this problem, this commit implement the
->irq_request_resources() and ->irq_release_resources() hooks,
ensuring that the runtime PM counter is properly
incremented/decremented. Since we override the default hooks, we keep
the existing behavior by making sure they call gpiochip_reqres_irq() /
gpiochip_relres_irq() respectively.
Signed-off-by: default avatarThomas Petazzoni <thomas.petazzoni@bootlin.com>
Reviewed-by: default avatarShubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent dac7da98
...@@ -555,6 +555,26 @@ static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) ...@@ -555,6 +555,26 @@ static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
return 0; return 0;
} }
static int zynq_gpio_irq_reqres(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
int ret;
ret = pm_runtime_get_sync(chip->parent);
if (ret < 0)
return ret;
return gpiochip_reqres_irq(chip, d->hwirq);
}
static void zynq_gpio_irq_relres(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
gpiochip_relres_irq(chip, d->hwirq);
pm_runtime_put(chip->parent);
}
/* irq chip descriptor */ /* irq chip descriptor */
static struct irq_chip zynq_gpio_level_irqchip = { static struct irq_chip zynq_gpio_level_irqchip = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
...@@ -564,6 +584,8 @@ static struct irq_chip zynq_gpio_level_irqchip = { ...@@ -564,6 +584,8 @@ static struct irq_chip zynq_gpio_level_irqchip = {
.irq_unmask = zynq_gpio_irq_unmask, .irq_unmask = zynq_gpio_irq_unmask,
.irq_set_type = zynq_gpio_set_irq_type, .irq_set_type = zynq_gpio_set_irq_type,
.irq_set_wake = zynq_gpio_set_wake, .irq_set_wake = zynq_gpio_set_wake,
.irq_request_resources = zynq_gpio_irq_reqres,
.irq_release_resources = zynq_gpio_irq_relres,
.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED | .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
IRQCHIP_MASK_ON_SUSPEND, IRQCHIP_MASK_ON_SUSPEND,
}; };
...@@ -576,6 +598,8 @@ static struct irq_chip zynq_gpio_edge_irqchip = { ...@@ -576,6 +598,8 @@ static struct irq_chip zynq_gpio_edge_irqchip = {
.irq_unmask = zynq_gpio_irq_unmask, .irq_unmask = zynq_gpio_irq_unmask,
.irq_set_type = zynq_gpio_set_irq_type, .irq_set_type = zynq_gpio_set_irq_type,
.irq_set_wake = zynq_gpio_set_wake, .irq_set_wake = zynq_gpio_set_wake,
.irq_request_resources = zynq_gpio_irq_reqres,
.irq_release_resources = zynq_gpio_irq_relres,
.flags = IRQCHIP_MASK_ON_SUSPEND, .flags = IRQCHIP_MASK_ON_SUSPEND,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment