[OpenWrt-Devel] [PATCH v2] gpio-button-hotplug: mind debounce interval consistently

David Bauer mail at david-bauer.net
Tue Jul 2 17:57:18 EDT 2019


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 <mail at 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 at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list