Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/touchscreen/mcs5000_ts.c
15112 views
1
/*
2
* mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
3
*
4
* Copyright (C) 2009 Samsung Electronics Co.Ltd
5
* Author: Joonyoung Shim <[email protected]>
6
*
7
* Based on wm97xx-core.c
8
*
9
* This program is free software; you can redistribute it and/or modify it
10
* under the terms of the GNU General Public License as published by the
11
* Free Software Foundation; either version 2 of the License, or (at your
12
* option) any later version.
13
*
14
*/
15
16
#include <linux/module.h>
17
#include <linux/init.h>
18
#include <linux/i2c.h>
19
#include <linux/i2c/mcs.h>
20
#include <linux/interrupt.h>
21
#include <linux/input.h>
22
#include <linux/irq.h>
23
#include <linux/slab.h>
24
25
/* Registers */
26
#define MCS5000_TS_STATUS 0x00
27
#define STATUS_OFFSET 0
28
#define STATUS_NO (0 << STATUS_OFFSET)
29
#define STATUS_INIT (1 << STATUS_OFFSET)
30
#define STATUS_SENSING (2 << STATUS_OFFSET)
31
#define STATUS_COORD (3 << STATUS_OFFSET)
32
#define STATUS_GESTURE (4 << STATUS_OFFSET)
33
#define ERROR_OFFSET 4
34
#define ERROR_NO (0 << ERROR_OFFSET)
35
#define ERROR_POWER_ON_RESET (1 << ERROR_OFFSET)
36
#define ERROR_INT_RESET (2 << ERROR_OFFSET)
37
#define ERROR_EXT_RESET (3 << ERROR_OFFSET)
38
#define ERROR_INVALID_REG_ADDRESS (8 << ERROR_OFFSET)
39
#define ERROR_INVALID_REG_VALUE (9 << ERROR_OFFSET)
40
41
#define MCS5000_TS_OP_MODE 0x01
42
#define RESET_OFFSET 0
43
#define RESET_NO (0 << RESET_OFFSET)
44
#define RESET_EXT_SOFT (1 << RESET_OFFSET)
45
#define OP_MODE_OFFSET 1
46
#define OP_MODE_SLEEP (0 << OP_MODE_OFFSET)
47
#define OP_MODE_ACTIVE (1 << OP_MODE_OFFSET)
48
#define GESTURE_OFFSET 4
49
#define GESTURE_DISABLE (0 << GESTURE_OFFSET)
50
#define GESTURE_ENABLE (1 << GESTURE_OFFSET)
51
#define PROXIMITY_OFFSET 5
52
#define PROXIMITY_DISABLE (0 << PROXIMITY_OFFSET)
53
#define PROXIMITY_ENABLE (1 << PROXIMITY_OFFSET)
54
#define SCAN_MODE_OFFSET 6
55
#define SCAN_MODE_INTERRUPT (0 << SCAN_MODE_OFFSET)
56
#define SCAN_MODE_POLLING (1 << SCAN_MODE_OFFSET)
57
#define REPORT_RATE_OFFSET 7
58
#define REPORT_RATE_40 (0 << REPORT_RATE_OFFSET)
59
#define REPORT_RATE_80 (1 << REPORT_RATE_OFFSET)
60
61
#define MCS5000_TS_SENS_CTL 0x02
62
#define MCS5000_TS_FILTER_CTL 0x03
63
#define PRI_FILTER_OFFSET 0
64
#define SEC_FILTER_OFFSET 4
65
66
#define MCS5000_TS_X_SIZE_UPPER 0x08
67
#define MCS5000_TS_X_SIZE_LOWER 0x09
68
#define MCS5000_TS_Y_SIZE_UPPER 0x0A
69
#define MCS5000_TS_Y_SIZE_LOWER 0x0B
70
71
#define MCS5000_TS_INPUT_INFO 0x10
72
#define INPUT_TYPE_OFFSET 0
73
#define INPUT_TYPE_NONTOUCH (0 << INPUT_TYPE_OFFSET)
74
#define INPUT_TYPE_SINGLE (1 << INPUT_TYPE_OFFSET)
75
#define INPUT_TYPE_DUAL (2 << INPUT_TYPE_OFFSET)
76
#define INPUT_TYPE_PALM (3 << INPUT_TYPE_OFFSET)
77
#define INPUT_TYPE_PROXIMITY (7 << INPUT_TYPE_OFFSET)
78
#define GESTURE_CODE_OFFSET 3
79
#define GESTURE_CODE_NO (0 << GESTURE_CODE_OFFSET)
80
81
#define MCS5000_TS_X_POS_UPPER 0x11
82
#define MCS5000_TS_X_POS_LOWER 0x12
83
#define MCS5000_TS_Y_POS_UPPER 0x13
84
#define MCS5000_TS_Y_POS_LOWER 0x14
85
#define MCS5000_TS_Z_POS 0x15
86
#define MCS5000_TS_WIDTH 0x16
87
#define MCS5000_TS_GESTURE_VAL 0x17
88
#define MCS5000_TS_MODULE_REV 0x20
89
#define MCS5000_TS_FIRMWARE_VER 0x21
90
91
/* Touchscreen absolute values */
92
#define MCS5000_MAX_XC 0x3ff
93
#define MCS5000_MAX_YC 0x3ff
94
95
enum mcs5000_ts_read_offset {
96
READ_INPUT_INFO,
97
READ_X_POS_UPPER,
98
READ_X_POS_LOWER,
99
READ_Y_POS_UPPER,
100
READ_Y_POS_LOWER,
101
READ_BLOCK_SIZE,
102
};
103
104
/* Each client has this additional data */
105
struct mcs5000_ts_data {
106
struct i2c_client *client;
107
struct input_dev *input_dev;
108
const struct mcs_platform_data *platform_data;
109
};
110
111
static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
112
{
113
struct mcs5000_ts_data *data = dev_id;
114
struct i2c_client *client = data->client;
115
u8 buffer[READ_BLOCK_SIZE];
116
int err;
117
int x;
118
int y;
119
120
err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
121
READ_BLOCK_SIZE, buffer);
122
if (err < 0) {
123
dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
124
goto out;
125
}
126
127
switch (buffer[READ_INPUT_INFO]) {
128
case INPUT_TYPE_NONTOUCH:
129
input_report_key(data->input_dev, BTN_TOUCH, 0);
130
input_sync(data->input_dev);
131
break;
132
133
case INPUT_TYPE_SINGLE:
134
x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
135
y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
136
137
input_report_key(data->input_dev, BTN_TOUCH, 1);
138
input_report_abs(data->input_dev, ABS_X, x);
139
input_report_abs(data->input_dev, ABS_Y, y);
140
input_sync(data->input_dev);
141
break;
142
143
case INPUT_TYPE_DUAL:
144
/* TODO */
145
break;
146
147
case INPUT_TYPE_PALM:
148
/* TODO */
149
break;
150
151
case INPUT_TYPE_PROXIMITY:
152
/* TODO */
153
break;
154
155
default:
156
dev_err(&client->dev, "Unknown ts input type %d\n",
157
buffer[READ_INPUT_INFO]);
158
break;
159
}
160
161
out:
162
return IRQ_HANDLED;
163
}
164
165
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
166
{
167
const struct mcs_platform_data *platform_data =
168
data->platform_data;
169
struct i2c_client *client = data->client;
170
171
/* Touch reset & sleep mode */
172
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
173
RESET_EXT_SOFT | OP_MODE_SLEEP);
174
175
/* Touch size */
176
i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
177
platform_data->x_size >> 8);
178
i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
179
platform_data->x_size & 0xff);
180
i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
181
platform_data->y_size >> 8);
182
i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
183
platform_data->y_size & 0xff);
184
185
/* Touch active mode & 80 report rate */
186
i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
187
OP_MODE_ACTIVE | REPORT_RATE_80);
188
}
189
190
static int __devinit mcs5000_ts_probe(struct i2c_client *client,
191
const struct i2c_device_id *id)
192
{
193
struct mcs5000_ts_data *data;
194
struct input_dev *input_dev;
195
int ret;
196
197
if (!client->dev.platform_data)
198
return -EINVAL;
199
200
data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
201
input_dev = input_allocate_device();
202
if (!data || !input_dev) {
203
dev_err(&client->dev, "Failed to allocate memory\n");
204
ret = -ENOMEM;
205
goto err_free_mem;
206
}
207
208
data->client = client;
209
data->input_dev = input_dev;
210
data->platform_data = client->dev.platform_data;
211
212
input_dev->name = "MELPAS MCS-5000 Touchscreen";
213
input_dev->id.bustype = BUS_I2C;
214
input_dev->dev.parent = &client->dev;
215
216
__set_bit(EV_ABS, input_dev->evbit);
217
__set_bit(EV_KEY, input_dev->evbit);
218
__set_bit(BTN_TOUCH, input_dev->keybit);
219
input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
220
input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
221
222
input_set_drvdata(input_dev, data);
223
224
if (data->platform_data->cfg_pin)
225
data->platform_data->cfg_pin();
226
227
ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,
228
IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);
229
230
if (ret < 0) {
231
dev_err(&client->dev, "Failed to register interrupt\n");
232
goto err_free_mem;
233
}
234
235
ret = input_register_device(data->input_dev);
236
if (ret < 0)
237
goto err_free_irq;
238
239
mcs5000_ts_phys_init(data);
240
i2c_set_clientdata(client, data);
241
242
return 0;
243
244
err_free_irq:
245
free_irq(client->irq, data);
246
err_free_mem:
247
input_free_device(input_dev);
248
kfree(data);
249
return ret;
250
}
251
252
static int __devexit mcs5000_ts_remove(struct i2c_client *client)
253
{
254
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
255
256
free_irq(client->irq, data);
257
input_unregister_device(data->input_dev);
258
kfree(data);
259
260
return 0;
261
}
262
263
#ifdef CONFIG_PM
264
static int mcs5000_ts_suspend(struct device *dev)
265
{
266
struct i2c_client *client = to_i2c_client(dev);
267
268
/* Touch sleep mode */
269
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
270
271
return 0;
272
}
273
274
static int mcs5000_ts_resume(struct device *dev)
275
{
276
struct i2c_client *client = to_i2c_client(dev);
277
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
278
279
mcs5000_ts_phys_init(data);
280
281
return 0;
282
}
283
284
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
285
#endif
286
287
static const struct i2c_device_id mcs5000_ts_id[] = {
288
{ "mcs5000_ts", 0 },
289
{ }
290
};
291
MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
292
293
static struct i2c_driver mcs5000_ts_driver = {
294
.probe = mcs5000_ts_probe,
295
.remove = __devexit_p(mcs5000_ts_remove),
296
.driver = {
297
.name = "mcs5000_ts",
298
#ifdef CONFIG_PM
299
.pm = &mcs5000_ts_pm,
300
#endif
301
},
302
.id_table = mcs5000_ts_id,
303
};
304
305
static int __init mcs5000_ts_init(void)
306
{
307
return i2c_add_driver(&mcs5000_ts_driver);
308
}
309
310
static void __exit mcs5000_ts_exit(void)
311
{
312
i2c_del_driver(&mcs5000_ts_driver);
313
}
314
315
module_init(mcs5000_ts_init);
316
module_exit(mcs5000_ts_exit);
317
318
/* Module information */
319
MODULE_AUTHOR("Joonyoung Shim <[email protected]>");
320
MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
321
MODULE_LICENSE("GPL");
322
323