[kernel] add a polled GPIO buttons input driver
authorGabor Juhos <juhosg@openwrt.org>
Mon, 7 Apr 2008 19:54:44 +0000 (19:54 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Mon, 7 Apr 2008 19:54:44 +0000 (19:54 +0000)
SVN-Revision: 10766

package/kernel/modules/other.mk
target/linux/generic-2.6/files/drivers/input/misc/gpio_buttons.c [new file with mode: 0644]
target/linux/generic-2.6/files/include/linux/gpio_buttons.h [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.22/410-gpio_buttons.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.23/410-gpio_buttons.patch [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.24/410-gpio_buttons.patch [new file with mode: 0644]

index 03d2f0de6d3d60895b2e8269668c7cc2ba3189e1..921cebf4cf54373dd44abb2d1848b99c743c3c19 100644 (file)
@@ -497,6 +497,40 @@ endef
 $(eval $(call KernelPackage,input-evdev))
 
 
+define KernelPackage/input-polldev
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Polled Input device support
+  DEPENDS:=+kmod-input-core @LINUX_2_6
+  KCONFIG:=CONFIG_INPUT_POLLDEV
+  FILES:=$(LINUX_DIR)/drivers/input/input-polldev.$(LINUX_KMOD_SUFFIX)
+  AUTOLOAD:=$(call AutoLoad,61,input-polldev)
+endef
+
+define KernelPackage/input-polldev/description
+ Kernel module for support of polled input devices
+endef
+
+$(eval $(call KernelPackage,input-polldev))
+
+
+define KernelPackage/input-gpio-buttons
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Polled GPIO buttons input device
+  DEPENDS:=+kmod-input-polldev @LINUX_2_6
+  KCONFIG:= \
+       CONFIG_INPUT_GPIO_BUTTONS \
+       CONFIG_INPUT_MISC=y
+  FILES:=$(LINUX_DIR)/drivers/input/misc/gpio_buttons.$(LINUX_KMOD_SUFFIX)
+  AUTOLOAD:=$(call AutoLoad,62,gpio_buttons)
+endef
+
+define KernelPackage/input-gpio-buttons/description
+ Kernel module for support polled GPIO buttons input device
+endef
+
+$(eval $(call KernelPackage,input-gpio-buttons))
+
+
 define KernelPackage/mmc-spi
   SUBMENU:=$(OTHER_MENU)
   TITLE:=MMC/SD over SPI Support
diff --git a/target/linux/generic-2.6/files/drivers/input/misc/gpio_buttons.c b/target/linux/generic-2.6/files/drivers/input/misc/gpio_buttons.c
new file mode 100644 (file)
index 0000000..0d219ff
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *  Driver for buttons on GPIO lines not capable of generating interrupts
+ *
+ *  Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This file was based on: /drivers/input/misc/cobalt_btns.c
+ *     Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  also was based on: /drivers/input/keyboard/gpio_keys.c
+ *     Copyright 2005 Phil Blundell
+ *
+ *  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
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/gpio_buttons.h>
+
+#include <asm/gpio.h>
+
+#define DRV_NAME       "gpio-buttons"
+#define DRV_VERSION    "0.1.0"
+#define PFX            DRV_NAME ": "
+
+struct gpio_buttons_dev {
+       struct input_polled_dev *poll_dev;
+       struct gpio_buttons_platform_data *pdata;
+};
+
+static void gpio_buttons_poll(struct input_polled_dev *dev)
+{
+       struct gpio_buttons_dev *bdev = dev->private;
+       struct gpio_buttons_platform_data *pdata = bdev->pdata;
+       struct input_dev *input = dev->input;
+       int i;
+
+       for (i = 0; i < bdev->pdata->nbuttons; i++) {
+               struct gpio_button *button = &pdata->buttons[i];
+               unsigned int type = button->type ?: EV_KEY;
+               int state;
+
+               state = gpio_get_value(button->gpio) ? 1 : 0;
+               state ^= button->active_low;
+
+               if (state) {
+                       button->count++;
+               } else {
+                       if (button->count >= button->threshold) {
+                               input_event(input, type, button->code, 1);
+                               input_sync(input);
+                       }
+                       button->count = 0;
+               }
+
+               if (button->count == button->threshold) {
+                       input_event(input, type, button->code, 0);
+                       input_sync(input);
+               }
+       }
+}
+
+static int __devinit gpio_buttons_probe(struct platform_device *pdev)
+{
+       struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_buttons_dev *bdev;
+       struct input_polled_dev *poll_dev;
+       struct input_dev *input;
+       int error, i;
+
+
+       if (!pdata)
+               return -ENXIO;
+
+       bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
+       if (!bdev) {
+               pr_err(DRV_NAME "no memory for device\n");
+               return -ENOMEM;
+       }
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               pr_err(DRV_NAME "no memory for polled device\n");
+               error = -ENOMEM;
+               goto err_free_bdev;
+       }
+
+       poll_dev->private = bdev;
+       poll_dev->poll = gpio_buttons_poll;
+       poll_dev->poll_interval = pdata->poll_interval;
+
+       input = poll_dev->input;
+
+       input->evbit[0] = BIT_MASK(EV_KEY);
+       input->name = pdev->name;
+       input->phys = "gpio-buttons/input0";
+       input->dev.parent = &pdev->dev;
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               struct gpio_button *button = &pdata->buttons[i];
+               unsigned int gpio = button->gpio;
+               unsigned int type = button->type ?: EV_KEY;
+
+               error = gpio_request(gpio, button->desc ?
+                               button->desc : DRV_NAME);
+               if (error) {
+                       pr_err(PFX "unable to claim gpio %u, error %d\n",
+                               gpio, error);
+                       goto err_free_gpio;
+               }
+
+               error = gpio_direction_input(gpio);
+               if (error) {
+                       pr_err(PFX "unable to set direction on gpio %u, "
+                               "error %d\n", gpio, error);
+                       goto err_free_gpio;
+               }
+
+               input_set_capability(input, type, button->code);
+               button->count = 0;
+       }
+
+       bdev->poll_dev = poll_dev;
+       bdev->pdata = pdata;
+       platform_set_drvdata(pdev, bdev);
+
+       error = input_register_polled_device(poll_dev);
+       if (error) {
+               pr_err(PFX "unable to register polled device, error %d\n",
+                           error);
+               goto err_free_gpio;
+       }
+
+       return 0;
+
+err_free_gpio:
+       for (i = i - 1; i >= 0; i--)
+               gpio_free(pdata->buttons[i].gpio);
+
+       input_free_polled_device(poll_dev);
+
+err_free_bdev:
+       kfree(bdev);
+err:
+       platform_set_drvdata(pdev, NULL);
+       return error;
+}
+
+static int __devexit gpio_buttons_remove(struct platform_device *pdev)
+{
+       struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
+       struct gpio_buttons_platform_data *pdata = bdev->pdata;
+       int i;
+
+       input_unregister_polled_device(bdev->poll_dev);
+
+       for (i = 0; i < pdata->nbuttons; i++)
+               gpio_free(pdata->buttons[i].gpio);
+
+       input_free_polled_device(bdev->poll_dev);
+
+       kfree(bdev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver gpio_buttons_driver = {
+       .probe  = gpio_buttons_probe,
+       .remove = __devexit_p(gpio_buttons_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init gpio_buttons_init(void)
+{
+       pr_info(DRV_NAME " driver version " DRV_VERSION "\n");
+       return platform_driver_register(&gpio_buttons_driver);
+}
+
+static void __exit gpio_buttons_exit(void)
+{
+       platform_driver_unregister(&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");
+
diff --git a/target/linux/generic-2.6/files/include/linux/gpio_buttons.h b/target/linux/generic-2.6/files/include/linux/gpio_buttons.h
new file mode 100644 (file)
index 0000000..f5e6297
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Definitions for the GPIO buttons interface driver
+ *
+ *  Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This file was based on: /include/linux/gpio_keys.h
+ *     The original gpio_keys.h seems not to have a license.
+ *
+ *  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
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _GPIO_BUTTONS_H_
+#define _GPIO_BUTTONS_H_
+
+struct gpio_button {
+       int     gpio;           /* GPIO line number */
+       int     active_low;
+       char    *desc;          /* button description */
+       int     type;           /* input event type (EV_KEY, EV_SW) */
+       int     code;           /* input event code (KEY_*, SW_*) */
+       int     count;
+       int     threshold;      /* count threshold */
+};
+
+struct gpio_buttons_platform_data {
+       struct gpio_button *buttons;
+       int     nbuttons;               /* number of buttons */
+       int     poll_interval;          /* polling interval */
+};
+
+#endif /* _GPIO_BUTTONS_H_ */
+
diff --git a/target/linux/generic-2.6/patches-2.6.22/410-gpio_buttons.patch b/target/linux/generic-2.6/patches-2.6.22/410-gpio_buttons.patch
new file mode 100644 (file)
index 0000000..8e215f9
--- /dev/null
@@ -0,0 +1,30 @@
+--- linux-2.6.22.orig/drivers/input/misc/Kconfig       2007-08-21 06:33:06.000000000 +0200
++++ linux-2.6.22/drivers/input/misc/Kconfig    2007-10-08 10:57:23.000000000 +0200
+@@ -178,4 +178,20 @@
+         Say Y here if you want to support the built-in real time clock
+         of the HP SDC controller.
++config INPUT_GPIO_BUTTONS
++      tristate "Polled GPIO buttons interface"
++      depends on GENERIC_GPIO
++      select INPUT_POLLDEV
++      help
++        This driver implements support for buttons connected
++        to GPIO pins of various CPUs (and some other chips).
++
++        Say Y here if your device has buttons connected
++        directly to such GPIO pins.  Your board-specific
++        setup logic must also provide a platform device,
++        with configuration data saying which GPIOs are used.
++
++        To compile this driver as a module, choose M here: the
++        module will be called gpio-buttons.
++
+ endif
+--- linux-2.6.22.4.orig/drivers/input/misc/Makefile    2007-08-21 06:33:06.000000000 +0200
++++ linux-2.6.22.4/drivers/input/misc/Makefile 2007-10-08 10:50:12.000000000 +0200
+@@ -18,3 +18,4 @@
+ obj-$(CONFIG_INPUT_YEALINK)           += yealink.o
+ obj-$(CONFIG_HP_SDC_RTC)              += hp_sdc_rtc.o
+ obj-$(CONFIG_INPUT_UINPUT)            += uinput.o
++obj-$(CONFIG_INPUT_GPIO_BUTTONS)      += gpio_buttons.o
diff --git a/target/linux/generic-2.6/patches-2.6.23/410-gpio_buttons.patch b/target/linux/generic-2.6/patches-2.6.23/410-gpio_buttons.patch
new file mode 100644 (file)
index 0000000..6de5d70
--- /dev/null
@@ -0,0 +1,30 @@
+--- linux-2.6.23.orig/drivers/input/misc/Kconfig       2007-08-21 06:33:06.000000000 +0200
++++ linux-2.6.23/drivers/input/misc/Kconfig    2007-10-08 10:57:23.000000000 +0200
+@@ -178,4 +178,20 @@
+         Say Y here if you want to support the built-in real time clock
+         of the HP SDC controller.
++config INPUT_GPIO_BUTTONS
++      tristate "Polled GPIO buttons interface"
++      depends on GENERIC_GPIO
++      select INPUT_POLLDEV
++      help
++        This driver implements support for buttons connected
++        to GPIO pins of various CPUs (and some other chips).
++
++        Say Y here if your device has buttons connected
++        directly to such GPIO pins.  Your board-specific
++        setup logic must also provide a platform device,
++        with configuration data saying which GPIOs are used.
++
++        To compile this driver as a module, choose M here: the
++        module will be called gpio-buttons.
++
+ endif
+--- linux-2.6.23.orig/drivers/input/misc/Makefile      2007-08-21 06:33:06.000000000 +0200
++++ linux-2.6.23/drivers/input/misc/Makefile   2007-10-08 10:50:12.000000000 +0200
+@@ -18,3 +18,4 @@
+ obj-$(CONFIG_INPUT_YEALINK)           += yealink.o
+ obj-$(CONFIG_HP_SDC_RTC)              += hp_sdc_rtc.o
+ obj-$(CONFIG_INPUT_UINPUT)            += uinput.o
++obj-$(CONFIG_INPUT_GPIO_BUTTONS)      += gpio_buttons.o
diff --git a/target/linux/generic-2.6/patches-2.6.24/410-gpio_buttons.patch b/target/linux/generic-2.6/patches-2.6.24/410-gpio_buttons.patch
new file mode 100644 (file)
index 0000000..0395715
--- /dev/null
@@ -0,0 +1,30 @@
+--- linux-2.6.24.2.orig/drivers/input/misc/Kconfig     2007-08-21 06:33:06.000000000 +0200
++++ linux-2.6.24.2/drivers/input/misc/Kconfig  2007-10-08 10:57:23.000000000 +0200
+@@ -178,4 +178,20 @@
+         Say Y here if you want to support the built-in real time clock
+         of the HP SDC controller.
++config INPUT_GPIO_BUTTONS
++      tristate "Polled GPIO buttons interface"
++      depends on GENERIC_GPIO
++      select INPUT_POLLDEV
++      help
++        This driver implements support for buttons connected
++        to GPIO pins of various CPUs (and some other chips).
++
++        Say Y here if your device has buttons connected
++        directly to such GPIO pins.  Your board-specific
++        setup logic must also provide a platform device,
++        with configuration data saying which GPIOs are used.
++
++        To compile this driver as a module, choose M here: the
++        module will be called gpio-buttons.
++
+ endif
+--- linux-2.6.24.2.orig/drivers/input/misc/Makefile    2007-08-21 06:33:06.000000000 +0200
++++ linux-2.6.24.2/drivers/input/misc/Makefile 2007-10-08 10:50:12.000000000 +0200
+@@ -18,3 +18,4 @@
+ obj-$(CONFIG_INPUT_YEALINK)           += yealink.o
+ obj-$(CONFIG_HP_SDC_RTC)              += hp_sdc_rtc.o
+ obj-$(CONFIG_INPUT_UINPUT)            += uinput.o
++obj-$(CONFIG_INPUT_GPIO_BUTTONS)      += gpio_buttons.o