@@ -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;
}
@@ -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