xref: /openbmc/linux/drivers/input/keyboard/gpio_keys.c (revision 6ee88d713fb75ab191515f66edffa4e866386565)
178a56aabSPhil Blundell /*
278a56aabSPhil Blundell  * Driver for keys on GPIO lines capable of generating interrupts.
378a56aabSPhil Blundell  *
478a56aabSPhil Blundell  * Copyright 2005 Phil Blundell
578a56aabSPhil Blundell  *
678a56aabSPhil Blundell  * This program is free software; you can redistribute it and/or modify
778a56aabSPhil Blundell  * it under the terms of the GNU General Public License version 2 as
878a56aabSPhil Blundell  * published by the Free Software Foundation.
978a56aabSPhil Blundell  */
1078a56aabSPhil Blundell 
1178a56aabSPhil Blundell #include <linux/module.h>
1278a56aabSPhil Blundell 
1378a56aabSPhil Blundell #include <linux/init.h>
1478a56aabSPhil Blundell #include <linux/fs.h>
1578a56aabSPhil Blundell #include <linux/interrupt.h>
1678a56aabSPhil Blundell #include <linux/irq.h>
1778a56aabSPhil Blundell #include <linux/sched.h>
1878a56aabSPhil Blundell #include <linux/pm.h>
1978a56aabSPhil Blundell #include <linux/sysctl.h>
2078a56aabSPhil Blundell #include <linux/proc_fs.h>
2178a56aabSPhil Blundell #include <linux/delay.h>
2278a56aabSPhil Blundell #include <linux/platform_device.h>
2378a56aabSPhil Blundell #include <linux/input.h>
2449015beeSDavid Brownell #include <linux/gpio_keys.h>
25da0d03feSJani Nikula #include <linux/workqueue.h>
26111bc59cSBen Dooks #include <linux/gpio.h>
2778a56aabSPhil Blundell 
28a33466e3SDmitry Baryshkov struct gpio_button_data {
29a33466e3SDmitry Baryshkov 	struct gpio_keys_button *button;
30a33466e3SDmitry Baryshkov 	struct input_dev *input;
31ca865a77SJani Nikula 	struct timer_list timer;
32da0d03feSJani Nikula 	struct work_struct work;
33a33466e3SDmitry Baryshkov };
34a33466e3SDmitry Baryshkov 
35a33466e3SDmitry Baryshkov struct gpio_keys_drvdata {
36a33466e3SDmitry Baryshkov 	struct input_dev *input;
37a33466e3SDmitry Baryshkov 	struct gpio_button_data data[0];
38a33466e3SDmitry Baryshkov };
39a33466e3SDmitry Baryshkov 
40*6ee88d71SDaniel Mack static void gpio_keys_report_event(struct gpio_button_data *bdata)
4178a56aabSPhil Blundell {
42ce25d7e9SUwe Kleine-König 	struct gpio_keys_button *button = bdata->button;
43ce25d7e9SUwe Kleine-König 	struct input_dev *input = bdata->input;
4484767d00SRoman Moravcik 	unsigned int type = button->type ?: EV_KEY;
45a33466e3SDmitry Baryshkov 	int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
4684767d00SRoman Moravcik 
4784767d00SRoman Moravcik 	input_event(input, type, button->code, !!state);
4878a56aabSPhil Blundell 	input_sync(input);
49a33466e3SDmitry Baryshkov }
50a33466e3SDmitry Baryshkov 
51*6ee88d71SDaniel Mack static void gpio_keys_work_func(struct work_struct *work)
52*6ee88d71SDaniel Mack {
53*6ee88d71SDaniel Mack 	struct gpio_button_data *bdata =
54*6ee88d71SDaniel Mack 		container_of(work, struct gpio_button_data, work);
55*6ee88d71SDaniel Mack 
56*6ee88d71SDaniel Mack 	gpio_keys_report_event(bdata);
57*6ee88d71SDaniel Mack }
58*6ee88d71SDaniel Mack 
59da0d03feSJani Nikula static void gpio_keys_timer(unsigned long _data)
60ca865a77SJani Nikula {
61ca865a77SJani Nikula 	struct gpio_button_data *data = (struct gpio_button_data *)_data;
62ca865a77SJani Nikula 
63da0d03feSJani Nikula 	schedule_work(&data->work);
64ca865a77SJani Nikula }
65ca865a77SJani Nikula 
66a33466e3SDmitry Baryshkov static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
67a33466e3SDmitry Baryshkov {
6857ffe9d5SUwe Kleine-König 	struct gpio_button_data *bdata = dev_id;
6957ffe9d5SUwe Kleine-König 	struct gpio_keys_button *button = bdata->button;
70a33466e3SDmitry Baryshkov 
7157ffe9d5SUwe Kleine-König 	BUG_ON(irq != gpio_to_irq(button->gpio));
72a33466e3SDmitry Baryshkov 
73ca865a77SJani Nikula 	if (button->debounce_interval)
74ca865a77SJani Nikula 		mod_timer(&bdata->timer,
75ca865a77SJani Nikula 			jiffies + msecs_to_jiffies(button->debounce_interval));
76ca865a77SJani Nikula 	else
77da0d03feSJani Nikula 		schedule_work(&bdata->work);
78a33466e3SDmitry Baryshkov 
791164ec1aSDavid Brownell 	return IRQ_HANDLED;
8078a56aabSPhil Blundell }
8178a56aabSPhil Blundell 
82bc8f1eafSBen Dooks static int __devinit gpio_keys_setup_key(struct device *dev,
83bc8f1eafSBen Dooks 					 struct gpio_button_data *bdata,
84bc8f1eafSBen Dooks 					 struct gpio_keys_button *button)
85bc8f1eafSBen Dooks {
86bc8f1eafSBen Dooks 	char *desc = button->desc ? button->desc : "gpio_keys";
87bc8f1eafSBen Dooks 	int irq, error;
88bc8f1eafSBen Dooks 
89bc8f1eafSBen Dooks 	setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
90*6ee88d71SDaniel Mack 	INIT_WORK(&bdata->work, gpio_keys_work_func);
91bc8f1eafSBen Dooks 
92bc8f1eafSBen Dooks 	error = gpio_request(button->gpio, desc);
93bc8f1eafSBen Dooks 	if (error < 0) {
94bc8f1eafSBen Dooks 		dev_err(dev, "failed to request GPIO %d, error %d\n",
95bc8f1eafSBen Dooks 			button->gpio, error);
96bc8f1eafSBen Dooks 		goto fail2;
97bc8f1eafSBen Dooks 	}
98bc8f1eafSBen Dooks 
99bc8f1eafSBen Dooks 	error = gpio_direction_input(button->gpio);
100bc8f1eafSBen Dooks 	if (error < 0) {
101bc8f1eafSBen Dooks 		dev_err(dev, "failed to configure"
102bc8f1eafSBen Dooks 			" direction for GPIO %d, error %d\n",
103bc8f1eafSBen Dooks 			button->gpio, error);
104bc8f1eafSBen Dooks 		goto fail3;
105bc8f1eafSBen Dooks 	}
106bc8f1eafSBen Dooks 
107bc8f1eafSBen Dooks 	irq = gpio_to_irq(button->gpio);
108bc8f1eafSBen Dooks 	if (irq < 0) {
109bc8f1eafSBen Dooks 		error = irq;
110bc8f1eafSBen Dooks 		dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
111bc8f1eafSBen Dooks 			button->gpio, error);
112bc8f1eafSBen Dooks 		goto fail3;
113bc8f1eafSBen Dooks 	}
114bc8f1eafSBen Dooks 
115bc8f1eafSBen Dooks 	error = request_irq(irq, gpio_keys_isr,
116bc8f1eafSBen Dooks 			    IRQF_SHARED |
117bc8f1eafSBen Dooks 			    IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
118bc8f1eafSBen Dooks 			    desc, bdata);
119bc8f1eafSBen Dooks 	if (error) {
120bc8f1eafSBen Dooks 		dev_err(dev, "Unable to claim irq %d; error %d\n",
121bc8f1eafSBen Dooks 			irq, error);
122bc8f1eafSBen Dooks 		goto fail3;
123bc8f1eafSBen Dooks 	}
124bc8f1eafSBen Dooks 
125bc8f1eafSBen Dooks 	return 0;
126bc8f1eafSBen Dooks 
127bc8f1eafSBen Dooks fail3:
128bc8f1eafSBen Dooks 	gpio_free(button->gpio);
129bc8f1eafSBen Dooks fail2:
130bc8f1eafSBen Dooks 	return error;
131bc8f1eafSBen Dooks }
132bc8f1eafSBen Dooks 
13378a56aabSPhil Blundell static int __devinit gpio_keys_probe(struct platform_device *pdev)
13478a56aabSPhil Blundell {
13578a56aabSPhil Blundell 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
136a33466e3SDmitry Baryshkov 	struct gpio_keys_drvdata *ddata;
137db19fd8bSBen Dooks 	struct device *dev = &pdev->dev;
13878a56aabSPhil Blundell 	struct input_dev *input;
13978a56aabSPhil Blundell 	int i, error;
140e15b0213SAnti Sullin 	int wakeup = 0;
14178a56aabSPhil Blundell 
142a33466e3SDmitry Baryshkov 	ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
143a33466e3SDmitry Baryshkov 			pdata->nbuttons * sizeof(struct gpio_button_data),
144a33466e3SDmitry Baryshkov 			GFP_KERNEL);
14578a56aabSPhil Blundell 	input = input_allocate_device();
146a33466e3SDmitry Baryshkov 	if (!ddata || !input) {
147db19fd8bSBen Dooks 		dev_err(dev, "failed to allocate state\n");
148a33466e3SDmitry Baryshkov 		error = -ENOMEM;
149a33466e3SDmitry Baryshkov 		goto fail1;
150a33466e3SDmitry Baryshkov 	}
15178a56aabSPhil Blundell 
152a33466e3SDmitry Baryshkov 	platform_set_drvdata(pdev, ddata);
15378a56aabSPhil Blundell 
15478a56aabSPhil Blundell 	input->name = pdev->name;
15578a56aabSPhil Blundell 	input->phys = "gpio-keys/input0";
156469ba4dfSDmitry Torokhov 	input->dev.parent = &pdev->dev;
15778a56aabSPhil Blundell 
15878a56aabSPhil Blundell 	input->id.bustype = BUS_HOST;
15978a56aabSPhil Blundell 	input->id.vendor = 0x0001;
16078a56aabSPhil Blundell 	input->id.product = 0x0001;
16178a56aabSPhil Blundell 	input->id.version = 0x0100;
16278a56aabSPhil Blundell 
163b67b4b11SDominic Curran 	/* Enable auto repeat feature of Linux input subsystem */
164b67b4b11SDominic Curran 	if (pdata->rep)
165b67b4b11SDominic Curran 		__set_bit(EV_REP, input->evbit);
166b67b4b11SDominic Curran 
167a33466e3SDmitry Baryshkov 	ddata->input = input;
168a33466e3SDmitry Baryshkov 
16978a56aabSPhil Blundell 	for (i = 0; i < pdata->nbuttons; i++) {
17084767d00SRoman Moravcik 		struct gpio_keys_button *button = &pdata->buttons[i];
171a33466e3SDmitry Baryshkov 		struct gpio_button_data *bdata = &ddata->data[i];
17284767d00SRoman Moravcik 		unsigned int type = button->type ?: EV_KEY;
17378a56aabSPhil Blundell 
174a33466e3SDmitry Baryshkov 		bdata->input = input;
17574dd4393SUwe Kleine-König 		bdata->button = button;
176a33466e3SDmitry Baryshkov 
177bc8f1eafSBen Dooks 		error = gpio_keys_setup_key(dev, bdata, button);
178bc8f1eafSBen Dooks 		if (error)
179a33466e3SDmitry Baryshkov 			goto fail2;
18084767d00SRoman Moravcik 
181e15b0213SAnti Sullin 		if (button->wakeup)
182e15b0213SAnti Sullin 			wakeup = 1;
183e15b0213SAnti Sullin 
18484767d00SRoman Moravcik 		input_set_capability(input, type, button->code);
18578a56aabSPhil Blundell 	}
18678a56aabSPhil Blundell 
18778a56aabSPhil Blundell 	error = input_register_device(input);
18878a56aabSPhil Blundell 	if (error) {
189db19fd8bSBen Dooks 		dev_err(dev, "Unable to register input device, "
190006df302SAnti Sullin 			"error: %d\n", error);
191a33466e3SDmitry Baryshkov 		goto fail2;
19278a56aabSPhil Blundell 	}
19378a56aabSPhil Blundell 
194*6ee88d71SDaniel Mack 	/* get current state of buttons */
195*6ee88d71SDaniel Mack 	for (i = 0; i < pdata->nbuttons; i++)
196*6ee88d71SDaniel Mack 		gpio_keys_report_event(&ddata->data[i]);
197*6ee88d71SDaniel Mack 	input_sync(input);
198*6ee88d71SDaniel Mack 
199e15b0213SAnti Sullin 	device_init_wakeup(&pdev->dev, wakeup);
200e15b0213SAnti Sullin 
20178a56aabSPhil Blundell 	return 0;
20278a56aabSPhil Blundell 
203a33466e3SDmitry Baryshkov  fail2:
2046a2e3911SHerbert Valerio Riedel 	while (--i >= 0) {
20557ffe9d5SUwe Kleine-König 		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
206ca865a77SJani Nikula 		if (pdata->buttons[i].debounce_interval)
207ca865a77SJani Nikula 			del_timer_sync(&ddata->data[i].timer);
208da0d03feSJani Nikula 		cancel_work_sync(&ddata->data[i].work);
2096a2e3911SHerbert Valerio Riedel 		gpio_free(pdata->buttons[i].gpio);
2106a2e3911SHerbert Valerio Riedel 	}
21178a56aabSPhil Blundell 
212006df302SAnti Sullin 	platform_set_drvdata(pdev, NULL);
213a33466e3SDmitry Baryshkov  fail1:
21478a56aabSPhil Blundell 	input_free_device(input);
215a33466e3SDmitry Baryshkov 	kfree(ddata);
21678a56aabSPhil Blundell 
21778a56aabSPhil Blundell 	return error;
21878a56aabSPhil Blundell }
21978a56aabSPhil Blundell 
22078a56aabSPhil Blundell static int __devexit gpio_keys_remove(struct platform_device *pdev)
22178a56aabSPhil Blundell {
22278a56aabSPhil Blundell 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
223a33466e3SDmitry Baryshkov 	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
224a33466e3SDmitry Baryshkov 	struct input_dev *input = ddata->input;
22578a56aabSPhil Blundell 	int i;
22678a56aabSPhil Blundell 
227e15b0213SAnti Sullin 	device_init_wakeup(&pdev->dev, 0);
228e15b0213SAnti Sullin 
22978a56aabSPhil Blundell 	for (i = 0; i < pdata->nbuttons; i++) {
2300d98f6bbSPhilipp Zabel 		int irq = gpio_to_irq(pdata->buttons[i].gpio);
23157ffe9d5SUwe Kleine-König 		free_irq(irq, &ddata->data[i]);
232ca865a77SJani Nikula 		if (pdata->buttons[i].debounce_interval)
233ca865a77SJani Nikula 			del_timer_sync(&ddata->data[i].timer);
234da0d03feSJani Nikula 		cancel_work_sync(&ddata->data[i].work);
2356a2e3911SHerbert Valerio Riedel 		gpio_free(pdata->buttons[i].gpio);
23678a56aabSPhil Blundell 	}
23778a56aabSPhil Blundell 
23878a56aabSPhil Blundell 	input_unregister_device(input);
23978a56aabSPhil Blundell 
24078a56aabSPhil Blundell 	return 0;
24178a56aabSPhil Blundell }
24278a56aabSPhil Blundell 
243e15b0213SAnti Sullin 
244e15b0213SAnti Sullin #ifdef CONFIG_PM
245ae78e0e0SMike Rapoport static int gpio_keys_suspend(struct device *dev)
246e15b0213SAnti Sullin {
247ae78e0e0SMike Rapoport 	struct platform_device *pdev = to_platform_device(dev);
248e15b0213SAnti Sullin 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
249e15b0213SAnti Sullin 	int i;
250e15b0213SAnti Sullin 
251e15b0213SAnti Sullin 	if (device_may_wakeup(&pdev->dev)) {
252e15b0213SAnti Sullin 		for (i = 0; i < pdata->nbuttons; i++) {
253e15b0213SAnti Sullin 			struct gpio_keys_button *button = &pdata->buttons[i];
254e15b0213SAnti Sullin 			if (button->wakeup) {
255e15b0213SAnti Sullin 				int irq = gpio_to_irq(button->gpio);
256e15b0213SAnti Sullin 				enable_irq_wake(irq);
257e15b0213SAnti Sullin 			}
258e15b0213SAnti Sullin 		}
259e15b0213SAnti Sullin 	}
260e15b0213SAnti Sullin 
261e15b0213SAnti Sullin 	return 0;
262e15b0213SAnti Sullin }
263e15b0213SAnti Sullin 
264ae78e0e0SMike Rapoport static int gpio_keys_resume(struct device *dev)
265e15b0213SAnti Sullin {
266ae78e0e0SMike Rapoport 	struct platform_device *pdev = to_platform_device(dev);
267*6ee88d71SDaniel Mack 	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
268e15b0213SAnti Sullin 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
269e15b0213SAnti Sullin 	int i;
270e15b0213SAnti Sullin 
271e15b0213SAnti Sullin 	for (i = 0; i < pdata->nbuttons; i++) {
272*6ee88d71SDaniel Mack 
273e15b0213SAnti Sullin 		struct gpio_keys_button *button = &pdata->buttons[i];
274*6ee88d71SDaniel Mack 		if (button->wakeup && device_may_wakeup(&pdev->dev)) {
275e15b0213SAnti Sullin 			int irq = gpio_to_irq(button->gpio);
276e15b0213SAnti Sullin 			disable_irq_wake(irq);
277e15b0213SAnti Sullin 		}
278*6ee88d71SDaniel Mack 
279*6ee88d71SDaniel Mack 		gpio_keys_report_event(&ddata->data[i]);
280e15b0213SAnti Sullin 	}
281*6ee88d71SDaniel Mack 	input_sync(ddata->input);
282e15b0213SAnti Sullin 
283e15b0213SAnti Sullin 	return 0;
284e15b0213SAnti Sullin }
285ae78e0e0SMike Rapoport 
286ae78e0e0SMike Rapoport static const struct dev_pm_ops gpio_keys_pm_ops = {
287ae78e0e0SMike Rapoport 	.suspend	= gpio_keys_suspend,
288ae78e0e0SMike Rapoport 	.resume		= gpio_keys_resume,
289ae78e0e0SMike Rapoport };
290e15b0213SAnti Sullin #endif
291e15b0213SAnti Sullin 
2929b07044cSUwe Kleine-König static struct platform_driver gpio_keys_device_driver = {
29378a56aabSPhil Blundell 	.probe		= gpio_keys_probe,
29478a56aabSPhil Blundell 	.remove		= __devexit_p(gpio_keys_remove),
29578a56aabSPhil Blundell 	.driver		= {
29678a56aabSPhil Blundell 		.name	= "gpio-keys",
297d7b5247bSKay Sievers 		.owner	= THIS_MODULE,
298ae78e0e0SMike Rapoport #ifdef CONFIG_PM
299ae78e0e0SMike Rapoport 		.pm	= &gpio_keys_pm_ops,
300ae78e0e0SMike Rapoport #endif
30178a56aabSPhil Blundell 	}
30278a56aabSPhil Blundell };
30378a56aabSPhil Blundell 
30478a56aabSPhil Blundell static int __init gpio_keys_init(void)
30578a56aabSPhil Blundell {
30678a56aabSPhil Blundell 	return platform_driver_register(&gpio_keys_device_driver);
30778a56aabSPhil Blundell }
30878a56aabSPhil Blundell 
30978a56aabSPhil Blundell static void __exit gpio_keys_exit(void)
31078a56aabSPhil Blundell {
31178a56aabSPhil Blundell 	platform_driver_unregister(&gpio_keys_device_driver);
31278a56aabSPhil Blundell }
31378a56aabSPhil Blundell 
31478a56aabSPhil Blundell module_init(gpio_keys_init);
31578a56aabSPhil Blundell module_exit(gpio_keys_exit);
31678a56aabSPhil Blundell 
31778a56aabSPhil Blundell MODULE_LICENSE("GPL");
31878a56aabSPhil Blundell MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
31978a56aabSPhil Blundell MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
320d7b5247bSKay Sievers MODULE_ALIAS("platform:gpio-keys");
321