Skip to content

Commit

Permalink
gpio: mxc: release the parent IRQ in runtime suspend
Browse files Browse the repository at this point in the history
Release the parent interrupt request during runtime suspend, allowing
the parent interrupt controller to enter runtime suspend if there are
no active users.

This change may not have a visible impact if the parent controller is
the GIC, but it can enable significant power savings for parent IRQ
controllers like IRQSteer inside a subsystem on i.MX8 SoCs. Releasing
the parent IRQ provides an opportunity for the subsystem to enter suspend
states if there are no active users.

Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
  • Loading branch information
Shenwei Wang authored and Bartosz Golaszewski committed Aug 11, 2023
1 parent b7df0f3 commit 5f6d199
Showing 1 changed file with 29 additions and 12 deletions.
41 changes: 29 additions & 12 deletions drivers/gpio/gpio-mxc.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct mxc_gpio_port {
struct clk *clk;
int irq;
int irq_high;
void (*mx_irq_handler)(struct irq_desc *desc);
struct irq_domain *domain;
struct gpio_chip gc;
struct device *dev;
Expand Down Expand Up @@ -399,6 +400,24 @@ static void mxc_gpio_free(struct gpio_chip *chip, unsigned int offset)
pm_runtime_put(chip->parent);
}

static void mxc_update_irq_chained_handler(struct mxc_gpio_port *port, bool enable)
{
if (enable)
irq_set_chained_handler_and_data(port->irq, port->mx_irq_handler, port);
else
irq_set_chained_handler_and_data(port->irq, NULL, NULL);

/* setup handler for GPIO 16 to 31 */
if (port->irq_high > 0) {
if (enable)
irq_set_chained_handler_and_data(port->irq_high,
port->mx_irq_handler,
port);
else
irq_set_chained_handler_and_data(port->irq_high, NULL, NULL);
}
}

static int mxc_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
Expand Down Expand Up @@ -460,18 +479,12 @@ static int mxc_gpio_probe(struct platform_device *pdev)
* the handler is needed only once, but doing it for every port
* is more robust and easier.
*/
irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
} else {
/* setup one handler for each entry */
irq_set_chained_handler_and_data(port->irq,
mx3_gpio_irq_handler, port);
if (port->irq_high > 0)
/* setup handler for GPIO 16 to 31 */
irq_set_chained_handler_and_data(port->irq_high,
mx3_gpio_irq_handler,
port);
}
port->irq_high = -1;
port->mx_irq_handler = mx2_gpio_irq_handler;
} else
port->mx_irq_handler = mx3_gpio_irq_handler;

mxc_update_irq_chained_handler(port, true);
err = bgpio_init(&port->gc, &pdev->dev, 4,
port->base + GPIO_PSR,
port->base + GPIO_DR, NULL,
Expand Down Expand Up @@ -604,6 +617,7 @@ static int mxc_gpio_runtime_suspend(struct device *dev)

mxc_gpio_save_regs(port);
clk_disable_unprepare(port->clk);
mxc_update_irq_chained_handler(port, false);

return 0;
}
Expand All @@ -613,9 +627,12 @@ static int mxc_gpio_runtime_resume(struct device *dev)
struct mxc_gpio_port *port = dev_get_drvdata(dev);
int ret;

mxc_update_irq_chained_handler(port, true);
ret = clk_prepare_enable(port->clk);
if (ret)
if (ret) {
mxc_update_irq_chained_handler(port, false);
return ret;
}

mxc_gpio_restore_regs(port);

Expand Down

0 comments on commit 5f6d199

Please sign in to comment.