diff options
author | Wendly Li <wendlyli@google.com> | 2023-03-22 07:15:39 +0000 |
---|---|---|
committer | Wendly Li <wendlyli@google.com> | 2023-03-22 07:16:37 +0000 |
commit | e42dc675eb1ebb1cf0e67653ca604743a51cb7e7 (patch) | |
tree | a0b3744d29fb992a9e708a89d14aff7065792ac5 | |
parent | f6f8d947b220e094ea67d3ecda81762a86403851 (diff) | |
parent | caacac38ecf3a00b7715817444a6cc490867413f (diff) | |
download | common-e42dc675eb1ebb1cf0e67653ca604743a51cb7e7.tar.gz |
Merge android14-gs-pixel-5.15 into android13-gs-pixel-5.10-udc
Change-Id: I7d71ff1eb648b32d7b68e54f8c52111e8662185a
Signed-off-by: Wendly Li <wendlyli@google.com>
-rw-r--r-- | BUILD.bazel | 43 | ||||
-rw-r--r-- | Kconfig | 8 | ||||
-rw-r--r-- | goog_touch_interface.c | 973 | ||||
-rw-r--r-- | goog_touch_interface.h | 110 | ||||
-rw-r--r-- | include/uapi/input/touch_offload.h | 8 | ||||
-rw-r--r-- | touch_bus_negotiator.c | 258 | ||||
-rw-r--r-- | touch_bus_negotiator.h | 39 | ||||
-rw-r--r-- | touch_offload.c | 6 |
8 files changed, 939 insertions, 506 deletions
diff --git a/BUILD.bazel b/BUILD.bazel index bdbe919..295e884 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,12 +1,6 @@ -# NOTE: THIS FILE IS EXPERIMENTAL FOR THE BAZEL MIGRATION AND NOT USED FOR -# YOUR BUILDS CURRENTLY. -# -# It is not yet the source of truth for your build. If you're looking to modify -# the build file, modify the Android.bp file instead. Do *not* modify this file -# unless you have coordinated with the team managing the Soong to Bazel -# migration. +# SPDX-License-Identifier: GPL-2.0-or-later -load("//build/kleaf:kernel.bzl", "kernel_module") +load("//build/kernel/kleaf:kernel.bzl", "kernel_module") filegroup( name = "headers", @@ -18,16 +12,43 @@ filegroup( ], ) +filegroup( + name = "touch.common.kconfig", + srcs = glob([ + "Kconfig", + ]), + visibility = [ + "//private/devices/google:__subpackages__", + "//private/google-modules/soc/gs:__pkg__", + ], +) + kernel_module( - name = "common.cloudripper", + name = "touch.common", + srcs = glob([ + "**/*.c", + "**/*.h", + "Kbuild", + ]) + [ + "//private/google-modules/aoc:headers", + "//private/google-modules/soc/gs:gs_soc_headers", + "//private/google-modules/display:headers", + "//private/google-modules/display/include:headers", + ], outs = [ + "goog_touch_interface.ko", "heatmap.ko", "touch_bus_negotiator.ko", "touch_offload.ko", ], - kernel_build = "//private/gs-google:cloudripper", + kernel_build = "//private/google-modules/soc/gs:gs_kernel_build", visibility = [ + "//private/devices/google:__subpackages__", + "//private/google-modules/soc/gs:__pkg__", "//private/google-modules/touch:__subpackages__", - "//private/gs-google:__pkg__", + ], + deps = [ + "//private/google-modules/aoc", + "//private/google-modules/soc/gs:gs_soc_module", ], ) @@ -20,6 +20,14 @@ config TOUCHSCREEN_TBN To compile this driver as a module, choose M here: the module will be called touch_bus_negotiator. +config TOUCHSCREEN_TBN_AOC_CHANNEL_MODE + bool "AOC channel mode for TBN" + depends on TOUCHSCREEN_TBN + help + Say Y here if you want to enable AOC channel mode for TBN. + + If unsure, say N. + config TOUCHSCREEN_OFFLOAD tristate "Touchscreen algorithm offload" depends on (TOUCHSCREEN_FTS || TOUCHSCREEN_SEC_TS) diff --git a/goog_touch_interface.c b/goog_touch_interface.c index a996756..e39ae5b 100644 --- a/goog_touch_interface.c +++ b/goog_touch_interface.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/input/mt.h> #include <linux/of.h> +#include <linux/power_supply.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <samsung/exynos_drm_connector.h> @@ -23,6 +24,7 @@ static u8 gti_dev_num; * GTI/common: forward declarations, structures and functions. */ static void goog_offload_set_running(struct goog_touch_interface *gti, bool running); +static void goog_lookup_touch_report_rate(struct goog_touch_interface *gti); static int goog_precheck_heatmap(struct goog_touch_interface *gti); static void goog_set_display_state(struct goog_touch_interface *gti, enum gti_display_state_setting display_state); @@ -325,6 +327,10 @@ static ssize_t force_active_show( struct device *dev, struct device_attribute *attr, char *buf); static ssize_t force_active_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t fw_coord_filter_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fw_coord_filter_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); static ssize_t fw_grip_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t fw_grip_store(struct device *dev, @@ -343,12 +349,6 @@ static ssize_t mf_mode_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t mf_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); -static ssize_t ms_base_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ms_diff_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ms_raw_show(struct device *dev, - struct device_attribute *attr, char *buf); static ssize_t offload_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t offload_enabled_store(struct device *dev, @@ -369,12 +369,6 @@ static ssize_t screen_protector_mode_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t self_test_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t ss_base_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ss_diff_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ss_raw_show(struct device *dev, - struct device_attribute *attr, char *buf); static ssize_t sensing_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t sensing_enabled_store(struct device *dev, @@ -383,49 +377,45 @@ static ssize_t v4l2_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t v4l2_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t vrr_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t vrr_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); static DEVICE_ATTR_RW(force_active); +static DEVICE_ATTR_RW(fw_coord_filter); static DEVICE_ATTR_RW(fw_grip); static DEVICE_ATTR_RW(fw_palm); static DEVICE_ATTR_RO(fw_ver); static DEVICE_ATTR_RW(irq_enabled); static DEVICE_ATTR_RW(mf_mode); -static DEVICE_ATTR_RO(ms_base); -static DEVICE_ATTR_RO(ms_diff); -static DEVICE_ATTR_RO(ms_raw); static DEVICE_ATTR_RW(offload_enabled); static DEVICE_ATTR_RO(ping); static DEVICE_ATTR_RW(reset); static DEVICE_ATTR_RW(scan_mode); static DEVICE_ATTR_RW(screen_protector_mode_enabled); static DEVICE_ATTR_RO(self_test); -static DEVICE_ATTR_RO(ss_base); -static DEVICE_ATTR_RO(ss_diff); -static DEVICE_ATTR_RO(ss_raw); static DEVICE_ATTR_RW(sensing_enabled); static DEVICE_ATTR_RW(v4l2_enabled); +static DEVICE_ATTR_RW(vrr_enabled); static struct attribute *goog_attributes[] = { &dev_attr_force_active.attr, + &dev_attr_fw_coord_filter.attr, &dev_attr_fw_grip.attr, &dev_attr_fw_palm.attr, &dev_attr_fw_ver.attr, &dev_attr_irq_enabled.attr, &dev_attr_mf_mode.attr, - &dev_attr_ms_base.attr, - &dev_attr_ms_diff.attr, - &dev_attr_ms_raw.attr, &dev_attr_offload_enabled.attr, &dev_attr_ping.attr, &dev_attr_reset.attr, &dev_attr_scan_mode.attr, &dev_attr_screen_protector_mode_enabled.attr, &dev_attr_self_test.attr, - &dev_attr_ss_base.attr, - &dev_attr_ss_diff.attr, - &dev_attr_ss_raw.attr, &dev_attr_sensing_enabled.attr, &dev_attr_v4l2_enabled.attr, + &dev_attr_vrr_enabled.attr, NULL, }; @@ -496,6 +486,70 @@ static ssize_t force_active_store(struct device *dev, return size; } +static ssize_t fw_coord_filter_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + ssize_t buf_idx = 0; + struct goog_touch_interface *gti = dev_get_drvdata(dev); + struct gti_coord_filter_cmd *cmd = >i->cmd.coord_filter_cmd; + + if (!gti->coord_filter_enabled) { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "error: not supported!\n"); + GOOG_INFO(gti, "%s", buf); + return buf_idx; + } + + cmd->setting = GTI_COORD_FILTER_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_COORD_FILTER_ENABLED); + if (ret == -EOPNOTSUPP) { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "error: not supported!\n"); + } else if (ret) { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "error: %d!\n", ret); + } else { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %u\n", cmd->setting | (gti->ignore_coord_filter_update << 1)); + } + GOOG_INFO(gti, "%s", buf); + + return buf_idx; +} + +static ssize_t fw_coord_filter_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret = 0; + struct goog_touch_interface *gti = dev_get_drvdata(dev); + int fw_coord_filter; + + if (kstrtou32(buf, 10, &fw_coord_filter)) { + GOOG_INFO(gti, "error: invalid input!\n"); + return -EINVAL; + } + + if (!gti->coord_filter_enabled) { + GOOG_INFO(gti, "error: not supported!\n"); + return -EOPNOTSUPP; + } + + gti->fw_coord_filter_enabled = fw_coord_filter & 0x01; + gti->ignore_coord_filter_update = (fw_coord_filter >> 1) & 0x01; + gti->cmd.coord_filter_cmd.setting = gti->fw_coord_filter_enabled ? + GTI_COORD_FILTER_ENABLE : GTI_COORD_FILTER_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_COORD_FILTER_ENABLED); + if (ret == -EOPNOTSUPP) + GOOG_INFO(gti, "error: not supported!\n"); + else if (ret) + GOOG_INFO(gti, "error: %d!\n", ret); + else + GOOG_INFO(gti, "fw_coord_filter= %u\n", fw_coord_filter); + + return size; +} + static ssize_t fw_grip_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -713,171 +767,6 @@ static ssize_t mf_mode_store(struct device *dev, return size; } -static ssize_t ms_base_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - ret = goog_precheck_heatmap(gti); - if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "result: N/A!\n"); - return buf_idx; - } - - ret = mutex_lock_interruptible(>i->input_process_lock); - if (ret != 0) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: has been interrupted!\n"); - return buf_idx; - } - - cmd->type = GTI_SENSOR_DATA_TYPE_MS_BASELINE; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: %d!\n", ret); - } else { - u8 width = GTI_SENSOR_2D_OUT_FORMAT_WIDTH(cmd->size); - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result:\n"); - if (cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - for (y = 0; y < rx; y++) { - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%*d,", width, ((s16 *)cmd->buffer)[y * tx + x]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\n"); - } - GOOG_INFO(gti, "%s", buf); - } - } - - mutex_unlock(>i->input_process_lock); - return buf_idx; -} - -static ssize_t ms_diff_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - ret = goog_precheck_heatmap(gti); - if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "result: N/A!\n"); - return buf_idx; - } - - ret = mutex_lock_interruptible(>i->input_process_lock); - if (ret != 0) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: has been interrupted!\n"); - return buf_idx; - } - - cmd->type = GTI_SENSOR_DATA_TYPE_MS_DIFF; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: %d!\n", ret); - } else { - u8 width = GTI_SENSOR_2D_OUT_FORMAT_WIDTH(cmd->size); - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result:\n"); - if (cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - for (y = 0; y < rx; y++) { - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%*d,", width, ((s16 *)cmd->buffer)[y * tx + x]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\n"); - } - GOOG_INFO(gti, "%s", buf); - } - } - - mutex_unlock(>i->input_process_lock); - return buf_idx; -} - -static ssize_t ms_raw_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - ret = goog_precheck_heatmap(gti); - if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "result: N/A!\n"); - return buf_idx; - } - - ret = mutex_lock_interruptible(>i->input_process_lock); - if (ret != 0) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: has been interrupted!\n"); - return buf_idx; - } - - cmd->type = GTI_SENSOR_DATA_TYPE_MS_RAW; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: %d!\n", ret); - } else { - u8 width = GTI_SENSOR_2D_OUT_FORMAT_WIDTH(cmd->size); - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result:\n"); - if (cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - for (y = 0; y < rx; y++) { - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%*d,", width, ((s16 *)cmd->buffer)[y * tx + x]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\n"); - } - GOOG_INFO(gti, "%s", buf); - } - } - - mutex_unlock(>i->input_process_lock); - return buf_idx; -} - static ssize_t offload_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1129,183 +1018,6 @@ static ssize_t self_test_show(struct device *dev, return buf_idx; } -static ssize_t ss_base_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - ret = goog_precheck_heatmap(gti); - if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "result: N/A!\n"); - return buf_idx; - } - - ret = mutex_lock_interruptible(>i->input_process_lock); - if (ret != 0) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: has been interrupted!\n"); - return buf_idx; - } - - cmd->type = GTI_SENSOR_DATA_TYPE_SS_BASELINE; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result:\n"); - if (cmd->buffer && - cmd->size == TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx)) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "TX:"); - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%5d,", ((s16 *)cmd->buffer)[x]); - } - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\nRX:"); - for (y = 0; y < rx; y++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%5d,", ((s16 *)cmd->buffer)[tx + y]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\n"); - GOOG_INFO(gti, "%s", buf); - } - } - - mutex_unlock(>i->input_process_lock); - return buf_idx; -} - -static ssize_t ss_diff_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - ret = goog_precheck_heatmap(gti); - if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "result: N/A!\n"); - return buf_idx; - } - - ret = mutex_lock_interruptible(>i->input_process_lock); - if (ret != 0) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: has been interrupted!\n"); - return buf_idx; - } - - cmd->type = GTI_SENSOR_DATA_TYPE_SS_DIFF; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result:\n"); - if (cmd->buffer && - cmd->size == TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx)) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "TX:"); - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%5d,", ((s16 *)cmd->buffer)[x]); - } - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\nRX:"); - for (y = 0; y < rx; y++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%5d,", ((s16 *)cmd->buffer)[tx + y]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\n"); - GOOG_INFO(gti, "%s", buf); - } - } - - mutex_unlock(>i->input_process_lock); - return buf_idx; -} - -static ssize_t ss_raw_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - ret = goog_precheck_heatmap(gti); - if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "result: N/A!\n"); - return buf_idx; - } - - ret = mutex_lock_interruptible(>i->input_process_lock); - if (ret != 0) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: has been interrupted!\n"); - return buf_idx; - } - - cmd->type = GTI_SENSOR_DATA_TYPE_SS_RAW; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result:\n"); - if (cmd->buffer && - cmd->size == TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx)) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "TX:"); - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%5d,", ((s16 *)cmd->buffer)[x]); - } - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\nRX:"); - for (y = 0; y < rx; y++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, - "%5d,", ((s16 *)cmd->buffer)[tx + y]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "\n"); - GOOG_INFO(gti, "%s", buf); - } - } - - mutex_unlock(>i->input_process_lock); - return buf_idx; -} - static ssize_t sensing_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1380,6 +1092,37 @@ static ssize_t v4l2_enabled_store(struct device *dev, return size; } +static ssize_t vrr_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t buf_idx = 0; + struct goog_touch_interface *gti = dev_get_drvdata(dev); + + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + "result: %d\n", gti->vrr_enabled); + GOOG_INFO(gti, "%s", buf); + + return buf_idx; +} + +static ssize_t vrr_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct goog_touch_interface *gti = dev_get_drvdata(dev); + + if (kstrtobool(buf, >i->vrr_enabled)) { + GOOG_INFO(gti, "error: invalid input!\n"); + } else if (gti->report_rate_table_size == 0) { + GOOG_INFO(gti, "error: No valid report rate table!\n"); + } else { + GOOG_INFO(gti, "vrr_enabled= %d\n", gti->vrr_enabled); + if (gti->vrr_enabled) + goog_lookup_touch_report_rate(gti); + } + + return size; +} + /*----------------------------------------------------------------------------- * Debug: functions. */ @@ -1479,6 +1222,7 @@ inline int gti_debug_input_pop(struct goog_touch_interface *gti, GOOG_ERR(gti, "invalid fifo pop len(%d)!\n", len); return -EINVAL; } + /* * Keep coords without pop-out to support different timing * print-out by each caller. @@ -1655,9 +1399,9 @@ static void panel_bridge_mode_set(struct drm_bridge *bridge, panel_is_lp_mode = panel_bridge_is_lp_mode(gti->connector); if (gti->panel_is_lp_mode != panel_is_lp_mode) { - GOOG_INFO(gti, "panel_is_lp_mode changed from %d to %d.\n", gti->panel_is_lp_mode, panel_is_lp_mode); + if (panel_is_lp_mode) goog_set_display_state(gti, GTI_DISPLAY_STATE_OFF); else @@ -1673,9 +1417,13 @@ static void panel_bridge_mode_set(struct drm_bridge *bridge, vrefresh, gti->display_vrefresh); gti->display_vrefresh = vrefresh; gti->cmd.display_vrefresh_cmd.setting = vrefresh; + gti->context_changed.display_refresh_rate = 1; ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_VREFRESH); if (ret && ret != -EOPNOTSUPP) GOOG_WARN(gti, "unexpected return(%d)!", ret); + + if (gti->vrr_enabled) + goog_lookup_touch_report_rate(gti); } } } @@ -1730,24 +1478,13 @@ static int goog_precheck_heatmap(struct goog_touch_interface *gti) { int ret = 0; - if (gti->display_state == GTI_DISPLAY_STATE_OFF) { - /* - * Ignore request on heatamp if project correlates closely with - * display for touch scanning or I/O transaction. - */ - if (gti->ignore_screenoff_heatmap) { - GOOG_WARN(gti, "N/A for screen-off!\n"); - ret = -ENODATA; - } - - /* - * Check the PM wakelock state for bus ownership before data - * request. - */ - if (!goog_pm_wake_get_locks(gti)) { - GOOG_WARN(gti, "N/A during inactive bus!\n"); - ret = -ENODATA; - } + /* + * Check the PM wakelock state and pm state for bus ownership before + * data request. + */ + if (!goog_pm_wake_get_locks(gti) || gti->pm.state == GTI_PM_SUSPEND) { + GOOG_WARN(gti, "N/A during inactive bus!\n"); + ret = -ENODATA; } return ret; @@ -1781,6 +1518,8 @@ static void goog_set_display_state(struct goog_touch_interface *gti, display_state); return; } + + gti->context_changed.screen_state = 1; gti->display_state = display_state; gti->cmd.display_state_cmd.setting = display_state; ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_STATE); @@ -1828,6 +1567,10 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type case GTI_CMD_GET_CONTEXT_STYLUS: ret = gti->options.get_context_stylus(private_data, >i->cmd.context_stylus_cmd); break; + case GTI_CMD_GET_COORD_FILTER_ENABLED: + ret = gti->options.get_coord_filter_enabled(private_data, + >i->cmd.coord_filter_cmd); + break; case GTI_CMD_GET_FW_VERSION: ret = gti->options.get_fw_version(private_data, >i->cmd.fw_version_cmd); break; @@ -1880,7 +1623,14 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type ret = gti->options.set_continuous_report(private_data, >i->cmd.continuous_report_cmd); break; + case GTI_CMD_SET_COORD_FILTER_ENABLED: + ret = gti->options.set_coord_filter_enabled(private_data, + >i->cmd.coord_filter_cmd); + break; case GTI_CMD_SET_GRIP_MODE: + GOOG_INFO(gti, "Set firmware grip %s", + gti->cmd.grip_cmd.setting == GTI_GRIP_ENABLE ? + "enabled" : "disabled"); ret = gti->options.set_grip_mode(private_data, >i->cmd.grip_cmd); break; case GTI_CMD_SET_HEATMAP_ENABLED: @@ -1890,13 +1640,25 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type ret = gti->options.set_irq_mode(private_data, >i->cmd.irq_cmd); break; case GTI_CMD_SET_PALM_MODE: + GOOG_INFO(gti, "Set firmware palm %s", + gti->cmd.palm_cmd.setting == GTI_PALM_ENABLE ? + "enabled" : "disabled"); ret = gti->options.set_palm_mode(private_data, >i->cmd.palm_cmd); break; + case GTI_CMD_SET_REPORT_RATE: + GOOG_INFO(gti, "Set touch report rate as %d Hz", gti->cmd.report_rate_cmd.setting); + ret = gti->options.set_report_rate(private_data, >i->cmd.report_rate_cmd); + break; case GTI_CMD_SET_SCAN_MODE: ret = gti->options.set_scan_mode(private_data, >i->cmd.scan_cmd); break; case GTI_CMD_SET_SCREEN_PROTECTOR_MODE: - ret = gti->options.set_screen_protector_mode(private_data, >i->cmd.screen_protector_mode_cmd); + GOOG_INFO(gti, "Set screen protector mode %s", + gti->cmd.screen_protector_mode_cmd.setting == + GTI_SCREEN_PROTECTOR_MODE_ENABLE + ? "enabled" : "disabled"); + ret = gti->options.set_screen_protector_mode(private_data, + >i->cmd.screen_protector_mode_cmd); break; case GTI_CMD_SET_SENSING_MODE: ret = gti->options.set_sensing_mode(private_data, >i->cmd.sensing_cmd); @@ -1913,6 +1675,9 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type if (ret == -EOPNOTSUPP) { GOOG_DBG(gti, "unsupported request cmd_type %#x!\n", cmd_type); ret = 0; + } else if (ret == -ESRCH) { + GOOG_WARN(gti, "No handler for cmd_type %#x!\n", cmd_type); + ret = 0; } return ret; @@ -2005,6 +1770,24 @@ void goog_v4l2_read(struct goog_touch_interface *gti, ktime_t timestamp) heatmap_read(>i->v4l2, ktime_to_ns(timestamp)); } +int goog_get_driver_status(struct goog_touch_interface *gti, + struct gti_context_driver_cmd *driver_cmd) +{ + gti->context_changed.offload_timestamp = 1; + + driver_cmd->context_changed.value = gti->context_changed.value; + driver_cmd->screen_state = gti->display_state; + driver_cmd->display_refresh_rate = gti->display_vrefresh; + driver_cmd->touch_report_rate = gti->report_rate_setting; + driver_cmd->noise_state = gti->fw_status.noise_level; + driver_cmd->water_mode = gti->fw_status.water_mode; + driver_cmd->charger_state = gti->charger_state; + driver_cmd->offload_timestamp = ktime_get(); + + /* vendor driver overwrite the context */ + return goog_process_vendor_cmd(gti, GTI_CMD_GET_CONTEXT_DRIVER); +} + void goog_offload_populate_coordinate_channel(struct goog_touch_interface *gti, struct touch_offload_frame *frame, int channel) { @@ -2084,17 +1867,25 @@ static void goog_offload_populate_driver_status_channel( ds->header.channel_type = (u32)CONTEXT_CHANNEL_TYPE_DRIVER_STATUS; ds->header.channel_size = sizeof(struct TouchOffloadDriverStatus); - ds->contents.screen_state = driver_cmd->contents.screen_state; + ds->contents.screen_state = driver_cmd->context_changed.screen_state; ds->screen_state = driver_cmd->screen_state; - ds->contents.display_refresh_rate = - driver_cmd->contents.display_refresh_rate; + ds->contents.display_refresh_rate = driver_cmd->context_changed.display_refresh_rate; ds->display_refresh_rate = driver_cmd->display_refresh_rate; - ds->contents.touch_report_rate = driver_cmd->contents.touch_report_rate; + ds->contents.touch_report_rate = driver_cmd->context_changed.touch_report_rate; ds->touch_report_rate = driver_cmd->touch_report_rate; - ds->contents.offload_timestamp = driver_cmd->contents.offload_timestamp; + ds->contents.noise_state = driver_cmd->context_changed.noise_state; + ds->noise_state = driver_cmd->noise_state; + + ds->contents.water_mode = driver_cmd->context_changed.water_mode; + ds->water_mode = driver_cmd->water_mode; + + ds->contents.charger_state = driver_cmd->context_changed.charger_state; + ds->charger_state = driver_cmd->charger_state; + + ds->contents.offload_timestamp = driver_cmd->context_changed.offload_timestamp; ds->offload_timestamp = driver_cmd->offload_timestamp; } @@ -2123,8 +1914,52 @@ static void goog_offload_populate_stylus_status_channel( ss->pen_active = stylus_cmd->pen_active; } +static int goog_get_sensor_data(struct goog_touch_interface *gti, + struct gti_sensor_data_cmd *cmd, bool reset_data) +{ + int ret = 0; + int err = 0; + u16 tx = gti->offload.caps.tx_size; + u16 rx = gti->offload.caps.rx_size; + + if (reset_data) { + if (cmd->type == GTI_SENSOR_DATA_TYPE_MS) { + cmd->size = TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx); + } else if (cmd->type == GTI_SENSOR_DATA_TYPE_SS) { + cmd->size = TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx); + } else { + ret = -EINVAL; + goto exit; + } + + memset(gti->heatmap_buf, 0, cmd->size); + cmd->buffer = gti->heatmap_buf; + goto exit; + } + + err = goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_SENSOR_DATA, true); + if (err < 0) { + GOOG_WARN(gti, "Failed to lock GTI_PM_WAKELOCK_TYPE_SENSOR_DATA: %d!\n", err); + ret = err; + goto exit; + } + + err = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + if (err < 0) { + GOOG_WARN(gti, "Failed to get sensor data: %d!\n", err); + ret = err; + } + + err = goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_SENSOR_DATA); + if (err < 0) + GOOG_WARN(gti, "Failed to unlock GTI_PM_WAKELOCK_TYPE_SENSOR_DATA: %d!\n", err); + +exit: + return ret; +} + void goog_offload_populate_frame(struct goog_touch_interface *gti, - struct touch_offload_frame *frame, bool report_from_irq) + struct touch_offload_frame *frame, bool reset_data) { static u64 index; char trace_tag[128]; @@ -2157,7 +1992,7 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, cmd->size = 0; if (channel_type == CONTEXT_CHANNEL_TYPE_DRIVER_STATUS) { ATRACE_BEGIN("populate driver context"); - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_CONTEXT_DRIVER); + ret = goog_get_driver_status(gti, >i->cmd.context_driver_cmd); if (ret == 0) goog_offload_populate_driver_status_channel( gti, frame, i, @@ -2178,14 +2013,8 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, } else if (channel_type & TOUCH_SCAN_TYPE_MUTUAL) { ATRACE_BEGIN("populate mutual data"); cmd->type = GTI_SENSOR_DATA_TYPE_MS; - if (!report_from_irq) { - cmd->size = TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx); - memset(gti->heatmap_buf, 0, cmd->size); - cmd->buffer = gti->heatmap_buf; - ret = 0; - } else { - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); - } + + ret = goog_get_sensor_data(gti, cmd, reset_data); if (ret == 0 && cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { goog_offload_populate_mutual_channel(gti, frame, i, @@ -2198,14 +2027,8 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, } else if (channel_type & TOUCH_SCAN_TYPE_SELF) { ATRACE_BEGIN("populate self data"); cmd->type = GTI_SENSOR_DATA_TYPE_SS; - if (!report_from_irq) { - cmd->size = TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx); - memset(gti->heatmap_buf, 0, cmd->size); - cmd->buffer = gti->heatmap_buf; - ret = 0; - } else { - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); - } + + ret = goog_get_sensor_data(gti, cmd, reset_data); if (ret == 0 && cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx)) { goog_offload_populate_self_channel(gti, frame, i, @@ -2228,6 +2051,8 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, void goog_update_fw_settings(struct goog_touch_interface *gti) { int ret = 0; + bool enabled = false; + if(!gti->ignore_grip_update) { if (gti->offload.offload_running && gti->offload.config.filter_grip) gti->cmd.grip_cmd.setting = GTI_GRIP_DISABLE; @@ -2248,6 +2073,23 @@ void goog_update_fw_settings(struct goog_touch_interface *gti) GOOG_WARN(gti, "unexpected return(%d)!", ret); } + if (gti->coord_filter_enabled) { + if (!gti->ignore_coord_filter_update) { + if (gti->offload.offload_running && gti->offload.config.coord_filter) + enabled = false; + else + enabled = gti->default_coord_filter_enabled; + } else { + enabled = gti->fw_coord_filter_enabled; + } + + gti->cmd.coord_filter_cmd.setting = enabled ? + GTI_COORD_FILTER_ENABLE : GTI_COORD_FILTER_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_COORD_FILTER_ENABLED); + if (ret) + GOOG_WARN(gti, "unexpected return(%d)!", ret); + } + gti->cmd.screen_protector_mode_cmd.setting = gti->screen_protector_mode_setting; ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_SCREEN_PROTECTOR_MODE); if (ret != 0) @@ -2259,12 +2101,21 @@ void goog_update_fw_settings(struct goog_touch_interface *gti) ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_HEATMAP_ENABLED); if (ret != 0) GOOG_ERR(gti, "Failed to enable heatmap!\n"); + + if (gti->vrr_enabled) { + gti->cmd.report_rate_cmd.setting = gti->report_rate_setting_next; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_REPORT_RATE); + if (ret != 0) + GOOG_ERR(gti, "Failed to set report rate!\n"); + } } static void goog_offload_set_running(struct goog_touch_interface *gti, bool running) { if (gti->offload.offload_running != running) { - GOOG_LOG(gti, "Offload state Changed: %d", running); + GOOG_INFO(gti, "Set offload_running=%d, irq_index=%d, input_index=%d\n", + running, gti->irq_index, gti->input_index); + gti->offload.offload_running = running; goog_update_fw_settings(gti); } @@ -2351,6 +2202,38 @@ void goog_offload_input_report(void *handle, ATRACE_END(); } +int gti_charger_state_change(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct goog_touch_interface *gti = + (struct goog_touch_interface *)container_of(nb, + struct goog_touch_interface, charger_notifier); + struct power_supply *psy = (struct power_supply *)data; + int ret; + + /* Attempt actual status parsing */ + if (psy && psy->desc->type == POWER_SUPPLY_TYPE_USB) { + union power_supply_propval present_val = { 0 }; + + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, + &present_val); + if (ret < 0) + GOOG_ERR(gti, + "Error while getting power supply property: %d!\n", + ret); + else if ((u8)present_val.intval != gti->charger_state) { + /* Note: the expected values for present_val.intval are + * 0 and 1. Cast to unsigned byte to ensure the + * comparison is handled in the same variable data type. + */ + gti->context_changed.charger_state = 1; + gti->charger_state = (u8)present_val.intval; + } + } + + return 0; +} + int goog_offload_probe(struct goog_touch_interface *gti) { int ret; @@ -2433,6 +2316,8 @@ int goog_offload_probe(struct goog_touch_interface *gti) gti->offload.caps.size_reporting = true; gti->offload.caps.filter_grip = true; gti->offload.caps.filter_palm = true; + gti->offload.caps.coord_filter = gti->coord_filter_enabled && + of_property_read_bool(np, "goog,offload-caps-coord-filter"); gti->offload.caps.num_sensitivity_settings = 1; gti->offload.caps.rotation_reporting = of_property_read_bool(np, "goog,offload-caps-rotation-reporting"); @@ -2458,6 +2343,9 @@ int goog_offload_probe(struct goog_touch_interface *gti) "goog,default-grip-disabled") ? GTI_GRIP_DISABLE : GTI_GRIP_ENABLE; gti->default_palm_enabled = of_property_read_bool(np, "goog,default-palm-disabled") ? GTI_PALM_DISABLE : GTI_PALM_ENABLE; + gti->default_coord_filter_enabled = of_property_read_bool(np, + "goog,default-coord-filter-disabled") ? + GTI_COORD_FILTER_DISABLE : GTI_COORD_FILTER_ENABLE; gti->heatmap_buf_size = gti->offload.caps.tx_size * gti->offload.caps.rx_size * sizeof(u16); gti->heatmap_buf = devm_kzalloc(gti->vendor_dev, gti->heatmap_buf_size, GFP_KERNEL); @@ -2494,6 +2382,14 @@ int goog_offload_probe(struct goog_touch_interface *gti) GOOG_INFO(gti, "v4l2 W/H=(%lu, %lu), v4l2_enabled=%d.\n", gti->v4l2.width, gti->v4l2.height, gti->v4l2_enabled); + /* Register for charger plugging status */ + gti->charger_notifier.notifier_call = gti_charger_state_change; + ret = power_supply_reg_notifier(>i->charger_notifier); + if (!ret) { + GOOG_ERR(gti, "Failed to register power_supply_reg_notifier!\n"); + goto err_offload_probe; + } + err_offload_probe: return ret; } @@ -2511,17 +2407,17 @@ bool goog_input_legacy_report(struct goog_touch_interface *gti) return false; } -int goog_input_process(struct goog_touch_interface *gti, bool report_from_irq) +int goog_input_process(struct goog_touch_interface *gti, bool reset_data) { int ret = 0; struct touch_offload_frame **frame = >i->offload_frame; /* * Only do the input process if active slot(s) update - * or slot(s) state change. + * or slot(s) state change or resetting frame data. */ if (!(gti->slot_bit_active & gti->slot_bit_in_use) && - !gti->slot_bit_changed) + !gti->slot_bit_changed && !reset_data) return -EPERM; /* @@ -2534,7 +2430,8 @@ int goog_input_process(struct goog_touch_interface *gti, bool report_from_irq) if (gti->offload_enabled) { ret = touch_offload_reserve_frame(>i->offload, frame); if (ret != 0 || frame == NULL) { - GOOG_ERR(gti, "could not reserve a frame(ret %d)!\n", ret); + GOOG_DBG(gti, "could not reserve a frame(ret %d)!\n", ret); + /* Stop offload when there are no buffers available. */ goog_offload_set_running(gti, false); /* @@ -2545,7 +2442,7 @@ int goog_input_process(struct goog_touch_interface *gti, bool report_from_irq) ret = -EBUSY; } else { goog_offload_set_running(gti, true); - goog_offload_populate_frame(gti, *frame, report_from_irq); + goog_offload_populate_frame(gti, *frame, reset_data); ret = touch_offload_queue_frame(>i->offload, *frame); if (ret) GOOG_ERR(gti, "failed to queue reserved frame(ret %d)!\n", ret); @@ -2567,7 +2464,7 @@ int goog_input_process(struct goog_touch_interface *gti, bool report_from_irq) cmd->buffer = NULL; cmd->size = 0; cmd->type = GTI_SENSOR_DATA_TYPE_MS; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + ret = goog_get_sensor_data(gti, cmd, reset_data); if (ret == 0 && cmd->buffer && cmd->size) memcpy(gti->heatmap_buf, cmd->buffer, cmd->size); goog_v4l2_read(gti, gti->input_timestamp); @@ -2729,9 +2626,7 @@ void goog_input_release_all_fingers(struct goog_touch_interface *gti) goog_input_unlock(gti); - mutex_lock(>i->input_process_lock); - goog_input_process(gti, false); - mutex_unlock(>i->input_process_lock); + goog_input_process(gti, true); } void goog_register_tbn(struct goog_touch_interface *gti) @@ -2761,6 +2656,12 @@ static int goog_get_context_stylus_nop( return -ESRCH; } +static int goog_get_coord_filter_enabled_nop( + void *private_data, struct gti_coord_filter_cmd *cmd) +{ + return -ESRCH; +} + static int goog_get_fw_version_nop( void *private_data, struct gti_fw_version_cmd *cmd) { @@ -2851,6 +2752,12 @@ static int goog_set_continuous_report_nop( return -ESRCH; } +static int goog_set_coord_filter_enabled_nop( + void *private_data, struct gti_coord_filter_cmd *cmd) +{ + return -ESRCH; +} + static int goog_set_grip_mode_nop( void *private_data, struct gti_grip_cmd *cmd) { @@ -2875,6 +2782,12 @@ static int goog_set_palm_mode_nop( return -ESRCH; } +static int goog_set_report_rate_nop( + void *private_data, struct gti_report_rate_cmd *cmd) +{ + return -ESRCH; +} + static int goog_set_scan_mode_nop( void *private_data, struct gti_scan_cmd *cmd) { @@ -2953,17 +2866,21 @@ void goog_init_options(struct goog_touch_interface *gti, struct gti_optional_configuration *options) { /* Initialize the common features. */ + gti->mf_mode = GTI_MF_MODE_DEFAULT; + gti->screen_protector_mode_setting = GTI_SCREEN_PROTECTOR_MODE_DISABLE; + gti->display_state = GTI_DISPLAY_STATE_ON; + if (gti->vendor_dev) { struct device_node *np = gti->vendor_dev->of_node; gti->ignore_force_active = of_property_read_bool(np, "goog,ignore-force-active"); - gti->ignore_screenoff_heatmap = - of_property_read_bool(np, "goog,ignore-screenoff-heatmap"); + gti->coord_filter_enabled = of_property_read_bool(np, "goog,coord-filter-enabled"); } /* Initialize default functions. */ gti->options.get_context_driver = goog_get_context_driver_nop; gti->options.get_context_stylus = goog_get_context_stylus_nop; + gti->options.get_coord_filter_enabled = goog_get_coord_filter_enabled_nop; gti->options.get_fw_version = goog_get_fw_version_nop; gti->options.get_grip_mode = goog_get_grip_mode_nop; gti->options.get_irq_mode = goog_get_irq_mode_nop; @@ -2979,10 +2896,12 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.reset = goog_reset_nop; gti->options.selftest = goog_selftest_nop; gti->options.set_continuous_report = goog_set_continuous_report_nop; + gti->options.set_coord_filter_enabled = goog_set_coord_filter_enabled_nop; gti->options.set_grip_mode = goog_set_grip_mode_nop; gti->options.set_heatmap_enabled = goog_set_heatmap_enabled_nop; gti->options.set_irq_mode = goog_set_irq_mode_nop; gti->options.set_palm_mode = goog_set_palm_mode_nop; + gti->options.set_report_rate = goog_set_report_rate_nop; gti->options.set_scan_mode = goog_set_scan_mode_nop; gti->options.set_screen_protector_mode = goog_set_screen_protector_mode_nop; gti->options.set_sensing_mode = goog_set_sensing_mode_nop; @@ -2993,6 +2912,8 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.get_context_driver = options->get_context_driver; if (options->get_context_stylus) gti->options.get_context_stylus = options->get_context_stylus; + if (options->get_coord_filter_enabled) + gti->options.get_coord_filter_enabled = options->get_coord_filter_enabled; if (options->get_fw_version) gti->options.get_fw_version = options->get_fw_version; if (options->get_grip_mode) @@ -3025,6 +2946,8 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.selftest = options->selftest; if (options->set_continuous_report) gti->options.set_continuous_report = options->set_continuous_report; + if (options->set_coord_filter_enabled) + gti->options.set_coord_filter_enabled = options->set_coord_filter_enabled; if (options->set_grip_mode) gti->options.set_grip_mode = options->set_grip_mode; if (options->set_heatmap_enabled) @@ -3033,6 +2956,8 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.set_irq_mode = options->set_irq_mode; if (options->set_palm_mode) gti->options.set_palm_mode = options->set_palm_mode; + if (options->set_report_rate) + gti->options.set_report_rate = options->set_report_rate; if (options->set_scan_mode) gti->options.set_scan_mode = options->set_scan_mode; if (options->set_screen_protector_mode) @@ -3196,8 +3121,7 @@ static void goog_pm_suspend(struct gti_pm *pm) gti_debug_hc_dump(gti); gti_debug_input_dump(gti); - if (gti->slot_bit_active) - goog_input_release_all_fingers(gti); + goog_input_release_all_fingers(gti); pm_relax(gti->dev); } @@ -3213,18 +3137,20 @@ static void goog_pm_resume(struct gti_pm *pm) GOOG_WARN(gti, "GTI already resumed!\n"); return; } - pm->state = GTI_PM_RESUME; pm_stay_awake(gti->dev); if (gti->tbn_register_mask) { - ret = tbn_request_bus(gti->tbn_register_mask); + gti->lptw_triggered = false; + ret = tbn_request_bus_with_result(gti->tbn_register_mask, >i->lptw_triggered); if (ret) GOOG_ERR(gti, "tbn_request_bus failed, ret %d!\n", ret); } if (pm->resume) pm->resume(gti->vendor_dev); + + pm->state = GTI_PM_RESUME; } void goog_pm_state_update_work(struct work_struct *work) { @@ -3291,15 +3217,28 @@ void goog_notify_fw_status_changed(struct goog_touch_interface *gti, case GTI_FW_STATUS_GRIP_EXIT: GOOG_INFO(gti, "Exit grip mode\n"); break; + case GTI_FW_STATUS_WATER_ENTER: + GOOG_INFO(gti, "Enter water mode\n"); + gti->fw_status.water_mode = 1; + gti->context_changed.water_mode = 1; + break; + case GTI_FW_STATUS_WATER_EXIT: + GOOG_INFO(gti, "Exit water mode\n"); + gti->fw_status.water_mode = 0; + gti->context_changed.water_mode = 1; + break; case GTI_FW_STATUS_NOISE_MODE: if (data == NULL) { GOOG_INFO(gti, "Noise level is changed, level: unknown\n"); } else { if (data->noise_level == GTI_NOISE_MODE_EXIT) { GOOG_INFO(gti, "Exit noise mode\n"); + gti->fw_status.noise_level= 0; } else { GOOG_INFO(gti, "Enter noise mode, level: %d\n", data->noise_level); + gti->fw_status.noise_level = data->noise_level; } + gti->context_changed.noise_state = 1; } break; default: @@ -3330,8 +3269,6 @@ static int goog_pm_probe(struct goog_touch_interface *gti) cpu_latency_qos_add_request(>i->pm_qos_req, PM_QOS_DEFAULT_VALUE); pm->enabled = true; - return ret; - err_alloc_workqueue: return ret; } @@ -3346,9 +3283,163 @@ static int goog_pm_remove(struct goog_touch_interface *gti) if (pm->event_wq) destroy_workqueue(pm->event_wq); } + + return 0; +} + +static void goog_lookup_touch_report_rate(struct goog_touch_interface *gti) +{ + int i; + u32 next_report_rate = 0; + + for (i = 0; i < gti->report_rate_table_size; i++) { + if (gti->display_vrefresh <= gti->display_refresh_rate_table[i]) { + next_report_rate = gti->touch_report_rate_table[i]; + break; + } + } + + /* + * Set the touch report as minimum value if the display_vrefresh is smaller + * than the minimum value of goog,display-vrr-table. + */ + if (next_report_rate == 0) + next_report_rate = gti->touch_report_rate_table[0]; + + if (gti->report_rate_setting_next != next_report_rate) { + cancel_delayed_work_sync(>i->set_report_rate_work); + gti->report_rate_setting_next = next_report_rate; + } + + if (gti->report_rate_setting_next != gti->report_rate_setting && + gti->pm.state == GTI_PM_RESUME) { + queue_delayed_work(gti->pm.event_wq, >i->set_report_rate_work, + (gti->report_rate_setting_next > gti->report_rate_setting) ? + msecs_to_jiffies(gti->increase_report_rate_delay * MSEC_PER_SEC) : + msecs_to_jiffies(gti->decrease_report_rate_delay * MSEC_PER_SEC)); + } +} + +static void goog_set_report_rate_work(struct work_struct *work) +{ + int ret; + struct goog_touch_interface *gti; + struct delayed_work *delayed_work; + delayed_work = container_of(work, struct delayed_work, work); + gti = container_of(delayed_work, struct goog_touch_interface, set_report_rate_work); + + if (gti->pm.state == GTI_PM_SUSPEND) + return; + + if (gti->report_rate_setting == gti->report_rate_setting_next) + return; + + /* Retry it 10ms later if there is finger on the screen. */ + if (gti->slot_bit_active) { + queue_delayed_work(gti->pm.event_wq, >i->set_report_rate_work, + msecs_to_jiffies(10)); + return; + } + + gti->cmd.report_rate_cmd.setting = gti->report_rate_setting_next; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_REPORT_RATE); + if (ret != 0) { + GOOG_ERR(gti, "Failed to set report rate!\n"); + return; + } + + gti->report_rate_setting = gti->report_rate_setting_next; + gti->context_changed.touch_report_rate = 1; +} + +static int goog_init_variable_report_rate(struct goog_touch_interface *gti) +{ + int table_size = 0; + + if (!gti->pm.event_wq) { + GOOG_ERR(gti, "No workqueue for variable report rate.\n"); + return -ENODEV; + } + + gti->vrr_enabled = of_property_read_bool(gti->vendor_dev->of_node, + "goog,vrr-enabled"); + if (!gti->vrr_enabled) + return 0; + + table_size = of_property_count_u32_elems(gti->vendor_dev->of_node, + "goog,vrr-display-rate"); + if (table_size != of_property_count_u32_elems(gti->vendor_dev->of_node, + "goog,vrr-touch-rate")) { + GOOG_ERR(gti, "Table size mismatch!\n"); + goto init_variable_report_rate_failed; + } + + gti->report_rate_table_size = table_size; + + gti->display_refresh_rate_table = devm_kzalloc(gti->vendor_dev, + sizeof(u32) * table_size, GFP_KERNEL); + if (!gti->display_refresh_rate_table) { + GOOG_ERR(gti, "display_refresh_rate_table alloc failed.\n"); + goto init_variable_report_rate_failed; + } + + gti->touch_report_rate_table = devm_kzalloc(gti->vendor_dev, + sizeof(u32) * table_size, GFP_KERNEL); + if (!gti->touch_report_rate_table) { + GOOG_ERR(gti, "touch_report_rate_table alloc failed.\n"); + goto init_variable_report_rate_failed; + } + + if (of_property_read_u32_array(gti->vendor_dev->of_node, "goog,vrr-display-rate", + gti->display_refresh_rate_table, table_size)) { + GOOG_ERR(gti, "Failed to parse goog,display-vrr-table.\n"); + goto init_variable_report_rate_failed; + } + + if (of_property_read_u32_array(gti->vendor_dev->of_node, "goog,vrr-touch-rate", + gti->touch_report_rate_table, table_size)) { + GOOG_ERR(gti, "Failed to parse goog,touch-vrr-table.\n"); + goto init_variable_report_rate_failed; + } + + if (of_property_read_u32(gti->vendor_dev->of_node, "goog,vrr-up-delay", + >i->increase_report_rate_delay)) { + gti->increase_report_rate_delay = 0; + } + + if (of_property_read_u32(gti->vendor_dev->of_node, "goog,vrr-down-delay", + >i->decrease_report_rate_delay)) { + gti->decrease_report_rate_delay = 0; + } + + GOOG_INFO(gti, "Default report rate: %uHz, report rate delay %u/%u)", + gti->touch_report_rate_table[0], + gti->increase_report_rate_delay, + gti->decrease_report_rate_delay); + + gti->report_rate_setting = gti->touch_report_rate_table[0]; + gti->report_rate_setting_next = gti->touch_report_rate_table[0]; + INIT_DELAYED_WORK(>i->set_report_rate_work, goog_set_report_rate_work); + + return 0; + +init_variable_report_rate_failed: + gti->vrr_enabled = false; + devm_kfree(gti->vendor_dev, gti->display_refresh_rate_table); + devm_kfree(gti->vendor_dev, gti->touch_report_rate_table); + return 0; } +int goog_get_lptw_triggered(struct goog_touch_interface *gti) +{ + if (gti == NULL) + return -ENODEV; + + return gti->lptw_triggered; +} +EXPORT_SYMBOL(goog_get_lptw_triggered); + static irqreturn_t gti_irq_handler(int irq, void *data) { irqreturn_t ret; @@ -3370,13 +3461,21 @@ static irqreturn_t gti_irq_thread_fn(int irq, void *data) ATRACE_BEGIN(__func__); cpu_latency_qos_update_request(>i->pm_qos_req, 100 /* usec */); + + /* + * Some vendor drivers read sensor data inside vendor_irq_thread_fn. + * We need to lock input_process_lock before vendor_irq_thread_fn to + * avoid thread safe issue. + */ + mutex_lock(>i->input_process_lock); + if (gti->vendor_irq_thread_fn) ret = gti->vendor_irq_thread_fn(irq, gti->vendor_irq_cookie); else ret = IRQ_HANDLED; - mutex_lock(>i->input_process_lock); - goog_input_process(gti, true); + goog_input_process(gti, false); + mutex_unlock(>i->input_process_lock); gti_debug_hc_update(gti, false); @@ -3457,9 +3556,6 @@ struct goog_touch_interface *goog_touch_interface_probe( gti->vendor_dev = dev; gti->vendor_input_dev = input_dev; gti->vendor_default_handler = default_handler; - gti->mf_mode = GTI_MF_MODE_DEFAULT; - gti->screen_protector_mode_setting = GTI_SCREEN_PROTECTOR_MODE_DISABLE; - gti->display_state = GTI_DISPLAY_STATE_ON; mutex_init(>i->input_lock); mutex_init(>i->input_process_lock); } @@ -3468,7 +3564,15 @@ struct goog_touch_interface *goog_touch_interface_probe( gti_class = class_create(THIS_MODULE, GTI_NAME); if (gti && gti_class) { - char *name = kasprintf(GFP_KERNEL, "gti.%d", gti_dev_num); + u32 dev_id = gti_dev_num; + char *name; + + if (gti->vendor_dev) { + struct device_node *np = gti->vendor_dev->of_node; + + of_property_read_u32(np, "goog,dev-id", &dev_id); + } + name = kasprintf(GFP_KERNEL, "gti.%d", dev_id); if (name && !alloc_chrdev_region(>i->dev_id, 0, 1, name)) { @@ -3506,10 +3610,11 @@ struct goog_touch_interface *goog_touch_interface_probe( * goog_init_input() needs the offload.cap initialization by goog_offload_probe(). */ goog_init_input(gti); - goog_update_fw_settings(gti); goog_register_tbn(gti); goog_pm_probe(gti); register_panel_bridge(gti); + goog_init_variable_report_rate(gti); + goog_update_fw_settings(gti); ret = sysfs_create_group(>i->dev->kobj, &goog_attr_group); if (ret) diff --git a/goog_touch_interface.h b/goog_touch_interface.h index 7321e47..9145538 100644 --- a/goog_touch_interface.h +++ b/goog_touch_interface.h @@ -49,6 +49,7 @@ enum gti_cmd_type : u32 { GTI_CMD_GET_OPS_START = 0x200, GTI_CMD_GET_CONTEXT_DRIVER, GTI_CMD_GET_CONTEXT_STYLUS, + GTI_CMD_GET_COORD_FILTER_ENABLED, GTI_CMD_GET_FW_VERSION, GTI_CMD_GET_GRIP_MODE, GTI_CMD_GET_IRQ_MODE, @@ -67,10 +68,12 @@ enum gti_cmd_type : u32 { /* GTI_CMD_SET operations. */ GTI_CMD_SET_OPS_START = 0x400, GTI_CMD_SET_CONTINUOUS_REPORT, + GTI_CMD_SET_COORD_FILTER_ENABLED, GTI_CMD_SET_GRIP_MODE, GTI_CMD_SET_HEATMAP_ENABLED, GTI_CMD_SET_IRQ_MODE, GTI_CMD_SET_PALM_MODE, + GTI_CMD_SET_REPORT_RATE, GTI_CMD_SET_SCAN_MODE, GTI_CMD_SET_SCREEN_PROTECTOR_MODE, GTI_CMD_SET_SENSING_MODE, @@ -82,6 +85,11 @@ enum gti_continuous_report_setting : u32 { GTI_CONTINUOUS_REPORT_DRIVER_DEFAULT, }; +enum gti_coord_filter_setting : u32 { + GTI_COORD_FILTER_DISABLE = 0, + GTI_COORD_FILTER_ENABLE, +}; + enum gti_display_state_setting : u32 { GTI_DISPLAY_STATE_OFF = 0, GTI_DISPLAY_STATE_ON, @@ -143,8 +151,8 @@ enum gti_ping_mode : u32 { }; enum gti_pm_state : u32 { - GTI_PM_RESUME = 0, - GTI_PM_SUSPEND, + GTI_PM_SUSPEND = 0, + GTI_PM_RESUME, }; #define GTI_PM_WAKELOCK_TYPE_LOCK_MASK 0xFFFF @@ -159,6 +167,7 @@ enum gti_pm_wakelock_type : u32 { GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE = (1 << 4), GTI_PM_WAKELOCK_TYPE_BUGREPORT = (1 << 5), GTI_PM_WAKELOCK_TYPE_OFFLOAD_REPORT = (1 << 6), + GTI_PM_WAKELOCK_TYPE_SENSOR_DATA = (1 << 7), }; enum gti_proc_type : u32 { @@ -231,17 +240,14 @@ enum gti_sensor_data_type : u32 { TOUCH_SCAN_TYPE_SELF | TOUCH_DATA_TYPE_BASELINE, }; -enum gti_vendor_dev_pm_state : u32 { - GTI_VENDOR_DEV_RESUME = 0, - GTI_VENDOR_DEV_SUSPEND, -}; - enum gti_fw_status : u32 { GTI_FW_STATUS_RESET = 0, GTI_FW_STATUS_PALM_ENTER, GTI_FW_STATUS_PALM_EXIT, GTI_FW_STATUS_GRIP_ENTER, GTI_FW_STATUS_GRIP_EXIT, + GTI_FW_STATUS_WATER_ENTER, + GTI_FW_STATUS_WATER_EXIT, GTI_FW_STATUS_NOISE_MODE, }; @@ -256,8 +262,9 @@ enum gti_noise_mode_level : u8 { * Structures. */ -struct gti_context_driver_cmd { - struct { +struct gti_context_changed { + union { + struct { u32 screen_state : 1; u32 display_refresh_rate : 1; u32 touch_report_rate : 1; @@ -266,7 +273,13 @@ struct gti_context_driver_cmd { u32 charger_state : 1; u32 hinge_angle : 1; u32 offload_timestamp : 1; - } contents; + }; + u32 value; + }; +}; + +struct gti_context_driver_cmd { + struct gti_context_changed context_changed; u8 screen_state; u8 display_refresh_rate; @@ -315,6 +328,10 @@ struct gti_debug_input { struct gti_debug_coord released; }; +struct gti_coord_filter_cmd { + enum gti_coord_filter_setting setting; +}; + struct gti_display_state_cmd { enum gti_display_state_setting setting; }; @@ -347,6 +364,10 @@ struct gti_ping_cmd { enum gti_ping_mode setting; }; +struct gti_report_rate_cmd { + u32 setting; +}; + struct gti_reset_cmd { enum gti_reset_mode setting; }; @@ -379,6 +400,7 @@ struct gti_sensor_data_cmd { * @context_driver_cmd: command to update touch offload driver context. * @context_stylus_cmd: command to update touch offload stylus context. * @continuous_report_cmd: command to set continuous reporting. + * @coord_filter_cmd: command to set/get coordinate filter enabled. * @display_state_cmd: command to notify display state. * @display_vrefresh_cmd: command to notify display vertical refresh rate. * @fw_version_cmd: command to get fw version. @@ -387,6 +409,7 @@ struct gti_sensor_data_cmd { * @irq_cmd: command to set/get irq mode. * @palm_cmd: command to set/get palm mode. * @ping_cmd: command to ping T-IC. + * @report_rate_cmd: command to change touch report rate. * @reset_cmd: command to reset T-IC. * @scan_cmd: command to set/get scan mode. * @screen_protector_mode_cmd: command to set/get screen protector mode. @@ -399,6 +422,7 @@ struct gti_union_cmd_data { struct gti_context_driver_cmd context_driver_cmd; struct gti_context_stylus_cmd context_stylus_cmd; struct gti_continuous_report_cmd continuous_report_cmd; + struct gti_coord_filter_cmd coord_filter_cmd; struct gti_display_state_cmd display_state_cmd; struct gti_display_vrefresh_cmd display_vrefresh_cmd; struct gti_fw_version_cmd fw_version_cmd; @@ -407,6 +431,7 @@ struct gti_union_cmd_data { struct gti_irq_cmd irq_cmd; struct gti_palm_cmd palm_cmd; struct gti_ping_cmd ping_cmd; + struct gti_report_rate_cmd report_rate_cmd; struct gti_reset_cmd reset_cmd; struct gti_scan_cmd scan_cmd; struct gti_screen_protector_mode_cmd screen_protector_mode_cmd; @@ -422,12 +447,14 @@ struct gti_union_cmd_data { */ struct gti_fw_status_data { enum gti_noise_mode_level noise_level; + u8 water_mode; }; /** * struct gti_optional_configuration - optional configuration by vendor driver. * @get_context_driver: vendor driver operation to update touch offload driver context. * @get_context_stylus: vendor driver operation to update touch offload stylus context. + * @get_coord_filter_enabled: vendor driver operation to get the coordinate filter enabled. * @get_fw_version: vendor driver operation to get fw version info. * @get_grip_mode: vendor driver operation to get the grip mode setting. * @get_irq_mode: vendor driver operation to get irq mode setting. @@ -443,10 +470,12 @@ struct gti_fw_status_data { * @reset: vendor driver operation to exec reset. * @selftest: vendor driver operation to exec self-test. * @set_continuous_report: vendor driver operation to apply the continuous reporting setting. + * @set_coord_filter_enabled: vendor driver operation to apply the coordinate filter enabled. * @set_grip_mode: vendor driver operation to apply the grip setting. * @set_heatmap_enabled: vendor driver operation to apply the heatmap setting. * @set_irq_mode: vendor driver operation to apply the irq setting. * @set_palm_mode: vendor driver operation to apply the palm setting. + * @set_report_rate: driver operation to set touch report rate. * @set_scan_mode: vendor driver operation to set scan mode. * @set_screen_protector_mode: vendor driver operation to set screen protector mode. * @set_sensing_mode: vendor driver operation to set sensing mode. @@ -454,13 +483,15 @@ struct gti_fw_status_data { struct gti_optional_configuration { int (*get_context_driver)(void *private_data, struct gti_context_driver_cmd *cmd); int (*get_context_stylus)(void *private_data, struct gti_context_stylus_cmd *cmd); + int (*get_coord_filter_enabled)(void *private_data, struct gti_coord_filter_cmd *cmd); int (*get_fw_version)(void *private_data, struct gti_fw_version_cmd *cmd); int (*get_grip_mode)(void *private_data, struct gti_grip_cmd *cmd); int (*get_irq_mode)(void *private_data, struct gti_irq_cmd *cmd); int (*get_mutual_sensor_data)(void *private_data, struct gti_sensor_data_cmd *cmd); int (*get_palm_mode)(void *private_data, struct gti_palm_cmd *cmd); int (*get_scan_mode)(void *private_data, struct gti_scan_cmd *cmd); - int (*get_screen_protector_mode)(void *private_data, struct gti_screen_protector_mode_cmd *cmd); + int (*get_screen_protector_mode)(void *private_data, + struct gti_screen_protector_mode_cmd *cmd); int (*get_self_sensor_data)(void *private_data, struct gti_sensor_data_cmd *cmd); int (*get_sensing_mode)(void *private_data, struct gti_sensing_cmd *cmd); int (*notify_display_state)(void *private_data, struct gti_display_state_cmd *cmd); @@ -469,12 +500,15 @@ struct gti_optional_configuration { int (*reset)(void *private_data, struct gti_reset_cmd *cmd); int (*selftest)(void *private_data, struct gti_selftest_cmd *cmd); int (*set_continuous_report)(void *private_data, struct gti_continuous_report_cmd *cmd); + int (*set_coord_filter_enabled)(void *private_data, struct gti_coord_filter_cmd *cmd); int (*set_grip_mode)(void *private_data, struct gti_grip_cmd *cmd); int (*set_heatmap_enabled)(void *private_data, struct gti_heatmap_cmd *cmd); int (*set_irq_mode)(void *private_data, struct gti_irq_cmd *cmd); int (*set_palm_mode)(void *private_data, struct gti_palm_cmd *cmd); + int (*set_report_rate)(void *private_data, struct gti_report_rate_cmd *cmd); int (*set_scan_mode)(void *private_data, struct gti_scan_cmd *cmd); - int (*set_screen_protector_mode)(void *private_data, struct gti_screen_protector_mode_cmd *cmd); + int (*set_screen_protector_mode)(void *private_data, + struct gti_screen_protector_mode_cmd *cmd); int (*set_sensing_mode)(void *private_data, struct gti_sensing_cmd *cmd); }; @@ -528,21 +562,36 @@ struct gti_pm { * @display_vrefresh: display vrefresh in Hz. * @mf_mode: current motion filter mode. * @mf_state: current motion filter state. + * @vrr_enabled: variable touch report rate is enabled or not. + * @report_rate_table_size: report rate table size from device tree. + * @touch_report_rate_table: touch report rate table parsed from device tree. + * @display_refresh_rate_table: display refresh rate table parsed from device tree. + * @report_rate_setting: current touch report rate. + * @report_rate_setting_next: next touch report rate going be set. + * @set_report_rate_work: delayed work for setting report rate. + * @increase_report_rate_delay: delayed work will be start after a delay in seconds. + * @decrease_report_rate_delay: delayed work will be start after a delay in seconds. * @screen_protector_mode_setting: the setting of screen protector mode. * @tbn_register_mask: the tbn_mask that used to request/release touch bus. * @pm: struct that used by gti pm. * @pm_qos_req: struct that used by pm qos. + * @fw_status: firmware status such as water_mode, noise_level, etc. + * @context_changed: flags that indicate driver status changing. * @panel_is_lp_mode: display is in low power mode. - * @offload_enable: touch offload is enabled or not. - * @v4l2_enable: v4l2 is enabled or not. - * @tbn_enable: tbn is enabled or not. + * @offload_enabled: touch offload is enabled or not. + * @v4l2_enabled: v4l2 is enabled or not. + * @tbn_enabled: tbn is enabled or not. + * @coord_filter_enabled: coordinate filter is enabled or not. * @input_timestamp_changed: input timestamp changed from touch vendor driver. * @ignore_grip_update: Ignore fw_grip status updates made on offload state change. * @default_grip_enabled: the grip default setting. * @ignore_palm_update: Ignore fw_palm status updates made on offload state change. * @default_palm_enabled: the palm default setting. + * @ignore_coord_filter_update: Ignore fw_coordinate_filter status updates. + * @fw_coord_filter_enabled: the current setting of coordinate filter. + * @default_coord_filter_enabled: the default setting of coordinate filter. + * @lptw_triggered: LPTW is triggered or not. * @ignore_force_active: Ignore the force_active sysfs request. - * @ignore_screenoff_heatmap: Ignore the heatmap request during screen-off. * @offload_id: id that used by touch offload. * @heatmap_buf: heatmap buffer that used by v4l2. * @heatmap_buf_size: heatmap buffer size that used by v4l2. @@ -551,6 +600,8 @@ struct gti_pm { * @slot_bit_changed: bitmap of slot state changed for this input process cycle. * @slot_bit_active: bitmap of active slot during GTI lifecycle. * @dev_id: dev_t used for google interface driver. + * @charger_state: indicates a USB charger is connected. + * @charger_notifier: notifier for power_supply updates. * @irq_index: irq count that handle by GTI. * @input_index: the count of slot bit changed during goog_input_process(). * @vendor_irq_handler: irq handler that register by vendor driver. @@ -583,6 +634,16 @@ struct goog_touch_interface { ktime_t input_timestamp; ktime_t mf_downtime; + bool vrr_enabled; + int report_rate_table_size; + u32 *display_refresh_rate_table; + u32 *touch_report_rate_table; + u32 report_rate_setting; + u32 report_rate_setting_next; + struct delayed_work set_report_rate_work; + u32 increase_report_rate_delay; + u32 decrease_report_rate_delay; + int display_vrefresh; enum gti_display_state_setting display_state; enum gti_mf_mode mf_mode; @@ -592,18 +653,24 @@ struct goog_touch_interface { struct gti_pm pm; struct pm_qos_request pm_qos_req; + struct gti_fw_status_data fw_status; + struct gti_context_changed context_changed; + bool panel_is_lp_mode; bool offload_enabled; bool v4l2_enabled; bool tbn_enabled; + bool coord_filter_enabled; bool input_timestamp_changed; bool ignore_grip_update; bool default_grip_enabled; bool ignore_palm_update; bool default_palm_enabled; + bool ignore_coord_filter_update; + bool fw_coord_filter_enabled; + bool default_coord_filter_enabled; + bool lptw_triggered; bool ignore_force_active; - bool ignore_screenoff_heatmap; - unsigned int wakeup_before_force_active_delay; union { u8 offload_id_byte[4]; u32 offload_id; @@ -616,6 +683,9 @@ struct goog_touch_interface { unsigned long slot_bit_active; dev_t dev_id; + u8 charger_state; + struct notifier_block charger_notifier; + u64 irq_index; u64 input_index; irq_handler_t vendor_irq_handler; @@ -666,7 +736,7 @@ inline int goog_request_threaded_irq(struct goog_touch_interface *gti, unsigned long irqflags, const char *devname, void *dev_id); int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type cmd_type); -int goog_input_process(struct goog_touch_interface *gti, bool report_from_irq); +int goog_input_process(struct goog_touch_interface *gti, bool reset_data); struct goog_touch_interface *goog_touch_interface_probe( void *private_data, struct device *dev, @@ -696,5 +766,7 @@ void goog_notify_fw_status_changed(struct goog_touch_interface *gti, void gti_debug_hc_dump(struct goog_touch_interface *gti); void gti_debug_input_dump(struct goog_touch_interface *gti); +int goog_get_lptw_triggered(struct goog_touch_interface *gti); + #endif // _GOOG_TOUCH_INTERFACE_ diff --git a/include/uapi/input/touch_offload.h b/include/uapi/input/touch_offload.h index 4a10ba1..eb8af30 100644 --- a/include/uapi/input/touch_offload.h +++ b/include/uapi/input/touch_offload.h @@ -61,6 +61,7 @@ * filter_palm - driver supports disabling underlying palm rejection * num_sensitivity_settings - number of sensitivity options provided * auto_reporting - report heatmap when screen is not touched + * coord_filter - driver supports disabling underlying coordinate filter */ struct TouchOffloadCaps { /* Version info */ @@ -95,7 +96,8 @@ struct TouchOffloadCaps { __u8 filter_palm; __u8 num_sensitivity_settings; __u8 auto_reporting; - __u8 reserved4[32]; + __u8 coord_filter; + __u8 reserved4[31]; } __attribute__((packed)); /* TouchOffloadConfig @@ -107,6 +109,7 @@ struct TouchOffloadCaps { * filter_palm - enable underlying palm rejection * sensitivity_setting - selected sensitivity * auto_reporting - enable reporting when screen is not touched + * coord_filter - enable underlying coordinate filter * read_coords - allocate a channel to coordinate data * mutual_data_types - bitfield of mutual data types to collect * self_data_types - bitfield of self data types to collect @@ -122,7 +125,8 @@ struct TouchOffloadConfig { __u8 filter_palm; __u8 sensitivity_setting; __u8 auto_reporting; - __u8 reserved1[16]; + __u8 coord_filter; + __u8 reserved1[15]; /* Data to read */ __u8 read_coords; diff --git a/touch_bus_negotiator.c b/touch_bus_negotiator.c index 94d7134..51898a0 100644 --- a/touch_bus_negotiator.c +++ b/touch_bus_negotiator.c @@ -17,20 +17,26 @@ #include <linux/delay.h> #include "touch_bus_negotiator.h" +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) +#include <uapi/linux/sched/types.h> +#include "aoc_tbn_service_dev.h" +#endif + #define TBN_MODULE_NAME "touch_bus_negotiator" +#define TBN_AOC_CHANNEL_THREAD_NAME "tbn_aoc_channel" -static struct tbn_context *tbn_context = NULL; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) +static void handle_tbn_event_response(struct tbn_context *tbn, + struct TbnEventResponse *response); +#endif -enum tbn_operation { - AP_RELEASE_BUS, - AP_REQUEST_BUS, -}; +static struct tbn_context *tbn_context; static irqreturn_t tbn_aoc2ap_irq_thread(int irq, void *ptr) { struct tbn_context *tbn = ptr; - dev_info(tbn_context->dev, "%s: bus_released:%d bus_requested:%d.\n", __func__, + dev_info(tbn->dev, "%s: bus_released:%d bus_requested:%d.\n", __func__, completion_done(&tbn->bus_released), completion_done(&tbn->bus_requested)); if (completion_done(&tbn->bus_released) && completion_done(&tbn->bus_requested)) @@ -65,7 +71,113 @@ static irqreturn_t tbn_aoc2ap_irq_thread(int irq, void *ptr) return IRQ_HANDLED; } -int tbn_handshaking(struct tbn_context *tbn, enum tbn_operation operation) +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) +static int aoc_channel_kthread(void *data) +{ + struct tbn_context *tbn = data; + struct TbnEventResponse resp; + ssize_t len; + bool service_ready = false; + + while (!kthread_should_stop()) { + if (service_ready != aoc_tbn_service_ready()) { + service_ready = !service_ready; + dev_info(tbn->dev, "%s: AOC TBN service is %s.\n", + __func__, service_ready ? "ready" : "not ready"); + } + + if (!service_ready) { + msleep(1000); + continue; + } + + len = aoc_tbn_service_read(&resp, sizeof(resp)); + if (len < 0) { + dev_err(tbn->dev, "%s: failed to read message, err: %d\n", + __func__, len); + msleep(1000); + continue; + } + + if (kthread_should_stop()) { + break; + } + + if (len == sizeof(resp)) { + handle_tbn_event_response(tbn, &resp); + } + } + + return 0; +} + +static void handle_tbn_event_response(struct tbn_context *tbn, + struct TbnEventResponse *response) +{ + mutex_lock(&tbn->event_lock); + + if (response->id != tbn->event.id) { + dev_err(tbn->dev, + "%s: receive wrong response, id: %d, expected id: %d, " + "bus_released:%d bus_requested:%d.\n", + __func__, response->id, tbn->event.id, + completion_done(&tbn->bus_released), + completion_done(&tbn->bus_requested)); + goto exit; + } + + if (response->err != 0) { + dev_err(tbn->dev, "%s: send tbn event failed, err %d!\n", + __func__, response->err); + tbn->event_resp.err = response->err; + } else { + tbn->event_resp.lptw_triggered = response->lptw_triggered; + } + + if (response->operation == TBN_OPERATION_AP_REQUEST_BUS) { + complete_all(&tbn->bus_requested); + } else if (response->operation == TBN_OPERATION_AP_RELEASE_BUS) { + complete_all(&tbn->bus_released); + } else { + dev_err(tbn->dev, "%s: response unknown operation, op: %d!\n", + __func__, response->operation); + } + +exit: + mutex_unlock(&tbn->event_lock); +} + +static void send_tbn_event(struct tbn_context *tbn, enum TbnOperation operation) +{ + ssize_t len; + int retry = 3; + + if (!aoc_tbn_service_ready()) { + dev_err(tbn_context->dev, "%s: AOC TBN service is not ready.\n", + __func__); + return; + } + + mutex_lock(&tbn->event_lock); + + tbn->event.operation = operation; + tbn->event.id++; + + while (retry) { + len = aoc_tbn_service_write(&tbn->event, sizeof(tbn->event)); + if (len == sizeof(tbn->event)) { + break; + } + dev_err(tbn_context->dev, "%s: failed to send TBN event, retry: %d.\n", + __func__, retry); + retry--; + } + + mutex_unlock(&tbn->event_lock); +} +#endif + +int tbn_handshaking(struct tbn_context *tbn, enum TbnOperation operation) { struct completion *wait_for_completion; enum tbn_bus_owner bus_owner; @@ -74,29 +186,35 @@ int tbn_handshaking(struct tbn_context *tbn, enum tbn_operation operation) const char *msg; int ret = 0; - if (!tbn || tbn->registered_mask == 0) - return 0; + if (!tbn || tbn->registered_mask == 0) { + dev_err(tbn_context->dev, "%s: tbn is not ready to serve.\n", __func__); + return -EINVAL; + } - if (operation == AP_REQUEST_BUS) { + if (operation == TBN_OPERATION_AP_REQUEST_BUS) { wait_for_completion = &tbn->bus_requested; bus_owner = TBN_BUS_OWNER_AP; irq_type = IRQF_TRIGGER_FALLING; timeout = TBN_REQUEST_BUS_TIMEOUT_MS; msg = "request"; - } else { + } else if (operation == TBN_OPERATION_AP_RELEASE_BUS) { wait_for_completion = &tbn->bus_released; bus_owner = TBN_BUS_OWNER_AOC; irq_type = IRQF_TRIGGER_RISING; timeout = TBN_RELEASE_BUS_TIMEOUT_MS; msg = "release"; + } else { + dev_err(tbn_context->dev, "%s: request unknown operation, op: %d.\n", + __func__, operation); + return -EINVAL; } - reinit_completion(wait_for_completion); - if (tbn->mode == TBN_MODE_GPIO) { int ap2aoc_val_org = gpio_get_value(tbn->ap2aoc_gpio); int aoc2ap_val_org = gpio_get_value(tbn->aoc2ap_gpio); + reinit_completion(wait_for_completion); + irq_set_irq_type(tbn->aoc2ap_irq, irq_type); enable_irq(tbn->aoc2ap_irq); gpio_direction_output(tbn->ap2aoc_gpio, bus_owner); @@ -117,12 +235,38 @@ int tbn_handshaking(struct tbn_context *tbn, enum tbn_operation operation) } else dev_info(tbn->dev, "AP %s bus ... SUCCESS!\n", msg); disable_irq_nosync(tbn->aoc2ap_irq); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + } else if (tbn->mode == TBN_MODE_AOC_CHANNEL) { + tbn->event_resp.lptw_triggered = false; + tbn->event_resp.err = 0; + + reinit_completion(wait_for_completion); + + send_tbn_event(tbn, operation); + if (wait_for_completion_timeout(wait_for_completion, + msecs_to_jiffies(timeout)) == 0) { + dev_err(tbn->dev, "AP %s bus ... timeout!\n", msg); + complete_all(wait_for_completion); + ret = -ETIMEDOUT; + } else { + if (tbn->event_resp.err == 0) { + dev_info(tbn->dev, "AP %s bus ... SUCCESS!\n", msg); + } else { + dev_info(tbn->dev, "AP %s bus ... failed!\n", msg); + ret = -EBUSY; + } + } +#endif + } else if (tbn->mode == TBN_MODE_MOCK) { + dev_info(tbn->dev, "AP %s bus ... SUCCESS!\n", msg); + } else { + ret = -EINVAL; } return ret; } -int tbn_request_bus(u32 dev_mask) +int tbn_request_bus_with_result(u32 dev_mask, bool *lptw_triggered) { int ret = 0; @@ -139,11 +283,13 @@ int tbn_request_bus(u32 dev_mask) } if (tbn_context->requested_dev_mask == 0) { - ret = tbn_handshaking(tbn_context, AP_REQUEST_BUS); + ret = tbn_handshaking(tbn_context, TBN_OPERATION_AP_REQUEST_BUS); + if ((ret == 0) && (lptw_triggered != NULL)) + *lptw_triggered = tbn_context->event_resp.lptw_triggered; } else { dev_dbg(tbn_context->dev, - "%s: Bus already requested, requested_dev_mask %#x dev_mask %#x.\n", - __func__, tbn_context->requested_dev_mask, dev_mask); + "%s: Bus already requested, requested_dev_mask %#x dev_mask %#x.\n", + __func__, tbn_context->requested_dev_mask, dev_mask); } tbn_context->requested_dev_mask |= dev_mask; @@ -151,6 +297,12 @@ int tbn_request_bus(u32 dev_mask) return ret; } +EXPORT_SYMBOL_GPL(tbn_request_bus_with_result); + +int tbn_request_bus(u32 dev_mask) +{ + return tbn_request_bus_with_result(dev_mask, NULL); +} EXPORT_SYMBOL_GPL(tbn_request_bus); int tbn_release_bus(u32 dev_mask) @@ -179,7 +331,7 @@ int tbn_release_bus(u32 dev_mask) /* Release the bus when the last requested_dev_mask bit releases. */ if (tbn_context->requested_dev_mask == dev_mask) { - ret = tbn_handshaking(tbn_context, AP_RELEASE_BUS); + ret = tbn_handshaking(tbn_context, TBN_OPERATION_AP_RELEASE_BUS); } else { dev_dbg(tbn_context->dev, "%s: Bus is still in use, requested_dev_mask %#x dev_mask %#x.\n", @@ -198,6 +350,8 @@ int register_tbn(u32 *output) { u32 i = 0; + *output = 0; + if (!tbn_context) { pr_warn("%s: tbn_context doesn't exist.", __func__); return 0; @@ -238,22 +392,30 @@ static int tbn_probe(struct platform_device *pdev) struct tbn_context *tbn = NULL; struct device_node *np = dev->of_node; int err = 0; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + struct sched_param param = { + .sched_priority = 10, + }; +#endif + tbn = devm_kzalloc(dev, sizeof(struct tbn_context), GFP_KERNEL); if (!tbn) goto failed; tbn->dev = dev; + tbn->event_resp.lptw_triggered = false; tbn_context = tbn; dev_set_drvdata(tbn->dev, tbn); if (of_property_read_u32(np, "tbn,max_devices", &tbn->max_devices)) tbn->max_devices = 1; - if (of_property_read_bool(np, "tbn,ap2aoc_gpio") && - of_property_read_bool(np, "tbn,aoc2ap_gpio")) { + err = of_property_read_u32(np, "tbn,mode", &tbn->mode); + if (err) tbn->mode = TBN_MODE_GPIO; + if (tbn->mode == TBN_MODE_GPIO) { tbn->ap2aoc_gpio = of_get_named_gpio(np, "tbn,ap2aoc_gpio", 0); if (gpio_is_valid(tbn->ap2aoc_gpio)) { err = devm_gpio_request_one(tbn->dev, tbn->ap2aoc_gpio, @@ -298,8 +460,32 @@ static int tbn_probe(struct platform_device *pdev) err = -EPROBE_DEFER; goto failed; } + + dev_info(tbn->dev, + "%s: gpios(aoc2ap: %d ap2aoc: %d)\n", + __func__, tbn->aoc2ap_gpio, tbn->ap2aoc_gpio); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + } else if (tbn->mode == TBN_MODE_AOC_CHANNEL) { + mutex_init(&tbn->event_lock); + + tbn->aoc_channel_task = kthread_run(&aoc_channel_kthread, tbn, + TBN_AOC_CHANNEL_THREAD_NAME); + if (IS_ERR(tbn->aoc_channel_task)) { + err = PTR_ERR(tbn->aoc_channel_task); + goto failed; + } + + err = sched_setscheduler(tbn->aoc_channel_task, SCHED_FIFO, ¶m); + if (err != 0) { + goto failed; + } +#endif + } else if (tbn->mode == TBN_MODE_MOCK) { + err = 0; } else { - tbn->mode = TBN_MODE_DISABLED; + dev_err(tbn->dev, "bus negotiator: invalid mode: %d\n", tbn->mode); + err = -EINVAL; + goto failed; } mutex_init(&tbn->dev_mask_mutex); @@ -309,29 +495,33 @@ static int tbn_probe(struct platform_device *pdev) complete_all(&tbn->bus_requested); complete_all(&tbn->bus_released); - dev_info(tbn->dev, - "%s: gpios(aoc2ap: %d ap2aoc: %d), mode %d\n", - __func__, tbn->aoc2ap_gpio, tbn->ap2aoc_gpio, tbn->mode); - - dev_dbg(tbn->dev, "bus negotiator initialized: %pK\n", tbn); + dev_info(tbn->dev, "bus negotiator initialized: %pK, mode: %d\n", tbn, tbn->mode); failed: - if (err) + if (err) { devm_kfree(dev, tbn); + tbn_context = NULL; + } return err; } static int tbn_remove(struct platform_device *pdev) { - struct tbn_context *tbn = dev_get_drvdata(&(pdev->dev)); - - free_irq(tbn->aoc2ap_irq, tbn); - if (gpio_is_valid(tbn->aoc2ap_gpio)) - gpio_free(tbn->aoc2ap_gpio); - if (gpio_is_valid(tbn->aoc2ap_gpio)) - gpio_free(tbn->aoc2ap_gpio); + struct device *dev = &pdev->dev; + struct tbn_context *tbn = dev_get_drvdata(dev); + if (tbn->mode == TBN_MODE_GPIO) { + free_irq(tbn->aoc2ap_irq, tbn); + if (gpio_is_valid(tbn->aoc2ap_gpio)) + gpio_free(tbn->aoc2ap_gpio); + if (gpio_is_valid(tbn->aoc2ap_gpio)) + gpio_free(tbn->aoc2ap_gpio); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + } else if (tbn->mode == TBN_MODE_AOC_CHANNEL) { + kthread_stop(tbn->aoc_channel_task); +#endif + } return 0; } diff --git a/touch_bus_negotiator.h b/touch_bus_negotiator.h index a4c157e..5697489 100644 --- a/touch_bus_negotiator.h +++ b/touch_bus_negotiator.h @@ -6,14 +6,20 @@ #include <linux/notifier.h> #include <linux/mutex.h> #include <linux/device.h> +#include <linux/cdev.h> +#include <linux/kthread.h> + +#define TBN_DEVICE_NAME "tbn" +#define TBN_CLASS_NAME "tbn" #define TBN_REQUEST_BUS_TIMEOUT_MS 500 #define TBN_RELEASE_BUS_TIMEOUT_MS 500 enum tbn_mode { - TBN_MODE_DISABLED, + TBN_MODE_DISABLED = 0, TBN_MODE_GPIO, - TBN_MODE_MAILBOX, + TBN_MODE_AOC_CHANNEL, + TBN_MODE_MOCK, }; enum tbn_bus_owner { @@ -21,22 +27,49 @@ enum tbn_bus_owner { TBN_BUS_OWNER_AOC = 1, }; +enum TbnOperation : __u32 { + TBN_OPERATION_IDLE = 0, + TBN_OPERATION_AP_RELEASE_BUS, + TBN_OPERATION_AP_REQUEST_BUS, +}; + +struct TbnEvent { + __u32 id; + enum TbnOperation operation; +} __packed; + +struct TbnEventResponse { + __u32 id; + __s32 err; + enum TbnOperation operation; + bool lptw_triggered; +} __packed; + struct tbn_context { struct device *dev; struct completion bus_requested; struct completion bus_released; struct mutex dev_mask_mutex; - u8 mode; + u32 mode; u32 max_devices; u32 registered_mask; u32 requested_dev_mask; int aoc2ap_gpio; int ap2aoc_gpio; int aoc2ap_irq; + struct task_struct *aoc_channel_task; + + /* event management */ + struct TbnEventResponse event_resp; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + struct TbnEvent event; + struct mutex event_lock; +#endif }; int register_tbn(u32 *output); void unregister_tbn(u32 *output); +int tbn_request_bus_with_result(u32 dev_mask, bool *lptw_triggered); int tbn_request_bus(u32 dev_mask); int tbn_release_bus(u32 dev_mask); diff --git a/touch_offload.c b/touch_offload.c index 6f2dab8..344b6ae 100644 --- a/touch_offload.c +++ b/touch_offload.c @@ -502,7 +502,9 @@ static long touch_offload_ioctl(struct file *file, unsigned int ioctl_num, (configure.config.filter_palm && !context->caps.filter_palm) || (configure.config.auto_reporting && - !context->caps.auto_reporting)) { + !context->caps.auto_reporting) || + (configure.config.coord_filter && + !context->caps.coord_filter)) { pr_err("%s: Invalid configuration enables unsupported features!\n", __func__); err = -EINVAL; @@ -728,8 +730,6 @@ int touch_offload_cleanup(struct touch_offload_context *context) { pr_debug("%s\n", __func__); - cdev_del(&context->dev); - device_destroy(context->cls, context->dev_num); class_destroy(context->cls); |