gpio_keys.c 6.4 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
#include <linux/workqueue.h>
26

27
#include <asm/gpio.h>
28

29 30 31
struct gpio_button_data {
	struct gpio_keys_button *button;
	struct input_dev *input;
32
	struct delayed_work work;
33 34 35 36 37 38 39
};

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

40
static void gpio_keys_report_event(struct work_struct *work)
41
{
42 43
	struct gpio_button_data *bdata =
		container_of(work, struct gpio_button_data, work.work);
44 45
	struct gpio_keys_button *button = bdata->button;
	struct input_dev *input = bdata->input;
46 47 48 49 50 51 52
	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);
}

53 54
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
55 56
	struct gpio_button_data *bdata = dev_id;
	struct gpio_keys_button *button = bdata->button;
57
	unsigned long delay;
58

59
	BUG_ON(irq != gpio_to_irq(button->gpio));
60

61 62 63
	delay = button->debounce_interval ?
			msecs_to_jiffies(button->debounce_interval) : 0;
	schedule_delayed_work(&bdata->work, delay);
64

65
	return IRQ_HANDLED;
66 67 68 69 70
}

static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
71
	struct gpio_keys_drvdata *ddata;
72 73
	struct input_dev *input;
	int i, error;
74
	int wakeup = 0;
75

76 77 78
	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
			pdata->nbuttons * sizeof(struct gpio_button_data),
			GFP_KERNEL);
79
	input = input_allocate_device();
80 81 82 83
	if (!ddata || !input) {
		error = -ENOMEM;
		goto fail1;
	}
84

85
	platform_set_drvdata(pdev, ddata);
86 87 88

	input->name = pdev->name;
	input->phys = "gpio-keys/input0";
89
	input->dev.parent = &pdev->dev;
90 91 92 93 94 95

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

96 97 98 99
	/* Enable auto repeat feature of Linux input subsystem */
	if (pdata->rep)
		__set_bit(EV_REP, input->evbit);

100 101
	ddata->input = input;

102
	for (i = 0; i < pdata->nbuttons; i++) {
103
		struct gpio_keys_button *button = &pdata->buttons[i];
104
		struct gpio_button_data *bdata = &ddata->data[i];
105
		int irq;
106
		unsigned int type = button->type ?: EV_KEY;
107

108
		bdata->input = input;
109
		bdata->button = button;
110
		INIT_DELAYED_WORK(&bdata->work, gpio_keys_report_event);
111

112 113 114 115
		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);
116
			goto fail2;
117 118 119 120 121 122 123 124
		}

		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);
125
			goto fail2;
126 127 128
		}

		irq = gpio_to_irq(button->gpio);
129 130
		if (irq < 0) {
			error = irq;
131 132
			pr_err("gpio-keys: Unable to get irq number"
				" for GPIO %d, error %d\n",
133
				button->gpio, error);
134
			gpio_free(button->gpio);
135
			goto fail2;
136 137 138
		}

		error = request_irq(irq, gpio_keys_isr,
139
				    IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
140
				    button->desc ? button->desc : "gpio_keys",
141
				    bdata);
142
		if (error) {
143
			pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
144
				irq, error);
145
			gpio_free(button->gpio);
146
			goto fail2;
147
		}
148

149 150 151
		if (button->wakeup)
			wakeup = 1;

152
		input_set_capability(input, type, button->code);
153 154 155 156
	}

	error = input_register_device(input);
	if (error) {
157
		pr_err("gpio-keys: Unable to register input device, "
158
			"error: %d\n", error);
159
		goto fail2;
160 161
	}

162 163
	device_init_wakeup(&pdev->dev, wakeup);

164 165
	return 0;

166
 fail2:
167
	while (--i >= 0) {
168
		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
169
		cancel_delayed_work_sync(&ddata->data[i].work);
170 171
		gpio_free(pdata->buttons[i].gpio);
	}
172

173
	platform_set_drvdata(pdev, NULL);
174
 fail1:
175
	input_free_device(input);
176
	kfree(ddata);
177 178 179 180 181 182 183

	return error;
}

static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
184 185
	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
	struct input_dev *input = ddata->input;
186 187
	int i;

188 189
	device_init_wakeup(&pdev->dev, 0);

190
	for (i = 0; i < pdata->nbuttons; i++) {
191
		int irq = gpio_to_irq(pdata->buttons[i].gpio);
192
		free_irq(irq, &ddata->data[i]);
193
		cancel_delayed_work_sync(&ddata->data[i].work);
194
		gpio_free(pdata->buttons[i].gpio);
195 196 197 198 199 200 201
	}

	input_unregister_device(input);

	return 0;
}

202 203 204 205 206 207 208 209 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

#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

244
static struct platform_driver gpio_keys_device_driver = {
245 246
	.probe		= gpio_keys_probe,
	.remove		= __devexit_p(gpio_keys_remove),
247 248
	.suspend	= gpio_keys_suspend,
	.resume		= gpio_keys_resume,
249 250
	.driver		= {
		.name	= "gpio-keys",
251
		.owner	= THIS_MODULE,
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
	}
};

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