[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