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
		}

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

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

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

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

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

170 171
	return 0;

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

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

	return error;
}

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

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

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

	input_unregister_device(input);

	return 0;
}

210 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

#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

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

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