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

1/*
2 * arch/ubicom32/mach-common/ubicom32input_i2c.c
3 * Ubicom32 Input driver for I2C
4 * Supports PCA953x and family
5 *
6 * We hog the I2C device, turning it all to input.
7 *
8 * Based on gpio-keys, pca953x
9 *
10 * (C) Copyright 2009, Ubicom, Inc.
11 *
12 * This file is part of the Ubicom32 Linux Kernel Port.
13 *
14 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
15 * it and/or modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
20 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
21 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
22 * the GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with the Ubicom32 Linux Kernel Port. If not,
26 * see <http://www.gnu.org/licenses/>.
27 *
28 * Ubicom32 implementation derived from (with many thanks):
29 * arch/m68knommu
30 * arch/blackfin
31 * arch/parisc
32 */
33#include <linux/kernel.h>
34#include <linux/module.h>
35#include <linux/platform_device.h>
36#include <linux/input.h>
37#include <linux/input-polldev.h>
38#include <linux/i2c.h>
39
40#include <asm/ubicom32input_i2c.h>
41
42#define UBICOM32INPUT_I2C_REG_INPUT 0
43#define UBICOM32INPUT_I2C_REG_OUTPUT 1
44#define UBICOM32INPUT_I2C_REG_INVERT 2
45#define UBICOM32INPUT_I2C_REG_DIRECTION 3
46
47static const struct i2c_device_id ubicom32input_i2c_id[] = {
48    { "ubicom32in_pca9534", 8, },
49    { "ubicom32in_pca9535", 16, },
50    { "ubicom32in_pca9536", 4, },
51    { "ubicom32in_pca9537", 4, },
52    { "ubicom32in_pca9538", 8, },
53    { "ubicom32in_pca9539", 16, },
54    { "ubicom32in_pca9554", 8, },
55    { "ubicom32in_pca9555", 16, },
56    { "ubicom32in_pca9557", 8, },
57    { "ubicom32in_max7310", 8, },
58    { }
59};
60MODULE_DEVICE_TABLE(i2c, ubicom32input_i2c_id);
61
62struct ubicom32input_i2c_data {
63    struct ubicom32input_i2c_platform_data *pdata;
64
65    struct i2c_client *client;
66
67    struct input_polled_dev *poll_dev;
68
69    /*
70     * collection of previous states for buttons
71     */
72    uint16_t prev_state;
73
74    uint8_t ngpios;
75};
76
77/*
78 * ubicom32input_i2c_write_reg
79 * writes a register to the I2C device.
80 */
81static int ubicom32input_i2c_write_reg(struct ubicom32input_i2c_data *ud,
82                       int reg, uint16_t val)
83{
84    int ret;
85
86    if (ud->ngpios <= 8) {
87        ret = i2c_smbus_write_byte_data(ud->client, reg, val);
88    } else {
89        ret = i2c_smbus_write_word_data(ud->client, reg << 1, val);
90    }
91
92    if (ret < 0) {
93        return ret;
94    }
95
96    return 0;
97}
98
99/*
100 * ubicom32input_i2c_read_reg
101 * reads a register from the I2C device.
102 */
103static int ubicom32input_i2c_read_reg(struct ubicom32input_i2c_data *ud,
104                      int reg, uint16_t *val)
105{
106    int ret;
107
108    if (ud->ngpios <= 8) {
109        ret = i2c_smbus_read_byte_data(ud->client, reg);
110    } else {
111        ret = i2c_smbus_read_word_data(ud->client, reg);
112    }
113
114    if (ret < 0) {
115        return ret;
116    }
117
118    *val = (uint16_t)ret;
119
120    return 0;
121}
122
123/*
124 * ubicom32input_i2c_poll
125 */
126static void ubicom32input_i2c_poll(struct input_polled_dev *dev)
127{
128    struct ubicom32input_i2c_data *ud =
129        (struct ubicom32input_i2c_data *)dev->private;
130    struct ubicom32input_i2c_platform_data *pdata = ud->pdata;
131    struct input_dev *id = dev->input;
132    int i;
133    int sync_needed = 0;
134    uint16_t val;
135    uint16_t change_mask;
136
137    /*
138     * Try to get the input status, if we fail, bail out, maybe we can do it
139     * next time.
140     */
141    if (ubicom32input_i2c_read_reg(ud, UBICOM32INPUT_I2C_REG_INPUT, &val)) {
142        return;
143    }
144
145    /*
146     * see if anything changed by using XOR
147     */
148    change_mask = ud->prev_state ^ val;
149    ud->prev_state = val;
150
151    for (i = 0; i < pdata->nbuttons; i++) {
152        const struct ubicom32input_i2c_button *ub = &pdata->buttons[i];
153        uint16_t mask = 1 << ub->bit;
154        int state = val & mask;
155
156        /*
157         * Check to see if the state changed from the last time we
158         * looked
159         */
160        if (!(change_mask & mask)) {
161            continue;
162        }
163        input_event(id, ub->type, ub->code, state);
164        sync_needed = 1;
165    }
166
167    if (sync_needed) {
168        input_sync(id);
169    }
170}
171
172/*
173 * ubicom32input_i2c_probe
174 */
175static int __devinit ubicom32input_i2c_probe(struct i2c_client *client,
176                         const struct i2c_device_id *id)
177{
178    int i;
179    struct ubicom32input_i2c_data *ud;
180    struct input_polled_dev *poll_dev;
181    struct input_dev *input_dev;
182    struct ubicom32input_i2c_platform_data *pdata;
183    int ret;
184    uint16_t invert_mask = 0;
185
186    pdata = client->dev.platform_data;
187    if (!pdata) {
188        return -EINVAL;
189    }
190
191    ud = kzalloc(sizeof(struct ubicom32input_i2c_data), GFP_KERNEL);
192    if (!ud) {
193        return -ENOMEM;
194    }
195    ud->pdata = pdata;
196    ud->client = client;
197    ud->ngpios = id->driver_data;
198
199    poll_dev = input_allocate_polled_device();
200    if (!poll_dev) {
201        ret = -ENOMEM;
202        goto fail;
203    }
204
205    ud->poll_dev = poll_dev;
206    poll_dev->private = ud;
207    poll_dev->poll = ubicom32input_i2c_poll;
208
209    /*
210     * Set the poll interval requested, default to 100 msec
211     */
212    if (pdata->poll_interval) {
213        poll_dev->poll_interval = pdata->poll_interval;
214    } else {
215        poll_dev->poll_interval = 100;
216    }
217
218    /*
219     * Setup the input device
220     */
221    input_dev = poll_dev->input;
222    input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input I2C";
223    input_dev->phys = "ubicom32input_i2c/input0";
224    input_dev->dev.parent = &client->dev;
225    input_dev->id.bustype = BUS_I2C;
226
227    /*
228     * Set the capabilities
229     */
230    for (i = 0; i < pdata->nbuttons; i++) {
231        const struct ubicom32input_i2c_button *ub = &pdata->buttons[i];
232
233        if (ub->active_low) {
234            invert_mask |= (1 << ub->bit);
235        }
236
237        input_set_capability(input_dev,
238                     ub->type ? ub->type : EV_KEY, ub->code);
239    }
240
241    /*
242     * Setup the device (all inputs)
243     */
244    ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_DIRECTION,
245                      0xFFFF);
246    if (ret < 0) {
247        goto fail;
248    }
249
250    ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_INVERT,
251                      invert_mask);
252    if (ret < 0) {
253        goto fail;
254    }
255
256    /*
257     * Register
258     */
259    ret = input_register_polled_device(ud->poll_dev);
260    if (ret) {
261        goto fail;
262    }
263
264    i2c_set_clientdata(client, ud);
265
266    return 0;
267
268fail:
269    printk(KERN_ERR "ubicom32input_i2c: Failed to register driver %d\n",
270           ret);
271    input_free_polled_device(poll_dev);
272    kfree(ud);
273    return ret;
274}
275
276/*
277 * ubicom32input_i2c_remove
278 */
279static int __devexit ubicom32input_i2c_remove(struct i2c_client *client)
280{
281    struct ubicom32input_i2c_data *ud =
282        (struct ubicom32input_i2c_data *)i2c_get_clientdata(client);
283
284    i2c_set_clientdata(client, NULL);
285    input_unregister_polled_device(ud->poll_dev);
286    input_free_polled_device(ud->poll_dev);
287
288    kfree(ud);
289
290    return 0;
291}
292
293static struct i2c_driver ubicom32input_i2c_driver = {
294    .driver = {
295        .name = "ubicom32input_i2c",
296        .owner = THIS_MODULE,
297    },
298    .remove = __devexit_p(ubicom32input_i2c_remove),
299    .id_table = ubicom32input_i2c_id,
300    .probe = ubicom32input_i2c_probe,
301};
302
303/*
304 * ubicom32input_i2c_init
305 */
306static int __devinit ubicom32input_i2c_init(void)
307{
308    return i2c_add_driver(&ubicom32input_i2c_driver);
309}
310
311/*
312 * ubicom32input_i2c_exit
313 */
314static void __exit ubicom32input_i2c_exit(void)
315{
316    i2c_del_driver(&ubicom32input_i2c_driver);
317}
318
319module_init(ubicom32input_i2c_init);
320module_exit(ubicom32input_i2c_exit);
321
322MODULE_AUTHOR("Pat Tjin <pattjin@ubicom.com>");
323MODULE_DESCRIPTION("Ubicom32 Input Driver I2C");
324MODULE_LICENSE("GPL");
325MODULE_ALIAS("platform:ubicom32-input");
326

Archive Download this file



interactive