Commit 0e7d0c860a0dee49dacb7bbb248d1eba637075ad

Authored by Gabor Juhos
Committed by Dmitry Torokhov
1 parent 8ed9e0e1b6

Input: add input driver for polled GPIO buttons

The existing gpio-keys driver can be usable only for GPIO lines with
interrupt support. Several devices have buttons connected to a GPIO
line which is not capable to generate interrupts. This patch adds a
new input driver using the generic GPIO layer and the input-polldev
to support such buttons.

[Ben Gardiner <bengardiner@nanometrics.ca: fold code to use more
 of the original gpio_keys infrastructure; cleanups and other
 improvements.]

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Tested-by: Ben Gardiner <bengardiner@nanometrics.ca>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

Showing 4 changed files with 280 additions and 0 deletions Side-by-side Diff

drivers/input/keyboard/Kconfig
... ... @@ -179,6 +179,22 @@
179 179 To compile this driver as a module, choose M here: the
180 180 module will be called gpio_keys.
181 181  
  182 +config KEYBOARD_GPIO_POLLED
  183 + tristate "Polled GPIO buttons"
  184 + depends on GENERIC_GPIO
  185 + select INPUT_POLLDEV
  186 + help
  187 + This driver implements support for buttons connected
  188 + to GPIO pins that are not capable of generating interrupts.
  189 +
  190 + Say Y here if your device has buttons connected
  191 + directly to such GPIO pins. Your board-specific
  192 + setup logic must also provide a platform device,
  193 + with configuration data saying which GPIOs are used.
  194 +
  195 + To compile this driver as a module, choose M here: the
  196 + module will be called gpio_keys_polled.
  197 +
182 198 config KEYBOARD_TCA6416
183 199 tristate "TCA6416 Keypad Support"
184 200 depends on I2C
drivers/input/keyboard/Makefile
... ... @@ -14,6 +14,7 @@
14 14 obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
15 15 obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
16 16 obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
  17 +obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
