Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/keyboard/mpr121_touchkey.c
15111 views
1
/*
2
* Touchkey driver for Freescale MPR121 Controllor
3
*
4
* Copyright (C) 2011 Freescale Semiconductor, Inc.
5
* Author: Zhang Jiejing <[email protected]>
6
*
7
* Based on mcs_touchkey.c
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License version 2 as
11
* published by the Free Software Foundation.
12
*
13
*/
14
15
#include <linux/module.h>
16
#include <linux/init.h>
17
#include <linux/input.h>
18
#include <linux/i2c.h>
19
#include <linux/slab.h>
20
#include <linux/delay.h>
21
#include <linux/bitops.h>
22
#include <linux/interrupt.h>
23
#include <linux/i2c/mpr121_touchkey.h>
24
25
/* Register definitions */
26
#define ELE_TOUCH_STATUS_0_ADDR 0x0
27
#define ELE_TOUCH_STATUS_1_ADDR 0X1
28
#define MHD_RISING_ADDR 0x2b
29
#define NHD_RISING_ADDR 0x2c
30
#define NCL_RISING_ADDR 0x2d
31
#define FDL_RISING_ADDR 0x2e
32
#define MHD_FALLING_ADDR 0x2f
33
#define NHD_FALLING_ADDR 0x30
34
#define NCL_FALLING_ADDR 0x31
35
#define FDL_FALLING_ADDR 0x32
36
#define ELE0_TOUCH_THRESHOLD_ADDR 0x41
37
#define ELE0_RELEASE_THRESHOLD_ADDR 0x42
38
#define AFE_CONF_ADDR 0x5c
39
#define FILTER_CONF_ADDR 0x5d
40
41
/*
42
* ELECTRODE_CONF_ADDR: This register configures the number of
43
* enabled capacitance sensing inputs and its run/suspend mode.
44
*/
45
#define ELECTRODE_CONF_ADDR 0x5e
46
#define AUTO_CONFIG_CTRL_ADDR 0x7b
47
#define AUTO_CONFIG_USL_ADDR 0x7d
48
#define AUTO_CONFIG_LSL_ADDR 0x7e
49
#define AUTO_CONFIG_TL_ADDR 0x7f
50
51
/* Threshold of touch/release trigger */
52
#define TOUCH_THRESHOLD 0x0f
53
#define RELEASE_THRESHOLD 0x0a
54
/* Masks for touch and release triggers */
55
#define TOUCH_STATUS_MASK 0xfff
56
/* MPR121 has 12 keys */
57
#define MPR121_MAX_KEY_COUNT 12
58
59
struct mpr121_touchkey {
60
struct i2c_client *client;
61
struct input_dev *input_dev;
62
unsigned int key_val;
63
unsigned int statusbits;
64
unsigned int keycount;
65
u16 keycodes[MPR121_MAX_KEY_COUNT];
66
};
67
68
struct mpr121_init_register {
69
int addr;
70
u8 val;
71
};
72
73
static const struct mpr121_init_register init_reg_table[] __devinitconst = {
74
{ MHD_RISING_ADDR, 0x1 },
75
{ NHD_RISING_ADDR, 0x1 },
76
{ MHD_FALLING_ADDR, 0x1 },
77
{ NHD_FALLING_ADDR, 0x1 },
78
{ NCL_FALLING_ADDR, 0xff },
79
{ FDL_FALLING_ADDR, 0x02 },
80
{ FILTER_CONF_ADDR, 0x04 },
81
{ AFE_CONF_ADDR, 0x0b },
82
{ AUTO_CONFIG_CTRL_ADDR, 0x0b },
83
};
84
85
static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
86
{
87
struct mpr121_touchkey *mpr121 = dev_id;
88
struct i2c_client *client = mpr121->client;
89
struct input_dev *input = mpr121->input_dev;
90
unsigned int key_num, key_val, pressed;
91
int reg;
92
93
reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
94
if (reg < 0) {
95
dev_err(&client->dev, "i2c read error [%d]\n", reg);
96
goto out;
97
}
98
99
reg <<= 8;
100
reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
101
if (reg < 0) {
102
dev_err(&client->dev, "i2c read error [%d]\n", reg);
103
goto out;
104
}
105
106
reg &= TOUCH_STATUS_MASK;
107
/* use old press bit to figure out which bit changed */
108
key_num = ffs(reg ^ mpr121->statusbits) - 1;
109
pressed = reg & (1 << key_num);
110
mpr121->statusbits = reg;
111
112
key_val = mpr121->keycodes[key_num];
113
114
input_event(input, EV_MSC, MSC_SCAN, key_num);
115
input_report_key(input, key_val, pressed);
116
input_sync(input);
117
118
dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
119
pressed ? "pressed" : "released");
120
121
out:
122
return IRQ_HANDLED;
123
}
124
125
static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
126
struct mpr121_touchkey *mpr121,
127
struct i2c_client *client)
128
{
129
const struct mpr121_init_register *reg;
130
unsigned char usl, lsl, tl;
131
int i, t, vdd, ret;
132
133
/* Set up touch/release threshold for ele0-ele11 */
134
for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
135
t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
136
ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
137
if (ret < 0)
138
goto err_i2c_write;
139
ret = i2c_smbus_write_byte_data(client, t + 1,
140
RELEASE_THRESHOLD);
141
if (ret < 0)
142
goto err_i2c_write;
143
}
144
145
/* Set up init register */
146
for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) {
147
reg = &init_reg_table[i];
148
ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val);
149
if (ret < 0)
150
goto err_i2c_write;
151
}
152
153
154
/*
155
* Capacitance on sensing input varies and needs to be compensated.
156
* The internal MPR121-auto-configuration can do this if it's
157
* registers are set properly (based on pdata->vdd_uv).
158
*/
159
vdd = pdata->vdd_uv / 1000;
160
usl = ((vdd - 700) * 256) / vdd;
161
lsl = (usl * 65) / 100;
162
tl = (usl * 90) / 100;
163
ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
164
ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
165
ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
166
ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
167
mpr121->keycount);
168
if (ret != 0)
169
goto err_i2c_write;
170
171
dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount);
172
173
return 0;
174
175
err_i2c_write:
176
dev_err(&client->dev, "i2c write error: %d\n", ret);
177
return ret;
178
}
179
180
static int __devinit mpr_touchkey_probe(struct i2c_client *client,
181
const struct i2c_device_id *id)
182
{
183
const struct mpr121_platform_data *pdata = client->dev.platform_data;
184
struct mpr121_touchkey *mpr121;
185
struct input_dev *input_dev;
186
int error;
187
int i;
188
189
if (!pdata) {
190
dev_err(&client->dev, "no platform data defined\n");
191
return -EINVAL;
192
}
193
194
if (!pdata->keymap || !pdata->keymap_size) {
195
dev_err(&client->dev, "missing keymap data\n");
196
return -EINVAL;
197
}
198
199
if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
200
dev_err(&client->dev, "too many keys defined\n");
201
return -EINVAL;
202
}
203
204
if (!client->irq) {
205
dev_err(&client->dev, "irq number should not be zero\n");
206
return -EINVAL;
207
}
208
209
mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
210
input_dev = input_allocate_device();
211
if (!mpr121 || !input_dev) {
212
dev_err(&client->dev, "Failed to allocate memory\n");
213
error = -ENOMEM;
214
goto err_free_mem;
215
}
216
217
mpr121->client = client;
218
mpr121->input_dev = input_dev;
219
mpr121->keycount = pdata->keymap_size;
220
221
input_dev->name = "Freescale MPR121 Touchkey";
222
input_dev->id.bustype = BUS_I2C;
223
input_dev->dev.parent = &client->dev;
224
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
225
226
input_dev->keycode = mpr121->keycodes;
227
input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
228
input_dev->keycodemax = mpr121->keycount;
229
230
for (i = 0; i < pdata->keymap_size; i++) {
231
input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
232
mpr121->keycodes[i] = pdata->keymap[i];
233
}
234
235
error = mpr121_phys_init(pdata, mpr121, client);
236
if (error) {
237
dev_err(&client->dev, "Failed to init register\n");
238
goto err_free_mem;
239
}
240
241
error = request_threaded_irq(client->irq, NULL,
242
mpr_touchkey_interrupt,
243
IRQF_TRIGGER_FALLING,
244
client->dev.driver->name, mpr121);
245
if (error) {
246
dev_err(&client->dev, "Failed to register interrupt\n");
247
goto err_free_mem;
248
}
249
250
error = input_register_device(input_dev);
251
if (error)
252
goto err_free_irq;
253
254
i2c_set_clientdata(client, mpr121);
255
device_init_wakeup(&client->dev, pdata->wakeup);
256
257
return 0;
258
259
err_free_irq:
260
free_irq(client->irq, mpr121);
261
err_free_mem:
262
input_free_device(input_dev);
263
kfree(mpr121);
264
return error;
265
}
266
267
static int __devexit mpr_touchkey_remove(struct i2c_client *client)
268
{
269
struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
270
271
free_irq(client->irq, mpr121);
272
input_unregister_device(mpr121->input_dev);
273
kfree(mpr121);
274
275
return 0;
276
}
277
278
#ifdef CONFIG_PM_SLEEP
279
static int mpr_suspend(struct device *dev)
280
{
281
struct i2c_client *client = to_i2c_client(dev);
282
283
if (device_may_wakeup(&client->dev))
284
enable_irq_wake(client->irq);
285
286
i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
287
288
return 0;
289
}
290
291
static int mpr_resume(struct device *dev)
292
{
293
struct i2c_client *client = to_i2c_client(dev);
294
struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
295
296
if (device_may_wakeup(&client->dev))
297
disable_irq_wake(client->irq);
298
299
i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
300
mpr121->keycount);
301
302
return 0;
303
}
304
#endif
305
306
static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
307
308
static const struct i2c_device_id mpr121_id[] = {
309
{ "mpr121_touchkey", 0 },
310
{ }
311
};
312
MODULE_DEVICE_TABLE(i2c, mpr121_id);
313
314
static struct i2c_driver mpr_touchkey_driver = {
315
.driver = {
316
.name = "mpr121",
317
.owner = THIS_MODULE,
318
.pm = &mpr121_touchkey_pm_ops,
319
},
320
.id_table = mpr121_id,
321
.probe = mpr_touchkey_probe,
322
.remove = __devexit_p(mpr_touchkey_remove),
323
};
324
325
static int __init mpr_touchkey_init(void)
326
{
327
return i2c_add_driver(&mpr_touchkey_driver);
328
}
329
module_init(mpr_touchkey_init);
330
331
static void __exit mpr_touchkey_exit(void)
332
{
333
i2c_del_driver(&mpr_touchkey_driver);
334
}
335
module_exit(mpr_touchkey_exit);
336
337
MODULE_LICENSE("GPL");
338
MODULE_AUTHOR("Zhang Jiejing <[email protected]>");
339
MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip");
340
341