diff --git a/drivers/Kconfig b/drivers/Kconfig index c4e1517..c058b25 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -14,5 +14,6 @@ source "drivers/mfd/Kconfig" source "drivers/led/Kconfig" source "drivers/eeprom/Kconfig" +source "drivers/input/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 592c39e..61e85af 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -13,3 +13,4 @@ obj-y += mfd/ obj-$(CONFIG_LED) += led/ obj-y += eeprom/ +obj-y += input/ diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig new file mode 100644 index 0000000..b488553 --- /dev/null +++ b/drivers/input/Kconfig @@ -0,0 +1,19 @@ +# +# Input device configuration +# + +menu "Input device support" + +config KEYBOARD_GPIO + bool "GPIO Buttons" + depends on GENERIC_GPIO + 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. + +endmenu diff --git a/drivers/input/Makefile b/drivers/input/Makefile new file mode 100644 index 0000000..7784d52 --- /dev/null +++ b/drivers/input/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o diff --git a/drivers/input/gpio_keys.c b/drivers/input/gpio_keys.c new file mode 100644 index 0000000..4d0f6ab --- /dev/null +++ b/drivers/input/gpio_keys.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include + +static inline struct gpio_keys_platform_data * +poller_to_gk_pdata(struct poller_struct *poller) +{ + return container_of(poller, struct gpio_keys_platform_data, poller); +} + +static inline struct gpio_keys_platform_data * +cdev_to_gk_pdata(struct console_device *cdev) +{ + return container_of(cdev, struct gpio_keys_platform_data, cdev); +} + +static void gpio_key_poller(struct poller_struct *poller) +{ + struct gpio_keys_platform_data *pdata = poller_to_gk_pdata(poller); + struct gpio_keys_button *gb; + int i, val; + + for (i = 0; i < pdata->nbuttons; i++) { + + gb = &pdata->buttons[i]; + val = gpio_get_value(gb->gpio); + + if (val != gb->previous_state && val != gb->active_low) { + kfifo_put(pdata->recv_fifo, (u_char*)&gb->code, sizeof(int)); + debug("pressed gpio(%d) as %d\n", gb->gpio, gb->code); + } + gb->previous_state = val; + } +} + +static int gpio_keys_tstc(struct console_device *cdev) +{ + struct gpio_keys_platform_data *pdata = cdev_to_gk_pdata(cdev); + + return (kfifo_len(pdata->recv_fifo) == 0) ? 0 : 1; +} + +static int gpio_keys_getc(struct console_device *cdev) +{ + int code = 0; + struct gpio_keys_platform_data *pdata = cdev_to_gk_pdata(cdev); + + kfifo_get(pdata->recv_fifo, (u_char*)&code, sizeof(int)); + return code; +} + +static int __init gpio_keys_probe(struct device_d *dev) +{ + int ret, i, gpio; + struct gpio_keys_platform_data *pdata; + struct console_device *cdev; + + pdata = dev->platform_data; + + if (!pdata) { + /* small (so we copy it) but critical! */ + pr_err("missing platform_data\n"); + return -ENODEV; + } + + if (!pdata->fifo_size) + pdata->fifo_size = 50; + + pdata->recv_fifo = kfifo_alloc(pdata->fifo_size); + + for (i = 0; i < pdata->nbuttons; i++) { + gpio = pdata->buttons->gpio; + ret = gpio_request(gpio, "gpio_keys"); + if (ret) { + pr_err("gpio_keys: (%d) can not be requested\n", gpio); + return ret; + } + gpio_direction_input(gpio); + } + + pdata->poller.func = gpio_key_poller; + + cdev = &pdata->cdev; + dev->type_data = cdev; + cdev->dev = dev; + cdev->f_caps = CONSOLE_STDIN; + cdev->tstc = gpio_keys_tstc; + cdev->getc = gpio_keys_getc; + + console_register(&pdata->cdev); + + return poller_register(&pdata->poller); +} + +static struct driver_d gpio_keys_driver = { + .name = "gpio_keys", + .probe = gpio_keys_probe, +}; + +static int gpio_keys_init(void) +{ + register_driver(&gpio_keys_driver); + return 0; +} +device_initcall(gpio_keys_init); diff --git a/include/driver.h b/include/driver.h index 1b8b16d..51d6393 100644 --- a/include/driver.h +++ b/include/driver.h @@ -260,6 +260,11 @@ return add_usb_ehci_device(id, base + 0x100, base + 0x140, pdata); } +static inline struct device_d *add_gpio_keys_device(int id, void *pdata) +{ + return add_generic_device_res("gpio_keys", id, 0, 0, pdata); +} + /* linear list over all available devices */ extern struct list_head device_list; diff --git a/include/gpio_keys.h b/include/gpio_keys.h new file mode 100644 index 0000000..fc548fa --- /dev/null +++ b/include/gpio_keys.h @@ -0,0 +1,30 @@ +#ifndef _GPIO_KEYS_H +#define _GPIO_KEYS_H + +#include +#include + +struct gpio_keys_button { + /* Configuration parameters */ + int code; + + int gpio; + int active_low; + + /* internal */ + int previous_state; +}; + +struct gpio_keys_platform_data { + struct gpio_keys_button *buttons; + int nbuttons; + + /* optional */ + int fifo_size; + + struct kfifo *recv_fifo; + struct poller_struct poller; + struct console_device cdev; +}; + +#endif