xref: /openbmc/linux/drivers/input/keyboard/gpio_keys.c (revision 6a2e391190b17f4fb895bd2d5e8b08c7c8f897a2)
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 #include <linux/version.h>
1378a56aabSPhil Blundell 
1478a56aabSPhil Blundell #include <linux/init.h>
1578a56aabSPhil Blundell #include <linux/fs.h>
1678a56aabSPhil Blundell #include <linux/interrupt.h>
1778a56aabSPhil Blundell #include <linux/irq.h>
1878a56aabSPhil Blundell #include <linux/sched.h>
1978a56aabSPhil Blundell #include <linux/pm.h>
2078a56aabSPhil Blundell #include <linux/sysctl.h>
2178a56aabSPhil Blundell #include <linux/proc_fs.h>
2278a56aabSPhil Blundell #include <linux/delay.h>
2378a56aabSPhil Blundell #include <linux/platform_device.h>
2478a56aabSPhil Blundell #include <linux/input.h>
2549015beeSDavid Brownell #include <linux/gpio_keys.h>
2678a56aabSPhil Blundell 
270d98f6bbSPhilipp Zabel #include <asm/gpio.h>
2878a56aabSPhil Blundell 
2978a56aabSPhil Blundell static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
3078a56aabSPhil Blundell {
3178a56aabSPhil Blundell 	int i;
3278a56aabSPhil Blundell 	struct platform_device *pdev = dev_id;
3378a56aabSPhil Blundell 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
3478a56aabSPhil Blundell 	struct input_dev *input = platform_get_drvdata(pdev);
3578a56aabSPhil Blundell 
3678a56aabSPhil Blundell 	for (i = 0; i < pdata->nbuttons; i++) {
3784767d00SRoman Moravcik 		struct gpio_keys_button *button = &pdata->buttons[i];
3884767d00SRoman Moravcik 		int gpio = button->gpio;
3978a56aabSPhil Blundell 
4084767d00SRoman Moravcik 		if (irq == gpio_to_irq(gpio)) {
4184767d00SRoman Moravcik 			unsigned int type = button->type ?: EV_KEY;
4284767d00SRoman Moravcik 			int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;
4384767d00SRoman Moravcik 
4484767d00SRoman Moravcik 			input_event(input, type, button->code, !!state);
4578a56aabSPhil Blundell 			input_sync(input);
4678a56aabSPhil Blundell 		}
4778a56aabSPhil Blundell 	}
4878a56aabSPhil Blundell 
4978a56aabSPhil Blundell 	return IRQ_HANDLED;
5078a56aabSPhil Blundell }
5178a56aabSPhil Blundell 
5278a56aabSPhil Blundell static int __devinit gpio_keys_probe(struct platform_device *pdev)
5378a56aabSPhil Blundell {
5478a56aabSPhil Blundell 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
5578a56aabSPhil Blundell 	struct input_dev *input;
5678a56aabSPhil Blundell 	int i, error;
57e15b0213SAnti Sullin 	int wakeup = 0;
5878a56aabSPhil Blundell 
5978a56aabSPhil Blundell 	input = input_allocate_device();
6078a56aabSPhil Blundell 	if (!input)
6178a56aabSPhil Blundell 		return -ENOMEM;
6278a56aabSPhil Blundell 
6378a56aabSPhil Blundell 	platform_set_drvdata(pdev, input);
6478a56aabSPhil Blundell 
657b19ada2SJiri Slaby 	input->evbit[0] = BIT_MASK(EV_KEY);
6678a56aabSPhil Blundell 
6778a56aabSPhil Blundell 	input->name = pdev->name;
6878a56aabSPhil Blundell 	input->phys = "gpio-keys/input0";
69469ba4dfSDmitry Torokhov 	input->dev.parent = &pdev->dev;
7078a56aabSPhil Blundell 
7178a56aabSPhil Blundell 	input->id.bustype = BUS_HOST;
7278a56aabSPhil Blundell 	input->id.vendor = 0x0001;
7378a56aabSPhil Blundell 	input->id.product = 0x0001;
7478a56aabSPhil Blundell 	input->id.version = 0x0100;
7578a56aabSPhil Blundell 
7678a56aabSPhil Blundell 	for (i = 0; i < pdata->nbuttons; i++) {
7784767d00SRoman Moravcik 		struct gpio_keys_button *button = &pdata->buttons[i];
78*6a2e3911SHerbert Valerio Riedel 		int irq;
7984767d00SRoman Moravcik 		unsigned int type = button->type ?: EV_KEY;
8078a56aabSPhil Blundell 
81*6a2e3911SHerbert Valerio Riedel 		error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
82*6a2e3911SHerbert Valerio Riedel 		if (error < 0) {
83*6a2e3911SHerbert Valerio Riedel 			pr_err("gpio-keys: failed to request GPIO %d,"
84*6a2e3911SHerbert Valerio Riedel 				" error %d\n", button->gpio, error);
85*6a2e3911SHerbert Valerio Riedel 			goto fail;
86*6a2e3911SHerbert Valerio Riedel 		}
87*6a2e3911SHerbert Valerio Riedel 
88*6a2e3911SHerbert Valerio Riedel 		error = gpio_direction_input(button->gpio);
89*6a2e3911SHerbert Valerio Riedel 		if (error < 0) {
90*6a2e3911SHerbert Valerio Riedel 			pr_err("gpio-keys: failed to configure input"
91*6a2e3911SHerbert Valerio Riedel 				" direction for GPIO %d, error %d\n",
92*6a2e3911SHerbert Valerio Riedel 				button->gpio, error);
93*6a2e3911SHerbert Valerio Riedel 			gpio_free(button->gpio);
94*6a2e3911SHerbert Valerio Riedel 			goto fail;
95*6a2e3911SHerbert Valerio Riedel 		}
96*6a2e3911SHerbert Valerio Riedel 
97*6a2e3911SHerbert Valerio Riedel 		irq = gpio_to_irq(button->gpio);
98006df302SAnti Sullin 		if (irq < 0) {
99006df302SAnti Sullin 			error = irq;
100*6a2e3911SHerbert Valerio Riedel 			pr_err("gpio-keys: Unable to get irq number"
101*6a2e3911SHerbert Valerio Riedel 				" for GPIO %d, error %d\n",
102006df302SAnti Sullin 				button->gpio, error);
103*6a2e3911SHerbert Valerio Riedel 			gpio_free(button->gpio);
104006df302SAnti Sullin 			goto fail;
105006df302SAnti Sullin 		}
106006df302SAnti Sullin 
107006df302SAnti Sullin 		error = request_irq(irq, gpio_keys_isr,
108006df302SAnti Sullin 				    IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
109006df302SAnti Sullin 					IRQF_TRIGGER_FALLING,
11084767d00SRoman Moravcik 				    button->desc ? button->desc : "gpio_keys",
11178a56aabSPhil Blundell 				    pdev);
11278a56aabSPhil Blundell 		if (error) {
113*6a2e3911SHerbert Valerio Riedel 			pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
1140d98f6bbSPhilipp Zabel 				irq, error);
115*6a2e3911SHerbert Valerio Riedel 			gpio_free(button->gpio);
11678a56aabSPhil Blundell 			goto fail;
11778a56aabSPhil Blundell 		}
11884767d00SRoman Moravcik 
119e15b0213SAnti Sullin 		if (button->wakeup)
120e15b0213SAnti Sullin 			wakeup = 1;
121e15b0213SAnti Sullin 
12284767d00SRoman Moravcik 		input_set_capability(input, type, button->code);
12378a56aabSPhil Blundell 	}
12478a56aabSPhil Blundell 
12578a56aabSPhil Blundell 	error = input_register_device(input);
12678a56aabSPhil Blundell 	if (error) {
127*6a2e3911SHerbert Valerio Riedel 		pr_err("gpio-keys: Unable to register input device, "
128006df302SAnti Sullin 			"error: %d\n", error);
12978a56aabSPhil Blundell 		goto fail;
13078a56aabSPhil Blundell 	}
13178a56aabSPhil Blundell 
132e15b0213SAnti Sullin 	device_init_wakeup(&pdev->dev, wakeup);
133e15b0213SAnti Sullin 
13478a56aabSPhil Blundell 	return 0;
13578a56aabSPhil Blundell 
13678a56aabSPhil Blundell  fail:
137*6a2e3911SHerbert Valerio Riedel 	while (--i >= 0) {
1380d98f6bbSPhilipp Zabel 		free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
139*6a2e3911SHerbert Valerio Riedel 		gpio_free(pdata->buttons[i].gpio);
140*6a2e3911SHerbert Valerio Riedel 	}
14178a56aabSPhil Blundell 
142006df302SAnti Sullin 	platform_set_drvdata(pdev, NULL);
14378a56aabSPhil Blundell 	input_free_device(input);
14478a56aabSPhil Blundell 
14578a56aabSPhil Blundell 	return error;
14678a56aabSPhil Blundell }
14778a56aabSPhil Blundell 
14878a56aabSPhil Blundell static int __devexit gpio_keys_remove(struct platform_device *pdev)
14978a56aabSPhil Blundell {
15078a56aabSPhil Blundell 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
15178a56aabSPhil Blundell 	struct input_dev *input = platform_get_drvdata(pdev);
15278a56aabSPhil Blundell 	int i;
15378a56aabSPhil Blundell 
154e15b0213SAnti Sullin 	device_init_wakeup(&pdev->dev, 0);
155e15b0213SAnti Sullin 
15678a56aabSPhil Blundell 	for (i = 0; i < pdata->nbuttons; i++) {
1570d98f6bbSPhilipp Zabel 		int irq = gpio_to_irq(pdata->buttons[i].gpio);
15878a56aabSPhil Blundell 		free_irq(irq, pdev);
159*6a2e3911SHerbert Valerio Riedel 		gpio_free(pdata->buttons[i].gpio);
16078a56aabSPhil Blundell 	}
16178a56aabSPhil Blundell 
16278a56aabSPhil Blundell 	input_unregister_device(input);
16378a56aabSPhil Blundell 
16478a56aabSPhil Blundell 	return 0;
16578a56aabSPhil Blundell }
16678a56aabSPhil Blundell 
167e15b0213SAnti Sullin 
168e15b0213SAnti Sullin #ifdef CONFIG_PM
169e15b0213SAnti Sullin static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
170e15b0213SAnti Sullin {
171e15b0213SAnti Sullin 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
172e15b0213SAnti Sullin 	int i;
173e15b0213SAnti Sullin 
174e15b0213SAnti Sullin 	if (device_may_wakeup(&pdev->dev)) {
175e15b0213SAnti Sullin 		for (i = 0; i < pdata->nbuttons; i++) {
176e15b0213SAnti Sullin 			struct gpio_keys_button *button = &pdata->buttons[i];
177e15b0213SAnti Sullin 			if (button->wakeup) {
178e15b0213SAnti Sullin 				int irq = gpio_to_irq(button->gpio);
179e15b0213SAnti Sullin 				enable_irq_wake(irq);
180e15b0213SAnti Sullin 			}
181e15b0213SAnti Sullin 		}
182e15b0213SAnti Sullin 	}
183e15b0213SAnti Sullin 
184e15b0213SAnti Sullin 	return 0;
185e15b0213SAnti Sullin }
186e15b0213SAnti Sullin 
187e15b0213SAnti Sullin static int gpio_keys_resume(struct platform_device *pdev)
188e15b0213SAnti Sullin {
189e15b0213SAnti Sullin 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
190e15b0213SAnti Sullin 	int i;
191e15b0213SAnti Sullin 
192e15b0213SAnti Sullin 	if (device_may_wakeup(&pdev->dev)) {
193e15b0213SAnti Sullin 		for (i = 0; i < pdata->nbuttons; i++) {
194e15b0213SAnti Sullin 			struct gpio_keys_button *button = &pdata->buttons[i];
195e15b0213SAnti Sullin 			if (button->wakeup) {
196e15b0213SAnti Sullin 				int irq = gpio_to_irq(button->gpio);
197e15b0213SAnti Sullin 				disable_irq_wake(irq);
198e15b0213SAnti Sullin 			}
199e15b0213SAnti Sullin 		}
200e15b0213SAnti Sullin 	}
201e15b0213SAnti Sullin 
202e15b0213SAnti Sullin 	return 0;
203e15b0213SAnti Sullin }
204e15b0213SAnti Sullin #else
205e15b0213SAnti Sullin #define gpio_keys_suspend	NULL
206e15b0213SAnti Sullin #define gpio_keys_resume	NULL
207e15b0213SAnti Sullin #endif
208e15b0213SAnti Sullin 
20978a56aabSPhil Blundell struct platform_driver gpio_keys_device_driver = {
21078a56aabSPhil Blundell 	.probe		= gpio_keys_probe,
21178a56aabSPhil Blundell 	.remove		= __devexit_p(gpio_keys_remove),
212e15b0213SAnti Sullin 	.suspend	= gpio_keys_suspend,
213e15b0213SAnti Sullin 	.resume		= gpio_keys_resume,
21478a56aabSPhil Blundell 	.driver		= {
21578a56aabSPhil Blundell 		.name	= "gpio-keys",
21678a56aabSPhil Blundell 	}
21778a56aabSPhil Blundell };
21878a56aabSPhil Blundell 
21978a56aabSPhil Blundell static int __init gpio_keys_init(void)
22078a56aabSPhil Blundell {
22178a56aabSPhil Blundell 	return platform_driver_register(&gpio_keys_device_driver);
22278a56aabSPhil Blundell }
22378a56aabSPhil Blundell 
22478a56aabSPhil Blundell static void __exit gpio_keys_exit(void)
22578a56aabSPhil Blundell {
22678a56aabSPhil Blundell 	platform_driver_unregister(&gpio_keys_device_driver);
22778a56aabSPhil Blundell }
22878a56aabSPhil Blundell 
22978a56aabSPhil Blundell module_init(gpio_keys_init);
23078a56aabSPhil Blundell module_exit(gpio_keys_exit);
23178a56aabSPhil Blundell 
23278a56aabSPhil Blundell MODULE_LICENSE("GPL");
23378a56aabSPhil Blundell MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
23478a56aabSPhil Blundell MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
235