unsigned int flags;
struct reset_control *rst;
struct clk_bulk_data clks[DWAPB_NR_CLOCKS];
+ bool clocks_on_for_wake;
struct dwapb_gpio_port ports[] __counted_by(nr_ports);
};
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
struct dwapb_context *ctx = gpio->ports[0].ctx;
irq_hw_number_t bit = irqd_to_hwirq(d);
+ u32 wake_en = ctx->wake_en;
if (enable)
- ctx->wake_en |= BIT(bit);
+ wake_en |= BIT(bit);
else
- ctx->wake_en &= ~BIT(bit);
+ wake_en &= ~BIT(bit);
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ if (d->parent_data && !!ctx->wake_en != !!wake_en) {
+ int err;
+
+ err = irq_chip_set_wake_parent(d, enable);
+ if (err)
+ return err;
+ }
+#endif
+
+ ctx->wake_en = wake_en;
return 0;
}
int i;
scoped_guard(gpio_generic_lock_irqsave, gen_gc) {
+ gpio->clocks_on_for_wake = false;
+
for (i = 0; i < gpio->nr_ports; i++) {
unsigned int offset;
unsigned int idx = gpio->ports[i].idx;
ctx->int_pol = dwapb_read(gpio, GPIO_INT_POLARITY);
ctx->int_type = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int dwapb_gpio_suspend_noirq(struct device *dev)
+{
+ struct dwapb_gpio *gpio = dev_get_drvdata(dev);
+ struct gpio_generic_chip *gen_gc = &gpio->ports[0].chip;
+ bool wake_enabled = false;
+ int i;
+
+ scoped_guard(gpio_generic_lock_irqsave, gen_gc) {
+ for (i = 0; i < gpio->nr_ports; i++) {
+ unsigned int idx = gpio->ports[i].idx;
+ struct dwapb_context *ctx = gpio->ports[i].ctx;
- /* Mask out interrupts */
+ if (idx == 0) {
+ wake_enabled = ctx->wake_en;
dwapb_write(gpio, GPIO_INTMASK, ~ctx->wake_en);
+ break;
}
}
+
+ gpio->clocks_on_for_wake = wake_enabled;
+ }
+
+ if (wake_enabled) {
+ device_set_wakeup_path(dev);
+ return 0;
}
clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
return 0;
}
-static int dwapb_gpio_resume(struct device *dev)
+static int dwapb_gpio_resume_noirq(struct device *dev)
{
struct dwapb_gpio *gpio = dev_get_drvdata(dev);
- struct gpio_chip *gc = &gpio->ports[0].chip.gc;
- struct gpio_generic_chip *gen_gc = to_gpio_generic_chip(gc);
- int i, err;
+ int err;
+
+ if (gpio->clocks_on_for_wake)
+ return 0;
err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks);
- if (err) {
+ if (err)
dev_err(gpio->dev, "Cannot reenable APB/Debounce clocks\n");
- return err;
- }
+
+ return err;
+}
+
+static int dwapb_gpio_resume(struct device *dev)
+{
+ struct dwapb_gpio *gpio = dev_get_drvdata(dev);
+ struct gpio_chip *gc = &gpio->ports[0].chip.gc;
+ struct gpio_generic_chip *gen_gc = to_gpio_generic_chip(gc);
+ int i;
guard(gpio_generic_lock_irqsave)(gen_gc);
return 0;
}
-static DEFINE_SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops,
- dwapb_gpio_suspend, dwapb_gpio_resume);
+static const struct dev_pm_ops dwapb_gpio_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(dwapb_gpio_suspend, dwapb_gpio_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(dwapb_gpio_suspend_noirq,
+ dwapb_gpio_resume_noirq)
+};
static struct platform_driver dwapb_gpio_driver = {
.driver = {