Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Gabor Juhos and committed by
Dmitry Torokhov
0e7d0c86 8ed9e0e1

+280
+16
drivers/input/keyboard/Kconfig
··· 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
+1
drivers/input/keyboard/Makefile
··· 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
+261
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);
+2
include/linux/gpio_keys.h
··· 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);