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> 2578a56aabSPhil Blundell #include <linux/irq.h> 2649015beeSDavid Brownell #include <linux/gpio_keys.h> 2778a56aabSPhil Blundell 280d98f6bbSPhilipp Zabel #include <asm/gpio.h> 2978a56aabSPhil Blundell 3078a56aabSPhil Blundell static irqreturn_t gpio_keys_isr(int irq, void *dev_id) 3178a56aabSPhil Blundell { 3278a56aabSPhil Blundell int i; 3378a56aabSPhil Blundell struct platform_device *pdev = dev_id; 3478a56aabSPhil Blundell struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 3578a56aabSPhil Blundell struct input_dev *input = platform_get_drvdata(pdev); 3678a56aabSPhil Blundell 3778a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) { 3884767d00SRoman Moravcik struct gpio_keys_button *button = &pdata->buttons[i]; 3984767d00SRoman Moravcik int gpio = button->gpio; 4078a56aabSPhil Blundell 4184767d00SRoman Moravcik if (irq == gpio_to_irq(gpio)) { 4284767d00SRoman Moravcik unsigned int type = button->type ?: EV_KEY; 4384767d00SRoman Moravcik int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; 4484767d00SRoman Moravcik 4584767d00SRoman Moravcik input_event(input, type, button->code, !!state); 4678a56aabSPhil Blundell input_sync(input); 4778a56aabSPhil Blundell } 4878a56aabSPhil Blundell } 4978a56aabSPhil Blundell 5078a56aabSPhil Blundell return IRQ_HANDLED; 5178a56aabSPhil Blundell } 5278a56aabSPhil Blundell 5378a56aabSPhil Blundell static int __devinit gpio_keys_probe(struct platform_device *pdev) 5478a56aabSPhil Blundell { 5578a56aabSPhil Blundell struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 5678a56aabSPhil Blundell struct input_dev *input; 5778a56aabSPhil Blundell int i, error; 58*e15b0213SAnti Sullin int wakeup = 0; 5978a56aabSPhil Blundell 6078a56aabSPhil Blundell input = input_allocate_device(); 6178a56aabSPhil Blundell if (!input) 6278a56aabSPhil Blundell return -ENOMEM; 6378a56aabSPhil Blundell 6478a56aabSPhil Blundell platform_set_drvdata(pdev, input); 6578a56aabSPhil Blundell 6678a56aabSPhil Blundell input->evbit[0] = BIT(EV_KEY); 6778a56aabSPhil Blundell 6878a56aabSPhil Blundell input->name = pdev->name; 6978a56aabSPhil Blundell input->phys = "gpio-keys/input0"; 70469ba4dfSDmitry Torokhov input->dev.parent = &pdev->dev; 7178a56aabSPhil Blundell 7278a56aabSPhil Blundell input->id.bustype = BUS_HOST; 7378a56aabSPhil Blundell input->id.vendor = 0x0001; 7478a56aabSPhil Blundell input->id.product = 0x0001; 7578a56aabSPhil Blundell input->id.version = 0x0100; 7678a56aabSPhil Blundell 7778a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) { 7884767d00SRoman Moravcik struct gpio_keys_button *button = &pdata->buttons[i]; 7984767d00SRoman Moravcik int irq = gpio_to_irq(button->gpio); 8084767d00SRoman Moravcik unsigned int type = button->type ?: EV_KEY; 8178a56aabSPhil Blundell 82006df302SAnti Sullin if (irq < 0) { 83006df302SAnti Sullin error = irq; 84006df302SAnti Sullin printk(KERN_ERR 85006df302SAnti Sullin "gpio-keys: " 86006df302SAnti Sullin "Unable to get irq number for GPIO %d," 87006df302SAnti Sullin "error %d\n", 88006df302SAnti Sullin button->gpio, error); 89006df302SAnti Sullin goto fail; 90006df302SAnti Sullin } 91006df302SAnti Sullin 92006df302SAnti Sullin error = request_irq(irq, gpio_keys_isr, 93006df302SAnti Sullin IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | 94006df302SAnti Sullin IRQF_TRIGGER_FALLING, 9584767d00SRoman Moravcik button->desc ? button->desc : "gpio_keys", 9678a56aabSPhil Blundell pdev); 9778a56aabSPhil Blundell if (error) { 98006df302SAnti Sullin printk(KERN_ERR 99006df302SAnti Sullin "gpio-keys: Unable to claim irq %d; error %d\n", 1000d98f6bbSPhilipp Zabel irq, error); 10178a56aabSPhil Blundell goto fail; 10278a56aabSPhil Blundell } 10384767d00SRoman Moravcik 104*e15b0213SAnti Sullin if (button->wakeup) 105*e15b0213SAnti Sullin wakeup = 1; 106*e15b0213SAnti Sullin 10784767d00SRoman Moravcik input_set_capability(input, type, button->code); 10878a56aabSPhil Blundell } 10978a56aabSPhil Blundell 11078a56aabSPhil Blundell error = input_register_device(input); 11178a56aabSPhil Blundell if (error) { 112006df302SAnti Sullin printk(KERN_ERR 113006df302SAnti Sullin "gpio-keys: Unable to register input device, " 114006df302SAnti Sullin "error: %d\n", error); 11578a56aabSPhil Blundell goto fail; 11678a56aabSPhil Blundell } 11778a56aabSPhil Blundell 118*e15b0213SAnti Sullin device_init_wakeup(&pdev->dev, wakeup); 119*e15b0213SAnti Sullin 12078a56aabSPhil Blundell return 0; 12178a56aabSPhil Blundell 12278a56aabSPhil Blundell fail: 123006df302SAnti Sullin while (--i >= 0) 1240d98f6bbSPhilipp Zabel free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); 12578a56aabSPhil Blundell 126006df302SAnti Sullin platform_set_drvdata(pdev, NULL); 12778a56aabSPhil Blundell input_free_device(input); 12878a56aabSPhil Blundell 12978a56aabSPhil Blundell return error; 13078a56aabSPhil Blundell } 13178a56aabSPhil Blundell 13278a56aabSPhil Blundell static int __devexit gpio_keys_remove(struct platform_device *pdev) 13378a56aabSPhil Blundell { 13478a56aabSPhil Blundell struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 13578a56aabSPhil Blundell struct input_dev *input = platform_get_drvdata(pdev); 13678a56aabSPhil Blundell int i; 13778a56aabSPhil Blundell 138*e15b0213SAnti Sullin device_init_wakeup(&pdev->dev, 0); 139*e15b0213SAnti Sullin 14078a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) { 1410d98f6bbSPhilipp Zabel int irq = gpio_to_irq(pdata->buttons[i].gpio); 14278a56aabSPhil Blundell free_irq(irq, pdev); 14378a56aabSPhil Blundell } 14478a56aabSPhil Blundell 14578a56aabSPhil Blundell input_unregister_device(input); 14678a56aabSPhil Blundell 14778a56aabSPhil Blundell return 0; 14878a56aabSPhil Blundell } 14978a56aabSPhil Blundell 150*e15b0213SAnti Sullin 151*e15b0213SAnti Sullin #ifdef CONFIG_PM 152*e15b0213SAnti Sullin static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) 153*e15b0213SAnti Sullin { 154*e15b0213SAnti Sullin struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 155*e15b0213SAnti Sullin int i; 156*e15b0213SAnti Sullin 157*e15b0213SAnti Sullin if (device_may_wakeup(&pdev->dev)) { 158*e15b0213SAnti Sullin for (i = 0; i < pdata->nbuttons; i++) { 159*e15b0213SAnti Sullin struct gpio_keys_button *button = &pdata->buttons[i]; 160*e15b0213SAnti Sullin if (button->wakeup) { 161*e15b0213SAnti Sullin int irq = gpio_to_irq(button->gpio); 162*e15b0213SAnti Sullin enable_irq_wake(irq); 163*e15b0213SAnti Sullin } 164*e15b0213SAnti Sullin } 165*e15b0213SAnti Sullin } 166*e15b0213SAnti Sullin 167*e15b0213SAnti Sullin return 0; 168*e15b0213SAnti Sullin } 169*e15b0213SAnti Sullin 170*e15b0213SAnti Sullin static int gpio_keys_resume(struct platform_device *pdev) 171*e15b0213SAnti Sullin { 172*e15b0213SAnti Sullin struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 173*e15b0213SAnti Sullin int i; 174*e15b0213SAnti Sullin 175*e15b0213SAnti Sullin if (device_may_wakeup(&pdev->dev)) { 176*e15b0213SAnti Sullin for (i = 0; i < pdata->nbuttons; i++) { 177*e15b0213SAnti Sullin struct gpio_keys_button *button = &pdata->buttons[i]; 178*e15b0213SAnti Sullin if (button->wakeup) { 179*e15b0213SAnti Sullin int irq = gpio_to_irq(button->gpio); 180*e15b0213SAnti Sullin disable_irq_wake(irq); 181*e15b0213SAnti Sullin } 182*e15b0213SAnti Sullin } 183*e15b0213SAnti Sullin } 184*e15b0213SAnti Sullin 185*e15b0213SAnti Sullin return 0; 186*e15b0213SAnti Sullin } 187*e15b0213SAnti Sullin #else 188*e15b0213SAnti Sullin #define gpio_keys_suspend NULL 189*e15b0213SAnti Sullin #define gpio_keys_resume NULL 190*e15b0213SAnti Sullin #endif 191*e15b0213SAnti Sullin 19278a56aabSPhil Blundell struct platform_driver gpio_keys_device_driver = { 19378a56aabSPhil Blundell .probe = gpio_keys_probe, 19478a56aabSPhil Blundell .remove = __devexit_p(gpio_keys_remove), 195*e15b0213SAnti Sullin .suspend = gpio_keys_suspend, 196*e15b0213SAnti Sullin .resume = gpio_keys_resume, 19778a56aabSPhil Blundell .driver = { 19878a56aabSPhil Blundell .name = "gpio-keys", 19978a56aabSPhil Blundell } 20078a56aabSPhil Blundell }; 20178a56aabSPhil Blundell 20278a56aabSPhil Blundell static int __init gpio_keys_init(void) 20378a56aabSPhil Blundell { 20478a56aabSPhil Blundell return platform_driver_register(&gpio_keys_device_driver); 20578a56aabSPhil Blundell } 20678a56aabSPhil Blundell 20778a56aabSPhil Blundell static void __exit gpio_keys_exit(void) 20878a56aabSPhil Blundell { 20978a56aabSPhil Blundell platform_driver_unregister(&gpio_keys_device_driver); 21078a56aabSPhil Blundell } 21178a56aabSPhil Blundell 21278a56aabSPhil Blundell module_init(gpio_keys_init); 21378a56aabSPhil Blundell module_exit(gpio_keys_exit); 21478a56aabSPhil Blundell 21578a56aabSPhil Blundell MODULE_LICENSE("GPL"); 21678a56aabSPhil Blundell MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); 21778a56aabSPhil Blundell MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); 218