unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
 
        unsigned int irq;
+       unsigned int wakeirq;
        unsigned int wakeup_trigger_type;
+
        spinlock_t lock;
        bool disabled;
        bool key_pressed;
        struct gpio_button_data *bdata = &ddata->data[idx];
        irq_handler_t isr;
        unsigned long irqflags;
+       const char *wakedesc;
        int irq;
        int error;
 
                                        !gpiod_cansleep(bdata->gpiod);
                }
 
+               /*
+                * If an interrupt was specified, use it instead of the gpio
+                * interrupt and use the gpio for reading the state. A separate
+                * interrupt may be used as the main button interrupt for
+                * runtime PM to detect events also in deeper idle states. If a
+                * dedicated wakeirq is used for system suspend only, see below
+                * for bdata->wakeirq setup.
+                */
                if (button->irq) {
                        bdata->irq = button->irq;
                } else {
                return error;
        }
 
+       if (!button->wakeirq)
+               return 0;
+
+       /* Use :wakeup suffix like drivers/base/power/wakeirq.c does */
+       wakedesc = devm_kasprintf(dev, GFP_KERNEL, "%s:wakeup", desc);
+       if (!wakedesc)
+               return -ENOMEM;
+
+       bdata->wakeirq = button->wakeirq;
+       irqflags |= IRQF_NO_SUSPEND;
+
+       /*
+        * Wakeirq shares the handler with the main interrupt, it's only
+        * active during system suspend. See gpio_keys_button_enable_wakeup()
+        * and gpio_keys_button_disable_wakeup().
+        */
+       error = devm_request_any_context_irq(dev, bdata->wakeirq, isr,
+                                            irqflags, wakedesc, bdata);
+       if (error < 0) {
+               dev_err(dev, "Unable to claim wakeirq %d; error %d\n",
+                       bdata->irq, error);
+               return error;
+       }
+
+       /*
+        * Disable wakeirq until suspend. IRQF_NO_AUTOEN won't work if
+        * IRQF_SHARED was set based on !button->can_disable.
+        */
+       disable_irq(bdata->wakeirq);
+
        return 0;
 }
 
        struct gpio_keys_platform_data *pdata;
        struct gpio_keys_button *button;
        struct fwnode_handle *child;
-       int nbuttons;
+       int nbuttons, irq;
 
        nbuttons = device_get_child_node_count(dev);
        if (nbuttons == 0)
        device_property_read_string(dev, "label", &pdata->name);
 
        device_for_each_child_node(dev, child) {
-               if (is_of_node(child))
-                       button->irq =
-                               irq_of_parse_and_map(to_of_node(child), 0);
+               if (is_of_node(child)) {
+                       irq = of_irq_get_byname(to_of_node(child), "irq");
+                       if (irq > 0)
+                               button->irq = irq;
+
+                       irq = of_irq_get_byname(to_of_node(child), "wakeup");
+                       if (irq > 0)
+                               button->wakeirq = irq;
+
+                       if (!button->irq && !button->wakeirq)
+                               button->irq =
+                                       irq_of_parse_and_map(to_of_node(child), 0);
+               }
 
                if (fwnode_property_read_u32(child, "linux,code",
                                             &button->code)) {
                }
        }
 
+       if (bdata->wakeirq) {
+               enable_irq(bdata->wakeirq);
+               disable_irq(bdata->irq);
+       }
+
        return 0;
 }
 
 {
        int error;
 
+       if (bdata->wakeirq) {
+               enable_irq(bdata->irq);
+               disable_irq(bdata->wakeirq);
+       }
+
        /*
         * The trigger type is always both edges for gpio-based keys and we do
         * not support changing wakeup trigger for interrupt-based keys.