All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Gardiner <bengardiner@nanometrics.ca>
To: Kevin Hilman <khilman@deeprootsystems.com>,
	davinci-linux-open-source@linux.davincidsp.com,
	linux-input@vger.kernel.org,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-kernel@vger.kernel.org,
	Chris Cordahi <christophercordahi@nanometrics.ca>,
	Paul Mundt <lethal@linux-sh.org>, Sekhar Nori <nsekhar@ti.com>,
	Alexander Clouter <alex@digriz.org.uk>
Subject: [PATCH v4 1/5] input: gpio_keys: polling mode support
Date: Tue, 23 Nov 2010 14:40:56 -0500	[thread overview]
Message-ID: <bf95cbdc51b1a8ac222a01ac57e5932c3224d5d9.1290540916.git.bengardiner@nanometrics.ca> (raw)
In-Reply-To: <cover.1290540916.git.bengardiner@nanometrics.ca>

From: Alexander Clouter <alex@digriz.org.uk>

This implements an optional polling mode for the gpio_keys driver,
necessary for GPIOs that are not able to generate IRQs.

gpio_keys_platform_data has been extended with poll_interval
which specifies the polling interval in ms, this is passed onto
input-polldev.

This work is a rebase of the patch by Alex Clouter [1] which was
based on the patch [2] originally conceived by Paul Mundt.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Alexander Clouter <alex@digriz.org.uk>
Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Reviewed-by: Chris Cordahi <christophercordahi@nanometrics.ca>
CC: Paul Mundt <lethal@linux-sh.org>

[1] http://article.gmane.org/gmane.linux.kernel.input/13919
[2] http://article.gmane.org/gmane.linux.kernel.input/5814

---

Changes since v3:
 * no changes to this patch in the series

Changes since v2:
 * rebased to 083eae3e28643e0eefc5243719f8b1572cf98299 of
  git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git

Changes since v1:
 * use locally defined functions that are no-ops/error checkers when
  INPUT_POLLDEV is not defined.
 * disable polling mode support when input-polldev is a module and gpio_keys
  is builtin

Changes since [1]:
 * rebased to 0b1c3ef1072f2b97c86351d3736d2b2d00293a11 of
  git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git
 * use _cansleep variant of gpio_get_value in the polling task
  to avoid WARN_ON when using I2C GPIO expanders
 * prevent unitialized access to 'input' in gpio_keys_close()

Changes since [2]:
 * absolute dependency on INPUT_POLLDEV removed

Tested with CONFIG_INPUT_POLLDEV={n,m,y} (gpio_keys as module for 'm').

---
 drivers/input/keyboard/gpio_keys.c |  120 ++++++++++++++++++++++++++++++------
 include/linux/gpio_keys.h          |    1 +
 2 files changed, 103 insertions(+), 18 deletions(-)

diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 6069abe..d2f23d9 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -1,7 +1,9 @@
 /*
- * Driver for keys on GPIO lines capable of generating interrupts.
+ * Driver for keys on GPIO lines, either IRQ-driven or polled.
  *
  * Copyright 2005 Phil Blundell
+ * Copyright 2008 Paul Mundt
+ * Copyright 2010 Alexander Clouter <alex@digriz.org.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -25,6 +27,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/input-polldev.h>
 
 struct gpio_button_data {
 	struct gpio_keys_button *button;
@@ -37,6 +40,7 @@ struct gpio_button_data {
 
 struct gpio_keys_drvdata {
 	struct input_dev *input;
+	struct input_polled_dev *poll_dev;
 	struct mutex disable_lock;
 	unsigned int n_buttons;
 	int (*enable)(struct device *dev);
@@ -44,6 +48,30 @@ struct gpio_keys_drvdata {
 	struct gpio_button_data data[0];
 };
 
+#if (!defined(CONFIG_INPUT_POLLDEV) && !defined(CONFIG_INPUT_POLLDEV_MODULE)) \
+	|| (defined(CONFIG_INPUT_POLLDEV_MODULE) \
+		&& !defined(CONFIG_KEYBOARD_GPIO_MODULE))
+
+static inline struct input_polled_dev *allocate_polled_device(
+					const struct device *dev)
+{
+	dev_err(dev, "device needs polling (enable INPUT_POLLDEV)\n");
+	return NULL;
+}
+
+#define free_polled_device(x)		do { } while (0)
+#define register_polled_device(x)	(-ENXIO)
+#define unregister_polled_device(x)	do { } while (0)
+
+#else
+
+#define allocate_polled_device(x)	input_allocate_polled_device()
+#define free_polled_device(x)		input_free_polled_device(x)
+#define register_polled_device(x)	input_register_polled_device(x)
+#define unregister_polled_device(x)	input_unregister_polled_device(x)
+
+#endif
+
 /*
  * SYSFS interface for enabling/disabling keys and switches:
  *
@@ -322,7 +350,8 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
 	struct gpio_keys_button *button = bdata->button;
 	struct input_dev *input = bdata->input;
 	unsigned int type = button->type ?: EV_KEY;
-	int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
+	int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0)
+			^ button->active_low;
 
 	input_event(input, type, button->code, !!state);
 	input_sync(input);
@@ -343,6 +372,16 @@ static void gpio_keys_timer(unsigned long _data)
 	schedule_work(&data->work);
 }
 
+static void gpio_handle_button_event(struct gpio_keys_button *button,
+				     struct gpio_button_data *bdata)
+{
+	if (bdata->timer_debounce)
+		mod_timer(&bdata->timer,
+			jiffies + msecs_to_jiffies(bdata->timer_debounce));
+	else
+		gpio_keys_report_event(bdata);
+}
+
 static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 {
 	struct gpio_button_data *bdata = dev_id;
@@ -350,15 +389,24 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 
 	BUG_ON(irq != gpio_to_irq(button->gpio));
 
-	if (bdata->timer_debounce)
-		mod_timer(&bdata->timer,
-			jiffies + msecs_to_jiffies(bdata->timer_debounce));
-	else
-		schedule_work(&bdata->work);
+	gpio_handle_button_event(button, bdata);
 
 	return IRQ_HANDLED;
 }
 
+static void gpio_keys_poll(struct input_polled_dev *dev)
+{
+	struct gpio_keys_drvdata *ddata = dev->private;
+	int i;
+
+	for (i = 0; i < ddata->n_buttons; i++) {
+		struct gpio_button_data *bdata = &ddata->data[i];
+		struct gpio_keys_button *button = bdata->button;
+
+		gpio_handle_button_event(button, bdata);
+	}
+}
+
 static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
 					 struct gpio_button_data *bdata,
 					 struct gpio_keys_button *button)
@@ -446,20 +494,28 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 	struct gpio_keys_drvdata *ddata;
 	struct device *dev = &pdev->dev;
 	struct input_dev *input;
+	struct input_polled_dev *poll_dev;
 	int i, error;
 	int wakeup = 0;
 
 	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
 			pdata->nbuttons * sizeof(struct gpio_button_data),
 			GFP_KERNEL);
-	input = input_allocate_device();
+	if (pdata->poll_interval) {
+		poll_dev = allocate_polled_device(dev);
+		input = poll_dev ? poll_dev->input : 0;
+	} else
+		input = input_allocate_device();
 	if (!ddata || !input) {
 		dev_err(dev, "failed to allocate state\n");
 		error = -ENOMEM;
 		goto fail1;
 	}
 
-	ddata->input = input;
+	if (pdata->poll_interval)
+		ddata->poll_dev = poll_dev;
+	else
+		ddata->input = input;
 	ddata->n_buttons = pdata->nbuttons;
 	ddata->enable = pdata->enable;
 	ddata->disable = pdata->disable;
@@ -468,6 +524,12 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, ddata);
 	input_set_drvdata(input, ddata);
 
+	if (pdata->poll_interval) {
+		poll_dev->private = ddata;
+		poll_dev->poll = gpio_keys_poll;
+		poll_dev->poll_interval = pdata->poll_interval;
+	}
+
 	input->name = pdev->name;
 	input->phys = "gpio-keys/input0";
 	input->dev.parent = &pdev->dev;
@@ -491,14 +553,17 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 		bdata->input = input;
 		bdata->button = button;
 
+		input_set_capability(input, type, button->code);
+
+		if (pdata->poll_interval)
+			continue;
+
 		error = gpio_keys_setup_key(pdev, bdata, button);
 		if (error)
 			goto fail2;
 
 		if (button->wakeup)
 			wakeup = 1;
-
-		input_set_capability(input, type, button->code);
 	}
 
 	error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -508,7 +573,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 		goto fail2;
 	}
 
-	error = input_register_device(input);
+	if (pdata->poll_interval)
+		error = register_polled_device(poll_dev);
+	else
+		error = input_register_device(input);
 	if (error) {
 		dev_err(dev, "Unable to register input device, error: %d\n",
 			error);
@@ -528,7 +596,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
  fail2:
 	while (--i >= 0) {
-		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
+		if (!pdata->poll_interval)
+			free_irq(gpio_to_irq(pdata->buttons[i].gpio),
+				&ddata->data[i]);
 		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
@@ -537,7 +607,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, NULL);
  fail1:
-	input_free_device(input);
+	if (pdata->poll_interval)
+		free_polled_device(poll_dev);
+	else
+		input_free_device(input);
 	kfree(ddata);
 
 	return error;
@@ -547,7 +620,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 {
 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
 	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
-	struct input_dev *input = ddata->input;
+	struct input_dev *input;
+	struct input_polled_dev *poll_dev;
 	int i;
 
 	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -555,15 +629,25 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 	device_init_wakeup(&pdev->dev, 0);
 
 	for (i = 0; i < pdata->nbuttons; i++) {
-		int irq = gpio_to_irq(pdata->buttons[i].gpio);
-		free_irq(irq, &ddata->data[i]);
+		if (!pdata->poll_interval) {
+			int irq = gpio_to_irq(pdata->buttons[i].gpio);
+			free_irq(irq, &ddata->data[i]);
+		}
 		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
 	}
 
-	input_unregister_device(input);
+	if (pdata->poll_interval) {
+		poll_dev = ddata->poll_dev;
+		unregister_polled_device(poll_dev);
+		free_polled_device(poll_dev);
+	} else {
+		input = ddata->input;
+		input_unregister_device(input);
+		input_free_device(input);
+	}
 
 	return 0;
 }
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index ce73a30..5fdd495 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -19,6 +19,7 @@ struct gpio_keys_platform_data {
 	unsigned int rep:1;		/* enable input subsystem auto repeat */
 	int (*enable)(struct device *dev);
 	void (*disable)(struct device *dev);
