7b19ada2ed
get rid of input BIT* duplicate defines use newly global defined macros for input layer. Also remove includes of input.h from non-input sources only for BIT macro definiton. Define the macro temporarily in local manner, all those local definitons will be removed further in this patchset (to not break bisecting). BIT macro will be globally defined (1<<x) Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Cc: <dtor@mail.ru> Acked-by: Jiri Kosina <jkosina@suse.cz> Cc: <lenb@kernel.org> Acked-by: Marcel Holtmann <marcel@holtmann.org> Cc: <perex@suse.cz> Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org> Cc: <vernux@us.ibm.com> Cc: <malattia@linux.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
216 lines
4.8 KiB
C
216 lines
4.8 KiB
C
/*
|
|
* Driver for keys on GPIO lines capable of generating interrupts.
|
|
*
|
|
* 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/module.h>
|
|
#include <linux/version.h>
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/sysctl.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/input.h>
|
|
#include <linux/gpio_keys.h>
|
|
|
|
#include <asm/gpio.h>
|
|
|
|
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
|
|
{
|
|
int i;
|
|
struct platform_device *pdev = dev_id;
|
|
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
|
struct input_dev *input = platform_get_drvdata(pdev);
|
|
|
|
for (i = 0; i < pdata->nbuttons; i++) {
|
|
struct gpio_keys_button *button = &pdata->buttons[i];
|
|
int gpio = button->gpio;
|
|
|
|
if (irq == gpio_to_irq(gpio)) {
|
|
unsigned int type = button->type ?: EV_KEY;
|
|
int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;
|
|
|
|
input_event(input, type, button->code, !!state);
|
|
input_sync(input);
|
|
}
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
|
{
|
|
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
|
struct input_dev *input;
|
|
int i, error;
|
|
int wakeup = 0;
|
|
|
|
input = input_allocate_device();
|
|
if (!input)
|
|
return -ENOMEM;
|
|
|
|
platform_set_drvdata(pdev, input);
|
|
|
|
input->evbit[0] = BIT_MASK(EV_KEY);
|
|
|
|
input->name = pdev->name;
|
|
input->phys = "gpio-keys/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_keys_button *button = &pdata->buttons[i];
|
|
int irq = gpio_to_irq(button->gpio);
|
|
unsigned int type = button->type ?: EV_KEY;
|
|
|
|
if (irq < 0) {
|
|
error = irq;
|
|
printk(KERN_ERR
|
|
"gpio-keys: "
|
|
"Unable to get irq number for GPIO %d,"
|
|
"error %d\n",
|
|
button->gpio, error);
|
|
goto fail;
|
|
}
|
|
|
|
error = request_irq(irq, gpio_keys_isr,
|
|
IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
|
|
IRQF_TRIGGER_FALLING,
|
|
button->desc ? button->desc : "gpio_keys",
|
|
pdev);
|
|
if (error) {
|
|
printk(KERN_ERR
|
|
"gpio-keys: Unable to claim irq %d; error %d\n",
|
|
irq, error);
|
|
goto fail;
|
|
}
|
|
|
|
if (button->wakeup)
|
|
wakeup = 1;
|
|
|
|
input_set_capability(input, type, button->code);
|
|
}
|
|
|
|
error = input_register_device(input);
|
|
if (error) {
|
|
printk(KERN_ERR
|
|
"gpio-keys: Unable to register input device, "
|
|
"error: %d\n", error);
|
|
goto fail;
|
|
}
|
|
|
|
device_init_wakeup(&pdev->dev, wakeup);
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
while (--i >= 0)
|
|
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
|
|
|
|
platform_set_drvdata(pdev, NULL);
|
|
input_free_device(input);
|
|
|
|
return error;
|
|
}
|
|
|
|
static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
|
{
|
|
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
|
struct input_dev *input = platform_get_drvdata(pdev);
|
|
int i;
|
|
|
|
device_init_wakeup(&pdev->dev, 0);
|
|
|
|
for (i = 0; i < pdata->nbuttons; i++) {
|
|
int irq = gpio_to_irq(pdata->buttons[i].gpio);
|
|
free_irq(irq, pdev);
|
|
}
|
|
|
|
input_unregister_device(input);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
|
|
{
|
|
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
|
int i;
|
|
|
|
if (device_may_wakeup(&pdev->dev)) {
|
|
for (i = 0; i < pdata->nbuttons; i++) {
|
|
struct gpio_keys_button *button = &pdata->buttons[i];
|
|
if (button->wakeup) {
|
|
int irq = gpio_to_irq(button->gpio);
|
|
enable_irq_wake(irq);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gpio_keys_resume(struct platform_device *pdev)
|
|
{
|
|
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
|
int i;
|
|
|
|
if (device_may_wakeup(&pdev->dev)) {
|
|
for (i = 0; i < pdata->nbuttons; i++) {
|
|
struct gpio_keys_button *button = &pdata->buttons[i];
|
|
if (button->wakeup) {
|
|
int irq = gpio_to_irq(button->gpio);
|
|
disable_irq_wake(irq);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
#define gpio_keys_suspend NULL
|
|
#define gpio_keys_resume NULL
|
|
#endif
|
|
|
|
struct platform_driver gpio_keys_device_driver = {
|
|
.probe = gpio_keys_probe,
|
|
.remove = __devexit_p(gpio_keys_remove),
|
|
.suspend = gpio_keys_suspend,
|
|
.resume = gpio_keys_resume,
|
|
.driver = {
|
|
.name = "gpio-keys",
|
|
}
|
|
};
|
|
|
|
static int __init gpio_keys_init(void)
|
|
{
|
|
return platform_driver_register(&gpio_keys_device_driver);
|
|
}
|
|
|
|
static void __exit gpio_keys_exit(void)
|
|
{
|
|
platform_driver_unregister(&gpio_keys_device_driver);
|
|
}
|
|
|
|
module_init(gpio_keys_init);
|
|
module_exit(gpio_keys_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
|
|
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
|