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