[PATCH] [RFC] Filter AUX button interrupt storm
Nelson
arhuaco at freaks-unidos.net
Mon Dec 22 08:08:30 CET 2008
From: Nelson Castillo <arhuaco at freaks-unidos.net>
This patch tries to address #2185 : AUX button makes interrupt storm [1].
We tried doing a pull-down of S3C2410_GPF6 but in my tests it did not
work (please check the ticket to see the code used for the test).
[1] https://docs.openmoko.org/trac/ticket/2185
We are still waiting for the confirmation that the fix works.
In my tests it did work but I do not get as many spurious
interrupts as the reporter does.
Signed-off-by: Nelson Castillo <arhuaco at freaks-unidos.net>
---
drivers/input/keyboard/neo1973kbd.c | 79 +++++++++++++++++++++++++++--------
1 files changed, 62 insertions(+), 17 deletions(-)
diff --git a/drivers/input/keyboard/neo1973kbd.c b/drivers/input/keyboard/neo1973kbd.c
index 4d412e0..0f07e0b 100644
--- a/drivers/input/keyboard/neo1973kbd.c
+++ b/drivers/input/keyboard/neo1973kbd.c
@@ -32,8 +32,11 @@ struct neo1973kbd {
struct platform_device *pdev;
struct input_dev *input;
struct device *cdev;
- struct work_struct work;
- int work_in_progress;
+ struct work_struct aux_work;
+ struct work_struct jack_work;
+ int hp_work_in_progress;
+ int aux_work_in_progress;
+ int aux_irq_count;
int hp_irq_count_in_work;
int hp_irq_count;
int jack_irq;
@@ -88,23 +91,63 @@ static struct neo1973kbd_key keys[] = {
},
};
-
-static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev_id)
+static void neo1973kbd_debounce_aux(struct work_struct *work)
{
- struct neo1973kbd *kbd = dev_id;
- int key_pressed = !gpio_get_value(
- kbd->pdev->resource[NEO1973_KEY_AUX].start);
- int *p = NULL;
-
- if (global_inside_suspend)
- printk("death %d\n", *p);
+ struct neo1973kbd *kbd =
+ container_of(work, struct neo1973kbd, aux_work);
+ unsigned long flags;
+ int dont_loop;
+ int key_pressed;
+ int key_pressed0;
+ key_pressed =
+ !gpio_get_value(kbd->pdev->resource[NEO1973_KEY_AUX].start);
+ key_pressed0 = key_pressed;
/* 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);
+ do {
+ int count = kbd->aux_irq_count;
+ msleep(60);
+
+ local_save_flags(flags);
+ dont_loop = count == kbd->aux_irq_count;
+ if (dont_loop)
+ kbd->aux_work_in_progress = 0;
+ local_irq_restore(flags);
+ } while (!dont_loop);
+
+ key_pressed =
+ !gpio_get_value(kbd->pdev->resource[NEO1973_KEY_AUX].start);
+ if (key_pressed0 != key_pressed) {
+ if (machine_is_neo1973_gta02())
+ key_pressed = !key_pressed;
+ input_report_key(kbd->input, KEY_PHONE, key_pressed);
+ input_sync(kbd->input);
+ }
+}
+
+static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev)
+{
+ struct neo1973kbd *data = dev;
+ int *p = NULL;
+
+ if (global_inside_suspend)
+ printk(KERN_ERR "death %d\n", *p);
+
+ data->aux_irq_count++;
+
+ if (!data->aux_work_in_progress) {
+ if (unlikely(!schedule_work(&data->aux_work)))
+ printk(KERN_ERR
+ "Unable to schedule AUX debounce\n");
+ else
+ data->aux_work_in_progress = 1;
+ }
+
return IRQ_HANDLED;
}
@@ -150,7 +193,8 @@ static void neo1973kbd_jack_event(struct device *dev, int num)
static void neo1973kbd_debounce_jack(struct work_struct *work)
{
- struct neo1973kbd *kbd = container_of(work, struct neo1973kbd, work);
+ struct neo1973kbd *kbd =
+ container_of(work, struct neo1973kbd, jack_work);
unsigned long flags;
int loop = 0;
int level;
@@ -181,7 +225,7 @@ static void neo1973kbd_debounce_jack(struct work_struct *work)
/* no interrupts during this work means we can exit the work */
loop = !!(kbd->hp_irq_count != kbd->hp_irq_count_in_work);
if (!loop)
- kbd->work_in_progress = 0;
+ kbd->hp_work_in_progress = 0;
local_irq_restore(flags);
/*
* interrupt that comes here will either queue a new work action
@@ -212,15 +256,15 @@ static irqreturn_t neo1973kbd_headphone_irq(int irq, void *dev_id)
* come in the meanwhile, we can tell by the difference in that
* stored count and hp_irq_count which increments every interrupt
*/
- if (!neo1973kbd_data->work_in_progress) {
+ if (!neo1973kbd_data->hp_work_in_progress) {
neo1973kbd_data->jack_irq = irq;
neo1973kbd_data->hp_irq_count_in_work =
neo1973kbd_data->hp_irq_count;
- if (!schedule_work(&neo1973kbd_data->work))
+ if (!schedule_work(&neo1973kbd_data->jack_work))
printk(KERN_ERR
"Unable to schedule headphone debounce\n");
else
- neo1973kbd_data->work_in_progress = 1;
+ neo1973kbd_data->hp_work_in_progress = 1;
}
return IRQ_HANDLED;
@@ -283,7 +327,8 @@ static int neo1973kbd_probe(struct platform_device *pdev)
neo1973kbd->input = input_dev;
- INIT_WORK(&neo1973kbd->work, neo1973kbd_debounce_jack);
+ INIT_WORK(&neo1973kbd->aux_work, neo1973kbd_debounce_aux);
+ INIT_WORK(&neo1973kbd->jack_work, neo1973kbd_debounce_jack);
input_dev->name = "Neo1973 Buttons";
input_dev->phys = "neo1973kbd/input0";
More information about the openmoko-kernel
mailing list