diff options
author | Wendly Li <wendlyli@google.com> | 2022-03-01 19:40:37 +0000 |
---|---|---|
committer | Wendly Li <wendlyli@google.com> | 2022-03-28 03:37:03 +0000 |
commit | 8e96b34084994ee6a085b7be916886ddcbe547b5 (patch) | |
tree | 4909adf10715b4c718a5ae6077349d3b24d07d8f | |
parent | 9d66e88a3704ee82c67c617ec6e7c9cef2403dca (diff) | |
download | goodix_touch-8e96b34084994ee6a085b7be916886ddcbe547b5.tar.gz |
Add motion filter mode
Bug: 214118990
Test: Check mf_mode works properly
Change-Id: I4dca2a71a396e7cff1cd5b7cc4d728a15312b8a9
Signed-off-by: Wendly Li <wendlyli@google.com>
-rw-r--r-- | Kbuild | 3 | ||||
-rw-r--r-- | Kconfig | 5 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | goodix_brl_hw.c | 15 | ||||
-rw-r--r-- | goodix_ts_core.c | 26 | ||||
-rw-r--r-- | goodix_ts_core.h | 8 | ||||
-rw-r--r-- | touch_apis.c | 36 | ||||
-rw-r--r-- | touch_apis.h | 3 | ||||
-rw-r--r-- | touch_mf_mode.c | 98 | ||||
-rw-r--r-- | touch_mf_mode.h | 44 |
10 files changed, 235 insertions, 4 deletions
@@ -12,4 +12,5 @@ goodix_brl_touch-objs += \ goodix_ts_utils.o \ goodix_ts_proc.o \ touch_apis.o \ - touch_pm.o + touch_pm.o \ + touch_mf_mode.o @@ -24,3 +24,8 @@ config TOUCHSCREEN_PM bool "touch power manager" help Say Y here if the touchscreen is connected via SPI bus. + +config TOUCHSCREEN_MOTION_FILTER + bool "touch motion filter" + help + Say Y here if motion filter is enabled. @@ -5,6 +5,7 @@ KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_GOODIX_BRL=m EXTRA_CFLAGS += -DDYNAMIC_DEBUG_MODULE EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_GOODIX_BRL_SPI EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_PM +EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_MOTION_FILTER #EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_TBN #EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_HEATMAP #EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_OFFLOAD diff --git a/goodix_brl_hw.c b/goodix_brl_hw.c index fd62579..2ec735d 100644 --- a/goodix_brl_hw.c +++ b/goodix_brl_hw.c @@ -1438,6 +1438,20 @@ int brl_set_scan_mode(struct goodix_ts_core *cd, int mode) return 0; } +#define GOODIX_CMD_SET_CONTINUOUSLY_REPORT_ENABLED 0xC3 +int brl_set_continuously_report_enabled(struct goodix_ts_core *cd, bool enabled) +{ + struct goodix_ts_cmd cmd; + + cmd.cmd = GOODIX_CMD_SET_CONTINUOUSLY_REPORT_ENABLED; + cmd.len = 5; + cmd.data[0] = enabled ? 0 : 1; + if (cd->hw_ops->send_cmd(cd, &cmd)) + ts_err("failed set continuous mode cmd"); + + return 0; +} + static struct goodix_ts_hw_ops brl_hw_ops = { .power_on = brl_power_on, .resume = brl_resume, @@ -1458,6 +1472,7 @@ static struct goodix_ts_hw_ops brl_hw_ops = { .get_capacitance_data = brl_get_capacitance_data, .ping = brl_dev_confirm, .set_scan_mode = brl_set_scan_mode, + .set_continuously_report_enabled = brl_set_continuously_report_enabled, }; struct goodix_ts_hw_ops *goodix_get_hw_ops(void) diff --git a/goodix_ts_core.c b/goodix_ts_core.c index 12ac0b4..a74ace9 100644 --- a/goodix_ts_core.c +++ b/goodix_ts_core.c @@ -749,6 +749,14 @@ static void goodix_ts_sysfs_exit(struct goodix_ts_core *core_data) sysfs_remove_group(&core_data->pdev->dev.kobj, &sysfs_group); } +#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) +int set_continuously_report_enabled(struct device *dev, bool enabled) +{ + struct goodix_ts_core *cd = dev_get_drvdata(dev); + return cd->hw_ops->set_continuously_report_enabled(cd, enabled); +} +#endif + int get_fw_version(struct device *dev, char *buf, size_t buf_size) { struct goodix_ts_core *cd = dev_get_drvdata(dev); @@ -1202,8 +1210,9 @@ static void goodix_ts_report_pen( } static void goodix_ts_report_finger( - struct input_dev *dev, struct goodix_touch_data *touch_data) + struct goodix_ts_core *cd, struct goodix_touch_data *touch_data) { + struct input_dev *dev = cd->input_dev; unsigned int touch_num = touch_data->touch_num; int i; @@ -1239,6 +1248,10 @@ static void goodix_ts_report_finger( input_report_key(dev, BTN_TOUCH, touch_num > 0 ? 1 : 0); input_sync(dev); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) + touch_mf_update_state(&cd->tmf, touch_num); +#endif + mutex_unlock(&dev->mutex); } @@ -1311,7 +1324,7 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) if (ts_event->event_type == EVENT_TOUCH) { /* report touch */ goodix_ts_report_finger( - core_data->input_dev, &ts_event->touch_data); + core_data, &ts_event->touch_data); } if (core_data->board_data.pen_enable && ts_event->event_type == EVENT_PEN) { @@ -2096,6 +2109,14 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) if (fb_register_client(&cd->fb_notifier)) ts_err("Failed to register fb notifier client:%d", ret); #endif + +#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) + cd->tmf.pdev = cd->pdev; + cd->tmf.set_continuously_report_enabled = + set_continuously_report_enabled; + touch_mf_init(&cd->tmf); +#endif + /* create sysfs files */ ret = goodix_ts_sysfs_init(cd); if (ret < 0) { @@ -2114,6 +2135,7 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) cd->apis_data.set_sensing_enabled = set_sensing_enabled; cd->apis_data.get_wake_lock_state = get_wake_lock_state; cd->apis_data.set_wake_lock_state = set_wake_lock_state; + cd->apis_data.tmf = &cd->tmf; ret = touch_apis_init(&cd->pdev->dev, &cd->apis_data); if (ret < 0) { diff --git a/goodix_ts_core.h b/goodix_ts_core.h index 6da626a..62a7233 100644 --- a/goodix_ts_core.h +++ b/goodix_ts_core.h @@ -43,6 +43,9 @@ #if IS_ENABLED(CONFIG_TOUCHSCREEN_PM) #include "touch_pm.h" #endif +#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) +#include "touch_mf_mode.h" +#endif #define GOODIX_CORE_DRIVER_NAME "goodix_ts" #define GOODIX_PEN_DRIVER_NAME "goodix_ts,pen" @@ -471,6 +474,8 @@ struct goodix_ts_hw_ops { struct goodix_ts_core *cd, struct ts_rawdata_info *info); int (*ping)(struct goodix_ts_core *cd); int (*set_scan_mode)(struct goodix_ts_core *cd, int mdoe); + int (*set_continuously_report_enabled)( + struct goodix_ts_core *cd, bool enabled); }; /* @@ -537,6 +542,9 @@ struct goodix_ts_core { #if IS_ENABLED(CONFIG_TOUCHSCREEN_PM) struct touch_pm tpm; #endif +#if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) + struct touch_mf tmf; +#endif }; /* external module structures */ diff --git a/touch_apis.c b/touch_apis.c index 2cd38ca..58a62e3 100644 --- a/touch_apis.c +++ b/touch_apis.c @@ -124,6 +124,38 @@ static ssize_t list_scan_mode_show( return ret; } +static ssize_t mf_mode_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "result: %d\n", apis->mf_mode); +} + +static ssize_t mf_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + enum touch_mf_mode mode = 0; + int ret = 0; + + if (buf == NULL || count < 0) + return -EINVAL; + + if (kstrtoint(buf, 10, (int *)&mode)) { + return -EINVAL; + } + + if (mode < TOUCH_MF_MODE_UNFILTERED || + mode > TOUCH_MF_MODE_AUTO_REPORT) { + return -EINVAL; + } + + ret = touch_mf_set_mode(apis->tmf, mode); + if (ret != 0) { + return ret; + } + apis->mf_mode = mode; + return count; +} + static ssize_t ping_show( struct device *dev, struct device_attribute *attr, char *buf) { @@ -200,7 +232,7 @@ static ssize_t scan_mode_store(struct device *dev, enum scan_mode mode = 0; int ret = 0; - if (buf == NULL || count < SCAN_MODE_AUTO) + if (buf == NULL || count < 0) return -EINVAL; if (kstrtoint(buf, 10, (int *)&mode)) { @@ -307,6 +339,7 @@ static DEVICE_ATTR_RO(fw_ver); static DEVICE_ATTR_RO(help); static DEVICE_ATTR_RW(irq_enabled); static DEVICE_ATTR_RO(list_scan_mode); +static DEVICE_ATTR_RW(mf_mode); static DEVICE_ATTR_RO(ping); static DEVICE_ATTR_RW(reset); static DEVICE_ATTR_RW(scan_mode); @@ -318,6 +351,7 @@ static struct attribute *sysfs_attrs[] = { &dev_attr_help.attr, &dev_attr_irq_enabled.attr, &dev_attr_list_scan_mode.attr, + &dev_attr_mf_mode.attr, &dev_attr_ping.attr, &dev_attr_reset.attr, &dev_attr_scan_mode.attr, diff --git a/touch_apis.h b/touch_apis.h index b189957..d1a501f 100644 --- a/touch_apis.h +++ b/touch_apis.h @@ -8,6 +8,7 @@ #ifndef _TOUCH_APIS_H_ #define _TOUCH_APIS_H_ +#include "touch_mf_mode.h" #include "touch_pm.h" enum scan_mode { @@ -29,6 +30,8 @@ enum reset_result { struct touch_apis_data { int reset_result; int scan_mode; + struct touch_mf *tmf; + enum touch_mf_mode mf_mode; int (*get_fw_version)(struct device *dev, char *buf, size_t buf_size); int (*get_irq_enabled)(struct device *dev); diff --git a/touch_mf_mode.c b/touch_mf_mode.c new file mode 100644 index 0000000..5715475 --- /dev/null +++ b/touch_mf_mode.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sysfs APIs for Google Pixel devices. + * + * Copyright 2022 Google LLC. + */ + +#include "touch_mf_mode.h" + +/* Update a state machine used to toggle control of the touch IC's motion + * filter. + */ +int touch_mf_update_state(struct touch_mf *tmf, u8 touches) +{ + /* Motion filter timeout, in milliseconds */ + const u32 mf_timeout_ms = 500; + u8 next_state = TOUCH_MF_STATE_UNFILTERED; + + mutex_lock(&tmf->update_mutex); + + tmf->touches = touches; + + if (tmf->mode == TOUCH_MF_MODE_UNFILTERED) { + next_state = TOUCH_MF_STATE_UNFILTERED; + } else if (tmf->mode == TOUCH_MF_MODE_DYNAMIC) { + /* 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 = tmf->state; + switch (tmf->state) { + case TOUCH_MF_STATE_FILTERED: + if (touches == 1) { + next_state = TOUCH_MF_STATE_UNFILTERED; + tmf->downtime = ktime_get(); + } + break; + case TOUCH_MF_STATE_UNFILTERED: + if (touches == 0) { + next_state = TOUCH_MF_STATE_FILTERED; + } else if (touches > 1 || + ktime_after(ktime_get(), + ktime_add_ms(tmf->downtime, + mf_timeout_ms))) { + next_state = TOUCH_MF_STATE_LOCKED; + } + break; + case TOUCH_MF_STATE_LOCKED: + if (touches == 0) { + next_state = TOUCH_MF_STATE_FILTERED; + } + break; + } + } else if (tmf->mode == TOUCH_MF_MODE_FILTERED) { + next_state = TOUCH_MF_STATE_FILTERED; + } else if (tmf->mode == TOUCH_MF_MODE_AUTO_REPORT) { + next_state = TOUCH_MF_STATE_UNFILTERED; + } + + /* Update continuously report switch if needed */ + if ((next_state == TOUCH_MF_STATE_UNFILTERED) != + (tmf->state == TOUCH_MF_STATE_UNFILTERED)) { + if (tmf->set_continuously_report_enabled != NULL) { + tmf->set_continuously_report_enabled(&tmf->pdev->dev, + next_state == TOUCH_MF_STATE_UNFILTERED); + } + } + + tmf->state = next_state; + + mutex_unlock(&tmf->update_mutex); + + return 0; +} + +int touch_mf_set_mode(struct touch_mf *tmf, enum touch_mf_mode mode) +{ + int ret = 0; + if ((mode < TOUCH_MF_MODE_UNFILTERED) || + (mode > TOUCH_MF_MODE_AUTO_REPORT)) { + ret = -EINVAL; + } else { + tmf->mode = mode; + touch_mf_update_state(tmf, tmf->touches); + } + return ret; +} + +int touch_mf_init(struct touch_mf *tmf) +{ + /* init motion filter mode */ + tmf->mode = TOUCH_MF_MODE_DYNAMIC; + tmf->touches = 0; + mutex_init(&tmf->update_mutex); + return 0; +} diff --git a/touch_mf_mode.h b/touch_mf_mode.h new file mode 100644 index 0000000..ead3924 --- /dev/null +++ b/touch_mf_mode.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Sysfs APIs for Google Pixel devices. + * + * Copyright 2022 Google LLC. + */ + +#ifndef _TOUCH_MF_MODE_H_ +#define _TOUCH_MF_MODE_H_ + +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/time.h> + +enum touch_mf_state { + TOUCH_MF_STATE_UNFILTERED = 0, + TOUCH_MF_STATE_FILTERED, + TOUCH_MF_STATE_LOCKED, +}; + +enum touch_mf_mode { + TOUCH_MF_MODE_UNFILTERED = 0, + TOUCH_MF_MODE_DYNAMIC, + TOUCH_MF_MODE_FILTERED, + TOUCH_MF_MODE_AUTO_REPORT, +}; + +struct touch_mf { + struct platform_device *pdev; + enum touch_mf_mode mode; + enum touch_mf_state state; + struct mutex update_mutex; + ktime_t downtime; + int touches; + + int (*set_continuously_report_enabled)( + struct device *dev, bool enabled); +}; + +extern int touch_mf_init(struct touch_mf *tmf); +extern int touch_mf_set_mode(struct touch_mf *tmf, enum touch_mf_mode mode); +extern int touch_mf_update_state(struct touch_mf *tmf, u8 touches); + +#endif |