+	unsigned int poll_interval;	/* polling interval in ms */
 };
 
 #endif
-- 
1.7.0.4


WARNING: multiple messages have this Message-ID (diff)
From: Ben Gardiner <bengardiner-ScDXFp4xN3PN+rMO2ozGnw@public.gmane.org>
To: Kevin Hilman
	<khilman-1D3HCaltpLuhEniVeURVKkEOCMrvLtNR@public.gmane.org>,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Dmitry Torokhov
	<dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Paul Mundt <lethal-M7jkjyW5wf5g9hUCZPvPmw@public.gmane.org>,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Alexander Clouter <alex-L4GPcECwBoDe9xe1eoZjHA@public.gmane.org>,
	Chris Cordahi
	<christophercordahi-ScDXFp4xN3PN+rMO2ozGnw@public.gmane.org>
Subject: [PATCH v4 1/5] input: gpio_keys: polling mode support
Date: Tue, 23 Nov 2010 14:40:56 -0500	[thread overview]
Message-ID: <bf95cbdc51b1a8ac222a01ac57e5932c3224d5d9.1290540916.git.bengardiner@nanometrics.ca> (raw)
In-Reply-To: <cover.1290540916.git.bengardiner-ScDXFp4xN3PN+rMO2ozGnw@public.gmane.org>

