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