gpio_keys.c 6.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * 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/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>
24
#include <linux/gpio_keys.h>
25

26
#include <asm/gpio.h>
27

28 29 30 31 32 33 34 35 36 37 38
struct gpio_button_data {
	struct gpio_keys_button *button;
	struct input_dev *input;
	struct timer_list timer;
};

struct gpio_keys_drvdata {
	struct input_dev *input;
	struct gpio_button_data data[0];
};

39
static void gpio_keys_report_event(struct gpio_button_data *bdata)
40
{
41 42
	struct gpio_keys_button *button = bdata->button;
	struct input_dev *input = bdata->input;
43 44 45 46 47 48 49 50 51 52 53
	unsigned int type = button->type ?: EV_KEY;
	int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;

	input_event(input, type, button->code, !!state);
	input_sync(input);
}

static void gpio_check_button(unsigned long _data)
{
	struct gpio_button_data *data = (struct gpio_button_data *)_data;

54
	gpio_keys_report_event(data);
55 56
}

57 58
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
59 60
	struct gpio_button_data *bdata = dev_id;
	struct gpio_keys_button *button = bdata->button;
61

62
	BUG_ON(irq != gpio_to_irq(button->gpio));
63

64 65 66 67
	if (button->debounce_interval)
		mod_timer(&bdata->timer,
			jiffies + msecs_to_jiffies(button->debounce_interval));
	else
68
		gpio_keys_report_event(bdata);
69

70
	return IRQ_HANDLED;
71 72 73 74 75
}

static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
76
	struct gpio_keys_drvdata *ddata;
77 78
	struct input_dev *input;
	int i, error;
79
	int wakeup = 0;
80

81 82 83
	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
			pdata->nbuttons * sizeof(struct gpio_button_data),
			GFP_KERNEL);
84
	input = input_allocate_device();
85 86 87 88
	if (!ddata || !input) {
		error = -ENOMEM;
		goto fail1;
	}
89

90
	platform_set_drvdata(pdev, ddata);
91 92 93

	input->name = pdev->name;
	input->phys = "gpio-keys/input0";
94
	input->dev.parent = &pdev->dev;
95 96 97 98 99 100

	input->id.bustype = BUS_HOST;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;

101 102 103 104
	/* Enable auto repeat feature of Linux input subsystem */
	if (pdata->rep)
		__set_bit(EV_REP, input->evbit);

105 106
	ddata->input = input;

107
	for (i = 0; i < pdata->nbuttons; i++) {
108
		struct gpio_keys_button *button = &pdata->buttons[i];
109
		struct gpio_button_data *bdata = &ddata->data[i];
110
		int irq;
111
		unsigned int type = button->type ?: EV_KEY;
112

113
		bdata->input = input;
114
		bdata->button = button;
115 116 117
		setup_timer(&bdata->timer,
			    gpio_check_button, (unsigned long)bdata);

118 119 120 121
		error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
		if (error < 0) {
			pr_err("gpio-keys: failed to request GPIO %d,"
				" error %d\n", button->gpio, error);
122
			goto fail2;
123 124 125 126 127 128 129 130
		}

		error = gpio_direction_input(button->gpio);
		if (error < 0) {
			pr_err("gpio-keys: failed to configure input"
				" direction for GPIO %d, error %d\n",
				button->gpio, error);
			gpio_free(button->gpio);
131
			goto fail2;
132 133 134
		}

		irq = gpio_to_irq(button->gpio);
135 136
		if (irq < 0) {
			error = irq;
137 138
			pr_err("gpio-keys: Unable to get irq number"
				" for GPIO %d, error %d\n",
139
				button->gpio, error);
140
			gpio_free(button->gpio);
141
			goto fail2;
142 143 144 145 146 147
		}

		error = request_irq(irq, gpio_keys_isr,
				    IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
					IRQF_TRIGGER_FALLING,
				    button->desc ? button->desc : "gpio_keys",
148
				    bdata);
149
		if (error) {
150
			pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
151
				irq, error);
152
			gpio_free(button->gpio);
153
			goto fail2;
154
		}
155

156 157 158
		if (button->wakeup)
			wakeup = 1;

159
		input_set_capability(input, type, button->code);
160 161 162 163
	}

	error = input_register_device(input);
	if (error) {
164
		pr_err("gpio-keys: Unable to register input device, "
165
			"error: %d\n", error);
166
		goto fail2;
167 168
	}

169 170
	device_init_wakeup(&pdev->dev, wakeup);

171 172
	return 0;

173
 fail2:
174
	while (--i >= 0) {
175
		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
176 177
		if (pdata->buttons[i].debounce_interval)
			del_timer_sync(&ddata->data[i].timer);
178 179
		gpio_free(pdata->buttons[i].gpio);
	}
180

181
	platform_set_drvdata(pdev, NULL);
182
 fail1:
183
	input_free_device(input);
184
	kfree(ddata);
185 186 187 188 189 190 191

	return error;
}

static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
192 193
	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
	struct input_dev *input = ddata->input;
194 195
	int i;

196 197
	device_init_wakeup(&pdev->dev, 0);

198
	for (i = 0; i < pdata->nbuttons; i++) {
199
		int irq = gpio_to_irq(pdata->buttons[i].gpio);
200
		free_irq(irq, &ddata->data[i]);
201 202
		if (pdata->buttons[i].debounce_interval)
			del_timer_sync(&ddata->data[i].timer);
203
		gpio_free(pdata->buttons[i].gpio);
204 205 206 207 208 209 210
	}

	input_unregister_device(input);

	return 0;
}

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

#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

253
static struct platform_driver gpio_keys_device_driver = {
254 255
	.probe		= gpio_keys_probe,
	.remove		= __devexit_p(gpio_keys_remove),
256 257
	.suspend	= gpio_keys_suspend,
	.resume		= gpio_keys_resume,
258 259
	.driver		= {
		.name	= "gpio-keys",
260
		.owner	= THIS_MODULE,
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
	}
};

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");
280
MODULE_ALIAS("platform:gpio-keys");