This patch implements consistent handling of the debounce interval set for the GPIO buttons. Hotplug events will only be fired if
1. It's the initial stable state (no state-change for duration of the debounce interval) for a switch. Buttons will not trigger an event for the initial stable state. 2. The input changes it's state and remains stable for the debounce interval. Prior to this patch, this was handled inconsistently for interrupt-based an polled gpio-keys. We unify the shared logic in button_hotplug_event and modify both implementations to read the initial state. Run-tested for 'gpio-keys' and 'gpio-keys-polled' on - devolo WiFi pro 1200e - devolo WiFi pro 1750c - devolo WiFi pro 1750x Signed-off-by: David Bauer <m...@david-bauer.net> --- v2: - Debounce interval is now correctly considered for polled GPIO-keys .../src/gpio-button-hotplug.c | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c index e63d414284..67b4549cc2 100644 --- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c @@ -57,6 +57,7 @@ struct bh_map { struct gpio_keys_button_data { struct delayed_work work; struct bh_priv bh; + int has_initial_state; int last_state; int count; int threshold; @@ -241,6 +242,7 @@ static int button_get_index(unsigned int code) static void button_hotplug_event(struct gpio_keys_button_data *data, unsigned int type, int value) { + int last_state = data->last_state; struct bh_priv *priv = &data->bh; unsigned long seen = jiffies; int btn; @@ -250,6 +252,15 @@ static void button_hotplug_event(struct gpio_keys_button_data *data, if ((type != EV_KEY) && (type != EV_SW)) return; + data->last_state = value; + + if (!data->has_initial_state) { + data->has_initial_state = 1; + if (type != EV_SW) + return; + } else if (value == last_state) + return; + btn = button_get_index(data->b->code); if (btn < 0) return; @@ -285,19 +296,22 @@ static int gpio_button_get_value(struct gpio_keys_button_data *bdata) static void gpio_keys_polled_check_state(struct gpio_keys_button_data *bdata) { + int has_initial_state = bdata->has_initial_state; + int last_state = bdata->last_state; int state = gpio_button_get_value(bdata); - if (state != bdata->last_state) { - unsigned int type = bdata->b->type ?: EV_KEY; + if (!has_initial_state && bdata->last_state == -1) { + bdata->last_state = state; + return; + } + if (state != last_state || (!has_initial_state && last_state == state)) { if (bdata->count < bdata->threshold) { bdata->count++; return; } - - if (bdata->last_state != -1 || type == EV_SW) - button_hotplug_event(bdata, type, state); - + button_hotplug_event(bdata, bdata->b->type ?: EV_KEY, state); + } else if (!has_initial_state && last_state != state) { bdata->last_state = state; } @@ -351,8 +365,8 @@ static irqreturn_t button_handle_irq(int irq, void *_bdata) struct gpio_keys_button_data *bdata = (struct gpio_keys_button_data *) _bdata; - schedule_delayed_work(&bdata->work, - msecs_to_jiffies(bdata->software_debounce)); + mod_delayed_work(system_wq, &bdata->work, + msecs_to_jiffies(bdata->software_debounce)); return IRQ_HANDLED; } @@ -540,6 +554,7 @@ static int gpio_keys_button_probe(struct platform_device *pdev, } bdata->can_sleep = gpio_cansleep(gpio); + bdata->has_initial_state = 0; bdata->last_state = -1; if (bdev->polled) { @@ -608,6 +623,9 @@ static int gpio_keys_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&bdata->work, gpio_keys_irq_work_func); + schedule_delayed_work(&bdata->work, + msecs_to_jiffies(bdata->software_debounce)); + ret = devm_request_threaded_irq(&pdev->dev, bdata->irq, NULL, button_handle_irq, irqflags, dev_name(&pdev->dev), bdata); @@ -621,9 +639,6 @@ static int gpio_keys_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "gpio:%d has irq:%d\n", button->gpio, bdata->irq); } - - if (bdata->b->type == EV_SW) - button_hotplug_event(bdata, EV_SW, gpio_button_get_value(bdata)); } return 0; @@ -648,9 +663,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) if (pdata->enable) pdata->enable(bdev->dev); - for (i = 0; i < pdata->nbuttons; i++) - gpio_keys_polled_check_state(&bdev->data[i]); - gpio_keys_polled_queue_work(bdev); return ret; -- 2.22.0 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel