[PATCH] Filter AUX key bouncing

Nelson arhuaco at freaks-unidos.net
Tue Dec 23 16:36:34 CET 2008


From: Nelson Castillo <arhuaco at freaks-unidos.net>

This patch filters AUX key bouncing. We store the state of
the AUX button and only change it when we notice that at
least AUX_TIMER_CONSECUTIVE_EVENTS consecutive equal GPIO
reads occur.

This should solve #2185 (AUX button makes interrupt storm)
but we still need the confirmation from someone affected by
the IRQ storm. In my test setup I could see an improvement
but I would only get 1 unwanted IRQ.

The next step is to use the same timer for more keys. For
that we could use the neo1973kbd_default_key_irq function
for the AUX key also.

Signed-off-by: Nelson Castillo <arhuaco at freaks-unidos.net>
---

 0 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/drivers/input/keyboard/neo1973kbd.c b/drivers/input/keyboard/neo1973kbd.c
index 4d412e0..20f0a34 100644
--- a/drivers/input/keyboard/neo1973kbd.c
+++ b/drivers/input/keyboard/neo1973kbd.c
@@ -33,6 +33,7 @@ struct neo1973kbd {
 	struct input_dev *input;
 	struct device *cdev;
 	struct work_struct work;
+	int aux_state;
 	int work_in_progress;
 	int hp_irq_count_in_work;
 	int hp_irq_count;
@@ -88,22 +89,67 @@ static struct neo1973kbd_key keys[] = {
 	},
 };
 
+/* This timer section filters AUX button IRQ bouncing */
 
-static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev_id)
+static void aux_key_timer_f(unsigned long data);
+
+static struct timer_list aux_key_timer =
+		TIMER_INITIALIZER(aux_key_timer_f, 0, 0);
+
+#define AUX_TIMER_TIMEOUT (HZ >> 7)
+#define AUX_TIMER_ALLOWED_NOOP 2
+#define AUX_TIMER_CONSECUTIVE_EVENTS 5
+
+struct neo1973kbd *timer_kbd;
+
+static void aux_key_timer_f(unsigned long data)
+{
+	static int noop_counter;
+	static int last_key = -1;
+	static int last_count;
+	int key_pressed;
+
+	key_pressed =
+	    !gpio_get_value(timer_kbd->pdev->resource[NEO1973_KEY_AUX].start);
+	if (machine_is_neo1973_gta02())
+		key_pressed = !key_pressed;
+
+	if (likely(key_pressed == last_key))
+		last_count++;
+	else {
+		last_count = 1;
+		last_key = key_pressed;
+	}
+
+	if (unlikely(last_count >= AUX_TIMER_CONSECUTIVE_EVENTS)) {
+		if (timer_kbd->aux_state != last_key) {
+			input_report_key(timer_kbd->input, KEY_PHONE, last_key);
+			input_sync(timer_kbd->input);
+
+			timer_kbd->aux_state = last_key;
+			noop_counter = 0;
+		}
+		last_count = 0;
+		if (unlikely(++noop_counter > AUX_TIMER_ALLOWED_NOOP)) {
+			noop_counter = 0;
+			return;
+		}
+	}
+
+	mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
+}
+
+static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev)
 {
-	struct neo1973kbd *kbd = dev_id;
-	int key_pressed = !gpio_get_value(
-				    kbd->pdev->resource[NEO1973_KEY_AUX].start);
 	int *p = NULL;
 
+	/* if you stall inside resume then AUX will force a panic,
+	   which in turn forces a dump of the pending syslog */
+
 	if (global_inside_suspend)
-		printk("death %d\n", *p);
+		printk(KERN_ERR "death %d\n", *p);
 
-	/* GTA02 has inverted sense level compared to GTA01 */
-	if (machine_is_neo1973_gta02())
-		key_pressed = !key_pressed;
-	input_report_key(kbd->input, KEY_PHONE, key_pressed);
-	input_sync(kbd->input);
+	mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
 
 	return IRQ_HANDLED;
 }
@@ -275,6 +321,7 @@ static int neo1973kbd_probe(struct platform_device *pdev)
 	}
 
 	neo1973kbd->pdev = pdev;
+	timer_kbd = neo1973kbd;
 
 	if (pdev->resource[0].flags != 0)
 		return -EINVAL;




More information about the openmoko-kernel mailing list