Commit | Line | Data |
---|---|---|
e7330fa0 HG |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Driver for ChipOne icn8505 i2c touchscreen controller | |
4 | * | |
5 | * Copyright (c) 2015-2018 Red Hat Inc. | |
6 | * | |
7 | * Red Hat authors: | |
8 | * Hans de Goede <hdegoede@redhat.com> | |
9 | */ | |
10 | ||
11 | #include <asm/unaligned.h> | |
12 | #include <linux/acpi.h> | |
13 | #include <linux/crc32.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/firmware.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/i2c.h> | |
18 | #include <linux/input.h> | |
19 | #include <linux/input/mt.h> | |
20 | #include <linux/input/touchscreen.h> | |
21 | #include <linux/module.h> | |
22 | ||
23 | /* Normal operation mode defines */ | |
24 | #define ICN8505_REG_ADDR_WIDTH 16 | |
25 | ||
26 | #define ICN8505_REG_POWER 0x0004 | |
27 | #define ICN8505_REG_TOUCHDATA 0x1000 | |
28 | #define ICN8505_REG_CONFIGDATA 0x8000 | |
29 | ||
30 | /* ICN8505_REG_POWER commands */ | |
31 | #define ICN8505_POWER_ACTIVE 0x00 | |
32 | #define ICN8505_POWER_MONITOR 0x01 | |
33 | #define ICN8505_POWER_HIBERNATE 0x02 | |
34 | /* | |
35 | * The Android driver uses these to turn on/off the charger filter, but the | |
36 | * filter is way too aggressive making e.g. onscreen keyboards unusable. | |
37 | */ | |
38 | #define ICN8505_POWER_ENA_CHARGER_MODE 0x55 | |
39 | #define ICN8505_POWER_DIS_CHARGER_MODE 0x66 | |
40 | ||
41 | #define ICN8505_MAX_TOUCHES 10 | |
42 | ||
43 | /* Programming mode defines */ | |
44 | #define ICN8505_PROG_I2C_ADDR 0x30 | |
45 | #define ICN8505_PROG_REG_ADDR_WIDTH 24 | |
46 | ||
47 | #define MAX_FW_UPLOAD_TRIES 3 | |
48 | ||
49 | struct icn8505_touch { | |
50 | u8 slot; | |
51 | u8 x[2]; | |
52 | u8 y[2]; | |
53 | u8 pressure; /* Seems more like finger width then pressure really */ | |
54 | u8 event; | |
55 | /* The difference between 2 and 3 is unclear */ | |
56 | #define ICN8505_EVENT_NO_DATA 1 /* No finger seen yet since wakeup */ | |
57 | #define ICN8505_EVENT_UPDATE1 2 /* New or updated coordinates */ | |
58 | #define ICN8505_EVENT_UPDATE2 3 /* New or updated coordinates */ | |
59 | #define ICN8505_EVENT_END 4 /* Finger lifted */ | |
60 | } __packed; | |
61 | ||
62 | struct icn8505_touch_data { | |
63 | u8 softbutton; | |
64 | u8 touch_count; | |
65 | struct icn8505_touch touches[ICN8505_MAX_TOUCHES]; | |
66 | } __packed; | |
67 | ||
68 | struct icn8505_data { | |
69 | struct i2c_client *client; | |
70 | struct input_dev *input; | |
e7330fa0 HG |
71 | struct touchscreen_properties prop; |
72 | char firmware_name[32]; | |
73 | }; | |
74 | ||
75 | static int icn8505_read_xfer(struct i2c_client *client, u16 i2c_addr, | |
76 | int reg_addr, int reg_addr_width, | |
77 | void *data, int len, bool silent) | |
78 | { | |
79 | u8 buf[3]; | |
80 | int i, ret; | |
81 | struct i2c_msg msg[2] = { | |
82 | { | |
83 | .addr = i2c_addr, | |
84 | .buf = buf, | |
85 | .len = reg_addr_width / 8, | |
86 | }, | |
87 | { | |
88 | .addr = i2c_addr, | |
89 | .flags = I2C_M_RD, | |
90 | .buf = data, | |
91 | .len = len, | |
92 | } | |
93 | }; | |
94 | ||
95 | for (i = 0; i < (reg_addr_width / 8); i++) | |
96 | buf[i] = (reg_addr >> (reg_addr_width - (i + 1) * 8)) & 0xff; | |
97 | ||
98 | ret = i2c_transfer(client->adapter, msg, 2); | |
99 | if (ret != ARRAY_SIZE(msg)) { | |
100 | if (ret >= 0) | |
101 | ret = -EIO; | |
102 | if (!silent) | |
103 | dev_err(&client->dev, | |
104 | "Error reading addr %#x reg %#x: %d\n", | |
105 | i2c_addr, reg_addr, ret); | |
106 | return ret; | |
107 | } | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | static int icn8505_write_xfer(struct i2c_client *client, u16 i2c_addr, | |
113 | int reg_addr, int reg_addr_width, | |
114 | const void *data, int len, bool silent) | |
115 | { | |
116 | u8 buf[3 + 32]; /* 3 bytes for 24 bit reg-addr + 32 bytes max len */ | |
117 | int i, ret; | |
118 | struct i2c_msg msg = { | |
119 | .addr = i2c_addr, | |
120 | .buf = buf, | |
121 | .len = reg_addr_width / 8 + len, | |
122 | }; | |
123 | ||
124 | if (WARN_ON(len > 32)) | |
125 | return -EINVAL; | |
126 | ||
127 | for (i = 0; i < (reg_addr_width / 8); i++) | |
128 | buf[i] = (reg_addr >> (reg_addr_width - (i + 1) * 8)) & 0xff; | |
129 | ||
130 | memcpy(buf + reg_addr_width / 8, data, len); | |
131 | ||
132 | ret = i2c_transfer(client->adapter, &msg, 1); | |
133 | if (ret != 1) { | |
134 | if (ret >= 0) | |
135 | ret = -EIO; | |
136 | if (!silent) | |
137 | dev_err(&client->dev, | |
138 | "Error writing addr %#x reg %#x: %d\n", | |
139 | i2c_addr, reg_addr, ret); | |
140 | return ret; | |
141 | } | |
142 | ||
143 | return 0; | |
144 | } | |
145 | ||
146 | static int icn8505_read_data(struct icn8505_data *icn8505, int reg, | |
147 | void *buf, int len) | |
148 | { | |
149 | return icn8505_read_xfer(icn8505->client, icn8505->client->addr, reg, | |
150 | ICN8505_REG_ADDR_WIDTH, buf, len, false); | |
151 | } | |
152 | ||
153 | static int icn8505_read_reg_silent(struct icn8505_data *icn8505, int reg) | |
154 | { | |
155 | u8 buf; | |
156 | int error; | |
157 | ||
158 | error = icn8505_read_xfer(icn8505->client, icn8505->client->addr, reg, | |
159 | ICN8505_REG_ADDR_WIDTH, &buf, 1, true); | |
160 | if (error) | |
161 | return error; | |
162 | ||
163 | return buf; | |
164 | } | |
165 | ||
166 | static int icn8505_write_reg(struct icn8505_data *icn8505, int reg, u8 val) | |
167 | { | |
168 | return icn8505_write_xfer(icn8505->client, icn8505->client->addr, reg, | |
169 | ICN8505_REG_ADDR_WIDTH, &val, 1, false); | |
170 | } | |
171 | ||
172 | static int icn8505_read_prog_data(struct icn8505_data *icn8505, int reg, | |
173 | void *buf, int len) | |
174 | { | |
175 | return icn8505_read_xfer(icn8505->client, ICN8505_PROG_I2C_ADDR, reg, | |
176 | ICN8505_PROG_REG_ADDR_WIDTH, buf, len, false); | |
177 | } | |
178 | ||
179 | static int icn8505_write_prog_data(struct icn8505_data *icn8505, int reg, | |
180 | const void *buf, int len) | |
181 | { | |
182 | return icn8505_write_xfer(icn8505->client, ICN8505_PROG_I2C_ADDR, reg, | |
183 | ICN8505_PROG_REG_ADDR_WIDTH, buf, len, false); | |
184 | } | |
185 | ||
186 | static int icn8505_write_prog_reg(struct icn8505_data *icn8505, int reg, u8 val) | |
187 | { | |
188 | return icn8505_write_xfer(icn8505->client, ICN8505_PROG_I2C_ADDR, reg, | |
189 | ICN8505_PROG_REG_ADDR_WIDTH, &val, 1, false); | |
190 | } | |
191 | ||
192 | /* | |
193 | * Note this function uses a number of magic register addresses and values, | |
194 | * there are deliberately no defines for these because the algorithm is taken | |
195 | * from the icn85xx Android driver and I do not want to make up possibly wrong | |
196 | * names for the addresses and/or values. | |
197 | */ | |
198 | static int icn8505_try_fw_upload(struct icn8505_data *icn8505, | |
199 | const struct firmware *fw) | |
200 | { | |
201 | struct device *dev = &icn8505->client->dev; | |
202 | size_t offset, count; | |
203 | int error; | |
204 | u8 buf[4]; | |
205 | u32 crc; | |
206 | ||
207 | /* Put the controller in programming mode */ | |
208 | error = icn8505_write_prog_reg(icn8505, 0xcc3355, 0x5a); | |
209 | if (error) | |
210 | return error; | |
211 | ||
212 | usleep_range(2000, 5000); | |
213 | ||
214 | error = icn8505_write_prog_reg(icn8505, 0x040400, 0x01); | |
215 | if (error) | |
216 | return error; | |
217 | ||
218 | usleep_range(2000, 5000); | |
219 | ||
220 | error = icn8505_read_prog_data(icn8505, 0x040002, buf, 1); | |
221 | if (error) | |
222 | return error; | |
223 | ||
224 | if (buf[0] != 0x85) { | |
225 | dev_err(dev, "Failed to enter programming mode\n"); | |
226 | return -ENODEV; | |
227 | } | |
228 | ||
229 | usleep_range(1000, 5000); | |
230 | ||
231 | /* Enable CRC mode */ | |
232 | error = icn8505_write_prog_reg(icn8505, 0x40028, 1); | |
233 | if (error) | |
234 | return error; | |
235 | ||
236 | /* Send the firmware to SRAM */ | |
237 | for (offset = 0; offset < fw->size; offset += count) { | |
238 | count = min_t(size_t, fw->size - offset, 32); | |
239 | error = icn8505_write_prog_data(icn8505, offset, | |
240 | fw->data + offset, count); | |
241 | if (error) | |
242 | return error; | |
243 | } | |
244 | ||
245 | /* Disable CRC mode */ | |
246 | error = icn8505_write_prog_reg(icn8505, 0x40028, 0); | |
247 | if (error) | |
248 | return error; | |
249 | ||
250 | /* Get and check length and CRC */ | |
251 | error = icn8505_read_prog_data(icn8505, 0x40034, buf, 2); | |
252 | if (error) | |
253 | return error; | |
254 | ||
255 | if (get_unaligned_le16(buf) != fw->size) { | |
256 | dev_warn(dev, "Length mismatch after uploading fw\n"); | |
257 | return -EIO; | |
258 | } | |
259 | ||
260 | error = icn8505_read_prog_data(icn8505, 0x4002c, buf, 4); | |
261 | if (error) | |
262 | return error; | |
263 | ||
264 | crc = crc32_be(0, fw->data, fw->size); | |
265 | if (get_unaligned_le32(buf) != crc) { | |
266 | dev_warn(dev, "CRC mismatch after uploading fw\n"); | |
267 | return -EIO; | |
268 | } | |
269 | ||
270 | /* Boot controller from SRAM */ | |
271 | error = icn8505_write_prog_reg(icn8505, 0x40400, 0x03); | |
272 | if (error) | |
273 | return error; | |
274 | ||
275 | usleep_range(2000, 5000); | |
276 | return 0; | |
277 | } | |
278 | ||
279 | static int icn8505_upload_fw(struct icn8505_data *icn8505) | |
280 | { | |
281 | struct device *dev = &icn8505->client->dev; | |
282 | const struct firmware *fw; | |
283 | int i, error; | |
284 | ||
285 | /* | |
286 | * Always load the firmware, even if we don't need it at boot, we | |
287 | * we may need it at resume. Having loaded it once will make the | |
288 | * firmware class code cache it at suspend/resume. | |
289 | */ | |
85bfb4af | 290 | error = firmware_request_platform(&fw, icn8505->firmware_name, dev); |
e7330fa0 HG |
291 | if (error) { |
292 | dev_err(dev, "Firmware request error %d\n", error); | |
293 | return error; | |
294 | } | |
295 | ||
296 | /* Check if the controller is not already up and running */ | |
297 | if (icn8505_read_reg_silent(icn8505, 0x000a) == 0x85) | |
298 | goto success; | |
299 | ||
300 | for (i = 1; i <= MAX_FW_UPLOAD_TRIES; i++) { | |
301 | error = icn8505_try_fw_upload(icn8505, fw); | |
302 | if (!error) | |
303 | goto success; | |
304 | ||
305 | dev_err(dev, "Failed to upload firmware: %d (attempt %d/%d)\n", | |
306 | error, i, MAX_FW_UPLOAD_TRIES); | |
307 | usleep_range(2000, 5000); | |
308 | } | |
309 | ||
310 | success: | |
311 | release_firmware(fw); | |
312 | return error; | |
313 | } | |
314 | ||
315 | static bool icn8505_touch_active(u8 event) | |
316 | { | |
317 | return event == ICN8505_EVENT_UPDATE1 || | |
318 | event == ICN8505_EVENT_UPDATE2; | |
319 | } | |
320 | ||
321 | static irqreturn_t icn8505_irq(int irq, void *dev_id) | |
322 | { | |
323 | struct icn8505_data *icn8505 = dev_id; | |
324 | struct device *dev = &icn8505->client->dev; | |
325 | struct icn8505_touch_data touch_data; | |
326 | int i, error; | |
327 | ||
328 | error = icn8505_read_data(icn8505, ICN8505_REG_TOUCHDATA, | |
329 | &touch_data, sizeof(touch_data)); | |
330 | if (error) { | |
331 | dev_err(dev, "Error reading touch data: %d\n", error); | |
332 | return IRQ_HANDLED; | |
333 | } | |
334 | ||
335 | if (touch_data.touch_count > ICN8505_MAX_TOUCHES) { | |
336 | dev_warn(dev, "Too many touches %d > %d\n", | |
337 | touch_data.touch_count, ICN8505_MAX_TOUCHES); | |
338 | touch_data.touch_count = ICN8505_MAX_TOUCHES; | |
339 | } | |
340 | ||
341 | for (i = 0; i < touch_data.touch_count; i++) { | |
342 | struct icn8505_touch *touch = &touch_data.touches[i]; | |
343 | bool act = icn8505_touch_active(touch->event); | |
344 | ||
345 | input_mt_slot(icn8505->input, touch->slot); | |
346 | input_mt_report_slot_state(icn8505->input, MT_TOOL_FINGER, act); | |
347 | if (!act) | |
348 | continue; | |
349 | ||
350 | touchscreen_report_pos(icn8505->input, &icn8505->prop, | |
351 | get_unaligned_le16(touch->x), | |
352 | get_unaligned_le16(touch->y), | |
353 | true); | |
354 | } | |
355 | ||
356 | input_mt_sync_frame(icn8505->input); | |
357 | input_report_key(icn8505->input, KEY_LEFTMETA, | |
358 | touch_data.softbutton == 1); | |
359 | input_sync(icn8505->input); | |
360 | ||
361 | return IRQ_HANDLED; | |
362 | } | |
363 | ||
364 | static int icn8505_probe_acpi(struct icn8505_data *icn8505, struct device *dev) | |
365 | { | |
600655cd AS |
366 | const char *subsys; |
367 | int error; | |
e7330fa0 | 368 | |
600655cd AS |
369 | subsys = acpi_get_subsystem_id(ACPI_HANDLE(dev)); |
370 | error = PTR_ERR_OR_ZERO(subsys); | |
371 | if (error == -ENODATA) | |
372 | subsys = "unknown"; | |
373 | else if (error) | |
374 | return error; | |
e7330fa0 HG |
375 | |
376 | snprintf(icn8505->firmware_name, sizeof(icn8505->firmware_name), | |
377 | "chipone/icn8505-%s.fw", subsys); | |
378 | ||
600655cd | 379 | kfree_const(subsys); |
e7330fa0 HG |
380 | return 0; |
381 | } | |
382 | ||
383 | static int icn8505_probe(struct i2c_client *client) | |
384 | { | |
385 | struct device *dev = &client->dev; | |
386 | struct icn8505_data *icn8505; | |
387 | struct input_dev *input; | |
388 | __le16 resolution[2]; | |
389 | int error; | |
390 | ||
391 | if (!client->irq) { | |
392 | dev_err(dev, "No irq specified\n"); | |
393 | return -EINVAL; | |
394 | } | |
395 | ||
396 | icn8505 = devm_kzalloc(dev, sizeof(*icn8505), GFP_KERNEL); | |
397 | if (!icn8505) | |
398 | return -ENOMEM; | |
399 | ||
400 | input = devm_input_allocate_device(dev); | |
401 | if (!input) | |
402 | return -ENOMEM; | |
403 | ||
404 | input->name = client->name; | |
405 | input->id.bustype = BUS_I2C; | |
406 | ||
407 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); | |
408 | input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); | |
409 | input_set_capability(input, EV_KEY, KEY_LEFTMETA); | |
410 | ||
411 | icn8505->client = client; | |
412 | icn8505->input = input; | |
413 | input_set_drvdata(input, icn8505); | |
414 | ||
415 | error = icn8505_probe_acpi(icn8505, dev); | |
416 | if (error) | |
417 | return error; | |
418 | ||
419 | error = icn8505_upload_fw(icn8505); | |
420 | if (error) | |
421 | return error; | |
422 | ||
423 | error = icn8505_read_data(icn8505, ICN8505_REG_CONFIGDATA, | |
424 | resolution, sizeof(resolution)); | |
425 | if (error) { | |
426 | dev_err(dev, "Error reading resolution: %d\n", error); | |
427 | return error; | |
428 | } | |
429 | ||
430 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, | |
431 | le16_to_cpu(resolution[0]) - 1, 0, 0); | |
432 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, | |
433 | le16_to_cpu(resolution[1]) - 1, 0, 0); | |
434 | ||
435 | touchscreen_parse_properties(input, true, &icn8505->prop); | |
436 | if (!input_abs_get_max(input, ABS_MT_POSITION_X) || | |
437 | !input_abs_get_max(input, ABS_MT_POSITION_Y)) { | |
438 | dev_err(dev, "Error touchscreen-size-x and/or -y missing\n"); | |
439 | return -EINVAL; | |
440 | } | |
441 | ||
442 | error = input_mt_init_slots(input, ICN8505_MAX_TOUCHES, | |
443 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); | |
444 | if (error) | |
445 | return error; | |
446 | ||
447 | error = devm_request_threaded_irq(dev, client->irq, NULL, icn8505_irq, | |
448 | IRQF_ONESHOT, client->name, icn8505); | |
449 | if (error) { | |
450 | dev_err(dev, "Error requesting irq: %d\n", error); | |
451 | return error; | |
452 | } | |
453 | ||
454 | error = input_register_device(input); | |
455 | if (error) | |
456 | return error; | |
457 | ||
458 | i2c_set_clientdata(client, icn8505); | |
459 | return 0; | |
460 | } | |
461 | ||
99e93cc9 | 462 | static int icn8505_suspend(struct device *dev) |
e7330fa0 HG |
463 | { |
464 | struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev)); | |
465 | ||
466 | disable_irq(icn8505->client->irq); | |
467 | ||
468 | icn8505_write_reg(icn8505, ICN8505_REG_POWER, ICN8505_POWER_HIBERNATE); | |
469 | ||
470 | return 0; | |
471 | } | |
472 | ||
99e93cc9 | 473 | static int icn8505_resume(struct device *dev) |
e7330fa0 HG |
474 | { |
475 | struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev)); | |
476 | int error; | |
477 | ||
478 | error = icn8505_upload_fw(icn8505); | |
479 | if (error) | |
480 | return error; | |
481 | ||
482 | enable_irq(icn8505->client->irq); | |
483 | return 0; | |
484 | } | |
485 | ||
99e93cc9 | 486 | static DEFINE_SIMPLE_DEV_PM_OPS(icn8505_pm_ops, icn8505_suspend, icn8505_resume); |
e7330fa0 HG |
487 | |
488 | static const struct acpi_device_id icn8505_acpi_match[] = { | |
489 | { "CHPN0001" }, | |
490 | { } | |
491 | }; | |
492 | MODULE_DEVICE_TABLE(acpi, icn8505_acpi_match); | |
493 | ||
494 | static struct i2c_driver icn8505_driver = { | |
495 | .driver = { | |
496 | .name = "chipone_icn8505", | |
99e93cc9 | 497 | .pm = pm_sleep_ptr(&icn8505_pm_ops), |
e7330fa0 HG |
498 | .acpi_match_table = icn8505_acpi_match, |
499 | }, | |
d8bde56d | 500 | .probe = icn8505_probe, |
e7330fa0 HG |
501 | }; |
502 | ||
503 | module_i2c_driver(icn8505_driver); | |
504 | ||
505 | MODULE_DESCRIPTION("ChipOne icn8505 I2C Touchscreen Driver"); | |
506 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | |
507 | MODULE_LICENSE("GPL"); |