From: Alexander Clouter <alex-L4GPcECwBoDe9xe1eoZjHA@public.gmane.org>

This implements an optional polling mode for the gpio_keys driver,
necessary for GPIOs that are not able to generate IRQs.

gpio_keys_platform_data has been extended with poll_interval
which specifies the polling interval in ms, this is passed onto
input-polldev.

This work is a rebase of the patch by Alex Clouter [1] which was
based on the patch [2] originally conceived by Paul Mundt.

Signed-off-by: Paul Mundt <lethal-M7jkjyW5wf5g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Alexander Clouter <alex-L4GPcECwBoDe9xe1eoZjHA@public.gmane.org>
Signed-off-by: Ben Gardiner <bengardiner-ScDXFp4xN3PN+rMO2ozGnw@public.gmane.org>
Reviewed-by: Chris Cordahi <christophercordahi-ScDXFp4xN3PN+rMO2ozGnw@public.gmane.org>
CC: Paul Mundt <lethal-M7jkjyW5wf5g9hUCZPvPmw@public.gmane.org>

[1] http://article.gmane.org/gmane.linux.kernel.input/13919
[2] http://article.gmane.org/gmane.linux.kernel.input/5814

---

Changes since v3:
 * no changes to this patch in the series

Changes since v2:
 * rebased to 083eae3e28643e0eefc5243719f8b1572cf98299 of
  git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git

Changes since v1:
 * use locally defined functions that are no-ops/error checkers when
  INPUT_POLLDEV is not defined.
 * disable polling mode support when input-polldev is a module and gpio_keys
  is builtin

Changes since [1]:
 * rebased to 0b1c3ef1072f2b97c86351d3736d2b2d00293a11 of
  git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git
 * use _cansleep variant of gpio_get_value in the polling task
  to avoid WARN_ON when using I2C GPIO expanders
 * prevent unitialized access to 'input' in gpio_keys_close()

Changes since [2]:
 * absolute dependency on INPUT_POLLDEV removed

Tested with CONFIG_INPUT_POLLDEV={n,m,y} (gpio_keys as module for 'm').

---
 drivers/input/keyboard/gpio_keys.c |  120 ++++++++++++++++++++++++++++++------
 include/linux/gpio_keys.h          |    1 +
 2 files changed, 103 insertions(+), 18 deletions(-)

diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 6069abe..d2f23d9 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -1,7 +1,9 @@
 /*
- * Driver for keys on GPIO lines capable of generating interrupts.
+ * Driver for keys on GPIO lines, either IRQ-driven or polled.
  *
  * Copyright 2005 Phil Blundell
+ * Copyright 2008 Paul Mundt
+ * Copyright 2010 Alexander Clouter <alex-L4GPcECwBoDe9xe1eoZjHA@public.gmane.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -25,6 +27,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/input-polldev.h>
 
 struct gpio_button_data {
 	struct gpio_keys_button *button;
@@ -37,6 +40,7 @@ struct gpio_button_data {
 
 struct gpio_keys_drvdata {
 	struct input_dev *input;
+	struct input_polled_dev *poll_dev;
 	struct mutex disable_lock;
 	unsigned int n_buttons;
 	int (*enable)(struct device *dev);
@@ -44,6 +48,30 @@ struct gpio_keys_drvdata {
 	struct gpio_button_data data[0];
 };
 
+#if (!defined(CONFIG_INPUT_POLLDEV) && !defined(CONFIG_INPUT_POLLDEV_MODULE)) \
+	|| (defined(CONFIG_INPUT_POLLDEV_MODULE) \
+		&& !defined(CONFIG_KEYBOARD_GPIO_MODULE))
+
+static inline struct input_polled_dev *allocate_polled_device(
+					const struct device *dev)
+{
+	dev_err(dev, "device needs polling (enable INPUT_POLLDEV)\n");
+	return NULL;
+}
+
+#define free_polled_device(x)		do { } while (0)
+#define register_polled_device(x)	(-ENXIO)
+#define unregister_polled_device(x)	do { } while (0)
+
+#else
+
+#define allocate_polled_device(x)	input_allocate_polled_device()
+#define free_polled_device(x)		input_free_polled_device(x)
+#define register_polled_device(x)	input_register_polled_device(x)
+#define unregister_polled_device(x)	input_unregister_polled_device(x)
+
+#endif
+
 /*
  * SYSFS interface for enabling/disabling keys and switches:
  *
@@ -322,7 +350,8 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
 	struct gpio_keys_button *button = bdata->button;
 	struct input_dev *input = bdata->input;
 	unsigned int type = button->type ?: EV_KEY;
-	int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
+	int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0)
+			^ button->active_low;
 
 	input_event(input, type, button->code, !!state);
 	input_sync(input);
@@ -343,6 +372,16 @@ static void gpio_keys_timer(unsigned long _data)
 	schedule_work(&data->work);
 }
 
+static void gpio_handle_button_event(struct gpio_keys_button *button,
+				     struct gpio_button_data *bdata)
+{
+	if (bdata->timer_debounce)
+		mod_timer(&bdata->timer,
+			jiffies + msecs_to_jiffies(bdata->timer_debounce));
+	else
+		gpio_keys_report_event(bdata);
+}
+
 static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 {
 	struct gpio_button_data *bdata = dev_id;
@@ -350,15 +389,24 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 
 	BUG_ON(irq != gpio_to_irq(button->gpio));
 
-	if (bdata->timer_debounce)
-		mod_timer(&bdata->timer,
-			jiffies + msecs_to_jiffies(bdata->timer_debounce));
-	else
-		schedule_work(&bdata->work);
+	gpio_handle_button_event(button, bdata);
 
 	return IRQ_HANDLED;
 }
 
+static void gpio_keys_poll(struct input_polled_dev *dev)
+{
+	struct gpio_keys_drvdata *ddata = dev->private;
+	int i;
+
+	for (i = 0; i < ddata->n_buttons; i++) {
+		struct gpio_button_data *bdata = &ddata->data[i];
+		struct gpio_keys_button *button = bdata->button;
+
+		gpio_handle_button_event(button, bdata);
+	}
+}
+
 static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
 					 struct gpio_button_data *bdata,
 					 struct gpio_keys_button *button)
@@ -446,20 +494,28 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 	struct gpio_keys_drvdata *ddata;
 	struct device *dev = &pdev->dev;
 	struct input_dev *input;
+	struct input_polled_dev *poll_dev;
 	int i, error;
 	int wakeup = 0;
 
 	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
 			pdata->nbuttons * sizeof(struct gpio_button_data),
 			GFP_KERNEL);
-	input = input_allocate_device();
+	if (pdata->poll_interval) {
+		poll_dev = allocate_polled_device(dev);
+		input = poll_dev ? poll_dev->input : 0;
+	} else
+		input = input_allocate_device();
 	if (!ddata || !input) {
 		dev_err(dev, "failed to allocate state\n");
 		error = -ENOMEM;
 		goto fail1;
 	}
 
-	ddata->input = input;
+	if (pdata->poll_interval)
+		ddata->poll_dev = poll_dev;
+	else
+		ddata->input = input;
 	ddata->n_buttons = pdata->nbuttons;
 	ddata->enable = pdata->enable;
 	ddata->disable = pdata->disable;
@@ -468,6 +524,12 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, ddata);
 	input_set_drvdata(input, ddata);
 
+	if (pdata->poll_interval) {
+		poll_dev->private = ddata;
+		poll_dev->poll = gpio_keys_poll;
+		poll_dev->poll_interval = pdata->poll_interval;
+	}
+
 	input->name = pdev->name;
 	input->phys = "gpio-keys/input0";
 	input->dev.parent = &pdev->dev;
@@ -491,14 +553,17 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 		bdata->input = input;
 		bdata->button = button;
 
+		input_set_capability(input, type, button->code);
+
+		if (pdata->poll_interval)
+			continue;
+
 		error = gpio_keys_setup_key(pdev, bdata, button);
 		if (error)
 			goto fail2;
 
 		if (button->wakeup)
 			wakeup = 1;
-
-		input_set_capability(input, type, button->code);
 	}
 
 	error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -508,7 +573,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 		goto fail2;
 	}
 
-	error = input_register_device(input);
+	if (pdata->poll_interval)
+		error = register_polled_device(poll_dev);
+	else
+		error = input_register_device(input);
 	if (error) {
 		dev_err(dev, "Unable to register input device, error: %d\n",
 			error);
@@ -528,7 +596,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
  fail2:
 	while (--i >= 0) {
-		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
+		if (!pdata->poll_interval)
+			free_irq(gpio_to_irq(pdata->buttons[i].gpio),
+				&ddata->data[i]);
 		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
@@ -537,7 +607,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, NULL);
  fail1:
-	input_free_device(input);
+	if (pdata->poll_interval)
+		free_polled_device(poll_dev);
+	else
+		input_free_device(input);
 	kfree(ddata);
 
 	return error;
@@ -547,7 +620,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 {
 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
 	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
-	struct input_dev *input = ddata->input;
+	struct input_dev *input;
+	struct input_polled_dev *poll_dev;
 	int i;
 
 	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -555,15 +629,25 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 	device_init_wakeup(&pdev->dev, 0);
 
 	for (i = 0; i < pdata->nbuttons; i++) {
-		int irq = gpio_to_irq(pdata->buttons[i].gpio);
-		free_irq(irq, &ddata->data[i]);
+		if (!pdata->poll_interval) {
+			int irq = gpio_to_irq(pdata->buttons[i].gpio);
+			free_irq(irq, &ddata->data[i]);
+		}
 		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
 	}
 
-	input_unregister_device(input);
+	if (pdata->poll_interval) {
+		poll_dev = ddata->poll_dev;
+		unregister_polled_device(poll_dev);
+		free_polled_device(poll_dev);
+	} else {
+		input = ddata->input;
+		input_unregister_device(input);
+		input_free_device(input);
+	}
 
 	return 0;
 }
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index ce73a30..5fdd495 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -19,6 +19,7 @@ struct gpio_keys_platform_data {
 	unsigned int rep:1;		/* enable input subsystem auto repeat */
 	int (*enable)(struct device *dev);
 	void (*disable)(struct device *dev);
