]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/input/touchscreen/ili210x.c
Input: ili210x - do not set parent device explicitly
[mirror_ubuntu-hirsute-kernel.git] / drivers / input / touchscreen / ili210x.c
CommitLineData
09c434b8 1// SPDX-License-Identifier: GPL-2.0-only
71f8e38a
DT
2#include <linux/delay.h>
3#include <linux/gpio/consumer.h>
5c6a7a62 4#include <linux/i2c.h>
5c6a7a62
OS
5#include <linux/input.h>
6#include <linux/input/mt.h>
f67cc3e9 7#include <linux/input/touchscreen.h>
71f8e38a
DT
8#include <linux/interrupt.h>
9#include <linux/module.h>
49588917 10#include <linux/of_device.h>
71f8e38a 11#include <linux/slab.h>
e3559442 12#include <asm/unaligned.h>
5c6a7a62 13
49588917 14#define ILI210X_TOUCHES 2
eb91ecc9 15#define ILI211X_TOUCHES 10
49588917 16#define ILI251X_TOUCHES 10
71f8e38a
DT
17
18#define ILI2XXX_POLL_PERIOD 20
5c6a7a62
OS
19
20/* Touchscreen commands */
21#define REG_TOUCHDATA 0x10
22#define REG_PANEL_INFO 0x20
23#define REG_FIRMWARE_VERSION 0x40
24#define REG_CALIBRATE 0xcc
25
5c6a7a62
OS
26struct firmware_version {
27 u8 id;
28 u8 major;
29 u8 minor;
30} __packed;
31
49588917
MV
32enum ili2xxx_model {
33 MODEL_ILI210X,
eb91ecc9 34 MODEL_ILI211X,
49588917
MV
35 MODEL_ILI251X,
36};
37
5c6a7a62
OS
38struct ili210x {
39 struct i2c_client *client;
40 struct input_dev *input;
201f3c80 41 struct gpio_desc *reset_gpio;
f67cc3e9 42 struct touchscreen_properties prop;
49588917
MV
43 enum ili2xxx_model model;
44 unsigned int max_touches;
71f8e38a 45 bool stop;
5c6a7a62
OS
46};
47
48static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
49 size_t len)
50{
49588917 51 struct ili210x *priv = i2c_get_clientdata(client);
5c6a7a62
OS
52 struct i2c_msg msg[2] = {
53 {
54 .addr = client->addr,
55 .flags = 0,
56 .len = 1,
57 .buf = &reg,
58 },
59 {
60 .addr = client->addr,
61 .flags = I2C_M_RD,
62 .len = len,
63 .buf = buf,
64 }
65 };
66
49588917
MV
67 if (priv->model == MODEL_ILI251X) {
68 if (i2c_transfer(client->adapter, msg, 1) != 1) {
69 dev_err(&client->dev, "i2c transfer failed\n");
70 return -EIO;
71 }
72
73 usleep_range(5000, 5500);
74
75 if (i2c_transfer(client->adapter, msg + 1, 1) != 1) {
76 dev_err(&client->dev, "i2c transfer failed\n");
77 return -EIO;
78 }
79 } else {
80 if (i2c_transfer(client->adapter, msg, 2) != 2) {
81 dev_err(&client->dev, "i2c transfer failed\n");
82 return -EIO;
83 }
84 }
85
86 return 0;
87}
88
89static int ili210x_read(struct i2c_client *client, void *buf, size_t len)
90{
91 struct i2c_msg msg = {
92 .addr = client->addr,
93 .flags = I2C_M_RD,
94 .len = len,
95 .buf = buf,
96 };
97
98 if (i2c_transfer(client->adapter, &msg, 1) != 1) {
5c6a7a62
OS
99 dev_err(&client->dev, "i2c transfer failed\n");
100 return -EIO;
101 }
102
103 return 0;
104}
105
e3559442
MV
106static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
107 unsigned int finger,
108 unsigned int *x, unsigned int *y)
109{
49588917 110 if (finger >= ILI210X_TOUCHES)
e3559442
MV
111 return false;
112
113 if (touchdata[0] & BIT(finger))
114 return false;
115
116 *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
117 *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
118
119 return true;
120}
121
eb91ecc9
MV
122static bool ili211x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
123 unsigned int finger,
124 unsigned int *x, unsigned int *y)
125{
126 u32 data;
127
128 if (finger >= ILI211X_TOUCHES)
129 return false;
130
131 data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0);
132 if (data == 0xffffffff) /* Finger up */
133 return false;
134
135 *x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) |
136 touchdata[1 + (finger * 4) + 1];
137 *y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) |
138 touchdata[1 + (finger * 4) + 2];
139
140 return true;
141}
142
49588917
MV
143static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
144 unsigned int finger,
145 unsigned int *x, unsigned int *y)
146{
147 if (finger >= ILI251X_TOUCHES)
148 return false;
149
150 *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
151 if (!(*x & BIT(15))) /* Touch indication */
152 return false;
153
154 *x &= 0x3fff;
155 *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
156
157 return true;
158}
159
e3559442 160static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
5c6a7a62 161{
e3559442 162 struct input_dev *input = priv->input;
5c6a7a62 163 int i;
49588917
MV
164 bool contact = false, touch = false;
165 unsigned int x = 0, y = 0;
5c6a7a62 166
49588917 167 for (i = 0; i < priv->max_touches; i++) {
49588917
MV
168 if (priv->model == MODEL_ILI210X) {
169 touch = ili210x_touchdata_to_coords(priv, touchdata,
170 i, &x, &y);
eb91ecc9
MV
171 } else if (priv->model == MODEL_ILI211X) {
172 touch = ili211x_touchdata_to_coords(priv, touchdata,
173 i, &x, &y);
49588917
MV
174 } else if (priv->model == MODEL_ILI251X) {
175 touch = ili251x_touchdata_to_coords(priv, touchdata,
176 i, &x, &y);
177 if (touch)
178 contact = true;
179 }
180
f67cc3e9 181 input_mt_slot(input, i);
5c6a7a62 182 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
f67cc3e9
MV
183 if (!touch)
184 continue;
185 touchscreen_report_pos(input, &priv->prop, x, y,
186 true);
5c6a7a62
OS
187 }
188
189 input_mt_report_pointer_emulation(input, false);
190 input_sync(input);
e3559442 191
49588917
MV
192 if (priv->model == MODEL_ILI210X)
193 contact = touchdata[0] & 0xf3;
194
195 return contact;
5c6a7a62
OS
196}
197
71f8e38a 198static irqreturn_t ili210x_irq(int irq, void *irq_data)
5c6a7a62 199{
71f8e38a 200 struct ili210x *priv = irq_data;
5c6a7a62 201 struct i2c_client *client = priv->client;
49588917 202 u8 touchdata[64] = { 0 };
eb91ecc9 203 s16 sum = 0;
e3559442 204 bool touch;
71f8e38a
DT
205 int i;
206 int error;
207
208 do {
209 if (priv->model == MODEL_ILI210X) {
210 error = ili210x_read_reg(client, REG_TOUCHDATA,
211 touchdata, sizeof(touchdata));
212 } else if (priv->model == MODEL_ILI211X) {
213 error = ili210x_read(client, touchdata, 43);
214 if (!error) {
215 /*
216 * This chip uses custom checksum at the end
217 * of data.
218 */
219 for (i = 0; i <= 41; i++)
220 sum = (sum + touchdata[i]) & 0xff;
221 if ((-sum & 0xff) != touchdata[42]) {
222 dev_err(&client->dev,
223 "CRC error (crc=0x%02x expected=0x%02x)\n",
224 sum, touchdata[42]);
225 break;
226 }
eb91ecc9 227 }
71f8e38a
DT
228 } else if (priv->model == MODEL_ILI251X) {
229 error = ili210x_read_reg(client, REG_TOUCHDATA,
230 touchdata, 31);
231 if (!error && touchdata[0] == 2)
232 error = ili210x_read(client,
233 &touchdata[31], 20);
eb91ecc9 234 }
5c6a7a62 235
71f8e38a
DT
236 if (error) {
237 dev_err(&client->dev,
238 "Unable to get touchdata, err = %d\n", error);
239 break;
240 }
5c6a7a62 241
71f8e38a
DT
242 touch = ili210x_report_events(priv, touchdata);
243 if (touch)
244 msleep(ILI2XXX_POLL_PERIOD);
245 } while (!priv->stop && touch);
5c6a7a62
OS
246
247 return IRQ_HANDLED;
248}
249
250static ssize_t ili210x_calibrate(struct device *dev,
251 struct device_attribute *attr,
252 const char *buf, size_t count)
253{
254 struct i2c_client *client = to_i2c_client(dev);
255 struct ili210x *priv = i2c_get_clientdata(client);
256 unsigned long calibrate;
257 int rc;
258 u8 cmd = REG_CALIBRATE;
259
260 if (kstrtoul(buf, 10, &calibrate))
261 return -EINVAL;
262
263 if (calibrate > 1)
264 return -EINVAL;
265
266 if (calibrate) {
267 rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
268 if (rc != sizeof(cmd))
269 return -EIO;
270 }
271
272 return count;
273}
b27c0d0c 274static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
5c6a7a62
OS
275
276static struct attribute *ili210x_attributes[] = {
277 &dev_attr_calibrate.attr,
278 NULL,
279};
280
281static const struct attribute_group ili210x_attr_group = {
282 .attrs = ili210x_attributes,
283};
284
201f3c80
MV
285static void ili210x_power_down(void *data)
286{
287 struct gpio_desc *reset_gpio = data;
288
289 gpiod_set_value_cansleep(reset_gpio, 1);
290}
291
71f8e38a 292static void ili210x_stop(void *data)
1bdec5d9
MV
293{
294 struct ili210x *priv = data;
295
71f8e38a
DT
296 /* Tell ISR to quit even if there is a contact. */
297 priv->stop = true;
1bdec5d9
MV
298}
299
5298cc4c 300static int ili210x_i2c_probe(struct i2c_client *client,
5c6a7a62
OS
301 const struct i2c_device_id *id)
302{
303 struct device *dev = &client->dev;
5c6a7a62 304 struct ili210x *priv;
201f3c80 305 struct gpio_desc *reset_gpio;
5c6a7a62 306 struct input_dev *input;
5c6a7a62 307 struct firmware_version firmware;
49588917 308 enum ili2xxx_model model;
5c6a7a62
OS
309 int error;
310
49588917
MV
311 model = (enum ili2xxx_model)id->driver_data;
312
5c6a7a62
OS
313 dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
314
5c6a7a62
OS
315 if (client->irq <= 0) {
316 dev_err(dev, "No IRQ!\n");
317 return -EINVAL;
318 }
319
201f3c80
MV
320 reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
321 if (IS_ERR(reset_gpio))
322 return PTR_ERR(reset_gpio);
323
324 if (reset_gpio) {
325 error = devm_add_action_or_reset(dev, ili210x_power_down,
326 reset_gpio);
327 if (error)
328 return error;
329
330 usleep_range(50, 100);
331 gpiod_set_value_cansleep(reset_gpio, 0);
332 msleep(100);
333 }
334
12294577
MV
335 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
336 if (!priv)
337 return -ENOMEM;
338
339 input = devm_input_allocate_device(dev);
340 if (!input)
341 return -ENOMEM;
342
343 priv->client = client;
344 priv->input = input;
12294577 345 priv->reset_gpio = reset_gpio;
49588917
MV
346 priv->model = model;
347 if (model == MODEL_ILI210X)
348 priv->max_touches = ILI210X_TOUCHES;
eb91ecc9
MV
349 if (model == MODEL_ILI211X)
350 priv->max_touches = ILI211X_TOUCHES;
49588917
MV
351 if (model == MODEL_ILI251X)
352 priv->max_touches = ILI251X_TOUCHES;
12294577
MV
353
354 i2c_set_clientdata(client, priv);
355
5c6a7a62
OS
356 /* Get firmware version */
357 error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
358 &firmware, sizeof(firmware));
359 if (error) {
360 dev_err(dev, "Failed to get firmware version, err: %d\n",
361 error);
362 return error;
363 }
364
5c6a7a62
OS
365 /* Setup input device */
366 input->name = "ILI210x Touchscreen";
367 input->id.bustype = BUS_I2C;
5c6a7a62 368
5c6a7a62 369 /* Multi touch */
f67cc3e9
MV
370 input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);
371 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);
372 touchscreen_parse_properties(input, true, &priv->prop);
43f06a4c
DT
373
374 error = input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
375 if (error) {
376 dev_err(dev, "Unable to set up slots, err: %d\n", error);
377 return error;
378 }
5c6a7a62 379
71f8e38a
DT
380 error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq,
381 IRQF_ONESHOT, client->name, priv);
5c6a7a62
OS
382 if (error) {
383 dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
384 error);
1bdec5d9 385 return error;
5c6a7a62
OS
386 }
387
71f8e38a
DT
388 error = devm_add_action_or_reset(dev, ili210x_stop, priv);
389 if (error)
390 return error;
391
576057bf 392 error = devm_device_add_group(dev, &ili210x_attr_group);
5c6a7a62
OS
393 if (error) {
394 dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
395 error);
1bdec5d9 396 return error;
5c6a7a62
OS
397 }
398
399 error = input_register_device(priv->input);
400 if (error) {
971bd8fa 401 dev_err(dev, "Cannot register input device, err: %d\n", error);
576057bf 402 return error;
5c6a7a62
OS
403 }
404
d7ddf154 405 device_init_wakeup(dev, 1);
5c6a7a62
OS
406
407 dev_dbg(dev,
408 "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
409 client->irq, firmware.id, firmware.major, firmware.minor);
410
411 return 0;
5c6a7a62
OS
412}
413
02b6a58b 414static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
5c6a7a62
OS
415{
416 struct i2c_client *client = to_i2c_client(dev);
417
418 if (device_may_wakeup(&client->dev))
419 enable_irq_wake(client->irq);
420
421 return 0;
422}
423
02b6a58b 424static int __maybe_unused ili210x_i2c_resume(struct device *dev)
5c6a7a62
OS
425{
426 struct i2c_client *client = to_i2c_client(dev);
427
428 if (device_may_wakeup(&client->dev))
429 disable_irq_wake(client->irq);
430
431 return 0;
432}
5c6a7a62
OS
433
434static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
435 ili210x_i2c_suspend, ili210x_i2c_resume);
436
437static const struct i2c_device_id ili210x_i2c_id[] = {
49588917 438 { "ili210x", MODEL_ILI210X },
eb91ecc9 439 { "ili2117", MODEL_ILI211X },
49588917 440 { "ili251x", MODEL_ILI251X },
5c6a7a62
OS
441 { }
442};
443MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
444
c5d0e4b5 445static const struct of_device_id ili210x_dt_ids[] = {
49588917 446 { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X },
eb91ecc9 447 { .compatible = "ilitek,ili2117", .data = (void *)MODEL_ILI211X },
49588917 448 { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X },
c5d0e4b5
MV
449 { },
450};
451MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
452
5c6a7a62
OS
453static struct i2c_driver ili210x_ts_driver = {
454 .driver = {
455 .name = "ili210x_i2c",
5c6a7a62 456 .pm = &ili210x_i2c_pm,
c5d0e4b5 457 .of_match_table = ili210x_dt_ids,
5c6a7a62
OS
458 },
459 .id_table = ili210x_i2c_id,
460 .probe = ili210x_i2c_probe,
5c6a7a62
OS
461};
462
463module_i2c_driver(ili210x_ts_driver);
464
465MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
466MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
467MODULE_LICENSE("GPL");