17 18 obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
18 19 obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
19 20 obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
drivers/input/keyboard/gpio_keys_polled.c
  1 +/*
  2 + * Driver for buttons on GPIO lines not capable of generating interrupts
  3 + *
  4 + * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
  5 + * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
  6 + *
  7 + * This file was based on: /drivers/input/misc/cobalt_btns.c
  8 + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
  9 + *
  10 + * also was based on: /drivers/input/keyboard/gpio_keys.c
  11 + * Copyright 2005 Phil Blundell
  12 + *
  13 + * This program is free software; you can redistribute it and/or modify
  14 + * it under the terms of the GNU General Public License version 2 as
  15 + * published by the Free Software Foundation.
  16 + */
  17 +
  18 +#include <linux/kernel.h>
  19 +#include <linux/module.h>
  20 +#include <linux/init.h>
  21 +#include <linux/slab.h>
  22 +#include <linux/input.h>
  23 +#include <linux/input-polldev.h>
  24 +#include <linux/ioport.h>
  25 +#include <linux/platform_device.h>
  26 +#include <linux/gpio.h>
  27 +#include <linux/gpio_keys.h>
  28 +
  29 +#define DRV_NAME "gpio-keys-polled"
  30 +
  31 +struct gpio_keys_button_data {
  32 + int last_state;
  33 + int count;
  34 + int threshold;
  35 + int can_sleep;
  36 +};
  37 +
  38 +struct gpio_keys_polled_dev {
  39 + struct input_polled_dev *poll_dev;
  40 + struct device *dev;
  41 + struct gpio_keys_platform_data *pdata;
  42 + struct gpio_keys_button_data data[0];
  43 +};
  44 +
  45 +static void gpio_keys_polled_check_state(struct input_dev *input,
  46 + struct gpio_keys_button *button,
  47 + struct gpio_keys_button_data *bdata)
  48 +{
  49 + int state;
  50 +
  51 + if (bdata->can_sleep)
  52 + state = !!gpio_get_value_cansleep(button->gpio);
  53 + else
  54 + state = !!gpio_get_value(button->gpio);
  55 +
  56 + if (state != bdata->last_state) {
  57 + unsigned int type = button->type ?: EV_KEY;
  58 +
  59 + input_event(input, type, button->code,
  60 + !!(state ^ button->active_low));
  61 + input_sync(input);
  62 + bdata->count = 0;
  63 + bdata->last_state = state;
  64 + }
  65 +}
  66 +
  67 +static void gpio_keys_polled_poll(struct input_polled_dev *dev)
  68 +{
  69 + struct gpio_keys_polled_dev *bdev = dev->private;
  70 + struct gpio_keys_platform_data *pdata = bdev->pdata;
  71 + struct input_dev *input = dev->input;
  72 + int i;
  73 +
  74 + for (i = 0; i < bdev->pdata->nbuttons; i++) {
  75 + struct gpio_keys_button_data *bdata = &bdev->data[i];
  76 +
  77 + if (bdata->count < bdata->threshold)
  78 + bdata->count++;
  79 + else
  80 + gpio_keys_polled_check_state(input, &pdata->buttons[i],
  81 + bdata);
  82 + }
  83 +}
  84 +
  85 +static void gpio_keys_polled_open(struct input_polled_dev *dev)
  86 +{
  87 + struct gpio_keys_polled_dev *bdev = dev->private;
  88 + struct gpio_keys_platform_data *pdata = bdev->pdata;
  89 +
  90 + if (pdata->enable)
  91 + pdata->enable(bdev->dev);
  92 +}
  93 +
  94 +static void gpio_keys_polled_close(struct input_polled_dev *dev)
  95 +{
  96 + struct gpio_keys_polled_dev *bdev = dev->private;
  97 + struct gpio_keys_platform_data *pdata = bdev->pdata;
  98 +
  99 + if (pdata->disable)
  100 + pdata->disable(bdev->dev);
  101 +}
  102 +
  103 +static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
  104 +{
  105 + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
  106 + struct device *dev = &pdev->dev;
  107 + struct gpio_keys_polled_dev *bdev;
  108 + struct input_polled_dev *poll_dev;
  109 + struct input_dev *input;
  110 + int error;
  111 + int i;
  112 +
  113 + if (!pdata || !pdata->poll_interval)
  114 + return -EINVAL;
  115 +
  116 + bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
  117 + pdata->nbuttons * sizeof(struct gpio_keys_button_data),
  118 + GFP_KERNEL);
  119 + if (!bdev) {
  120 + dev_err(dev, "no memory for private data\n");
  121 + return -ENOMEM;
  122 + }
  123 +
  124 + poll_dev = input_allocate_polled_device();
  125 + if (!poll_dev) {
  126 + dev_err(dev, "no memory for polled device\n");
  127 + error = -ENOMEM;
  128 + goto err_free_bdev;
  129 + }
  130 +
  131 + poll_dev->private = bdev;
  132 + poll_dev->poll = gpio_keys_polled_poll;
  133 + poll_dev->poll_interval = pdata->poll_interval;
  134 + poll_dev->open = gpio_keys_polled_open;
  135 + poll_dev->close = gpio_keys_polled_close;
  136 +
  137 + input = poll_dev->input;
  138 +
  139 + input->evbit[0] = BIT(EV_KEY);
  140 + input->name = pdev->name;
  141 + input->phys = DRV_NAME"/input0";
  142 + input->dev.parent = &pdev->dev;
  143 +
  144 + input->id.bustype = BUS_HOST;
  145 + input->id.vendor = 0x0001;
  146 + input->id.product = 0x0001;
  147 + input->id.version = 0x0100;
  148 +
  149 + for (i = 0; i < pdata->nbuttons; i++) {
  150 + struct gpio_keys_button *button = &pdata->buttons[i];
  151 + struct gpio_keys_button_data *bdata = &bdev->data[i];
  152 + unsigned int gpio = button->gpio;
  153 + unsigned int type = button->type ?: EV_KEY;
  154 +
  155 + if (button->wakeup) {
  156 + dev_err(dev, DRV_NAME " does not support wakeup\n");
  157 + error = -EINVAL;
  158 + goto err_free_gpio;
  159 + }
  160 +
  161 + error = gpio_request(gpio,
  162 + button->desc ? button->desc : DRV_NAME);
  163 + if (error) {
  164 + dev_err(dev, "unable to claim gpio %u, err=%d\n",
  165 + gpio, error);
  166 + goto err_free_gpio;
  167 + }
  168 +
  169 + error = gpio_direction_input(gpio);
  170 + if (error) {
  171 + dev_err(dev,
  172 + "unable to set direction on gpio %u, err=%d\n",
  173 + gpio, error);
  174 + goto err_free_gpio;
  175 + }
  176 +
  177 + bdata->can_sleep = gpio_cansleep(gpio);
  178 + bdata->last_state = -1;
  179 + bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
  180 + pdata->poll_interval);
  181 +
  182 + input_set_capability(input, type, button->code);
  183 + }
  184 +
  185 + bdev->poll_dev = poll_dev;
  186 + bdev->dev = dev;
  187 + bdev->pdata = pdata;
  188 + platform_set_drvdata(pdev, bdev);
  189 +
  190 + error = input_register_polled_device(poll_dev);
  191 + if (error) {
  192 + dev_err(dev, "unable to register polled device, err=%d\n",
  193 + error);
  194 + goto err_free_gpio;
  195 + }
  196 +
  197 + /* report initial state of the buttons */
  198 + for (i = 0; i < pdata->nbuttons; i++)
  199 + gpio_keys_polled_check_state(input, &pdata->buttons[i],
  200 + &bdev->data[i]);
  201 +
  202 + return 0;
  203 +
  204 +err_free_gpio:
  205 + while (--i >= 0)
  206 + gpio_free(pdata->buttons[i].gpio);
  207 +
  208 + input_free_polled_device(poll_dev);
  209 +
  210 +err_free_bdev:
  211 + kfree(bdev);
  212 +
  213 + platform_set_drvdata(pdev, NULL);
  214 + return error;
  215 +}
  216 +
  217 +static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
  218 +{
  219 + struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
  220 + struct gpio_keys_platform_data *pdata = bdev->pdata;
  221 + int i;
  222 +
  223 + input_unregister_polled_device(bdev->poll_dev);
  224 +
  225 + for (i = 0; i < pdata->nbuttons; i++)
  226 + gpio_free(pdata->buttons[i].gpio);
  227 +
  228 + input_free_polled_device(bdev->poll_dev);
  229 +
  230 + kfree(bdev);
  231 + platform_set_drvdata(pdev, NULL);
  232 +
  233 + return 0;
  234 +}
  235 +
  236 +static struct platform_driver gpio_keys_polled_driver = {
  237 + .probe = gpio_keys_polled_probe,
  238 + .remove = __devexit_p(gpio_keys_polled_remove),
  239 + .driver = {
  240 + .name = DRV_NAME,
  241 + .owner = THIS_MODULE,
  242 + },
  243 +};
  244 +
  245 +static int __init gpio_keys_polled_init(void)
  246 +{
  247 + return platform_driver_register(&gpio_keys_polled_driver);
  248 +}
  249 +
  250 +static void __exit gpio_keys_polled_exit(void)
  251 +{
  252 + platform_driver_unregister(&gpio_keys_polled_driver);
  253 +}
  254 +
  255 +module_init(gpio_keys_polled_init);
  256 +module_exit(gpio_keys_polled_exit);
  257 +
  258 +MODULE_LICENSE("GPL v2");
  259 +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
  260 +MODULE_DESCRIPTION("Polled GPIO Buttons driver");
  261 +MODULE_ALIAS("platform:" DRV_NAME);
include/linux/gpio_keys.h
... ... @@ -16,6 +16,8 @@
16 16 struct gpio_keys_platform_data {
17 17 struct gpio_keys_button *buttons;
18 18 int nbuttons;
  19 + unsigned int poll_interval; /* polling interval in msecs -
  20 + for polling driver only */
19 21 unsigned int rep:1; /* enable input subsystem auto repeat */
20 22 int (*enable)(struct device *dev);
21 23 void (*disable)(struct device *dev);