Path: blob/master/drivers/input/keyboard/gpio_keys_polled.c
15111 views
/*1* Driver for buttons on GPIO lines not capable of generating interrupts2*3* Copyright (C) 2007-2010 Gabor Juhos <[email protected]>4* Copyright (C) 2010 Nuno Goncalves <[email protected]>5*6* This file was based on: /drivers/input/misc/cobalt_btns.c7* Copyright (C) 2007 Yoichi Yuasa <[email protected]>8*9* also was based on: /drivers/input/keyboard/gpio_keys.c10* Copyright 2005 Phil Blundell11*12* This program is free software; you can redistribute it and/or modify13* it under the terms of the GNU General Public License version 2 as14* published by the Free Software Foundation.15*/1617#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/init.h>20#include <linux/slab.h>21#include <linux/input.h>22#include <linux/input-polldev.h>23#include <linux/ioport.h>24#include <linux/platform_device.h>25#include <linux/gpio.h>26#include <linux/gpio_keys.h>2728#define DRV_NAME "gpio-keys-polled"2930struct gpio_keys_button_data {31int last_state;32int count;33int threshold;34int can_sleep;35};3637struct gpio_keys_polled_dev {38struct input_polled_dev *poll_dev;39struct device *dev;40struct gpio_keys_platform_data *pdata;41struct gpio_keys_button_data data[0];42};4344static void gpio_keys_polled_check_state(struct input_dev *input,45struct gpio_keys_button *button,46struct gpio_keys_button_data *bdata)47{48int state;4950if (bdata->can_sleep)51state = !!gpio_get_value_cansleep(button->gpio);52else53state = !!gpio_get_value(button->gpio);5455if (state != bdata->last_state) {56unsigned int type = button->type ?: EV_KEY;5758input_event(input, type, button->code,59!!(state ^ button->active_low));60input_sync(input);61bdata->count = 0;62bdata->last_state = state;63}64}6566static void gpio_keys_polled_poll(struct input_polled_dev *dev)67{68struct gpio_keys_polled_dev *bdev = dev->private;69struct gpio_keys_platform_data *pdata = bdev->pdata;70struct input_dev *input = dev->input;71int i;7273for (i = 0; i < bdev->pdata->nbuttons; i++) {74struct gpio_keys_button_data *bdata = &bdev->data[i];7576if (bdata->count < bdata->threshold)77bdata->count++;78else79gpio_keys_polled_check_state(input, &pdata->buttons[i],80bdata);81}82}8384static void gpio_keys_polled_open(struct input_polled_dev *dev)85{86struct gpio_keys_polled_dev *bdev = dev->private;87struct gpio_keys_platform_data *pdata = bdev->pdata;8889if (pdata->enable)90pdata->enable(bdev->dev);91}9293static void gpio_keys_polled_close(struct input_polled_dev *dev)94{95struct gpio_keys_polled_dev *bdev = dev->private;96struct gpio_keys_platform_data *pdata = bdev->pdata;9798if (pdata->disable)99pdata->disable(bdev->dev);100}101102static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)103{104struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;105struct device *dev = &pdev->dev;106struct gpio_keys_polled_dev *bdev;107struct input_polled_dev *poll_dev;108struct input_dev *input;109int error;110int i;111112if (!pdata || !pdata->poll_interval)113return -EINVAL;114115bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +116pdata->nbuttons * sizeof(struct gpio_keys_button_data),117GFP_KERNEL);118if (!bdev) {119dev_err(dev, "no memory for private data\n");120return -ENOMEM;121}122123poll_dev = input_allocate_polled_device();124if (!poll_dev) {125dev_err(dev, "no memory for polled device\n");126error = -ENOMEM;127goto err_free_bdev;128}129130poll_dev->private = bdev;131poll_dev->poll = gpio_keys_polled_poll;132poll_dev->poll_interval = pdata->poll_interval;133poll_dev->open = gpio_keys_polled_open;134poll_dev->close = gpio_keys_polled_close;135136input = poll_dev->input;137138input->evbit[0] = BIT(EV_KEY);139input->name = pdev->name;140input->phys = DRV_NAME"/input0";141input->dev.parent = &pdev->dev;142143input->id.bustype = BUS_HOST;144input->id.vendor = 0x0001;145input->id.product = 0x0001;146input->id.version = 0x0100;147148for (i = 0; i < pdata->nbuttons; i++) {149struct gpio_keys_button *button = &pdata->buttons[i];150struct gpio_keys_button_data *bdata = &bdev->data[i];151unsigned int gpio = button->gpio;152unsigned int type = button->type ?: EV_KEY;153154if (button->wakeup) {155dev_err(dev, DRV_NAME " does not support wakeup\n");156error = -EINVAL;157goto err_free_gpio;158}159160error = gpio_request(gpio,161button->desc ? button->desc : DRV_NAME);162if (error) {163dev_err(dev, "unable to claim gpio %u, err=%d\n",164gpio, error);165goto err_free_gpio;166}167168error = gpio_direction_input(gpio);169if (error) {170dev_err(dev,171"unable to set direction on gpio %u, err=%d\n",172gpio, error);173goto err_free_gpio;174}175176bdata->can_sleep = gpio_cansleep(gpio);177bdata->last_state = -1;178bdata->threshold = DIV_ROUND_UP(button->debounce_interval,179pdata->poll_interval);180181input_set_capability(input, type, button->code);182}183184bdev->poll_dev = poll_dev;185bdev->dev = dev;186bdev->pdata = pdata;187platform_set_drvdata(pdev, bdev);188189error = input_register_polled_device(poll_dev);190if (error) {191dev_err(dev, "unable to register polled device, err=%d\n",192error);193goto err_free_gpio;194}195196/* report initial state of the buttons */197for (i = 0; i < pdata->nbuttons; i++)198gpio_keys_polled_check_state(input, &pdata->buttons[i],199&bdev->data[i]);200201return 0;202203err_free_gpio:204while (--i >= 0)205gpio_free(pdata->buttons[i].gpio);206207input_free_polled_device(poll_dev);208209err_free_bdev:210kfree(bdev);211212platform_set_drvdata(pdev, NULL);213return error;214}215216static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)217{218struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);219struct gpio_keys_platform_data *pdata = bdev->pdata;220int i;221222input_unregister_polled_device(bdev->poll_dev);223224for (i = 0; i < pdata->nbuttons; i++)225gpio_free(pdata->buttons[i].gpio);226227input_free_polled_device(bdev->poll_dev);228229kfree(bdev);230platform_set_drvdata(pdev, NULL);231232return 0;233}234235static struct platform_driver gpio_keys_polled_driver = {236.probe = gpio_keys_polled_probe,237.remove = __devexit_p(gpio_keys_polled_remove),238.driver = {239.name = DRV_NAME,240.owner = THIS_MODULE,241},242};243244static int __init gpio_keys_polled_init(void)245{246return platform_driver_register(&gpio_keys_polled_driver);247}248249static void __exit gpio_keys_polled_exit(void)250{251platform_driver_unregister(&gpio_keys_polled_driver);252}253254module_init(gpio_keys_polled_init);255module_exit(gpio_keys_polled_exit);256257MODULE_LICENSE("GPL v2");258MODULE_AUTHOR("Gabor Juhos <[email protected]>");259MODULE_DESCRIPTION("Polled GPIO Buttons driver");260MODULE_ALIAS("platform:" DRV_NAME);261262263