• 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 *  qt2160.c - Atmel AT42QT2160 Touch Sense Controller
3 *
4 *  Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com>
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software
18 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/jiffies.h>
26#include <linux/i2c.h>
27#include <linux/irq.h>
28#include <linux/interrupt.h>
29#include <linux/input.h>
30
31#define QT2160_VALID_CHIPID  0x11
32
33#define QT2160_CMD_CHIPID     0
34#define QT2160_CMD_CODEVER    1
35#define QT2160_CMD_GSTAT      2
36#define QT2160_CMD_KEYS3      3
37#define QT2160_CMD_KEYS4      4
38#define QT2160_CMD_SLIDE      5
39#define QT2160_CMD_GPIOS      6
40#define QT2160_CMD_SUBVER     7
41#define QT2160_CMD_CALIBRATE  10
42
43#define QT2160_CYCLE_INTERVAL	(2*HZ)
44
45static unsigned char qt2160_key2code[] = {
46	KEY_0, KEY_1, KEY_2, KEY_3,
47	KEY_4, KEY_5, KEY_6, KEY_7,
48	KEY_8, KEY_9, KEY_A, KEY_B,
49	KEY_C, KEY_D, KEY_E, KEY_F,
50};
51
52struct qt2160_data {
53	struct i2c_client *client;
54	struct input_dev *input;
55	struct delayed_work dwork;
56	spinlock_t lock;        /* Protects canceling/rescheduling of dwork */
57	unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
58	u16 key_matrix;
59};
60
61static int qt2160_read_block(struct i2c_client *client,
62			     u8 inireg, u8 *buffer, unsigned int count)
63{
64	int error, idx = 0;
65
66	/*
67	 * Can't use SMBus block data read. Check for I2C functionality to speed
68	 * things up whenever possible. Otherwise we will be forced to read
69	 * sequentially.
70	 */
71	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))	{
72
73		error = i2c_smbus_write_byte(client, inireg + idx);
74		if (error) {
75			dev_err(&client->dev,
76				"couldn't send request. Returned %d\n", error);
77			return error;
78		}
79
80		error = i2c_master_recv(client, buffer, count);
81		if (error != count) {
82			dev_err(&client->dev,
83				"couldn't read registers. Returned %d bytes\n", error);
84			return error;
85		}
86	} else {
87
88		while (count--) {
89			int data;
90
91			error = i2c_smbus_write_byte(client, inireg + idx);
92			if (error) {
93				dev_err(&client->dev,
94					"couldn't send request. Returned %d\n", error);
95				return error;
96			}
97
98			data = i2c_smbus_read_byte(client);
99			if (data < 0) {
100				dev_err(&client->dev,
101					"couldn't read register. Returned %d\n", data);
102				return data;
103			}
104
105			buffer[idx++] = data;
106		}
107	}
108
109	return 0;
110}
111
112static int qt2160_get_key_matrix(struct qt2160_data *qt2160)
113{
114	struct i2c_client *client = qt2160->client;
115	struct input_dev *input = qt2160->input;
116	u8 regs[6];
117	u16 old_matrix, new_matrix;
118	int ret, i, mask;
119
120	dev_dbg(&client->dev, "requesting keys...\n");
121
122	/*
123	 * Read all registers from General Status Register
124	 * to GPIOs register
125	 */
126	ret = qt2160_read_block(client, QT2160_CMD_GSTAT, regs, 6);
127	if (ret) {
128		dev_err(&client->dev,
129			"could not perform chip read.\n");
130		return ret;
131	}
132
133	old_matrix = qt2160->key_matrix;
134	qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1];
135
136	mask = 0x01;
137	for (i = 0; i < 16; ++i, mask <<= 1) {
138		int keyval = new_matrix & mask;
139
140		if ((old_matrix & mask) != keyval) {
141			input_report_key(input, qt2160->keycodes[i], keyval);
142			dev_dbg(&client->dev, "key %d %s\n",
143				i, keyval ? "pressed" : "released");
144		}
145	}
146
147	input_sync(input);
148
149	return 0;
150}
151
152static irqreturn_t qt2160_irq(int irq, void *_qt2160)
153{
154	struct qt2160_data *qt2160 = _qt2160;
155	unsigned long flags;
156
157	spin_lock_irqsave(&qt2160->lock, flags);
158
159	__cancel_delayed_work(&qt2160->dwork);
160	schedule_delayed_work(&qt2160->dwork, 0);
161
162	spin_unlock_irqrestore(&qt2160->lock, flags);
163
164	return IRQ_HANDLED;
165}
166
167static void qt2160_schedule_read(struct qt2160_data *qt2160)
168{
169	spin_lock_irq(&qt2160->lock);
170	schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL);
171	spin_unlock_irq(&qt2160->lock);
172}
173
174static void qt2160_worker(struct work_struct *work)
175{
176	struct qt2160_data *qt2160 =
177		container_of(work, struct qt2160_data, dwork.work);
178
179	dev_dbg(&qt2160->client->dev, "worker\n");
180
181	qt2160_get_key_matrix(qt2160);
182
183	/* Avoid device lock up by checking every so often */
184	qt2160_schedule_read(qt2160);
185}
186
187static int __devinit qt2160_read(struct i2c_client *client, u8 reg)
188{
189	int ret;
190
191	ret = i2c_smbus_write_byte(client, reg);
192	if (ret) {
193		dev_err(&client->dev,
194			"couldn't send request. Returned %d\n", ret);
195		return ret;
196	}
197
198	ret = i2c_smbus_read_byte(client);
199	if (ret < 0) {
200		dev_err(&client->dev,
201			"couldn't read register. Returned %d\n", ret);
202		return ret;
203	}
204
205	return ret;
206}
207
208static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data)
209{
210	int error;
211
212	error = i2c_smbus_write_byte(client, reg);
213	if (error) {
214		dev_err(&client->dev,
215			"couldn't send request. Returned %d\n", error);
216		return error;
217	}
218
219	error = i2c_smbus_write_byte(client, data);
220	if (error) {
221		dev_err(&client->dev,
222			"couldn't write data. Returned %d\n", error);
223		return error;
224	}
225
226	return error;
227}
228
229
230static bool __devinit qt2160_identify(struct i2c_client *client)
231{
232	int id, ver, rev;
233
234	/* Read Chid ID to check if chip is valid */
235	id = qt2160_read(client, QT2160_CMD_CHIPID);
236	if (id != QT2160_VALID_CHIPID) {
237		dev_err(&client->dev, "ID %d not supported\n", id);
238		return false;
239	}
240
241	/* Read chip firmware version */
242	ver = qt2160_read(client, QT2160_CMD_CODEVER);
243	if (ver < 0) {
244		dev_err(&client->dev, "could not get firmware version\n");
245		return false;
246	}
247
248	/* Read chip firmware revision */
249	rev = qt2160_read(client, QT2160_CMD_SUBVER);
250	if (rev < 0) {
251		dev_err(&client->dev, "could not get firmware revision\n");
252		return false;
253	}
254
255	dev_info(&client->dev, "AT42QT2160 firmware version %d.%d.%d\n",
256			ver >> 4, ver & 0xf, rev);
257
258	return true;
259}
260
261static int __devinit qt2160_probe(struct i2c_client *client,
262				  const struct i2c_device_id *id)
263{
264	struct qt2160_data *qt2160;
265	struct input_dev *input;
266	int i;
267	int error;
268
269	/* Check functionality */
270	error = i2c_check_functionality(client->adapter,
271			I2C_FUNC_SMBUS_BYTE);
272	if (!error) {
273		dev_err(&client->dev, "%s adapter not supported\n",
274				dev_driver_string(&client->adapter->dev));
275		return -ENODEV;
276	}
277
278	if (!qt2160_identify(client))
279		return -ENODEV;
280
281	/* Chip is valid and active. Allocate structure */
282	qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL);
283	input = input_allocate_device();
284	if (!qt2160 || !input) {
285		dev_err(&client->dev, "insufficient memory\n");
286		error = -ENOMEM;
287		goto err_free_mem;
288	}
289
290	qt2160->client = client;
291	qt2160->input = input;
292	INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker);
293	spin_lock_init(&qt2160->lock);
294
295	input->name = "AT42QT2160 Touch Sense Keyboard";
296	input->id.bustype = BUS_I2C;
297
298	input->keycode = qt2160->keycodes;
299	input->keycodesize = sizeof(qt2160->keycodes[0]);
300	input->keycodemax = ARRAY_SIZE(qt2160_key2code);
301
302	__set_bit(EV_KEY, input->evbit);
303	__clear_bit(EV_REP, input->evbit);
304	for (i = 0; i < ARRAY_SIZE(qt2160_key2code); i++) {
305		qt2160->keycodes[i] = qt2160_key2code[i];
306		__set_bit(qt2160_key2code[i], input->keybit);
307	}
308	__clear_bit(KEY_RESERVED, input->keybit);
309
310	/* Calibrate device */
311	error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1);
312	if (error) {
313		dev_err(&client->dev, "failed to calibrate device\n");
314		goto err_free_mem;
315	}
316
317	if (client->irq) {
318		error = request_irq(client->irq, qt2160_irq,
319				    IRQF_TRIGGER_FALLING, "qt2160", qt2160);
320		if (error) {
321			dev_err(&client->dev,
322				"failed to allocate irq %d\n", client->irq);
323			goto err_free_mem;
324		}
325	}
326
327	error = input_register_device(qt2160->input);
328	if (error) {
329		dev_err(&client->dev,
330			"Failed to register input device\n");
331		goto err_free_irq;
332	}
333
334	i2c_set_clientdata(client, qt2160);
335	qt2160_schedule_read(qt2160);
336
337	return 0;
338
339err_free_irq:
340	if (client->irq)
341		free_irq(client->irq, qt2160);
342err_free_mem:
343	input_free_device(input);
344	kfree(qt2160);
345	return error;
346}
347
348static int __devexit qt2160_remove(struct i2c_client *client)
349{
350	struct qt2160_data *qt2160 = i2c_get_clientdata(client);
351
352	/* Release IRQ so no queue will be scheduled */
353	if (client->irq)
354		free_irq(client->irq, qt2160);
355
356	cancel_delayed_work_sync(&qt2160->dwork);
357
358	input_unregister_device(qt2160->input);
359	kfree(qt2160);
360
361	return 0;
362}
363
364static const struct i2c_device_id qt2160_idtable[] = {
365	{ "qt2160", 0, },
366	{ }
367};
368
369MODULE_DEVICE_TABLE(i2c, qt2160_idtable);
370
371static struct i2c_driver qt2160_driver = {
372	.driver = {
373		.name	= "qt2160",
374		.owner  = THIS_MODULE,
375	},
376
377	.id_table	= qt2160_idtable,
378	.probe		= qt2160_probe,
379	.remove		= __devexit_p(qt2160_remove),
380};
381
382static int __init qt2160_init(void)
383{
384	return i2c_add_driver(&qt2160_driver);
385}
386module_init(qt2160_init);
387
388static void __exit qt2160_cleanup(void)
389{
390	i2c_del_driver(&qt2160_driver);
391}
392module_exit(qt2160_cleanup);
393
394MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
395MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
396MODULE_LICENSE("GPL");
397