+	unsigned int poll_interval;	/* polling interval in ms */
 };
 
 #endif
-- 
1.7.0.4

  reply	other threads:[~2010-11-23 19:41 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cover.1289835508.git.bengardiner@nanometrics.ca>
     [not found] ` <8891d088e9a16122c780f737b1b1ec35f9517c36.1289835508.git.bengardiner@nanometrics.ca>
2010-11-16  9:36   ` [PATCH 1/4] input: gpio_keys: polling mode support Paul Mundt
2010-11-16 18:28     ` Ben Gardiner
2010-11-16 19:39 ` [PATCH v2 0/4] da850-evm: add gpio-{keys,leds} for UI and BB expanders Ben Gardiner
2010-11-16 19:39   ` [PATCH v2 0/4] da850-evm: add gpio-{keys, leds} " Ben Gardiner
2010-11-16 19:39   ` [PATCH v2 1/4] input: gpio_keys: polling mode support Ben Gardiner
2010-11-16 19:39   ` [PATCH v2 2/4] da850-evm: add UI Expander pushbuttons Ben Gardiner
2010-11-19  9:58     ` Nori, Sekhar
2010-11-19  9:58       ` Nori, Sekhar
2010-11-19 15:38       ` Ben Gardiner
2010-11-19 15:38         ` Ben Gardiner
2010-11-22 11:49         ` Nori, Sekhar
2010-11-22 11:49           ` Nori, Sekhar
2010-11-22 13:50           ` Ben Gardiner
2010-11-22 13:50             ` Ben Gardiner
2010-11-23 12:38             ` Nori, Sekhar
2010-11-23 12:38               ` Nori, Sekhar
2010-11-23 13:29               ` Ben Gardiner
2010-11-23 13:29                 ` Ben Gardiner
2010-11-23 15:48               ` Kevin Hilman
2010-11-23 15:48                 ` Kevin Hilman
2010-11-23 17:58                 ` Ben Gardiner
2010-11-23 17:58                   ` Ben Gardiner
2010-11-24  6:09                 ` Paul Mundt
2010-11-24  6:09                   ` Paul Mundt
2010-11-24 17:17                   ` Ben Gardiner
2010-11-24 17:17                     ` Ben Gardiner
2010-11-16 19:39   ` [PATCH v2 3/4] da850-evm: extract defines for SEL{A,B,C} pins in UI expander Ben Gardiner
2010-11-16 19:39     ` [PATCH v2 3/4] da850-evm: extract defines for SEL{A, B, C} " Ben Gardiner
2010-11-19 11:19     ` Nori, Sekhar
2010-11-19 11:19       ` Nori, Sekhar
2010-11-19 15:38       ` Ben Gardiner
2010-11-19 15:38         ` Ben Gardiner
2010-11-16 19:39   ` [PATCH v2 4/4] da850-evm: add baseboard UI expander buttons, switches and LEDs Ben Gardiner
2010-11-19 12:14     ` Nori, Sekhar
2010-11-19 12:14       ` Nori, Sekhar
2010-11-19 15:40       ` Ben Gardiner
2010-11-19 15:40         ` Ben Gardiner
2010-11-19 17:02         ` Dmitry Torokhov
2010-11-19 17:02           ` Dmitry Torokhov
2010-11-19 17:15           ` Ben Gardiner
2010-11-19 17:15             ` Ben Gardiner
2010-11-22 12:00         ` Nori, Sekhar
2010-11-22 12:00           ` Nori, Sekhar
2010-11-22 14:15           ` Ben Gardiner
2010-11-22 14:15             ` Ben Gardiner
2010-11-23 12:42             ` Nori, Sekhar
2010-11-23 12:42               ` Nori, Sekhar
2010-11-23 13:32               ` Ben Gardiner
2010-11-23 13:32                 ` Ben Gardiner
2010-11-19 21:37   ` [PATCH v3 0/4] da850-evm: add gpio-{keys,leds} for UI and BB expanders Ben Gardiner
2010-11-19 21:37     ` [PATCH v3 1/4] input: gpio_keys: polling mode support Ben Gardiner
2010-11-19 21:37     ` [PATCH v3 2/4] da850-evm: add UI Expander pushbuttons Ben Gardiner
2010-11-19 21:37     ` [PATCH v3 3/4] da850-evm: extract defines for SEL{A,B,C} pins in UI expander Ben Gardiner
2010-11-19 21:41       ` [PATCH v3 3/4] da850-evm: extract defines for SEL{A, B, C} " Victor Rodriguez
2010-11-19 21:41         ` Victor Rodriguez
2010-11-19 22:25         ` Ben Gardiner
2010-11-19 22:25           ` Ben Gardiner
2010-11-19 21:37     ` [PATCH v3 4/4] da850-evm: add baseboard GPIO expander buttons, switches and LEDs Ben Gardiner
2010-11-23 19:40     ` [PATCH v4 0/5] da850-evm: add gpio-{keys,leds} for UI and BB expanders Ben Gardiner
2010-11-23 19:40       ` Ben Gardiner [this message]
2010-11-23 19:40         ` [PATCH v4 1/5] input: gpio_keys: polling mode support Ben Gardiner
2010-11-23 19:40       ` [PATCH v4 2/5] da850-evm: add UI Expander pushbuttons Ben Gardiner
2010-11-23 19:40         ` Ben Gardiner
2010-11-24 13:16         ` Nori, Sekhar
2010-11-24 13:16           ` Nori, Sekhar
2010-11-24 17:16           ` Ben Gardiner
2010-11-24 17:16             ` Ben Gardiner
2010-11-23 19:40       ` [PATCH v4 3/5] da850-evm: extract defines for SEL{A,B,C} pins in UI expander Ben Gardiner
2010-11-23 19:40       ` [PATCH v4 4/5] da850-evm: add baseboard GPIO expander buttons, switches and LEDs Ben Gardiner
2010-11-23 19:41       ` [PATCH v4 5/5] da850-evm: KEYBOARD_GPIO and INPUT_POLLDEV Kconfig conditionals Ben Gardiner
2010-11-23 19:41         ` Ben Gardiner
2010-11-24 21:59       ` [PATCH v5 0/5] da850-evm: add gpio-{keys,leds} for UI and BB expanders Ben Gardiner
2010-11-24 21:59         ` [PATCH v5 1/5] [WIP] input: add input driver for polled GPIO buttons Ben Gardiner
2010-11-24 21:59           ` Ben Gardiner
2010-11-24 21:59         ` [PATCH v5 2/5] da850-evm: add UI Expander pushbuttons Ben Gardiner
2010-11-24 21:59           ` Ben Gardiner
2010-11-24 21:59         ` [PATCH v5 3/5] da850-evm: extract defines for SEL{A,B,C} pins in UI expander Ben Gardiner
2010-11-24 21:59         ` [PATCH v5 4/5] da850-evm: add baseboard GPIO expander buttons, switches and LEDs Ben Gardiner
2010-11-24 21:59         ` [PATCH v5 5/5] da850-evm: KEYBOARD_GPIO_POLLED Kconfig conditional Ben Gardiner
2010-11-24 21:59           ` Ben Gardiner
2010-12-09 21:51         ` [PATCH v6 0/5] da850-evm: add gpio-{keys,leds} for UI and BB expanders Ben Gardiner
2010-12-09 21:51           ` [PATCH v6 1/5] Input: add input driver for polled GPIO buttons Ben Gardiner
2010-12-09 21:51             ` Ben Gardiner
2010-12-10 15:50             ` Kevin Hilman
2010-12-09 21:51           ` [PATCH v6 2/5] da850-evm: add UI Expander pushbuttons Ben Gardiner
2010-12-09 21:51             ` Ben Gardiner
2010-12-09 21:51           ` [PATCH v6 3/5] da850-evm: extract defines for SEL{A,B,C} pins in UI expander Ben Gardiner
2010-12-09 21:51           ` [PATCH v6 4/5] da850-evm: add baseboard GPIO expander buttons, switches and LEDs Ben Gardiner
2010-12-09 21:51           ` [PATCH v6 5/5] da850-evm: KEYBOARD_GPIO_POLLED Kconfig conditional Ben Gardiner
2010-12-09 21:51             ` Ben Gardiner
2010-12-10 16:16           ` [PATCH v6 0/5] da850-evm: add gpio-{keys,leds} for UI and BB expanders Kevin Hilman
2010-12-10 16:33             ` Ben Gardiner
2010-12-10 16:33               ` Ben Gardiner
2010-12-11  0:04               ` Kevin Hilman
2010-12-11  0:04                 ` Kevin Hilman
2010-12-13 17:02               ` Ben Gardiner
2010-12-13 17:02                 ` Ben Gardiner
2010-12-13 21:53                 ` Kevin Hilman
2010-12-13 21:53                   ` [PATCH v6 0/5] da850-evm: add gpio-{keys, leds} " Kevin Hilman
2010-12-14  4:31                   ` [PATCH v6 0/5] da850-evm: add gpio-{keys,leds} " Ben Gardiner
2010-12-14  4:31                     ` Ben Gardiner
2010-12-14 16:17                   ` Ben Gardiner
2010-12-14 17:10                     ` Kevin Hilman
2010-12-17 15:15                       ` Ben Gardiner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bf95cbdc51b1a8ac222a01ac57e5932c3224d5d9.1290540916.git.bengardiner@nanometrics.ca \
    --to=bengardiner@nanometrics.ca \
    --cc=alex@digriz.org.uk \
    --cc=christophercordahi@nanometrics.ca \
    --cc=davinci-linux-open-source@linux.davincidsp.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=khilman@deeprootsystems.com \
    --cc=lethal@linux-sh.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nsekhar@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.