touchscreen_mmi: Add poison slot support.

Import a new gesture, poison slot.
When the report point is in this supression area, and the Y-axis
coordinate changes in little range over a period of time.
This is considered to be a point caused by the user's grip at edge.
Temporarily close all events report function for this slot from driver,
until this slot receives a release event or touch screen suspend.

Change-Id: Id7541aab8314e611d6943ed081f07776e5939f1b
Signed-off-by: haojl2 <haojl2@motorola.com>
Reviewed-on: https://gerrit.mot.com/1584617
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Jianqi Yang <yangj@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
haojl2 2020-05-28 16:59:48 +08:00 • committed by Jialei Hao
commit ef916eb278
7 changed files with 342 additions and 3 deletions

View file

@ -9,6 +9,10 @@ ifeq ($(TOUCHCLASS_MMI_DEBUG_INFO),true)
KERNEL_CFLAGS += CONFIG_TOUCHCLASS_MMI_DEBUG_INFO=y
endif
ifeq ($(TOUCHCLASS_MMI_GESTURE_POISON_EVENT),true)
KERNEL_CFLAGS += CONFIG_TOUCHCLASS_MMI_GESTURE_POISON_EVENT=y
endif
include $(CLEAR_VARS)
LOCAL_MODULE := touchscreen_mmi.ko
LOCAL_MODULE_TAGS := optional

View file

@ -11,6 +11,9 @@ endif
ifneq ($(filter m y, $(CONFIG_TOUCHCLASS_MMI_DEBUG_INFO)),)
EXTRA_CFLAGS += -DCONFIG_TOUCHCLASS_MMI_DEBUG_INFO
endif
ifneq ($(filter m y, $(CONFIG_TOUCHCLASS_MMI_GESTURE_POISON_EVENT)),)
EXTRA_CFLAGS += -DTS_MMI_TOUCH_GESTURE_POISON_EVENT
endif
obj-m := touchscreen_mmi.o
touchscreen_mmi-objs := touchscreen_mmi_class.o touchscreen_mmi_panel.o touchscreen_mmi_notif.o touchscreen_mmi_gesture.o

View file

@ -122,6 +122,11 @@ TOUCH_MMI_GET_ATTR_RW(suppression, FMT_HEX_INTEGER);
TOUCH_MMI_GET_ATTR_RW(hold_grip, FMT_HEX_INTEGER);
TOUCH_MMI_GET_ATTR_RW(hold_distance, FMT_HEX_INTEGER);
TOUCH_MMI_GET_ATTR_RW(gs_distance, FMT_HEX_INTEGER);
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
TOUCH_MMI_GET_ATTR_RW(poison_timeout, FMT_HEX_INTEGER);
TOUCH_MMI_GET_ATTR_RW(poison_distance, FMT_HEX_INTEGER);
TOUCH_MMI_GET_ATTR_RW(poison_trigger_distance, FMT_HEX_INTEGER);
#endif
TOUCH_MMI_GET_ATTR_WO(reset);
TOUCH_MMI_GET_ATTR_WO(pinctrl);
TOUCH_MMI_GET_ATTR_WO(refresh_rate);
@ -302,6 +307,11 @@ static struct attribute *sysfs_class_attrs[] = {
&dev_attr_refresh_rate.attr,
&dev_attr_charger_mode.attr,
&dev_attr_update_baseline.attr,
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
&dev_attr_poison_timeout.attr,
&dev_attr_poison_distance.attr,
&dev_attr_poison_trigger_distance.attr,
#endif
NULL,
};
@ -443,6 +453,13 @@ static int ts_mmi_sysfs_create_edge_entries(struct ts_mmi_dev *touch_cdev, bool
goto CREATE_HOLD_GRIP_FAILED;
}
}
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
if (touch_cdev->pdata.poison_slot_ctrl) {
touch_cdev->poison_distance = TOUCHSCREEN_MMI_DEFAULT_POISON_DISTANCE;
touch_cdev->poison_trigger_distance = TOUCHSCREEN_MMI_DEFAULT_POISON_TRIGGER_DISTANCE;
touch_cdev->poison_timeout = TOUCHSCREEN_MMI_DEFAULT_POISON_TIMEOUT_MS;
}
#endif
return 0;
}

