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