summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kbuild3
-rw-r--r--Kconfig5
-rw-r--r--Makefile1
-rw-r--r--goodix_brl_hw.c15
-rw-r--r--goodix_ts_core.c26
-rw-r--r--goodix_ts_core.h8
-rw-r--r--touch_apis.c36
-rw-r--r--touch_apis.h3
-rw-r--r--touch_mf_mode.c98
-rw-r--r--touch_mf_mode.h44
10 files changed, 235 insertions, 4 deletions
diff --git a/Kbuild b/Kbuild
index 8df601b..4bfdc99 100644
--- a/Kbuild
+++ b/Kbuild
@@ -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
diff --git a/Kconfig b/Kconfig
index 692694e..438f19b 100644
--- a/Kconfig
+++ b/Kconfig
@@ -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.
diff --git a/Makefile b/Makefile
index 7e4a4fc..d7e07bb 100644
--- a/Makefile
+++ b/Makefile
@@ -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