View file

@ -15,9 +15,37 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/touchscreen_mmi.h>
#include <linux/sensors.h>
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
/* Declare depended feature */
#ifndef TS_MMI_TOUCH_GESTURE_LOG_EVENT
#define TS_MMI_TOUCH_GESTURE_LOG_EVENT
#endif
#ifndef TS_MMI_TOUCH_GESTURE_REPORT_TOUCH_EVENT
#define TS_MMI_TOUCH_GESTURE_REPORT_TOUCH_EVENT
#endif
#ifndef TS_MMI_TOUCH_GESTURE_SUPPRESSION
#define TS_MMI_TOUCH_GESTURE_SUPPRESSION
#endif
#ifndef TS_MMI_TOUCH_GESTURE_GS_DISTANCE
#define TS_MMI_TOUCH_GESTURE_GS_DISTANCE
#endif
#endif /* TS_MMI_TOUCH_GESTURE_POISON_EVENT */
#ifdef TS_MMI_TOUCH_GESTURE_SUPPRESSION
/* Declare depended feature */
#ifndef TS_MMI_TOUCH_GESTURE_GS_DISTANCE
#define TS_MMI_TOUCH_GESTURE_GS_DISTANCE
#endif
#endif /* TS_MMI_TOUCH_GESTURE_SUPPRESSION */
struct ts_mmi_sensor_platform_data {
struct input_dev *input_sensor_dev;
struct sensors_classdev ps_cdev;
@ -26,13 +54,159 @@ struct ts_mmi_sensor_platform_data {
struct ts_mmi_dev *touch_cdev;
};
#ifdef TS_MMI_TOUCH_GESTURE_LOG_EVENT
struct touch_event_with_time_data {
struct touch_event_data event;
ktime_t time;
};
#endif
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
struct touch_event_slot_poison_data {
struct touch_event_with_time_data center;
bool is_slot_poisoned;
};
#endif
struct ts_mmi_touch_events_data {
struct ts_mmi_dev *touch_cdev;
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
/* Touch slot is poisoned, do not report this slot point until slot release or IC resumed. */
struct touch_event_slot_poison_data poison_events[TS_MMI_MAX_POINT_NUM];
#endif
};
static struct ts_mmi_sensor_platform_data *sensor_pdata;
static struct ts_mmi_touch_events_data *events_data;
#ifdef TS_MMI_TOUCH_GESTURE_LOG_EVENT
static inline void ts_mmi_touch_log_event(struct touch_event_with_time_data *dst, const struct touch_event_data *src)
{
memcpy(&dst->event, src, sizeof(struct touch_event_data));
dst->time = ktime_get();
}
static inline void ts_mmi_touch_clear_event(struct touch_event_with_time_data *dst)
{
memset(dst, 0, sizeof(struct touch_event_with_time_data));
}
#endif /* TS_MMI_TOUCH_GESTURE_LOG_EVENT */
#ifdef TS_MMI_TOUCH_GESTURE_REPORT_TOUCH_EVENT
static inline void ts_mmi_touch_event_report_event_release(int index, struct input_dev *input_dev)
{
input_mt_slot(input_dev, index);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
}
#endif
#ifdef TS_MMI_TOUCH_GESTURE_GS_DISTANCE
static inline bool ts_mmi_touch_can_handle_gs_distance(void)
{
struct ts_mmi_dev *touch_cdev = events_data->touch_cdev;
return (touch_cdev->pdata.gs_distance_ctrl);
}
static inline int ts_mmi_touch_event_get_gs_distance(struct ts_mmi_dev *touch_cdev)
{
return (ts_mmi_touch_can_handle_gs_distance()) ? touch_cdev->gs_distance : TOUCHSCREEN_MMI_DEFAULT_GS_DISTANCE;
}
#endif /* TS_MMI_TOUCH_GESTURE_GS_DISTANCE */
#ifdef TS_MMI_TOUCH_GESTURE_SUPPRESSION
static inline bool ts_mmi_touch_can_handle_suppression(void)
{
struct ts_mmi_dev *touch_cdev = events_data->touch_cdev;
return ((touch_cdev->pdata.suppression_ctrl) &&
(touch_cdev->pdata.gs_distance_ctrl) &&
(touch_cdev->pdata.max_x > 0) &&
(touch_cdev->pdata.max_y > 0));
}
static inline bool ts_mmi_touch_event_is_in_suppression(struct touch_event_data *tev, struct ts_mmi_dev *touch_cdev)
{
int gs_distance = ts_mmi_touch_event_get_gs_distance(touch_cdev);
if (touch_cdev->suppression == TS_MMI_DISABLE_SUPPRESSION_ALL)
return false;
if (touch_cdev->suppression == TS_MMI_DISABLE_SUPPRESSION_LEFT)
return (tev->x > (touch_cdev->pdata.max_x - gs_distance)) ? true : false;
if (touch_cdev->suppression == TS_MMI_DISABLE_SUPPRESSION_RIGHT)
return (tev->x < gs_distance) ? true : false;
return ((tev->x < gs_distance) || (tev->x > (touch_cdev->pdata.max_x - gs_distance))) ? true : false;
}
#endif /* TS_MMI_TOUCH_GESTURE_SUPPRESSION */
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
static inline bool ts_mmi_touch_event_rescue_slot(int slot_id)
{
if (events_data->poison_events[slot_id].is_slot_poisoned) {
ts_mmi_touch_clear_event(&events_data->poison_events[slot_id].center);
events_data->poison_events[slot_id].is_slot_poisoned = false;
return true;
}
return false;
}
static inline bool ts_mmi_touch_can_handle_poison_slot(void)
{
struct ts_mmi_dev *touch_cdev = events_data->touch_cdev;
return ((touch_cdev->pdata.suppression_ctrl) &&
(touch_cdev->pdata.gs_distance_ctrl) &&
(touch_cdev->pdata.poison_slot_ctrl) &&
(touch_cdev->pdata.max_x > 0) &&
(touch_cdev->pdata.max_y > 0));
}
static inline bool ts_mmi_touch_event_is_in_poison_trigger(struct touch_event_data *tev, struct ts_mmi_dev *touch_cdev)
{
int trigger_distance = touch_cdev->poison_trigger_distance;
if (touch_cdev->suppression == TS_MMI_DISABLE_SUPPRESSION_ALL)
return false;
if (touch_cdev->suppression == TS_MMI_DISABLE_SUPPRESSION_LEFT)
return (tev->x > (touch_cdev->pdata.max_x - trigger_distance)) ? true : false;
if (touch_cdev->suppression == TS_MMI_DISABLE_SUPPRESSION_RIGHT)
return (tev->x < trigger_distance) ? true : false;
return ((tev->x < trigger_distance) || (tev->x > (touch_cdev->pdata.max_x - trigger_distance))) ? true : false;
}
static inline bool need_handle_poison_event(int id)
{
return ((events_data->poison_events[id].center.event.type == TS_COORDINATE_ACTION_PRESS) ||
(events_data->poison_events[id].center.event.type == TS_COORDINATE_ACTION_MOVE));
}
static inline bool is_far_from_poison_center(struct touch_event_data *tev)
{
int delta_y = abs(tev->y - events_data->poison_events[tev->id].center.event.y);
return (delta_y > events_data->touch_cdev->poison_distance) ? true : false;
}
static inline bool is_stack_at_poison_center(struct touch_event_data *tev)
{
if (events_data->poison_events[tev->id].center.time) {
unsigned long long duration = timediff_ms(
ktime_to_timespec(events_data->poison_events[tev->id].center.time),
ktime_to_timespec(ktime_get()));
return (duration > events_data->touch_cdev->poison_timeout) ? true : false;
}
return false;
}
static inline void update_poison_center(struct touch_event_data *tev)
{
return ts_mmi_touch_log_event(&events_data->poison_events[tev->id].center, tev);
}
#endif /* TS_MMI_TOUCH_GESTURE_POISON_EVENT */
static int ts_mmi_gesture_handler(struct gesture_event_data *gev)
{
int key_code;
@ -65,17 +239,74 @@ static int ts_mmi_gesture_handler(struct gesture_event_data *gev)
return 0;
}
static int ts_mmi_touch_event_handler(struct touch_event_data *tev)
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
static int ts_mmi_touch_event_poison_slot_handler(struct touch_event_data *tev, struct input_dev *input_dev)
{
struct ts_mmi_dev *touch_cdev = events_data->touch_cdev;
if (tev->type == TS_COORDINATE_ACTION_PRESS) {
if (ts_mmi_touch_event_is_in_poison_trigger(tev, touch_cdev)) {
update_poison_center(tev);
}
} else if (tev->type == TS_COORDINATE_ACTION_RELEASE) {
if (need_handle_poison_event(tev->id)) {
if (events_data->poison_events[tev->id].is_slot_poisoned) {
if (ts_mmi_touch_event_rescue_slot(tev->id))
pr_info("%s: Poison slot(%d) rescued\n", __func__, tev->id);
tev->skip_report = true;
tev->type = TS_COORDINATE_ACTION_NONE;
}
}
} else if (tev->type == TS_COORDINATE_ACTION_MOVE) {
if (need_handle_poison_event(tev->id)) {
if (events_data->poison_events[tev->id].is_slot_poisoned) {
dev_dbg(DEV_TS, "%s: slot(%d) is poisoned\n", __func__, tev->id);
tev->skip_report = true;
tev->type = TS_COORDINATE_ACTION_NONE;
} else if (is_far_from_poison_center(tev) && ts_mmi_touch_event_is_in_suppression(tev, touch_cdev)) {
update_poison_center(tev);
} else if (is_stack_at_poison_center(tev) && ts_mmi_touch_event_is_in_suppression(tev, touch_cdev)) {
dev_info(DEV_TS, "%s: slot(%d) is stacked near poison center. Mark this slot poisoned\n", __func__, tev->id);
ts_mmi_touch_event_report_event_release(tev->id, input_dev);
events_data->poison_events[tev->id].is_slot_poisoned = true;
tev->skip_report = true;
tev->type = TS_COORDINATE_ACTION_NONE;
}
}
}
return 0;
}
#endif /* TS_MMI_TOUCH_GESTURE_POISON_EVENT */
#ifdef TS_MMI_TOUCH_EDGE_GESTURE
static int ts_mmi_touch_event_edge_handler(struct touch_event_data *tev, struct input_dev *input_dev)
{
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
if (ts_mmi_touch_can_handle_poison_slot())
ts_mmi_touch_event_poison_slot_handler(tev, input_dev);
#endif
return 0;
}
#endif
static int ts_mmi_touch_event_handler(struct touch_event_data *tev, struct input_dev *input_dev)
{
struct ts_mmi_dev *touch_cdev = events_data->touch_cdev;
int ret = 0;
#ifdef TS_MMI_TOUCH_EDGE_GESTURE
ts_mmi_touch_event_edge_handler(tev, input_dev);
#endif
switch (tev->type) {
case TS_COORDINATE_ACTION_PRESS:
#if defined(CONFIG_TOUCHCLASS_MMI_DEBUG_INFO)
pr_info("%s: [P]Finger %d: Down, x=%d, y=%d, major=%d, minor=%d",
__func__, tev->id, tev->x, tev->y, tev->major, tev->minor);
#endif
case TS_COORDINATE_ACTION_MOVE:
break;
case TS_COORDINATE_ACTION_RELEASE:
@ -92,7 +323,8 @@ static int ts_mmi_touch_event_handler(struct touch_event_data *tev)
}
}
break;
case TS_COORDINATE_ACTION_NONE:
break;
default:
pr_info("%s: unsupport type=%d\n", __func__, tev->type);
@ -150,6 +382,19 @@ static struct sensors_classdev __maybe_unused sensors_touch_cdev = {
.sensors_poll_delay = NULL,
};
#ifdef TS_MMI_TOUCH_EDGE_GESTURE
int ts_mmi_gesture_suspend(struct ts_mmi_dev *touch_cdev)
{
#ifdef TS_MMI_TOUCH_GESTURE_POISON_EVENT
int i;
for (i = 0; i < TS_MMI_MAX_POINT_NUM; i++)
if (ts_mmi_touch_event_rescue_slot(i))
pr_info("%s: Poison slot(%d) rescued\n", __func__, i);
#endif
return 0;
}
#endif
int ts_mmi_gesture_init(struct ts_mmi_dev *touch_cdev)
{
struct input_dev *sensor_input_dev;

View file

@ -73,6 +73,9 @@ static int ts_mmi_panel_off(struct ts_mmi_dev *touch_cdev) {
touch_cdev->pm_mode = TS_MMI_PM_DEEPSLEEP;
}
#ifdef TS_MMI_TOUCH_EDGE_GESTURE
ts_mmi_gesture_suspend(touch_cdev);
#endif
TRY_TO_CALL(post_suspend);
dev_info(DEV_MMI, "%s: done\n", __func__);

View file

@ -46,6 +46,7 @@ int ts_mmi_parse_dt(struct ts_mmi_dev *touch_cdev,
{
struct device_node *chosen;
struct ts_mmi_dev_pdata *ppdata = &touch_cdev->pdata;
u32 coords[2];
dev_info(DEV_TS, "%s: Start parse touchscreen mmi device tree.\n", __func__);
if (!of_property_read_string(of_node, "mmi,class-entry-name", &ppdata->class_entry_name))
@ -113,11 +114,22 @@ int ts_mmi_parse_dt(struct ts_mmi_dev *touch_cdev,
ppdata->hold_grip_ctrl = true;
}
if (of_property_read_bool(of_node, "mmi,poison-slot-control")) {
dev_info(DEV_TS, "%s: using poison slot\n", __func__);
ppdata->poison_slot_ctrl = true;
}
if (of_property_read_bool(of_node, "mmi,fps_detection")) {
dev_info(DEV_TS, "%s: using fps detection\n", __func__);
ppdata->fps_detection = true;
}
if (!of_property_read_u32_array(of_node, "mmi,max_coords", coords, 2)) {
dev_info(DEV_TS, "%s: get max_coords property\n", __func__);
ppdata->max_x = coords[0] - 1;
ppdata->max_y = coords[1] - 1;
}
chosen = of_find_node_by_name(NULL, "chosen");
if (chosen) {
struct device_node *child;

View file

@ -18,6 +18,8 @@
#include <linux/device.h>
#include <linux/kfifo.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/input.h>
#if defined(CONFIG_PANEL_NOTIFICATIONS)
@ -101,6 +103,34 @@ struct msm_drm_notifier *evdata = evd; \
#endif /* LINUX_VERSION_CODE */
#endif /* CONFIG_PANEL_NOTIFICATIONS */
#if defined (TS_MMI_TOUCH_GESTURE_POISON_EVENT)
#ifndef TS_MMI_TOUCH_EDGE_GESTURE
#define TS_MMI_TOUCH_EDGE_GESTURE
#endif
#endif
#define NANO_SEC 1000000000
#define SEC_TO_MSEC 1000
#define NANO_TO_MSEC 1000000
static inline unsigned long long timediff_ms(
struct timespec start, struct timespec end)
{
struct timespec temp;
if ((end.tv_nsec - start.tv_nsec) < 0) {
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
temp.tv_nsec = NANO_SEC + end.tv_nsec - start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec - start.tv_sec;
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
}
return (temp.tv_sec * SEC_TO_MSEC) + (temp.tv_nsec / NANO_TO_MSEC);
}
#define TS_MMI_MAX_POINT_NUM 10
#define TS_MMI_MAX_FW_PATH 64
#define TS_MMI_MAX_ID_LEN 16
#define TS_MMI_MAX_VENDOR_LEN 16
@ -117,6 +147,7 @@ enum touch_event_mode {
};
struct touch_event_data {
bool skip_report;
enum touch_event_mode type; /* TS_TOUCH, TS_RELEASE */
int id; /* Finger id */
int x, y, w, p; /* X, Y, Area, Pressure */
@ -138,7 +169,7 @@ struct gesture_event_data {
struct ts_mmi_class_methods {
int (*report_gesture)(struct gesture_event_data *gev);
int (*get_class_fname)(struct device *dev , const char **fname);
int (*report_touch_event)(struct touch_event_data *tev);
int (*report_touch_event)(struct touch_event_data *tev, struct input_dev *input_dev);
struct kobject *kobj_notify;
};
@ -159,6 +190,15 @@ enum ts_mmi_pm_mode {
#define TS_MMI_UPDATE_BASELINE_OFF 0
#define TS_MMI_UPDATE_BASELINE_ON 1
#define TS_MMI_DISABLE_SUPPRESSION_NONE 0
#define TS_MMI_DISABLE_SUPPRESSION_ALL 1
#define TS_MMI_DISABLE_SUPPRESSION_LEFT 2
#define TS_MMI_DISABLE_SUPPRESSION_RIGHT 3
#define TOUCHSCREEN_MMI_DEFAULT_GS_DISTANCE 0x1E
#define TOUCHSCREEN_MMI_DEFAULT_POISON_TIMEOUT_MS 800
#define TOUCHSCREEN_MMI_DEFAULT_POISON_TRIGGER_DISTANCE 120
#define TOUCHSCREEN_MMI_DEFAULT_POISON_DISTANCE 25
/**
* struct touchscreen_mmi_methods - hold vendor provided functions
*
@ -190,6 +230,9 @@ enum ts_mmi_pm_mode {
int (*get_pill_region)(struct device *dev, void *uiadata);
int (*get_hold_distance)(struct device *dev, void *idata);
int (*get_gs_distance)(struct device *dev, void *idata);
int (*get_poison_timeout)(struct device *dev, void *idata);
int (*get_poison_distance)(struct device *dev, void *idata);
int (*get_poison_trigger_distance)(struct device *dev, void *idata);
/* SET methods */
int (*reset)(struct device *dev, int type);
int (*drv_irq)(struct device *dev, int state);
@ -202,6 +245,9 @@ enum ts_mmi_pm_mode {
int (*pill_region)(struct device *dev, int *region_array);
int (*hold_distance)(struct device *dev, int dis);
int (*gs_distance)(struct device *dev, int dis);
int (*poison_timeout)(struct device *dev, int timeout);
int (*poison_distance)(struct device *dev, int dis);
int (*poison_trigger_distance)(struct device *dev, int dis);
int (*update_baseline)(struct device *dev, int enable);
/* Firmware */
int (*firmware_update)(struct device *dev, char *fwname);
@ -238,6 +284,9 @@ struct ts_mmi_dev_pdata {
bool hold_distance_ctrl;
bool gs_distance_ctrl;
bool hold_grip_ctrl;
bool poison_slot_ctrl;
int max_x;
int max_y;
int ctrl_dsi;
int reset;
const char *class_entry_name;
@ -312,6 +361,9 @@ struct ts_mmi_dev {
int hold_distance;
int gs_distance;
int hold_grip;
int poison_timeout;
int poison_distance;
int poison_trigger_distance;
int charger_mode;
int reset;
int pinctrl;
@ -363,6 +415,9 @@ extern void ts_mmi_dev_unregister(struct device *parent);
extern int ts_mmi_parse_dt(struct ts_mmi_dev *touch_cdev, struct device_node *of_node);
extern int ts_mmi_gesture_init(struct ts_mmi_dev *data);
extern int ts_mmi_gesture_remove(struct ts_mmi_dev *data);
#ifdef TS_MMI_TOUCH_EDGE_GESTURE
extern int ts_mmi_gesture_suspend(struct ts_mmi_dev *touch_cdev);
#endif
/*sensor*/
extern bool ts_mmi_is_sensor_enable(void);