Root/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c

1/*
2 * arch/ubicom32/mach-common/ubicom32input.c
3 * Ubicom32 Input driver
4 *
5 * based on gpio-keys
6 *
7 * (C) Copyright 2009, Ubicom, Inc.
8 *
9 * This file is part of the Ubicom32 Linux Kernel Port.
10 *
11 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
12 * it and/or modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
17 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
18 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
19 * the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with the Ubicom32 Linux Kernel Port. If not,
23 * see <http://www.gnu.org/licenses/>.
24 *
25 * Ubicom32 implementation derived from (with many thanks):
26 * arch/m68knommu
27 * arch/blackfin
28 * arch/parisc
29 *
30 *
31 * TODO: add groups for inputs which can be sampled together (i.e. I2C)
32 */
33
34#include <linux/kernel.h>
35#include <linux/module.h>
36#include <linux/platform_device.h>
37#include <linux/input.h>
38#include <linux/input-polldev.h>
39#include <linux/delay.h>
40#include <linux/gpio.h>
41
42#include <asm/ubicom32input.h>
43
44struct ubicom32input_data {
45    struct ubicom32input_platform_data *pdata;
46
47    struct input_polled_dev *poll_dev;
48
49    /*
50     * collection of previous states for buttons
51     */
52    u8 prev_state[0];
53};
54
55/*
56 * ubicom32input_poll
57 */
58static void ubicom32input_poll(struct input_polled_dev *dev)
59{
60    struct ubicom32input_data *ud =
61        (struct ubicom32input_data *)dev->private;
62    struct ubicom32input_platform_data *pdata = ud->pdata;
63    struct input_dev *id = dev->input;
64    int i;
65    int sync_needed = 0;
66
67    for (i = 0; i < pdata->nbuttons; i++) {
68        const struct ubicom32input_button *ub = &pdata->buttons[i];
69        int state = 0;
70
71        int val = gpio_get_value(ub->gpio);
72
73        /*
74         * Check to see if the state changed from the last time we
75         * looked
76         */
77        if (val == ud->prev_state[i]) {
78            continue;
79        }
80
81        /*
82         * The state has changed, determine if we are "up" or "down"
83         */
84        ud->prev_state[i] = val;
85
86        if ((!val && ub->active_low) || (val && !ub->active_low)) {
87            state = 1;
88        }
89
90        input_event(id, ub->type, ub->code, state);
91        sync_needed = 1;
92    }
93
94    if (sync_needed) {
95        input_sync(id);
96    }
97}
98
99/*
100 * ubicom32input_probe
101 */
102static int __devinit ubicom32input_probe(struct platform_device *pdev)
103{
104    int i;
105    struct ubicom32input_data *ud;
106    struct input_polled_dev *poll_dev;
107    struct input_dev *input_dev;
108    struct ubicom32input_platform_data *pdata;
109    int ret;
110
111    pdata = pdev->dev.platform_data;
112    if (!pdata) {
113        return -EINVAL;
114    }
115
116    ud = kzalloc(sizeof(struct ubicom32input_data) +
117             pdata->nbuttons, GFP_KERNEL);
118    if (!ud) {
119        return -ENOMEM;
120    }
121    ud->pdata = pdata;
122
123    poll_dev = input_allocate_polled_device();
124    if (!poll_dev) {
125        ret = -ENOMEM;
126        goto fail;
127    }
128
129    platform_set_drvdata(pdev, ud);
130
131    ud->poll_dev = poll_dev;
132    poll_dev->private = ud;
133    poll_dev->poll = ubicom32input_poll;
134
135    /*
136     * Set the poll interval requested, default to 50 msec
137     */
138    if (pdata->poll_interval) {
139        poll_dev->poll_interval = pdata->poll_interval;
140    } else {
141        poll_dev->poll_interval = 50;
142    }
143
144    /*
145     * Setup the input device
146     */
147    input_dev = poll_dev->input;
148    input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input";
149    input_dev->phys = "ubicom32input/input0";
150    input_dev->dev.parent = &pdev->dev;
151    input_dev->id.bustype = BUS_HOST;
152
153    /*
154     * Reserve the GPIOs
155     */
156    for (i = 0; i < pdata->nbuttons; i++) {
157        const struct ubicom32input_button *ub = &pdata->buttons[i];
158
159        ret = gpio_request(ub->gpio,
160                   ub->desc ? ub->desc : "ubicom32input");
161        if (ret < 0) {
162            pr_err("ubicom32input: failed to request "
163                   "GPIO %d ret=%d\n", ub->gpio, ret);
164            goto fail2;
165        }
166
167        ret = gpio_direction_input(ub->gpio);
168        if (ret < 0) {
169            pr_err("ubicom32input: failed to set "
170                   "GPIO %d to input ret=%d\n", ub->gpio, ret);
171            goto fail2;
172        }
173
174        /*
175         * Set the previous state to the non-active stae
176         */
177        ud->prev_state[i] = ub->active_low;
178
179        input_set_capability(input_dev,
180                     ub->type ? ub->type : EV_KEY, ub->code);
181    }
182
183    /*
184     * Register
185     */
186    ret = input_register_polled_device(ud->poll_dev);
187    if (ret) {
188        goto fail2;
189    }
190
191    return 0;
192
193fail2:
194    /*
195     * release the GPIOs we have already requested.
196     */
197    while (--i >= 0) {
198        gpio_free(pdata->buttons[i].gpio);
199    }
200
201fail:
202    printk(KERN_ERR "Ubicom32Input: Failed to register driver %d", ret);
203    platform_set_drvdata(pdev, NULL);
204    input_free_polled_device(poll_dev);
205    kfree(ud);
206    return ret;
207}
208
209/*
210 * ubicom32input_remove
211 */
212static int __devexit ubicom32input_remove(struct platform_device *dev)
213{
214    struct ubicom32input_data *ud =
215        (struct ubicom32input_data *)platform_get_drvdata(dev);
216    int i;
217
218    /*
219     * Free the GPIOs
220     */
221    for (i = 0; i < ud->pdata->nbuttons; i++) {
222        gpio_free(ud->pdata->buttons[i].gpio);
223    }
224
225    platform_set_drvdata(dev, NULL);
226    input_unregister_polled_device(ud->poll_dev);
227    input_free_polled_device(ud->poll_dev);
228
229    kfree(ud);
230
231    return 0;
232}
233
234static struct platform_driver ubicom32input_driver = {
235    .driver = {
236        .name = "ubicom32input",
237        .owner = THIS_MODULE,
238    },
239    .probe = ubicom32input_probe,
240    .remove = __devexit_p(ubicom32input_remove),
241};
242
243/*
244 * ubicom32input_init
245 */
246static int __devinit ubicom32input_init(void)
247{
248    return platform_driver_register(&ubicom32input_driver);
249}
250
251/*
252 * ubicom32input_exit
253 */
254static void __exit ubicom32input_exit(void)
255{
256    platform_driver_unregister(&ubicom32input_driver);
257}
258
259module_init(ubicom32input_init);
260module_exit(ubicom32input_exit);
261
262MODULE_AUTHOR("Pat Tjin <pattjin@ubicom.com>");
263MODULE_DESCRIPTION("Ubicom32 Input Driver");
264MODULE_LICENSE("GPL");
265MODULE_ALIAS("platform:ubicom32-input");
266

Archive Download this file



interactive