summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYen-Chao Chen <davidycchen@google.com>2022-02-21 10:00:23 +0000
committerAndroid Partner Code Review <android-gerrit-partner@google.com>2022-02-21 10:00:23 +0000
commitdf62c0c6d6af7052fcbd62f270fe9224daad34f2 (patch)
tree223d217c29fe9329a3a2c5417221eb3e7498589a
parenta2a6d77276ead3abb9200d417906641cf2dbb0af (diff)
parent15833c2bfe2d17dc577e6476b6673b0e058ea341 (diff)
downloadsynaptics_touch-df62c0c6d6af7052fcbd62f270fe9224daad34f2.tar.gz
Merge changes I428f1b9d,I00318352 into android13-gs-pixel-5.10
* changes: synaptics: enable continuously touch reporting synaptics: support to enable/disable the firmware grip and plam mode
-rw-r--r--syna_tcm2.c127
-rw-r--r--syna_tcm2.h30
-rw-r--r--syna_tcm2_sysfs.c273
-rw-r--r--tcm/synaptics_touchcom_core_dev.h2
4 files changed, 431 insertions, 1 deletions
diff --git a/syna_tcm2.c b/syna_tcm2.c
index 9a8159d..61d98c8 100644
--- a/syna_tcm2.c
+++ b/syna_tcm2.c
@@ -272,6 +272,109 @@ static void syna_dev_set_heatmap_mode(struct syna_tcm *tcm, bool en)
}
}
+/**
+ * syna_dev_restore_feature_setting()
+ *
+ * Restore the feature settings after the device resume.
+ *
+ * @param
+ * [ in] tcm: tcm driver handle
+ *
+ * @return
+ * on success, 0; otherwise, negative value on error.
+ */
+static void syna_dev_restore_feature_setting(struct syna_tcm *tcm)
+{
+ syna_dev_set_heatmap_mode(tcm, true);
+
+ syna_tcm_set_dynamic_config(tcm->tcm_dev,
+ DC_ENABLE_PALM_REJECTION,
+ (tcm->enable_fw_palm & 0x01),
+ RESP_IN_POLLING);
+
+ syna_tcm_set_dynamic_config(tcm->tcm_dev,
+ DC_ENABLE_GRIP_SUPPRESSION,
+ (tcm->enable_fw_grip & 0x01),
+ RESP_IN_POLLING);
+}
+/* Update a state machine used to toggle control of the touch IC's motion
+ * filter.
+ */
+static int syna_update_motion_filter(struct syna_tcm *tcm, u8 touches)
+{
+ /* Motion filter timeout, in milliseconds */
+ const u32 mf_timeout_ms = 500;
+ u8 next_state;
+
+ if (tcm->mf_mode == 0) {
+ if (touches != 0)
+ next_state = MF_UNFILTERED;
+ else
+ next_state = MF_FILTERED;
+ } else if (tcm->mf_mode == 1) {
+ /* Determine the next filter state. The motion filter is enabled by
+ * default and it is disabled while a single finger is touching the
+ * screen. If another finger is touched down or if a timeout expires,
+ * the motion filter is reenabled and remains enabled until all fingers
+ * are lifted.
+ */
+ next_state = tcm->mf_state;
+ switch (tcm->mf_state) {
+ case MF_FILTERED:
+ if (touches == 1) {
+ next_state = MF_UNFILTERED;
+ tcm->mf_downtime = ktime_get();
+ }
+ break;
+ case MF_UNFILTERED:
+ if (touches == 0) {
+ next_state = MF_FILTERED;
+ } else if (touches > 1 ||
+ ktime_after(ktime_get(),
+ ktime_add_ms(tcm->mf_downtime,
+ mf_timeout_ms))) {
+ next_state = MF_FILTERED_LOCKED;
+ }
+ break;
+ case MF_FILTERED_LOCKED:
+ if (touches == 0) {
+ next_state = MF_FILTERED;
+ }
+ break;
+ }
+ } else if (tcm->mf_mode == 2) {
+ next_state = MF_FILTERED;
+ } else {
+ /* Set 0 as default when an invalid value is found. */
+ tcm->mf_mode = 0;
+ return 0;
+ }
+
+ /* Queue work to update filter state */
+ if ((next_state == MF_UNFILTERED) !=
+ (tcm->mf_state == MF_UNFILTERED)) {
+ tcm->set_continuously_report = (next_state == MF_UNFILTERED) ? 0x01 : 0x00;
+ queue_work(tcm->event_wq, &tcm->motion_filter_work);
+ }
+
+ tcm->mf_state = next_state;
+
+ return 0;
+}
+
+static void syna_motion_filter_work(struct work_struct *work)
+{
+ struct syna_tcm *tcm = container_of(work, struct syna_tcm, motion_filter_work);
+
+ /* Send command to update filter state */
+ LOGD("setting motion filter = %s.\n",
+ tcm->set_continuously_report ? "false" : "true");
+ syna_tcm_set_dynamic_config(tcm->tcm_dev,
+ DC_CONTINUOUSLY_REPORT,
+ tcm->set_continuously_report,
+ RESP_IN_ATTN);
+}
+
#ifdef ENABLE_CUSTOM_TOUCH_ENTITY
/**
* syna_dev_parse_custom_touch_data_cb()
@@ -553,6 +656,7 @@ static void syna_dev_report_input_events(struct syna_tcm *tcm)
break;
case FINGER:
case GLOVED_OBJECT:
+ case PALM:
x = object_data[idx].x_pos;
y = object_data[idx].y_pos;
wx = object_data[idx].x_width;
@@ -630,6 +734,8 @@ static void syna_dev_report_input_events(struct syna_tcm *tcm)
input_set_timestamp(input_dev, tcm->coords_timestamp);
input_sync(input_dev);
+ syna_update_motion_filter(tcm, touch_count);
+
#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
}
#endif
@@ -839,6 +945,13 @@ static void syna_offload_set_running(struct syna_tcm *tcm, bool running)
if (tcm->offload.offload_running != running) {
tcm->offload.offload_running = running;
}
+ if (tcm->offload.offload_running == tcm->enable_fw_grip && tcm->enable_fw_grip < 2) {
+ tcm->enable_fw_grip = tcm->offload.offload_running ? 0 : 1;
+ syna_tcm_set_dynamic_config(tcm->tcm_dev,
+ DC_ENABLE_GRIP_SUPPRESSION,
+ tcm->enable_fw_grip,
+ RESP_IN_POLLING);
+ }
}
static void syna_offload_report(void *handle,
@@ -847,6 +960,7 @@ static void syna_offload_report(void *handle,
struct syna_tcm *tcm = (struct syna_tcm *)handle;
bool touch_down = 0;
int i;
+ int touch_count = 0;
syna_pal_mutex_lock(&tcm->tp_event_mutex);
@@ -855,6 +969,7 @@ static void syna_offload_report(void *handle,
for (i = 0; i < MAX_COORDS; i++) {
if (report->coords[i].status == COORD_STATUS_FINGER) {
input_mt_slot(tcm->input_dev, i);
+ touch_count++;
touch_down = 1;
input_report_key(tcm->input_dev, BTN_TOUCH,
touch_down);
@@ -885,6 +1000,7 @@ static void syna_offload_report(void *handle,
input_report_key(tcm->input_dev, BTN_TOOL_FINGER, touch_down);
input_sync(tcm->input_dev);
+ syna_update_motion_filter(tcm, touch_count);
syna_pal_mutex_unlock(&tcm->tp_event_mutex);
}
@@ -1737,7 +1853,7 @@ static int syna_dev_resume(struct device *dev)
goto exit;
}
- syna_dev_set_heatmap_mode(tcm, true);
+ syna_dev_restore_feature_setting(tcm);
retval = 0;
@@ -2512,6 +2628,11 @@ static int syna_dev_probe(struct platform_device *pdev)
goto err_heatmap_probe;
#endif
+ /* init motion filter mode */
+ tcm->mf_mode = 0;
+
+ INIT_WORK(&tcm->motion_filter_work, syna_motion_filter_work);
+
#ifdef HAS_SYSFS_INTERFACE
/* create the device file and register to char device classes */
retval = syna_cdev_create_sysfs(tcm, pdev);
@@ -2522,6 +2643,10 @@ static int syna_dev_probe(struct platform_device *pdev)
}
#endif
+ tcm->enable_fw_grip = 0x00;
+ tcm->enable_fw_palm = 0x01;
+ syna_dev_restore_feature_setting(tcm);
+
#if defined(USE_DRM_BRIDGE)
retval = syna_register_panel_bridge(tcm);
#elif defined(ENABLE_DISP_NOTIFIER)
diff --git a/syna_tcm2.h b/syna_tcm2.h
index 0edfb8b..ba7b95e 100644
--- a/syna_tcm2.h
+++ b/syna_tcm2.h
@@ -301,6 +301,17 @@ enum {
SYNA_BUS_REF_BUGREPORT = 0x0020,
};
+/* Motion filter finite state machine (FSM) states
+ * MF_FILTERED - default coordinate filtering
+ * MF_UNFILTERED - unfiltered single-touch coordinates
+ * MF_FILTERED_LOCKED - filtered coordinates. Locked until touch is lifted.
+ */
+typedef enum {
+ MF_FILTERED = 0,
+ MF_UNFILTERED = 1,
+ MF_FILTERED_LOCKED = 2
+} motion_filter_state_t;
+
#if defined(ENABLE_HELPER)
/**
* @brief: Tasks for helper
@@ -435,6 +446,23 @@ struct syna_tcm {
struct v4l2_heatmap v4l2;
#endif
+ /* Motion filter mode.
+ * 0 = Always unfilter.
+ * 1 = Dynamic change motion filter.
+ * 2 = Always filter by touch FW.
+ */
+ u8 mf_mode;
+ /* Payload for continuously report. */
+ u16 set_continuously_report;
+ /* Motion filter finite state machine (FSM) state */
+ motion_filter_state_t mf_state;
+ /* Time of initial single-finger touch down. This timestamp is used to
+ * compute the duration a single finger is touched before it is lifted.
+ */
+ ktime_t mf_downtime;
+ /* Work for motion filter commands. */
+ struct work_struct motion_filter_work;
+
/* IOCTL-related variables */
pid_t proc_pid;
struct task_struct *proc_task;
@@ -455,6 +483,8 @@ struct syna_tcm {
s16 *raw_data_buffer;
struct completion raw_data_completion;
bool high_sensitivity_mode;
+ u8 enable_fw_grip;
+ u8 enable_fw_palm;
#if defined(USE_DRM_BRIDGE)
struct drm_bridge panel_bridge;
diff --git a/syna_tcm2_sysfs.c b/syna_tcm2_sysfs.c
index a4512c9..1f6aa9e 100644
--- a/syna_tcm2_sysfs.c
+++ b/syna_tcm2_sysfs.c
@@ -973,6 +973,276 @@ static struct kobj_attribute kobj_attr_high_sensitivity =
__ATTR(high_sensitivity, 0664, syna_sysfs_high_sensitivity_show,
syna_sysfs_high_sensitivity_store);
+/**
+ * syna_sysfs_fw_grip_show()
+ *
+ * Attribute to show current grip suppression mode.
+ *
+ * @param
+ * [ in] kobj: an instance of kobj
+ * [ in] attr: an instance of kobj attribute structure
+ * [out] buf: string buffer shown on console
+ *
+ * @return
+ * on success, number of characters being output;
+ * otherwise, negative value on error.
+ */
+static ssize_t syna_sysfs_fw_grip_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int retval = 0;
+ struct device *p_dev;
+ struct kobject *p_kobj;
+ struct syna_tcm *tcm;
+
+ p_kobj = g_sysfs_dir->parent;
+ p_dev = container_of(p_kobj, struct device, kobj);
+ tcm = dev_get_drvdata(p_dev);
+
+ syna_pal_mutex_lock(&g_extif_mutex);
+
+ retval = scnprintf(buf, PAGE_SIZE, "%u\n", tcm->enable_fw_grip);
+
+ syna_pal_mutex_unlock(&g_extif_mutex);
+ return retval;
+}
+
+/**
+ * syna_sysfs_fw_grip_store()
+ *
+ * Attribute to set grip suppression mode.
+ * 0 - Disable fw grip suppression.
+ * 1 - Enable fw grip suppression.
+ * 2 - Force disable fw grip suppression.
+ * 3 - Force enable fw grip suppression.
+ *
+ * @param
+ * [ in] kobj: an instance of kobj
+ * [ in] attr: an instance of kobj attribute structure
+ * [ in] buf: string buffer input
+ * [ in] count: size of buffer input
+ *
+ * @return
+ * on success, return count; otherwise, return error code
+ */
+static ssize_t syna_sysfs_fw_grip_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int retval = count;
+ u8 input;
+ struct device *p_dev;
+ struct kobject *p_kobj;
+ struct syna_tcm *tcm;
+
+ p_kobj = g_sysfs_dir->parent;
+ p_dev = container_of(p_kobj, struct device, kobj);
+ tcm = dev_get_drvdata(p_dev);
+
+ if (kstrtou8(buf, 16, &input)) {
+ LOGE("Invalid input %s", buf);
+ return -EINVAL;
+ }
+
+ syna_set_bus_ref(tcm, SYNA_BUS_REF_SYSFS, true);
+ syna_pal_mutex_lock(&g_extif_mutex);
+
+ tcm->enable_fw_grip = input;
+
+ retval = syna_tcm_set_dynamic_config(tcm->tcm_dev,
+ DC_ENABLE_GRIP_SUPPRESSION,
+ (input & 0x01),
+ RESP_IN_ATTN);
+
+ LOGI("Set fw grip suppression mode %u.\n", tcm->enable_fw_grip);
+
+ retval = count;
+
+ syna_pal_mutex_unlock(&g_extif_mutex);
+ syna_set_bus_ref(tcm, SYNA_BUS_REF_SYSFS, false);
+ return retval;
+}
+
+static struct kobj_attribute kobj_attr_fw_grip =
+ __ATTR(fw_grip, 0664, syna_sysfs_fw_grip_show,
+ syna_sysfs_fw_grip_store);
+
+/**
+ * syna_sysfs_fw_palm_show()
+ *
+ * Attribute to show current palm rejection mode.
+ *
+ * @param
+ * [ in] kobj: an instance of kobj
+ * [ in] attr: an instance of kobj attribute structure
+ * [out] buf: string buffer shown on console
+ *
+ * @return
+ * on success, number of characters being output;
+ * otherwise, negative value on error.
+ */
+static ssize_t syna_sysfs_fw_palm_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int retval = 0;
+ struct device *p_dev;
+ struct kobject *p_kobj;
+ struct syna_tcm *tcm;
+
+ p_kobj = g_sysfs_dir->parent;
+ p_dev = container_of(p_kobj, struct device, kobj);
+ tcm = dev_get_drvdata(p_dev);
+
+ syna_pal_mutex_lock(&g_extif_mutex);
+
+ retval = scnprintf(buf, PAGE_SIZE, "%u\n", tcm->enable_fw_palm);
+
+ syna_pal_mutex_unlock(&g_extif_mutex);
+ return retval;
+}
+
+/**
+ * syna_sysfs_fw_palm_store()
+ *
+ * Attribute to set palm rejection mode.
+ * 0 - Disable fw palm rejection.
+ * 1 - Enable fw palm rejection.
+ * 2 - Force disable fw palm rejection.
+ * 3 - Force enable fw palm rejection.
+ *
+ * @param
+ * [ in] kobj: an instance of kobj
+ * [ in] attr: an instance of kobj attribute structure
+ * [ in] buf: string buffer input
+ * [ in] count: size of buffer input
+ *
+ * @return
+ * on success, return count; otherwise, return error code
+ */
+static ssize_t syna_sysfs_fw_palm_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int retval = count;
+ u8 input;
+ struct device *p_dev;
+ struct kobject *p_kobj;
+ struct syna_tcm *tcm;
+
+ p_kobj = g_sysfs_dir->parent;
+ p_dev = container_of(p_kobj, struct device, kobj);
+ tcm = dev_get_drvdata(p_dev);
+
+ if (kstrtou8(buf, 16, &input)) {
+ LOGE("Invalid input %s", buf);
+ return -EINVAL;
+ }
+
+ syna_set_bus_ref(tcm, SYNA_BUS_REF_SYSFS, true);
+ syna_pal_mutex_lock(&g_extif_mutex);
+
+ tcm->enable_fw_palm = input;
+
+ retval = syna_tcm_set_dynamic_config(tcm->tcm_dev,
+ DC_ENABLE_PALM_REJECTION,
+ (input & 0x01),
+ RESP_IN_ATTN);
+
+ LOGI("Set fw palm rejection mode %u.\n", tcm->enable_fw_palm);
+
+ retval = count;
+
+ syna_pal_mutex_unlock(&g_extif_mutex);
+ syna_set_bus_ref(tcm, SYNA_BUS_REF_SYSFS, false);
+ return retval;
+}
+
+static struct kobj_attribute kobj_attr_fw_palm =
+ __ATTR(fw_palm, 0664, syna_sysfs_fw_palm_show,
+ syna_sysfs_fw_palm_store);
+
+/**
+ * syna_sysfs_default_mf_show()
+ *
+ * Attribute to show motion filter mode.
+ *
+ * @param
+ * [ in] kobj: an instance of kobj
+ * [ in] attr: an instance of kobj attribute structure
+ * [out] buf: string buffer shown on console
+ *
+ * @return
+ * on success, number of characters being output;
+ * otherwise, negative value on error.
+ */
+static ssize_t syna_sysfs_mf_mode_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int retval = 0;
+ struct device *p_dev;
+ struct kobject *p_kobj;
+ struct syna_tcm *tcm;
+
+ p_kobj = g_sysfs_dir->parent;
+ p_dev = container_of(p_kobj, struct device, kobj);
+ tcm = dev_get_drvdata(p_dev);
+
+ syna_pal_mutex_lock(&g_extif_mutex);
+
+ retval = scnprintf(buf, PAGE_SIZE, "%d\n", tcm->mf_mode);
+
+ syna_pal_mutex_unlock(&g_extif_mutex);
+ return retval;
+}
+
+/**
+ * syna_sysfs_mf_mode_store()
+ *
+ * Attribute to set motion filter mode.
+ * 0 = Always unfilter.
+ * 1 = Dynamic change motion filter.
+ * 2 = Always filter by touch FW.
+ *
+ * @param
+ * [ in] kobj: an instance of kobj
+ * [ in] attr: an instance of kobj attribute structure
+ * [ in] buf: string buffer input
+ * [ in] count: size of buffer input
+ *
+ * @return
+ * on success, return count; otherwise, return error code
+ */
+static ssize_t syna_sysfs_mf_mode_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int retval = count;
+ u8 input;
+ struct device *p_dev;
+ struct kobject *p_kobj;
+ struct syna_tcm *tcm;
+
+ p_kobj = g_sysfs_dir->parent;
+ p_dev = container_of(p_kobj, struct device, kobj);
+ tcm = dev_get_drvdata(p_dev);
+
+ if (kstrtou8(buf, 16, &input)) {
+ LOGE("Invalid input %s", buf);
+ return -EINVAL;
+ }
+
+ syna_set_bus_ref(tcm, SYNA_BUS_REF_SYSFS, true);
+ syna_pal_mutex_lock(&g_extif_mutex);
+
+ tcm->mf_mode = input;
+
+ LOGI("Set motion filer mode %d.\n", tcm->mf_mode);
+
+ syna_pal_mutex_unlock(&g_extif_mutex);
+ syna_set_bus_ref(tcm, SYNA_BUS_REF_SYSFS, false);
+ return retval;
+}
+
+static struct kobj_attribute kobj_attr_mf_mode =
+ __ATTR(mf_mode, 0664, syna_sysfs_mf_mode_show,
+ syna_sysfs_mf_mode_store);
/**
* declaration of sysfs attributes
@@ -985,6 +1255,9 @@ static struct attribute *attrs[] = {
&kobj_attr_force_active.attr,
&kobj_attr_get_raw_data.attr,
&kobj_attr_high_sensitivity.attr,
+ &kobj_attr_fw_grip.attr,
+ &kobj_attr_fw_palm.attr,
+ &kobj_attr_mf_mode.attr,
NULL,
};
diff --git a/tcm/synaptics_touchcom_core_dev.h b/tcm/synaptics_touchcom_core_dev.h
index 204357f..043d686 100644
--- a/tcm/synaptics_touchcom_core_dev.h
+++ b/tcm/synaptics_touchcom_core_dev.h
@@ -209,6 +209,8 @@ enum dynamic_tcm_config_id {
DC_DISABLE_PROXIMITY = 0x10,
DC_HIGH_SENSITIVIRY_MODE = 0xCB,
DC_FORCE_DOZE_MODE = 0xF0,
+ DC_ENABLE_PALM_REJECTION = 0xF3,
+ DC_CONTINUOUSLY_REPORT = 0xF5,
};
/**