#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-
+#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
-
+#include <linux/gpio.h>
#include <linux/gpio_buttons.h>
-#include <asm/gpio.h>
-
#define DRV_NAME "gpio-buttons"
-#define DRV_VERSION "0.1.2"
-#define PFX DRV_NAME ": "
struct gpio_button_data {
int last_state;
int count;
+ int can_sleep;
};
struct gpio_buttons_dev {
struct gpio_button_data *data;
};
+static void gpio_buttons_check_state(struct input_dev *input,
+ struct gpio_button *button,
+ struct gpio_button_data *bdata)
+{
+ int state;
+
+ if (bdata->can_sleep)
+ state = !!gpio_get_value_cansleep(button->gpio);
+ else
+ state = !!gpio_get_value(button->gpio);
+
+ if (state != bdata->last_state) {
+ unsigned int type = button->type ?: EV_KEY;
+
+ input_event(input, type, button->code,
+ !!(state ^ button->active_low));
+ input_sync(input);
+ bdata->count = 0;
+ bdata->last_state = state;
+ }
+}
+
static void gpio_buttons_poll(struct input_polled_dev *dev)
{
struct gpio_buttons_dev *bdev = dev->private;
for (i = 0; i < bdev->pdata->nbuttons; i++) {
struct gpio_button *button = &pdata->buttons[i];
- unsigned int type = button->type ?: EV_KEY;
- int state;
+ struct gpio_button_data *bdata = &bdev->data[i];
- if (bdev->data[i].count < button->threshold) {
- bdev->data[i].count++;
- continue;
- }
+ if (bdata->count < button->threshold)
+ bdata->count++;
+ else
+ gpio_buttons_check_state(input, button, bdata);
- state = gpio_get_value(button->gpio) ? 1 : 0;
- if (state != bdev->data[i].last_state) {
- input_event(input, type, button->code,
- !!(state ^ button->active_low));
- input_sync(input);
- bdev->data[i].count = 0;
- bdev->data[i].last_state = state;
- }
}
}
static int __devinit gpio_buttons_probe(struct platform_device *pdev)
{
struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
struct gpio_buttons_dev *bdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
- int error, i;
+ int error;
+ int i;
if (!pdata)
return -ENXIO;
bdev = kzalloc(sizeof(struct gpio_buttons_dev) +
- sizeof(struct gpio_button_data) * pdata->nbuttons,
+ pdata->nbuttons * sizeof(struct gpio_button_data),
GFP_KERNEL);
if (!bdev) {
- printk(KERN_ERR DRV_NAME "no memory for device\n");
+ dev_err(dev, "no memory for private data\n");
return -ENOMEM;
}
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
- printk(KERN_ERR DRV_NAME "no memory for polled device\n");
+ dev_err(dev, "no memory for polled device\n");
error = -ENOMEM;
goto err_free_bdev;
}
unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
- error = gpio_request(gpio, button->desc ?
- button->desc : DRV_NAME);
+ error = gpio_request(gpio,
+ button->desc ? button->desc : DRV_NAME);
if (error) {
- printk(KERN_ERR PFX "unable to claim gpio %u, "
- "error %d\n", gpio, error);
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ gpio, error);
goto err_free_gpio;
}
error = gpio_direction_input(gpio);
if (error) {
- printk(KERN_ERR PFX "unable to set direction on "
- "gpio %u, error %d\n", gpio, error);
+ dev_err(dev,
+ "unable to set direction on gpio %u, err=%d\n",
+ gpio, error);
goto err_free_gpio;
}
+ bdev->data[i].can_sleep = gpio_cansleep(gpio);
+ bdev->data[i].last_state = -1;
+
input_set_capability(input, type, button->code);
- bdev->data[i].last_state = gpio_get_value(button->gpio) ? 1 : 0;
}
bdev->poll_dev = poll_dev;
error = input_register_polled_device(poll_dev);
if (error) {
- printk(KERN_ERR PFX "unable to register polled device, "
- "error %d\n", error);
+ dev_err(dev, "unable to register polled device, err=%d\n",
+ error);
goto err_free_gpio;
}
+ /* report initial state of the buttons */
+ for (i = 0; i < pdata->nbuttons; i++)
+ gpio_buttons_check_state(input, &pdata->buttons[i],
+ &bdev->data[i]);
+
return 0;
err_free_gpio:
static int __init gpio_buttons_init(void)
{
- printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
return platform_driver_register(&gpio_buttons_driver);
}
module_init(gpio_buttons_init);
module_exit(gpio_buttons_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
-MODULE_VERSION(DRV_VERSION);
-MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");
-
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("Polled GPIO Buttons driver");