diff options
-rw-r--r-- | syna_tcm2.c | 87 | ||||
-rw-r--r-- | syna_tcm2.h | 28 | ||||
-rw-r--r-- | syna_tcm2_sysfs.c | 86 | ||||
-rw-r--r-- | tcm/synaptics_touchcom_core_dev.h | 1 |
4 files changed, 202 insertions, 0 deletions
diff --git a/syna_tcm2.c b/syna_tcm2.c index 584275d..ffff0ce 100644 --- a/syna_tcm2.c +++ b/syna_tcm2.c @@ -297,6 +297,83 @@ static void syna_dev_restore_feature_setting(struct syna_tcm *tcm) (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 /** @@ -657,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 @@ -881,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); @@ -889,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); @@ -919,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); } @@ -2541,6 +2623,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); diff --git a/syna_tcm2.h b/syna_tcm2.h index 08c8765..c46ebd8 100644 --- a/syna_tcm2.h +++ b/syna_tcm2.h @@ -299,6 +299,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 @@ -433,6 +444,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; diff --git a/syna_tcm2_sysfs.c b/syna_tcm2_sysfs.c index c9e535c..1f6aa9e 100644 --- a/syna_tcm2_sysfs.c +++ b/syna_tcm2_sysfs.c @@ -1160,6 +1160,91 @@ static struct kobj_attribute kobj_attr_fw_palm = 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 */ static struct attribute *attrs[] = { @@ -1172,6 +1257,7 @@ static struct attribute *attrs[] = { &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 700a340..043d686 100644 --- a/tcm/synaptics_touchcom_core_dev.h +++ b/tcm/synaptics_touchcom_core_dev.h @@ -210,6 +210,7 @@ enum dynamic_tcm_config_id { DC_HIGH_SENSITIVIRY_MODE = 0xCB, DC_FORCE_DOZE_MODE = 0xF0, DC_ENABLE_PALM_REJECTION = 0xF3, + DC_CONTINUOUSLY_REPORT = 0xF5, }; /** |