.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Atmel maXTouch Touchscreen driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Copyright (C) 2016 Zodiac Inflight Innovations |
---|
8 | 9 | * |
---|
9 | 10 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or modify it |
---|
12 | | - * under the terms of the GNU General Public License as published by the |
---|
13 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
14 | | - * option) any later version. |
---|
15 | | - * |
---|
16 | 11 | */ |
---|
17 | 12 | |
---|
18 | 13 | #include <linux/acpi.h> |
---|
.. | .. |
---|
25 | 20 | #include <linux/i2c.h> |
---|
26 | 21 | #include <linux/input/mt.h> |
---|
27 | 22 | #include <linux/interrupt.h> |
---|
| 23 | +#include <linux/irq.h> |
---|
28 | 24 | #include <linux/of.h> |
---|
29 | 25 | #include <linux/property.h> |
---|
30 | 26 | #include <linux/slab.h> |
---|
31 | 27 | #include <linux/gpio/consumer.h> |
---|
32 | | -#include <linux/property.h> |
---|
33 | 28 | #include <asm/unaligned.h> |
---|
34 | 29 | #include <media/v4l2-device.h> |
---|
35 | 30 | #include <media/v4l2-ioctl.h> |
---|
.. | .. |
---|
135 | 130 | /* MXT_SPT_COMMSCONFIG_T18 */ |
---|
136 | 131 | #define MXT_COMMS_CTRL 0 |
---|
137 | 132 | #define MXT_COMMS_CMD 1 |
---|
| 133 | +#define MXT_COMMS_RETRIGEN BIT(6) |
---|
138 | 134 | |
---|
139 | 135 | /* MXT_DEBUG_DIAGNOSTIC_T37 */ |
---|
140 | 136 | #define MXT_DIAGNOSTIC_PAGEUP 0x01 |
---|
.. | .. |
---|
262 | 258 | MXT_V4L_INPUT_MAX, |
---|
263 | 259 | }; |
---|
264 | 260 | |
---|
265 | | -static const struct v4l2_file_operations mxt_video_fops = { |
---|
266 | | - .owner = THIS_MODULE, |
---|
267 | | - .open = v4l2_fh_open, |
---|
268 | | - .release = vb2_fop_release, |
---|
269 | | - .unlocked_ioctl = video_ioctl2, |
---|
270 | | - .read = vb2_fop_read, |
---|
271 | | - .mmap = vb2_fop_mmap, |
---|
272 | | - .poll = vb2_fop_poll, |
---|
273 | | -}; |
---|
274 | | - |
---|
275 | 261 | enum mxt_suspend_mode { |
---|
276 | 262 | MXT_SUSPEND_DEEP_SLEEP = 0, |
---|
277 | 263 | MXT_SUSPEND_T9_CTRL = 1, |
---|
.. | .. |
---|
324 | 310 | struct t7_config t7_cfg; |
---|
325 | 311 | struct mxt_dbg dbg; |
---|
326 | 312 | struct gpio_desc *reset_gpio; |
---|
| 313 | + bool use_retrigen_workaround; |
---|
327 | 314 | |
---|
328 | 315 | /* Cached parameters from object table */ |
---|
329 | 316 | u16 T5_address; |
---|
.. | .. |
---|
334 | 321 | u16 T71_address; |
---|
335 | 322 | u8 T9_reportid_min; |
---|
336 | 323 | u8 T9_reportid_max; |
---|
| 324 | + u16 T18_address; |
---|
337 | 325 | u8 T19_reportid; |
---|
338 | 326 | u16 T44_address; |
---|
339 | 327 | u8 T100_reportid_min; |
---|
.. | .. |
---|
489 | 477 | bootloader = appmode - 0x24; |
---|
490 | 478 | break; |
---|
491 | 479 | } |
---|
492 | | - /* Fall through for normal case */ |
---|
| 480 | + fallthrough; /* for normal case */ |
---|
493 | 481 | case 0x4c: |
---|
494 | 482 | case 0x4d: |
---|
495 | 483 | case 0x5a: |
---|
.. | .. |
---|
838 | 826 | * have happened. |
---|
839 | 827 | */ |
---|
840 | 828 | if (status & MXT_T9_RELEASE) { |
---|
841 | | - input_mt_report_slot_state(input_dev, |
---|
842 | | - MT_TOOL_FINGER, 0); |
---|
| 829 | + input_mt_report_slot_inactive(input_dev); |
---|
843 | 830 | mxt_input_sync(data); |
---|
844 | 831 | } |
---|
845 | 832 | |
---|
.. | .. |
---|
855 | 842 | input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); |
---|
856 | 843 | } else { |
---|
857 | 844 | /* Touch no longer active, close out slot */ |
---|
858 | | - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0); |
---|
| 845 | + input_mt_report_slot_inactive(input_dev); |
---|
859 | 846 | } |
---|
860 | 847 | |
---|
861 | 848 | data->update_input = true; |
---|
.. | .. |
---|
963 | 950 | dev_dbg(dev, "[%u] release\n", id); |
---|
964 | 951 | |
---|
965 | 952 | /* close out slot */ |
---|
966 | | - input_mt_report_slot_state(input_dev, 0, 0); |
---|
| 953 | + input_mt_report_slot_inactive(input_dev); |
---|
967 | 954 | } |
---|
968 | 955 | |
---|
969 | 956 | data->update_input = true; |
---|
.. | .. |
---|
1207 | 1194 | |
---|
1208 | 1195 | enable_irq(data->irq); |
---|
1209 | 1196 | |
---|
1210 | | - error = mxt_process_messages_until_invalid(data); |
---|
1211 | | - if (error) |
---|
1212 | | - return error; |
---|
| 1197 | + if (data->use_retrigen_workaround) { |
---|
| 1198 | + error = mxt_process_messages_until_invalid(data); |
---|
| 1199 | + if (error) |
---|
| 1200 | + return error; |
---|
| 1201 | + } |
---|
1213 | 1202 | |
---|
1214 | 1203 | return 0; |
---|
1215 | 1204 | } |
---|
.. | .. |
---|
1297 | 1286 | crc &= 0x00FFFFFF; |
---|
1298 | 1287 | |
---|
1299 | 1288 | return crc; |
---|
| 1289 | +} |
---|
| 1290 | + |
---|
| 1291 | +static int mxt_check_retrigen(struct mxt_data *data) |
---|
| 1292 | +{ |
---|
| 1293 | + struct i2c_client *client = data->client; |
---|
| 1294 | + int error; |
---|
| 1295 | + int val; |
---|
| 1296 | + struct irq_data *irqd; |
---|
| 1297 | + |
---|
| 1298 | + data->use_retrigen_workaround = false; |
---|
| 1299 | + |
---|
| 1300 | + irqd = irq_get_irq_data(data->irq); |
---|
| 1301 | + if (!irqd) |
---|
| 1302 | + return -EINVAL; |
---|
| 1303 | + |
---|
| 1304 | + if (irqd_is_level_type(irqd)) |
---|
| 1305 | + return 0; |
---|
| 1306 | + |
---|
| 1307 | + if (data->T18_address) { |
---|
| 1308 | + error = __mxt_read_reg(client, |
---|
| 1309 | + data->T18_address + MXT_COMMS_CTRL, |
---|
| 1310 | + 1, &val); |
---|
| 1311 | + if (error) |
---|
| 1312 | + return error; |
---|
| 1313 | + |
---|
| 1314 | + if (val & MXT_COMMS_RETRIGEN) |
---|
| 1315 | + return 0; |
---|
| 1316 | + } |
---|
| 1317 | + |
---|
| 1318 | + dev_warn(&client->dev, "Enabling RETRIGEN workaround\n"); |
---|
| 1319 | + data->use_retrigen_workaround = true; |
---|
| 1320 | + return 0; |
---|
1300 | 1321 | } |
---|
1301 | 1322 | |
---|
1302 | 1323 | static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) |
---|
.. | .. |
---|
1527 | 1548 | } else if (config_crc == data->config_crc) { |
---|
1528 | 1549 | dev_dbg(dev, "Config CRC 0x%06X: OK\n", |
---|
1529 | 1550 | data->config_crc); |
---|
1530 | | - return 0; |
---|
| 1551 | + ret = 0; |
---|
| 1552 | + goto release_raw; |
---|
1531 | 1553 | } else { |
---|
1532 | 1554 | dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", |
---|
1533 | 1555 | data->config_crc, config_crc); |
---|
.. | .. |
---|
1577 | 1599 | |
---|
1578 | 1600 | mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); |
---|
1579 | 1601 | |
---|
| 1602 | + ret = mxt_check_retrigen(data); |
---|
| 1603 | + if (ret) |
---|
| 1604 | + goto release_mem; |
---|
| 1605 | + |
---|
1580 | 1606 | ret = mxt_soft_reset(data); |
---|
1581 | 1607 | if (ret) |
---|
1582 | 1608 | goto release_mem; |
---|
.. | .. |
---|
1620 | 1646 | data->T71_address = 0; |
---|
1621 | 1647 | data->T9_reportid_min = 0; |
---|
1622 | 1648 | data->T9_reportid_max = 0; |
---|
| 1649 | + data->T18_address = 0; |
---|
1623 | 1650 | data->T19_reportid = 0; |
---|
1624 | 1651 | data->T44_address = 0; |
---|
1625 | 1652 | data->T100_reportid_min = 0; |
---|
.. | .. |
---|
1693 | 1720 | data->T9_reportid_max = min_id + |
---|
1694 | 1721 | object->num_report_ids - 1; |
---|
1695 | 1722 | data->num_touchids = object->num_report_ids; |
---|
| 1723 | + break; |
---|
| 1724 | + case MXT_SPT_COMMSCONFIG_T18: |
---|
| 1725 | + data->T18_address = object->start_address; |
---|
1696 | 1726 | break; |
---|
1697 | 1727 | case MXT_SPT_MESSAGECOUNT_T44: |
---|
1698 | 1728 | data->T44_address = object->start_address; |
---|
.. | .. |
---|
2153 | 2183 | msleep(MXT_FW_RESET_TIME); |
---|
2154 | 2184 | } |
---|
2155 | 2185 | |
---|
| 2186 | + error = mxt_check_retrigen(data); |
---|
| 2187 | + if (error) |
---|
| 2188 | + return error; |
---|
| 2189 | + |
---|
2156 | 2190 | error = mxt_acquire_irq(data); |
---|
2157 | 2191 | if (error) |
---|
2158 | 2192 | return error; |
---|
.. | .. |
---|
2224 | 2258 | } |
---|
2225 | 2259 | |
---|
2226 | 2260 | #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 |
---|
| 2261 | +static const struct v4l2_file_operations mxt_video_fops = { |
---|
| 2262 | + .owner = THIS_MODULE, |
---|
| 2263 | + .open = v4l2_fh_open, |
---|
| 2264 | + .release = vb2_fop_release, |
---|
| 2265 | + .unlocked_ioctl = video_ioctl2, |
---|
| 2266 | + .read = vb2_fop_read, |
---|
| 2267 | + .mmap = vb2_fop_mmap, |
---|
| 2268 | + .poll = vb2_fop_poll, |
---|
| 2269 | +}; |
---|
| 2270 | + |
---|
2227 | 2271 | static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, |
---|
2228 | 2272 | unsigned int y) |
---|
2229 | 2273 | { |
---|
.. | .. |
---|
2995 | 3039 | int error; |
---|
2996 | 3040 | |
---|
2997 | 3041 | if (device_property_present(dev, keymap_property)) { |
---|
2998 | | - n_keys = device_property_read_u32_array(dev, keymap_property, |
---|
2999 | | - NULL, 0); |
---|
| 3042 | + n_keys = device_property_count_u32(dev, keymap_property); |
---|
3000 | 3043 | if (n_keys <= 0) { |
---|
3001 | 3044 | error = n_keys < 0 ? n_keys : -EINVAL; |
---|
3002 | 3045 | dev_err(dev, "invalid/malformed '%s' property: %d\n", |
---|
.. | .. |
---|
3091 | 3134 | if (error) |
---|
3092 | 3135 | return error; |
---|
3093 | 3136 | |
---|
| 3137 | + /* Request the RESET line as asserted so we go into reset */ |
---|
3094 | 3138 | data->reset_gpio = devm_gpiod_get_optional(&client->dev, |
---|
3095 | | - "reset", GPIOD_OUT_LOW); |
---|
| 3139 | + "reset", GPIOD_OUT_HIGH); |
---|
3096 | 3140 | if (IS_ERR(data->reset_gpio)) { |
---|
3097 | 3141 | error = PTR_ERR(data->reset_gpio); |
---|
3098 | 3142 | dev_err(&client->dev, "Failed to get reset gpio: %d\n", error); |
---|
.. | .. |
---|
3110 | 3154 | disable_irq(client->irq); |
---|
3111 | 3155 | |
---|
3112 | 3156 | if (data->reset_gpio) { |
---|
| 3157 | + /* Wait a while and then de-assert the RESET GPIO line */ |
---|
3113 | 3158 | msleep(MXT_RESET_GPIO_TIME); |
---|
3114 | | - gpiod_set_value(data->reset_gpio, 1); |
---|
| 3159 | + gpiod_set_value(data->reset_gpio, 0); |
---|
3115 | 3160 | msleep(MXT_RESET_INVALID_CHG); |
---|
3116 | 3161 | } |
---|
3117 | 3162 | |
---|