2 * Driver for keys on TCA6416 I2C IO expander
4 * Copyright (C) 2010 Texas Instruments
6 * Author : Sriramakrishnan.A.G. <srk@ti.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/types.h>
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/slab.h>
18 #include <linux/interrupt.h>
19 #include <linux/workqueue.h>
20 #include <linux/gpio.h>
21 #include <linux/i2c.h>
22 #include <linux/input.h>
23 #include <linux/tca6416_keypad.h>
25 #define TCA6416_INPUT 0
26 #define TCA6416_OUTPUT 1
27 #define TCA6416_INVERT 2
28 #define TCA6416_DIRECTION 3
30 static const struct i2c_device_id tca6416_id
[] = {
31 { "tca6416-keys", 16, },
32 { "tca6408-keys", 8, },
35 MODULE_DEVICE_TABLE(i2c
, tca6416_id
);
37 struct tca6416_drv_data
{
38 struct input_dev
*input
;
39 struct tca6416_button data
[0];
42 struct tca6416_keypad_chip
{
44 uint16_t reg_direction
;
47 struct i2c_client
*client
;
48 struct input_dev
*input
;
49 struct delayed_work dwork
;
54 struct tca6416_button buttons
[0];
57 static int tca6416_write_reg(struct tca6416_keypad_chip
*chip
, int reg
, u16 val
)
61 error
= chip
->io_size
> 8 ?
62 i2c_smbus_write_word_data(chip
->client
, reg
<< 1, val
) :
63 i2c_smbus_write_byte_data(chip
->client
, reg
, val
);
65 dev_err(&chip
->client
->dev
,
66 "%s failed, reg: %d, val: %d, error: %d\n",
67 __func__
, reg
, val
, error
);
74 static int tca6416_read_reg(struct tca6416_keypad_chip
*chip
, int reg
, u16
*val
)
78 retval
= chip
->io_size
> 8 ?
79 i2c_smbus_read_word_data(chip
->client
, reg
<< 1) :
80 i2c_smbus_read_byte_data(chip
->client
, reg
);
82 dev_err(&chip
->client
->dev
, "%s failed, reg: %d, error: %d\n",
83 __func__
, reg
, retval
);
91 static void tca6416_keys_scan(struct tca6416_keypad_chip
*chip
)
93 struct input_dev
*input
= chip
->input
;
95 int error
, i
, pin_index
;
97 error
= tca6416_read_reg(chip
, TCA6416_INPUT
, ®_val
);
101 reg_val
&= chip
->pinmask
;
103 /* Figure out which lines have changed */
104 val
= reg_val
^ chip
->reg_input
;
105 chip
->reg_input
= reg_val
;
107 for (i
= 0, pin_index
= 0; i
< 16; i
++) {
108 if (val
& (1 << i
)) {
109 struct tca6416_button
*button
= &chip
->buttons
[pin_index
];
110 unsigned int type
= button
->type
?: EV_KEY
;
111 int state
= ((reg_val
& (1 << i
)) ? 1 : 0)
112 ^ button
->active_low
;
114 input_event(input
, type
, button
->code
, !!state
);
118 if (chip
->pinmask
& (1 << i
))
124 * This is threaded IRQ handler and this can (and will) sleep.
126 static irqreturn_t
tca6416_keys_isr(int irq
, void *dev_id
)
128 struct tca6416_keypad_chip
*chip
= dev_id
;
130 tca6416_keys_scan(chip
);
135 static void tca6416_keys_work_func(struct work_struct
*work
)
137 struct tca6416_keypad_chip
*chip
=
138 container_of(work
, struct tca6416_keypad_chip
, dwork
.work
);
140 tca6416_keys_scan(chip
);
141 schedule_delayed_work(&chip
->dwork
, msecs_to_jiffies(100));
144 static int tca6416_keys_open(struct input_dev
*dev
)
146 struct tca6416_keypad_chip
*chip
= input_get_drvdata(dev
);
148 /* Get initial device state in case it has switches */
149 tca6416_keys_scan(chip
);
151 if (chip
->use_polling
)
152 schedule_delayed_work(&chip
->dwork
, msecs_to_jiffies(100));
154 enable_irq(chip
->irqnum
);
159 static void tca6416_keys_close(struct input_dev
*dev
)
161 struct tca6416_keypad_chip
*chip
= input_get_drvdata(dev
);
163 if (chip
->use_polling
)
164 cancel_delayed_work_sync(&chip
->dwork
);
166 disable_irq(chip
->irqnum
);
169 static int __devinit
tca6416_setup_registers(struct tca6416_keypad_chip
*chip
)
173 error
= tca6416_read_reg(chip
, TCA6416_OUTPUT
, &chip
->reg_output
);
177 error
= tca6416_read_reg(chip
, TCA6416_DIRECTION
, &chip
->reg_direction
);
181 /* ensure that keypad pins are set to input */
182 error
= tca6416_write_reg(chip
, TCA6416_DIRECTION
,
183 chip
->reg_direction
| chip
->pinmask
);
187 error
= tca6416_read_reg(chip
, TCA6416_DIRECTION
, &chip
->reg_direction
);
191 error
= tca6416_read_reg(chip
, TCA6416_INPUT
, &chip
->reg_input
);
195 chip
->reg_input
&= chip
->pinmask
;
200 static int __devinit
tca6416_keypad_probe(struct i2c_client
*client
,
201 const struct i2c_device_id
*id
)
203 struct tca6416_keys_platform_data
*pdata
;
204 struct tca6416_keypad_chip
*chip
;
205 struct input_dev
*input
;
209 /* Check functionality */
210 if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_SMBUS_BYTE
)) {
211 dev_err(&client
->dev
, "%s adapter not supported\n",
212 dev_driver_string(&client
->adapter
->dev
));
216 pdata
= client
->dev
.platform_data
;
218 dev_dbg(&client
->dev
, "no platform data\n");
222 chip
= kzalloc(sizeof(struct tca6416_keypad_chip
) +
223 pdata
->nbuttons
* sizeof(struct tca6416_button
),
225 input
= input_allocate_device();
226 if (!chip
|| !input
) {
231 chip
->client
= client
;
233 chip
->io_size
= id
->driver_data
;
234 chip
->pinmask
= pdata
->pinmask
;
235 chip
->use_polling
= pdata
->use_polling
;
237 INIT_DELAYED_WORK(&chip
->dwork
, tca6416_keys_work_func
);
239 input
->phys
= "tca6416-keys/input0";
240 input
->name
= client
->name
;
241 input
->dev
.parent
= &client
->dev
;
243 input
->open
= tca6416_keys_open
;
244 input
->close
= tca6416_keys_close
;
246 input
->id
.bustype
= BUS_HOST
;
247 input
->id
.vendor
= 0x0001;
248 input
->id
.product
= 0x0001;
249 input
->id
.version
= 0x0100;
251 /* Enable auto repeat feature of Linux input subsystem */
253 __set_bit(EV_REP
, input
->evbit
);
255 for (i
= 0; i
< pdata
->nbuttons
; i
++) {
258 chip
->buttons
[i
] = pdata
->buttons
[i
];
259 type
= (pdata
->buttons
[i
].type
) ?: EV_KEY
;
260 input_set_capability(input
, type
, pdata
->buttons
[i
].code
);
263 input_set_drvdata(input
, chip
);
266 * Initialize cached registers from their original values.
267 * we can't share this chip with another i2c master.
269 error
= tca6416_setup_registers(chip
);
273 if (!chip
->use_polling
) {
274 if (pdata
->irq_is_gpio
)
275 chip
->irqnum
= gpio_to_irq(client
->irq
);
277 chip
->irqnum
= client
->irq
;
279 error
= request_threaded_irq(chip
->irqnum
, NULL
,
281 IRQF_TRIGGER_FALLING
,
282 "tca6416-keypad", chip
);
284 dev_dbg(&client
->dev
,
285 "Unable to claim irq %d; error %d\n",
286 chip
->irqnum
, error
);
289 disable_irq(chip
->irqnum
);
292 error
= input_register_device(input
);
294 dev_dbg(&client
->dev
,
295 "Unable to register input device, error: %d\n", error
);
299 i2c_set_clientdata(client
, chip
);
300 device_init_wakeup(&client
->dev
, 1);
305 if (!chip
->use_polling
) {
306 free_irq(chip
->irqnum
, chip
);
307 enable_irq(chip
->irqnum
);
310 input_free_device(input
);
315 static int __devexit
tca6416_keypad_remove(struct i2c_client
*client
)
317 struct tca6416_keypad_chip
*chip
= i2c_get_clientdata(client
);
319 if (!chip
->use_polling
) {
320 free_irq(chip
->irqnum
, chip
);
321 enable_irq(chip
->irqnum
);
324 input_unregister_device(chip
->input
);
330 #ifdef CONFIG_PM_SLEEP
331 static int tca6416_keypad_suspend(struct device
*dev
)
333 struct i2c_client
*client
= to_i2c_client(dev
);
334 struct tca6416_keypad_chip
*chip
= i2c_get_clientdata(client
);
336 if (device_may_wakeup(dev
))
337 enable_irq_wake(chip
->irqnum
);
342 static int tca6416_keypad_resume(struct device
*dev
)
344 struct i2c_client
*client
= to_i2c_client(dev
);
345 struct tca6416_keypad_chip
*chip
= i2c_get_clientdata(client
);
347 if (device_may_wakeup(dev
))
348 disable_irq_wake(chip
->irqnum
);
354 static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops
,
355 tca6416_keypad_suspend
, tca6416_keypad_resume
);
357 static struct i2c_driver tca6416_keypad_driver
= {
359 .name
= "tca6416-keypad",
360 .pm
= &tca6416_keypad_dev_pm_ops
,
362 .probe
= tca6416_keypad_probe
,
363 .remove
= __devexit_p(tca6416_keypad_remove
),
364 .id_table
= tca6416_id
,
367 static int __init
tca6416_keypad_init(void)
369 return i2c_add_driver(&tca6416_keypad_driver
);
372 subsys_initcall(tca6416_keypad_init
);
374 static void __exit
tca6416_keypad_exit(void)
376 i2c_del_driver(&tca6416_keypad_driver
);
378 module_exit(tca6416_keypad_exit
);
380 MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
381 MODULE_DESCRIPTION("Keypad driver over tca6146 IO expander");
382 MODULE_LICENSE("GPL");