From 39a497b0421174c3f23ef3dffb0675a4db3aa3a0 Mon Sep 17 00:00:00 2001 From: Nelson Castillo Date: Mon, 29 Dec 2008 12:11:40 +0000 Subject: Filter AUX key bouncing 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 --- drivers/input/keyboard/neo1973kbd.c | 67 +++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/neo1973kbd.c b/drivers/input/keyboard/neo1973kbd.c index 4d412e0b980..20f0a348a36 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; -- cgit v1.2.3