xref: /linux/drivers/input/keyboard/tca6416-keypad.c (revision e7d759f31ca295d589f7420719c311870bb3166f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Driver for keys on TCA6416 I2C IO expander
4  *
5  * Copyright (C) 2010 Texas Instruments
6  *
7  * Author : Sriramakrishnan.A.G. <srk@ti.com>
8  */
9 
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>
20 
21 #define TCA6416_INPUT          0
22 #define TCA6416_OUTPUT         1
23 #define TCA6416_INVERT         2
24 #define TCA6416_DIRECTION      3
25 
26 #define TCA6416_POLL_INTERVAL	100 /* msec */
27 
28 static const struct i2c_device_id tca6416_id[] = {
29 	{ "tca6416-keys", 16, },
30 	{ "tca6408-keys", 8, },
31 	{ }
32 };
33 MODULE_DEVICE_TABLE(i2c, tca6416_id);
34 
35 struct tca6416_drv_data {
36 	struct input_dev *input;
37 	struct tca6416_button data[];
38 };
39 
40 struct tca6416_keypad_chip {
41 	uint16_t reg_output;
42 	uint16_t reg_direction;
43 	uint16_t reg_input;
44 
45 	struct i2c_client *client;
46 	struct input_dev *input;
47 	int io_size;
48 	int irqnum;
49 	u16 pinmask;
50 	bool use_polling;
51 	struct tca6416_button buttons[];
52 };
53 
54 static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
55 {
56 	int error;
57 
58 	error = chip->io_size > 8 ?
59 		i2c_smbus_write_word_data(chip->client, reg << 1, val) :
60 		i2c_smbus_write_byte_data(chip->client, reg, val);
61 	if (error < 0) {
62 		dev_err(&chip->client->dev,
63 			"%s failed, reg: %d, val: %d, error: %d\n",
64 			__func__, reg, val, error);
65 		return error;
66 	}
67 
68 	return 0;
69 }
70 
71 static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
72 {
73 	int retval;
74 
75 	retval = chip->io_size > 8 ?
76 		 i2c_smbus_read_word_data(chip->client, reg << 1) :
77 		 i2c_smbus_read_byte_data(chip->client, reg);
78 	if (retval < 0) {
79 		dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
80 			__func__, reg, retval);
81 		return retval;
82 	}
83 
84 	*val = (u16)retval;
85 	return 0;
86 }
87 
88 static void tca6416_keys_scan(struct input_dev *input)
89 {
90 	struct tca6416_keypad_chip *chip = input_get_drvdata(input);
91 	u16 reg_val, val;
92 	int error, i, pin_index;
93 
94 	error = tca6416_read_reg(chip, TCA6416_INPUT, &reg_val);
95 	if (error)
96 		return;
97 
98 	reg_val &= chip->pinmask;
99 
100 	/* Figure out which lines have changed */
101 	val = reg_val ^ chip->reg_input;
102 	chip->reg_input = reg_val;
103 
104 	for (i = 0, pin_index = 0; i < 16; i++) {
105 		if (val & (1 << i)) {
106 			struct tca6416_button *button = &chip->buttons[pin_index];
107 			unsigned int type = button->type ?: EV_KEY;
108 			int state = ((reg_val & (1 << i)) ? 1 : 0)
109 						^ button->active_low;
110 
111 			input_event(input, type, button->code, !!state);
112 			input_sync(input);
113 		}
114 
115 		if (chip->pinmask & (1 << i))
116 			pin_index++;
117 	}
118 }
119 
120 /*
121  * This is threaded IRQ handler and this can (and will) sleep.
122  */
123 static irqreturn_t tca6416_keys_isr(int irq, void *dev_id)
124 {
125 	tca6416_keys_scan(dev_id);
126 
127 	return IRQ_HANDLED;
128 }
129 
130 static int tca6416_keys_open(struct input_dev *dev)
131 {
132 	struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
133 
134 	if (!chip->use_polling) {
135 		/* Get initial device state in case it has switches */
136 		tca6416_keys_scan(dev);
137 		enable_irq(chip->client->irq);
138 	}
139 
140 	return 0;
141 }
142 
143 static void tca6416_keys_close(struct input_dev *dev)
144 {
145 	struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
146 
147 	if (!chip->use_polling)
148 		disable_irq(chip->client->irq);
149 }
150 
151 static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
152 {
153 	int error;
154 
155 	error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output);
156 	if (error)
157 		return error;
158 
159 	error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
160 	if (error)
161 		return error;
162 
163 	/* ensure that keypad pins are set to input */
164 	error = tca6416_write_reg(chip, TCA6416_DIRECTION,
165 				  chip->reg_direction | chip->pinmask);
166 	if (error)
167 		return error;
168 
169 	error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
170 	if (error)
171 		return error;
172 
173 	error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input);
174 	if (error)
175 		return error;
176 
177 	chip->reg_input &= chip->pinmask;
178 
179 	return 0;
180 }
181 
182 static int tca6416_keypad_probe(struct i2c_client *client)
183 {
184 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
185 	struct tca6416_keys_platform_data *pdata;
186 	struct tca6416_keypad_chip *chip;
187 	struct input_dev *input;
188 	int error;
189 	int i;
190 
191 	/* Check functionality */
192 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
193 		dev_err(&client->dev, "%s adapter not supported\n",
194 			dev_driver_string(&client->adapter->dev));
195 		return -ENODEV;
196 	}
197 
198 	pdata = dev_get_platdata(&client->dev);
199 	if (!pdata) {
200 		dev_dbg(&client->dev, "no platform data\n");
201 		return -EINVAL;
202 	}
203 
204 	chip = devm_kzalloc(&client->dev,
205 			    struct_size(chip, buttons, pdata->nbuttons),
206 			    GFP_KERNEL);
207 	if (!chip)
208 		return -ENOMEM;
209 
210 	input = devm_input_allocate_device(&client->dev);
211 	if (!input)
212 		return -ENOMEM;
213 
214 	chip->client = client;
215 	chip->input = input;
216 	chip->io_size = id->driver_data;
217 	chip->pinmask = pdata->pinmask;
218 	chip->use_polling = pdata->use_polling;
219 
220 	input->phys = "tca6416-keys/input0";
221 	input->name = client->name;
222 
223 	input->open = tca6416_keys_open;
224 	input->close = tca6416_keys_close;
225 
226 	input->id.bustype = BUS_HOST;
227 	input->id.vendor = 0x0001;
228 	input->id.product = 0x0001;
229 	input->id.version = 0x0100;
230 
231 	/* Enable auto repeat feature of Linux input subsystem */
232 	if (pdata->rep)
233 		__set_bit(EV_REP, input->evbit);
234 
235 	for (i = 0; i < pdata->nbuttons; i++) {
236 		unsigned int type;
237 
238 		chip->buttons[i] = pdata->buttons[i];
239 		type = (pdata->buttons[i].type) ?: EV_KEY;
240 		input_set_capability(input, type, pdata->buttons[i].code);
241 	}
242 
243 	input_set_drvdata(input, chip);
244 
245 	/*
246 	 * Initialize cached registers from their original values.
247 	 * we can't share this chip with another i2c master.
248 	 */
249 	error = tca6416_setup_registers(chip);
250 	if (error)
251 		return error;
252 
253 	if (chip->use_polling) {
254 		error = input_setup_polling(input, tca6416_keys_scan);
255 		if (error) {
256 			dev_err(&client->dev, "Failed to setup polling\n");
257 			return error;
258 		}
259 
260 		input_set_poll_interval(input, TCA6416_POLL_INTERVAL);
261 	} else {
262 		error = devm_request_threaded_irq(&client->dev, client->irq,
263 						  NULL, tca6416_keys_isr,
264 						  IRQF_TRIGGER_FALLING |
265 							IRQF_ONESHOT |
266 							IRQF_NO_AUTOEN,
267 						  "tca6416-keypad", input);
268 		if (error) {
269 			dev_dbg(&client->dev,
270 				"Unable to claim irq %d; error %d\n",
271 				client->irq, error);
272 			return error;
273 		}
274 	}
275 
276 	error = input_register_device(input);
277 	if (error) {
278 		dev_dbg(&client->dev,
279 			"Unable to register input device, error: %d\n", error);
280 		return error;
281 	}
282 
283 	i2c_set_clientdata(client, chip);
284 
285 	return 0;
286 }
287 
288 static struct i2c_driver tca6416_keypad_driver = {
289 	.driver = {
290 		.name	= "tca6416-keypad",
291 	},
292 	.probe		= tca6416_keypad_probe,
293 	.id_table	= tca6416_id,
294 };
295 
296 static int __init tca6416_keypad_init(void)
297 {
298 	return i2c_add_driver(&tca6416_keypad_driver);
299 }
300 
301 subsys_initcall(tca6416_keypad_init);
302 
303 static void __exit tca6416_keypad_exit(void)
304 {
305 	i2c_del_driver(&tca6416_keypad_driver);
306 }
307 module_exit(tca6416_keypad_exit);
308 
309 MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
310 MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander");
311 MODULE_LICENSE("GPL");
312