Root/target/linux/generic/files/drivers/input/misc/gpio_buttons.c

1/*
2 * Driver for buttons on GPIO lines not capable of generating interrupts
3 *
4 * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
6 *
7 * This file was based on: /drivers/input/misc/cobalt_btns.c
8 * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
9 *
10 * also was based on: /drivers/input/keyboard/gpio_keys.c
11 * Copyright 2005 Phil Blundell
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/slab.h>
23#include <linux/input.h>
24#include <linux/input-polldev.h>
25#include <linux/ioport.h>
26#include <linux/platform_device.h>
27#include <linux/gpio.h>
28#include <linux/gpio_buttons.h>
29
30#define DRV_NAME "gpio-buttons"
31
32struct gpio_button_data {
33    int last_state;
34    int count;
35    int can_sleep;
36};
37
38struct gpio_buttons_dev {
39    struct input_polled_dev *poll_dev;
40    struct gpio_buttons_platform_data *pdata;
41    struct gpio_button_data *data;
42};
43
44static void gpio_buttons_check_state(struct input_dev *input,
45                      struct gpio_button *button,
46                      struct gpio_button_data *bdata)
47{
48    int state;
49
50    if (bdata->can_sleep)
51        state = !!gpio_get_value_cansleep(button->gpio);
52    else
53        state = !!gpio_get_value(button->gpio);
54
55    if (state != bdata->last_state) {
56        unsigned int type = button->type ?: EV_KEY;
57
58        input_event(input, type, button->code,
59                !!(state ^ button->active_low));
60        input_sync(input);
61        bdata->count = 0;
62        bdata->last_state = state;
63    }
64}
65
66static void gpio_buttons_poll(struct input_polled_dev *dev)
67{
68    struct gpio_buttons_dev *bdev = dev->private;
69    struct gpio_buttons_platform_data *pdata = bdev->pdata;
70    struct input_dev *input = dev->input;
71    int i;
72
73    for (i = 0; i < bdev->pdata->nbuttons; i++) {
74        struct gpio_button *button = &pdata->buttons[i];
75        struct gpio_button_data *bdata = &bdev->data[i];
76
77        if (bdata->count < button->threshold)
78            bdata->count++;
79        else
80            gpio_buttons_check_state(input, button, bdata);
81
82    }
83}
84
85static int __devinit gpio_buttons_probe(struct platform_device *pdev)
86{
87    struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
88    struct device *dev = &pdev->dev;
89    struct gpio_buttons_dev *bdev;
90    struct input_polled_dev *poll_dev;
91    struct input_dev *input;
92    int error;
93    int i;
94
95    if (!pdata)
96        return -ENXIO;
97
98    bdev = kzalloc(sizeof(struct gpio_buttons_dev) +
99               pdata->nbuttons * sizeof(struct gpio_button_data),
100               GFP_KERNEL);
101    if (!bdev) {
102        dev_err(dev, "no memory for private data\n");
103        return -ENOMEM;
104    }
105
106    bdev->data = (struct gpio_button_data *) &bdev[1];
107
108    poll_dev = input_allocate_polled_device();
109    if (!poll_dev) {
110        dev_err(dev, "no memory for polled device\n");
111        error = -ENOMEM;
112        goto err_free_bdev;
113    }
114
115    poll_dev->private = bdev;
116    poll_dev->poll = gpio_buttons_poll;
117    poll_dev->poll_interval = pdata->poll_interval;
118
119    input = poll_dev->input;
120
121    input->evbit[0] = BIT(EV_KEY);
122    input->name = pdev->name;
123    input->phys = "gpio-buttons/input0";
124    input->dev.parent = &pdev->dev;
125
126    input->id.bustype = BUS_HOST;
127    input->id.vendor = 0x0001;
128    input->id.product = 0x0001;
129    input->id.version = 0x0100;
130
131    for (i = 0; i < pdata->nbuttons; i++) {
132        struct gpio_button *button = &pdata->buttons[i];
133        unsigned int gpio = button->gpio;
134        unsigned int type = button->type ?: EV_KEY;
135
136        error = gpio_request(gpio,
137                     button->desc ? button->desc : DRV_NAME);
138        if (error) {
139            dev_err(dev, "unable to claim gpio %u, err=%d\n",
140                gpio, error);
141            goto err_free_gpio;
142        }
143
144        error = gpio_direction_input(gpio);
145        if (error) {
146            dev_err(dev,
147                "unable to set direction on gpio %u, err=%d\n",
148                gpio, error);
149            goto err_free_gpio;
150        }
151
152        bdev->data[i].can_sleep = gpio_cansleep(gpio);
153        bdev->data[i].last_state = -1;
154
155        input_set_capability(input, type, button->code);
156    }
157
158    bdev->poll_dev = poll_dev;
159    bdev->pdata = pdata;
160    platform_set_drvdata(pdev, bdev);
161
162    error = input_register_polled_device(poll_dev);
163    if (error) {
164        dev_err(dev, "unable to register polled device, err=%d\n",
165            error);
166        goto err_free_gpio;
167    }
168
169    /* report initial state of the buttons */
170    for (i = 0; i < pdata->nbuttons; i++)
171        gpio_buttons_check_state(input, &pdata->buttons[i],
172                     &bdev->data[i]);
173
174    return 0;
175
176err_free_gpio:
177    for (i = i - 1; i >= 0; i--)
178        gpio_free(pdata->buttons[i].gpio);
179
180    input_free_polled_device(poll_dev);
181
182err_free_bdev:
183    kfree(bdev);
184
185    platform_set_drvdata(pdev, NULL);
186    return error;
187}
188
189static int __devexit gpio_buttons_remove(struct platform_device *pdev)
190{
191    struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
192    struct gpio_buttons_platform_data *pdata = bdev->pdata;
193    int i;
194
195    input_unregister_polled_device(bdev->poll_dev);
196
197    for (i = 0; i < pdata->nbuttons; i++)
198        gpio_free(pdata->buttons[i].gpio);
199
200    input_free_polled_device(bdev->poll_dev);
201
202    kfree(bdev);
203    platform_set_drvdata(pdev, NULL);
204
205    return 0;
206}
207
208static struct platform_driver gpio_buttons_driver = {
209    .probe = gpio_buttons_probe,
210    .remove = __devexit_p(gpio_buttons_remove),
211    .driver = {
212        .name = DRV_NAME,
213        .owner = THIS_MODULE,
214    },
215};
216
217static int __init gpio_buttons_init(void)
218{
219    return platform_driver_register(&gpio_buttons_driver);
220}
221
222static void __exit gpio_buttons_exit(void)
223{
224    platform_driver_unregister(&gpio_buttons_driver);
225}
226
227module_init(gpio_buttons_init);
228module_exit(gpio_buttons_exit);
229
230MODULE_LICENSE("GPL v2");
231MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
232MODULE_DESCRIPTION("Polled GPIO Buttons driver");
233

Archive Download this file



interactive