unsigned int release_delay;     /* in msecs, for IRQ-only buttons */
 
        struct delayed_work work;
+       struct hrtimer debounce_timer;
        unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
 
        unsigned int irq;
        bool disabled;
        bool key_pressed;
        bool suspended;
+       bool debounce_use_hrtimer;
 };
 
 struct gpio_keys_drvdata {
                 */
                disable_irq(bdata->irq);
 
-               if (bdata->gpiod)
-                       cancel_delayed_work_sync(&bdata->work);
-               else
+               if (bdata->debounce_use_hrtimer)
                        hrtimer_cancel(&bdata->release_timer);
+               else
+                       cancel_delayed_work_sync(&bdata->work);
 
                bdata->disabled = true;
        }
        unsigned int type = button->type ?: EV_KEY;
        int state;
 
-       state = gpiod_get_value_cansleep(bdata->gpiod);
+       state = bdata->debounce_use_hrtimer ?
+                       gpiod_get_value(bdata->gpiod) :
+                       gpiod_get_value_cansleep(bdata->gpiod);
        if (state < 0) {
                dev_err(input->dev.parent,
                        "failed to get gpio state: %d\n", state);
        }
 }
 
-static void gpio_keys_gpio_work_func(struct work_struct *work)
+static void gpio_keys_debounce_event(struct gpio_button_data *bdata)
 {
-       struct gpio_button_data *bdata =
-               container_of(work, struct gpio_button_data, work.work);
-
        gpio_keys_gpio_report_event(bdata);
        input_sync(bdata->input);
 
                pm_relax(bdata->input->dev.parent);
 }
 
+static void gpio_keys_gpio_work_func(struct work_struct *work)
+{
+       struct gpio_button_data *bdata =
+               container_of(work, struct gpio_button_data, work.work);
+
+       gpio_keys_debounce_event(bdata);
+}
+
+static enum hrtimer_restart gpio_keys_debounce_timer(struct hrtimer *t)
+{
+       struct gpio_button_data *bdata =
+               container_of(t, struct gpio_button_data, debounce_timer);
+
+       gpio_keys_debounce_event(bdata);
+
+       return HRTIMER_NORESTART;
+}
+
 static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 {
        struct gpio_button_data *bdata = dev_id;
                }
        }
 
-       mod_delayed_work(system_wq,
-                        &bdata->work,
-                        msecs_to_jiffies(bdata->software_debounce));
+       if (bdata->debounce_use_hrtimer) {
+               hrtimer_start(&bdata->debounce_timer,
+                             ms_to_ktime(bdata->software_debounce),
+                             HRTIMER_MODE_REL);
+       } else {
+               mod_delayed_work(system_wq,
+                                &bdata->work,
+                                msecs_to_jiffies(bdata->software_debounce));
+       }
 
        return IRQ_HANDLED;
 }
 {
        struct gpio_button_data *bdata = data;
 
-       if (bdata->gpiod)
-               cancel_delayed_work_sync(&bdata->work);
+       if (bdata->debounce_use_hrtimer)
+               hrtimer_cancel(&bdata->debounce_timer);
        else
-               hrtimer_cancel(&bdata->release_timer);
+               cancel_delayed_work_sync(&bdata->work);
 }
 
 static int gpio_keys_setup_key(struct platform_device *pdev,
                        if (error < 0)
                                bdata->software_debounce =
                                                button->debounce_interval;
+
+                       /*
+                        * If reading the GPIO won't sleep, we can use a
+                        * hrtimer instead of a standard timer for the software
+                        * debounce, to reduce the latency as much as possible.
+                        */
+                       bdata->debounce_use_hrtimer =
+                                       !gpiod_cansleep(bdata->gpiod);
                }
 
                if (button->irq) {
 
                INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
 
+               hrtimer_init(&bdata->debounce_timer,
+                            CLOCK_REALTIME, HRTIMER_MODE_REL);
+               bdata->debounce_timer.function = gpio_keys_debounce_timer;
+
                isr = gpio_keys_gpio_isr;
                irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
 
                }
 
                bdata->release_delay = button->debounce_interval;
+               bdata->debounce_use_hrtimer = true;
                hrtimer_init(&bdata->release_timer,
                             CLOCK_REALTIME, HRTIMER_MODE_REL_HARD);
                bdata->release_timer.function = gpio_keys_irq_timer;