From patchwork Fri Mar 5 17:01:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 12118907 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 185ACC433E0 for ; Fri, 5 Mar 2021 17:02:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D25766507C for ; Fri, 5 Mar 2021 17:02:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231143AbhCERB4 (ORCPT ); Fri, 5 Mar 2021 12:01:56 -0500 Received: from aposti.net ([89.234.176.197]:60846 "EHLO aposti.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229573AbhCERBe (ORCPT ); Fri, 5 Mar 2021 12:01:34 -0500 From: Paul Cercueil To: Dmitry Torokhov Cc: od@zcrc.me, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Paul Cercueil Subject: [PATCH 1/3] input: gpio-keys: Remove extra call to input_sync Date: Fri, 5 Mar 2021 17:01:09 +0000 Message-Id: <20210305170111.214782-1-paul@crapouillou.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org The input_sync() function will already be called within gpio_keys_gpio_report_event(), so there's no need to call it again after the loop in gpio_keys_report_state(). Signed-off-by: Paul Cercueil --- drivers/input/keyboard/gpio_keys.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 77bac4ddf324..0be204693ab0 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -641,7 +641,6 @@ static int gpio_keys_setup_key(struct platform_device *pdev, static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) { - struct input_dev *input = ddata->input; int i; for (i = 0; i < ddata->pdata->nbuttons; i++) { @@ -649,7 +648,6 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) if (bdata->gpiod) gpio_keys_gpio_report_event(bdata); } - input_sync(input); } static int gpio_keys_open(struct input_dev *input) From patchwork Fri Mar 5 17:01:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 12118909 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 74157C433E6 for ; Fri, 5 Mar 2021 17:02:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4111B6508C for ; Fri, 5 Mar 2021 17:02:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231289AbhCERB5 (ORCPT ); Fri, 5 Mar 2021 12:01:57 -0500 Received: from aposti.net ([89.234.176.197]:60868 "EHLO aposti.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230259AbhCERBk (ORCPT ); Fri, 5 Mar 2021 12:01:40 -0500 From: Paul Cercueil To: Dmitry Torokhov Cc: od@zcrc.me, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Paul Cercueil Subject: [PATCH 2/3] input: gpio-keys: Use hrtimer for release timer Date: Fri, 5 Mar 2021 17:01:10 +0000 Message-Id: <20210305170111.214782-2-paul@crapouillou.net> In-Reply-To: <20210305170111.214782-1-paul@crapouillou.net> References: <20210305170111.214782-1-paul@crapouillou.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Dealing with input, timing is important; if the button should be released in one millisecond, then it should be done in one millisecond and not a hundred milliseconds. Therefore, the standard timer API is not really suitable for this task. Convert the gpio-keys driver to use a hrtimer instead of the standard timer to address this issue. Note that by using a hard IRQ for the hrtimer callback, we can get rid of the spin_lock_irqsave() and spin_unlock_irqrestore(). Signed-off-by: Paul Cercueil --- drivers/input/keyboard/gpio_keys.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 0be204693ab0..1ab112267aa8 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -36,7 +37,7 @@ struct gpio_button_data { unsigned short *code; - struct timer_list release_timer; + struct hrtimer release_timer; unsigned int release_delay; /* in msecs, for IRQ-only buttons */ struct delayed_work work; @@ -146,7 +147,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) if (bdata->gpiod) cancel_delayed_work_sync(&bdata->work); else - del_timer_sync(&bdata->release_timer); + hrtimer_cancel(&bdata->release_timer); bdata->disabled = true; } @@ -415,19 +416,20 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static void gpio_keys_irq_timer(struct timer_list *t) +static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t) { - struct gpio_button_data *bdata = from_timer(bdata, t, release_timer); + struct gpio_button_data *bdata = container_of(t, + struct gpio_button_data, + release_timer); struct input_dev *input = bdata->input; - unsigned long flags; - spin_lock_irqsave(&bdata->lock, flags); if (bdata->key_pressed) { input_event(input, EV_KEY, *bdata->code, 0); input_sync(input); bdata->key_pressed = false; } - spin_unlock_irqrestore(&bdata->lock, flags); + + return HRTIMER_NORESTART; } static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) @@ -457,8 +459,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) } if (bdata->release_delay) - mod_timer(&bdata->release_timer, - jiffies + msecs_to_jiffies(bdata->release_delay)); + hrtimer_start(&bdata->release_timer, + ms_to_ktime(bdata->release_delay), + HRTIMER_MODE_REL_HARD); out: spin_unlock_irqrestore(&bdata->lock, flags); return IRQ_HANDLED; @@ -471,7 +474,7 @@ static void gpio_keys_quiesce_key(void *data) if (bdata->gpiod) cancel_delayed_work_sync(&bdata->work); else - del_timer_sync(&bdata->release_timer); + hrtimer_cancel(&bdata->release_timer); } static int gpio_keys_setup_key(struct platform_device *pdev, @@ -595,7 +598,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev, } bdata->release_delay = button->debounce_interval; - timer_setup(&bdata->release_timer, gpio_keys_irq_timer, 0); + hrtimer_init(&bdata->release_timer, + CLOCK_REALTIME, HRTIMER_MODE_REL_HARD); + bdata->release_timer.function = gpio_keys_irq_timer; isr = gpio_keys_irq_isr; irqflags = 0; From patchwork Fri Mar 5 17:01:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 12118911 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B3DC8C4332B for ; Fri, 5 Mar 2021 17:02:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7C1D7650A6 for ; Fri, 5 Mar 2021 17:02:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231324AbhCERB5 (ORCPT ); Fri, 5 Mar 2021 12:01:57 -0500 Received: from aposti.net ([89.234.176.197]:60870 "EHLO aposti.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230489AbhCERBq (ORCPT ); Fri, 5 Mar 2021 12:01:46 -0500 From: Paul Cercueil To: Dmitry Torokhov Cc: od@zcrc.me, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Paul Cercueil Subject: [PATCH 3/3] input: gpio-keys: Use hrtimer for software debounce Date: Fri, 5 Mar 2021 17:01:11 +0000 Message-Id: <20210305170111.214782-3-paul@crapouillou.net> In-Reply-To: <20210305170111.214782-1-paul@crapouillou.net> References: <20210305170111.214782-1-paul@crapouillou.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org We want to be able to report the input event as soon as the debounce delay elapsed. However, the current code does not really ensure that, as it uses the jiffies-based schedule_delayed_work() API. With a small enough HZ value (HZ <= 100), this results in some input events being lost, when a key is quickly pressed then released (on a human's time scale). Switching to hrtimers fixes this issue, and will work even on extremely low HZ values (tested at HZ=24). Signed-off-by: Paul Cercueil --- drivers/input/keyboard/gpio_keys.c | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 1ab112267aa8..267ed99e1911 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,7 @@ struct gpio_button_data { struct hrtimer release_timer; 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; @@ -145,7 +144,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) disable_irq(bdata->irq); if (bdata->gpiod) - cancel_delayed_work_sync(&bdata->work); + hrtimer_cancel(&bdata->debounce_timer); else hrtimer_cancel(&bdata->release_timer); @@ -377,15 +376,18 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) input_sync(input); } -static void gpio_keys_gpio_work_func(struct work_struct *work) +static enum hrtimer_restart gpio_keys_debounce_timer(struct hrtimer *t) { - struct gpio_button_data *bdata = - container_of(work, struct gpio_button_data, work.work); + struct gpio_button_data *bdata = container_of(t, + struct gpio_button_data, + debounce_timer); gpio_keys_gpio_report_event(bdata); if (bdata->button->wakeup) pm_relax(bdata->input->dev.parent); + + return HRTIMER_NORESTART; } static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) @@ -409,9 +411,9 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) } } - mod_delayed_work(system_wq, - &bdata->work, - msecs_to_jiffies(bdata->software_debounce)); + hrtimer_start(&bdata->debounce_timer, + ms_to_ktime(bdata->software_debounce), + HRTIMER_MODE_REL_SOFT); return IRQ_HANDLED; } @@ -472,7 +474,7 @@ static void gpio_keys_quiesce_key(void *data) struct gpio_button_data *bdata = data; if (bdata->gpiod) - cancel_delayed_work_sync(&bdata->work); + hrtimer_cancel(&bdata->debounce_timer); else hrtimer_cancel(&bdata->release_timer); } @@ -562,11 +564,13 @@ static int gpio_keys_setup_key(struct platform_device *pdev, bdata->irq = irq; } - INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func); - isr = gpio_keys_gpio_isr; irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + hrtimer_init(&bdata->debounce_timer, + CLOCK_REALTIME, HRTIMER_MODE_REL_SOFT); + bdata->debounce_timer.function = gpio_keys_debounce_timer; + switch (button->wakeup_event_action) { case EV_ACT_ASSERTED: bdata->wakeup_trigger_type = active_low ? @@ -615,10 +619,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, *bdata->code = button->code; input_set_capability(input, button->type ?: EV_KEY, *bdata->code); - /* - * Install custom action to cancel release timer and - * workqueue item. - */ + /* Install custom action to cancel timers. */ error = devm_add_action(dev, gpio_keys_quiesce_key, bdata); if (error) { dev_err(dev, "failed to register quiesce action, error: %d\n",