Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/keyboard/qt2160.c
15111 views
1
/*
2
* qt2160.c - Atmel AT42QT2160 Touch Sense Controller
3
*
4
* Copyright (C) 2009 Raphael Derosso Pereira <[email protected]>
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
45
static 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
52
struct 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
61
static 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
112
static 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
152
static 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
167
static 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
174
static 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
187
static 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
208
static 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
230
static 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
261
static 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
339
err_free_irq:
340
if (client->irq)
341
free_irq(client->irq, qt2160);
342
err_free_mem:
343
input_free_device(input);
344
kfree(qt2160);
345
return error;
346
}
347
348
static 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
364
static const struct i2c_device_id qt2160_idtable[] = {
365
{ "qt2160", 0, },
366
{ }
367
};
368
369
MODULE_DEVICE_TABLE(i2c, qt2160_idtable);
370
371
static 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
382
static int __init qt2160_init(void)
383
{
384
return i2c_add_driver(&qt2160_driver);
385
}
386
module_init(qt2160_init);
387
388
static void __exit qt2160_cleanup(void)
389
{
390
i2c_del_driver(&qt2160_driver);
391
}
392
module_exit(qt2160_cleanup);
393
394
MODULE_AUTHOR("Raphael Derosso Pereira <[email protected]>");
395
MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
396
MODULE_LICENSE("GPL");
397
398