1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for keys on TCA6416 I2C IO expander
5 * Copyright (C) 2010 Texas Instruments
7 * Author : Sriramakrishnan.A.G. <srk@ti.com>
10 #include <linux/types.h>
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/delay.h>
14 #include <linux/slab.h>
15 #include <linux/interrupt.h>
16 #include <linux/workqueue.h>
17 #include <linux/i2c.h>
18 #include <linux/input.h>
19 #include <linux/tca6416_keypad.h>
21 #define TCA6416_INPUT 0
22 #define TCA6416_OUTPUT 1
23 #define TCA6416_INVERT 2
24 #define TCA6416_DIRECTION 3
26 #define TCA6416_POLL_INTERVAL 100 /* msec */
28 static const struct i2c_device_id tca6416_id
[] = {
29 { "tca6416-keys", 16, },
30 { "tca6408-keys", 8, },
33 MODULE_DEVICE_TABLE(i2c
, tca6416_id
);
35 struct tca6416_keypad_chip
{
37 uint16_t reg_direction
;
40 struct i2c_client
*client
;
41 struct input_dev
*input
;
45 struct tca6416_button buttons
[];
48 static int tca6416_write_reg(struct tca6416_keypad_chip
*chip
, int reg
, u16 val
)
52 error
= chip
->io_size
> 8 ?
53 i2c_smbus_write_word_data(chip
->client
, reg
<< 1, val
) :
54 i2c_smbus_write_byte_data(chip
->client
, reg
, val
);
56 dev_err(&chip
->client
->dev
,
57 "%s failed, reg: %d, val: %d, error: %d\n",
58 __func__
, reg
, val
, error
);
65 static int tca6416_read_reg(struct tca6416_keypad_chip
*chip
, int reg
, u16
*val
)
69 retval
= chip
->io_size
> 8 ?
70 i2c_smbus_read_word_data(chip
->client
, reg
<< 1) :
71 i2c_smbus_read_byte_data(chip
->client
, reg
);
73 dev_err(&chip
->client
->dev
, "%s failed, reg: %d, error: %d\n",
74 __func__
, reg
, retval
);
82 static void tca6416_keys_scan(struct input_dev
*input
)
84 struct tca6416_keypad_chip
*chip
= input_get_drvdata(input
);
86 int error
, i
, pin_index
;
88 error
= tca6416_read_reg(chip
, TCA6416_INPUT
, ®_val
);
92 reg_val
&= chip
->pinmask
;
94 /* Figure out which lines have changed */
95 val
= reg_val
^ chip
->reg_input
;
96 chip
->reg_input
= reg_val
;
98 for (i
= 0, pin_index
= 0; i
< 16; i
++) {
100 struct tca6416_button
*button
= &chip
->buttons
[pin_index
];
101 unsigned int type
= button
->type
?: EV_KEY
;
102 int state
= ((reg_val
& (1 << i
)) ? 1 : 0)
103 ^ button
->active_low
;
105 input_event(input
, type
, button
->code
, !!state
);
109 if (chip
->pinmask
& (1 << i
))
115 * This is threaded IRQ handler and this can (and will) sleep.
117 static irqreturn_t
tca6416_keys_isr(int irq
, void *dev_id
)
119 tca6416_keys_scan(dev_id
);
124 static int tca6416_keys_open(struct input_dev
*dev
)
126 struct tca6416_keypad_chip
*chip
= input_get_drvdata(dev
);
128 if (!chip
->use_polling
) {
129 /* Get initial device state in case it has switches */
130 tca6416_keys_scan(dev
);
131 enable_irq(chip
->client
->irq
);
137 static void tca6416_keys_close(struct input_dev
*dev
)
139 struct tca6416_keypad_chip
*chip
= input_get_drvdata(dev
);
141 if (!chip
->use_polling
)
142 disable_irq(chip
->client
->irq
);
145 static int tca6416_setup_registers(struct tca6416_keypad_chip
*chip
)
149 error
= tca6416_read_reg(chip
, TCA6416_OUTPUT
, &chip
->reg_output
);
153 error
= tca6416_read_reg(chip
, TCA6416_DIRECTION
, &chip
->reg_direction
);
157 /* ensure that keypad pins are set to input */
158 error
= tca6416_write_reg(chip
, TCA6416_DIRECTION
,
159 chip
->reg_direction
| chip
->pinmask
);
163 error
= tca6416_read_reg(chip
, TCA6416_DIRECTION
, &chip
->reg_direction
);
167 error
= tca6416_read_reg(chip
, TCA6416_INPUT
, &chip
->reg_input
);
171 chip
->reg_input
&= chip
->pinmask
;
176 static int tca6416_keypad_probe(struct i2c_client
*client
)
178 const struct i2c_device_id
*id
= i2c_client_get_device_id(client
);
179 struct tca6416_keys_platform_data
*pdata
;
180 struct tca6416_keypad_chip
*chip
;
181 struct input_dev
*input
;
185 /* Check functionality */
186 if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_SMBUS_BYTE
)) {
187 dev_err(&client
->dev
, "%s adapter not supported\n",
188 dev_driver_string(&client
->adapter
->dev
));
192 pdata
= dev_get_platdata(&client
->dev
);
194 dev_dbg(&client
->dev
, "no platform data\n");
198 chip
= devm_kzalloc(&client
->dev
,
199 struct_size(chip
, buttons
, pdata
->nbuttons
),
204 input
= devm_input_allocate_device(&client
->dev
);
208 chip
->client
= client
;
210 chip
->io_size
= id
->driver_data
;
211 chip
->pinmask
= pdata
->pinmask
;
212 chip
->use_polling
= pdata
->use_polling
;
214 input
->phys
= "tca6416-keys/input0";
215 input
->name
= client
->name
;
217 input
->open
= tca6416_keys_open
;
218 input
->close
= tca6416_keys_close
;
220 input
->id
.bustype
= BUS_HOST
;
221 input
->id
.vendor
= 0x0001;
222 input
->id
.product
= 0x0001;
223 input
->id
.version
= 0x0100;
225 /* Enable auto repeat feature of Linux input subsystem */
227 __set_bit(EV_REP
, input
->evbit
);
229 for (i
= 0; i
< pdata
->nbuttons
; i
++) {
232 chip
->buttons
[i
] = pdata
->buttons
[i
];
233 type
= (pdata
->buttons
[i
].type
) ?: EV_KEY
;
234 input_set_capability(input
, type
, pdata
->buttons
[i
].code
);
237 input_set_drvdata(input
, chip
);
240 * Initialize cached registers from their original values.
241 * we can't share this chip with another i2c master.
243 error
= tca6416_setup_registers(chip
);
247 if (chip
->use_polling
) {
248 error
= input_setup_polling(input
, tca6416_keys_scan
);
250 dev_err(&client
->dev
, "Failed to setup polling\n");
254 input_set_poll_interval(input
, TCA6416_POLL_INTERVAL
);
256 error
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
257 NULL
, tca6416_keys_isr
,
258 IRQF_TRIGGER_FALLING
|
261 "tca6416-keypad", input
);
263 dev_dbg(&client
->dev
,
264 "Unable to claim irq %d; error %d\n",
270 error
= input_register_device(input
);
272 dev_dbg(&client
->dev
,
273 "Unable to register input device, error: %d\n", error
);
277 i2c_set_clientdata(client
, chip
);
282 static struct i2c_driver tca6416_keypad_driver
= {
284 .name
= "tca6416-keypad",
286 .probe
= tca6416_keypad_probe
,
287 .id_table
= tca6416_id
,
290 static int __init
tca6416_keypad_init(void)
292 return i2c_add_driver(&tca6416_keypad_driver
);
295 subsys_initcall(tca6416_keypad_init
);
297 static void __exit
tca6416_keypad_exit(void)
299 i2c_del_driver(&tca6416_keypad_driver
);
301 module_exit(tca6416_keypad_exit
);
303 MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
304 MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander");
305 MODULE_LICENSE("GPL");