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