Support goodix ghost touch log capture

TP:
Support goodix ghost touch log capture

Change-Id: I49946e6eb8adcec4387915a8d80572be9e008789
Signed-off-by: Wenge Zhu <zhuwg1@motorola.com>
Reviewed-on: https://gerrit.mot.com/2583262
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Wei Deng <dengwei1@motorola.com>
Reviewed-by: Guobin Zhang <zhanggb@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Wenge Zhu 2023-04-20 12:04:40 +08:00 • committed by zhuwg1
commit 529e12857d
7 changed files with 354 additions and 1 deletions

View file

@ -53,6 +53,10 @@ ifneq ($(GTP_ENABLE_TOUCH_PALM),)
KBUILD_OPTIONS += CONFIG_INPUT_GOODIX_MMI_ENABLE_PALM=y
endif
ifeq ($(ENABLE_TP_GHOST_LOG_CAPTURE),true)
KBUILD_OPTIONS += CONFIG_GTP_GHOST_LOG_CAPTURE=y
endif
include $(CLEAR_VARS)
LOCAL_MODULE := goodix_brl_mmi.ko
LOCAL_MODULE_TAGS := optional

View file

@ -73,6 +73,13 @@ ifneq ($(filter m y,$(CONFIG_INPUT_GOODIX_MMI_ENABLE_PALM)),)
EXTRA_CFLAGS += -DGOODIX_PALM_SENSOR_EN
endif
ifeq ($(TARGET_BUILD_VARIANT), userdebug)
ifneq ($(filter m y, $(CONFIG_GTP_GHOST_LOG_CAPTURE)),)
EXTRA_CFLAGS += -DCONFIG_GTP_GHOST_LOG_CAPTURE
goodix_brl_mmi-objs += goodix_ts_log_capture.o
endif
endif
ifneq ($(findstring _factory,$(TARGET_PRODUCT)),)
USE_TARGET_PRODUCT := $(strip $(subst _factory,, $(TARGET_PRODUCT)))
else

View file

@ -42,6 +42,7 @@
#define GOODIX_IC_INFO_ADDR_BRA 0x10068
#define GOODIX_IC_INFO_ADDR 0x10070
#define TRIGGER_FRAME_CNT 50
enum brl_request_code {
BRL_REQUEST_CODE_CONFIG = 0x01,
@ -50,6 +51,20 @@ enum brl_request_code {
BRL_REQUEST_CODE_CLOCK = 0x04,
};
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
enum {
PROCESS_REF = 0,
PROCESS_RAW,
PROCESS_DIFF,
PROCESS_B_ARRAY
};
static struct frame_log_t {
u8 *buf;
int used;
} frame_log;
#endif
static int brl_select_spi_mode(struct goodix_ts_core *cd)
{
int ret;
@ -885,6 +900,8 @@ static void print_ic_info(struct goodix_ic_info *ic_info)
misc->fw_state_addr, misc->fw_state_len);
ts_info("FW-Buffer: 0x%04X, %d",
misc->fw_buffer_addr, misc->fw_buffer_max_len);
ts_info("frame_data_addr: 0x%04x",
misc->frame_data_addr);
ts_info("Touch-Data: 0x%04X, %d",
misc->touch_data_addr, misc->touch_data_head_len);
ts_info("point_struct_len: %d",
@ -1235,6 +1252,121 @@ static int goodix_touch_handler(struct goodix_ts_core *cd,
return 0;
}
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
int frame_log_capture_start(struct goodix_ts_core *cd)
{
struct goodix_ts_cmd tmp_cmd;
if (atomic_read(&cd->trigger_enable) != 0)
return 0;
frame_log.buf = vmalloc(4 * 1024);
if (!frame_log.buf)
return -ENOMEM;
frame_log.used = 0;
tmp_cmd.len = 5;
tmp_cmd.cmd = 0x90;
tmp_cmd.data[0] = 0x83;
cd->hw_ops->send_cmd(cd, &tmp_cmd);
atomic_set(&cd->trigger_enable, 1);
return 0;
}
static void goodix_cache_debug_log(struct goodix_ts_core *cd)
{
u8 sync = 0;
u8 diff_cmd[] = {0x00, 0x00, 0x05, 0x90, 0x82, 0x17, 0x01};
u8 raw_cmd[] = {0x00, 0x00, 0x05, 0x90, 0x81, 0x16, 0x01};
u8 b_cmd[] = {0x00, 0x00, 0x05, 0x90, 0x87, 0x1C, 0x01};
u8 freq_cmd[] = {0x00, 0x00, 0x05, 0x9C, 0x00, 0xA1, 0x00};
struct goodix_ts_hw_ops *hw_ops = cd->hw_ops;
struct goodix_ic_info_misc *misc = &cd->ic_info.misc;
static int discard_frames = 3;
static int frame_cnt;
static int freq_index;
static int process;
u32 cmd_addr = misc->cmd_addr;
int freq_num = cd->ic_info.parm.mutual_freq_num;
u8 frame_type = 0;
u8 *frame_ptr = misc->frame_data_addr - misc->touch_data_addr + cd->trigger_buf;
int frame_len = le16_to_cpup((__le16 *)(frame_ptr + 3));
static size_t total_cnt;
hw_ops->write(cd, misc->frame_data_addr, &sync, 1);
if (discard_frames > 0) {
discard_frames--;
return;
}
if (process == PROCESS_REF)
frame_type = 0x01;
else if (process == PROCESS_DIFF)
frame_type = 0x03;
else if (process == PROCESS_RAW)
frame_type = 0x02;
else if (process == PROCESS_B_ARRAY)
frame_type = 0x04;
memset(frame_log.buf + frame_log.used, 0xAA, 4);
frame_log.used += 4;
frame_log.buf[frame_log.used++] = frame_len & 0xFF;
frame_log.buf[frame_log.used++] = (frame_len >> 8) & 0xFF;
frame_log.buf[frame_log.used++] = frame_type;
memcpy(frame_log.buf + frame_log.used, frame_ptr, frame_len);
frame_log.used += frame_len;
total_cnt += frame_log.used;
ts_info("frame log used:%d, total cnt:%zu", frame_log.used, total_cnt);
put_fifo_with_discard(frame_log.buf, frame_log.used);
memset(frame_log.buf, 0x0, sizeof(frame_log.used));
frame_log.used = 0;
if (process == PROCESS_REF) {
hw_ops->write(cd, cmd_addr, diff_cmd, (int)sizeof(diff_cmd));
discard_frames = 3;
process = PROCESS_DIFF;
} else if (process == PROCESS_DIFF) {
frame_cnt++;
if (frame_cnt >= TRIGGER_FRAME_CNT) {
hw_ops->write(cd, cmd_addr, raw_cmd, (int)sizeof(raw_cmd));
discard_frames = 3;
frame_cnt = 0;
process = PROCESS_RAW;
}
} else if (process == PROCESS_RAW) {
frame_cnt++;
if (frame_cnt >= TRIGGER_FRAME_CNT) {
discard_frames = 3;
frame_cnt = 0;
freq_cmd[4] = freq_index;
freq_cmd[5] += freq_index;
freq_index++;
if (freq_index > freq_num) {
process = 0;
freq_index = 0;
hw_ops->reset(cd, 100);
atomic_set(&cd->trigger_enable, 0);
total_cnt = 0;
vfree(frame_log.buf);
ts_info("Notify raw data capture down");
sysfs_notify(cd->imports->kobj_notify, NULL, "log_trigger");
} else {
hw_ops->write(cd, cmd_addr, freq_cmd, (int)sizeof(freq_cmd));
usleep_range(5000, 5100);
hw_ops->write(cd, cmd_addr, b_cmd, (int)sizeof(b_cmd));
process = PROCESS_B_ARRAY;
}
}
} else if (process == PROCESS_B_ARRAY) {
discard_frames = 3;
frame_cnt = 0;
process = PROCESS_DIFF;
hw_ops->write(cd, cmd_addr, diff_cmd, (int)sizeof(diff_cmd));
}
}
#endif
static int brl_event_handler(struct goodix_ts_core *cd,
struct goodix_ts_event *ts_event)
{
@ -1247,8 +1379,19 @@ static int brl_event_handler(struct goodix_ts_core *cd,
pre_read_len = IRQ_EVENT_HEAD_LEN +
BYTES_PER_POINT * 2 + COOR_DATA_CHECKSUM_SIZE;
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
if (atomic_read(&cd->trigger_enable) == 1) {
ret = hw_ops->read(cd, misc->touch_data_addr, cd->trigger_buf, sizeof(cd->trigger_buf));
memcpy(pre_buf, cd->trigger_buf, pre_read_len);
goodix_cache_debug_log(cd);
} else {
ret = hw_ops->read(cd, misc->touch_data_addr,
pre_buf, pre_read_len);
}
#else
ret = hw_ops->read(cd, misc->touch_data_addr,
pre_buf, pre_read_len);
pre_buf, pre_read_len);
#endif
if (ret) {
ts_debug("failed get event head data");
return ret;

View file

@ -2545,6 +2545,12 @@ static int goodix_ts_probe(struct platform_device *pdev)
core_data->palm_release_delay_ms = GOODIX_PALM_RELEASE_DELAY_MS;
#endif
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
goodix_log_capture_register_misc();
if (ret)
ts_err("Failed register log device, %d", ret);
#endif
ts_info("goodix_ts_core probe success");
return 0;
@ -2577,6 +2583,10 @@ static int goodix_ts_remove(struct platform_device *pdev)
#endif
goodix_tools_exit();
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
goodix_log_capture_unregister_misc();
#endif
if (core_data->init_stage >= CORE_INIT_STAGE2) {
gesture_module_exit();
inspect_module_exit();

View file

@ -572,6 +572,11 @@ struct goodix_ts_core {
unsigned short gesture_cmd;
atomic_t pm_resume;
wait_queue_head_t pm_wq;
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
atomic_t trigger_enable;
u8 trigger_buf[2000];
#endif
};
/* external module structures */
@ -739,4 +744,12 @@ int goodix_stylus_dda_register_cdevice(void);
void goodix_dda_process_pen_report(struct goodix_pen_data *pen_data);
#endif
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
int frame_log_capture_start(struct goodix_ts_core *cd);
void put_fifo_with_discard(char *log_buf, int len);
void clear_kfifo(void);
int goodix_log_capture_register_misc(void);
int goodix_log_capture_unregister_misc(void);
#endif
#endif

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2023 Motorola Mobility LLC
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/kfifo.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include "goodix_ts_core.h"
#define LOG_FIFO_SIZE 8172
#define GOODIX_LOG_DEVICE_NAME "tp_tools"
struct goodix_ts_log {
struct kfifo fifo;
wait_queue_head_t wq;
struct miscdevice miscdev;
};
static struct goodix_ts_log ts_log_dev;
/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
void put_fifo_with_discard(char *log_buf, int len)
{
int ret = 0;
if (!kfifo_initialized(&ts_log_dev.fifo))
return;
if (kfifo_is_full(&ts_log_dev.fifo)) {
kfifo_skip(&ts_log_dev.fifo);
ts_info("Save a byte to a FIFO and discard the oldest byte if FIFO is full");
}
ret = kfifo_in(&ts_log_dev.fifo, log_buf, len);
wake_up_interruptible(&ts_log_dev.wq);
}
void clear_kfifo(void)
{
if (kfifo_len(&ts_log_dev.fifo) != 0) {
kfifo_reset(&ts_log_dev.fifo);
}
}
static __poll_t log_file_poll(struct file *file,
struct poll_table_struct *pt)
{
struct goodix_ts_log *log = file->private_data;
poll_wait(file, &log->wq, pt);
return !kfifo_is_empty(&log->fifo) ? (POLLPRI|POLLIN) : 0;
}
static ssize_t log_file_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct goodix_ts_log *log = file->private_data;
unsigned int copied;
int ret = 0;
if (kfifo_is_empty(&log->fifo)) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
ret = wait_event_interruptible(log->wq,
!kfifo_is_empty(&log->fifo));
if (ret == -ERESTARTSYS)
return -EINTR;
}
ret = kfifo_to_user(&log->fifo, buffer, count, &copied);
if (ret)
return ret;
return copied;
}
static int goodix_log_device_open(struct inode *inode, struct file *filp)
{
filp->private_data = &ts_log_dev;
ts_info("success open log device");
return 0;
}
static const struct file_operations log_device_fops = {
.owner = THIS_MODULE,
.open = goodix_log_device_open,
.read = log_file_read,
.poll = log_file_poll,
.llseek = noop_llseek,
};
int goodix_log_capture_register_misc(void)
{
int rc = 0;
init_waitqueue_head(&ts_log_dev.wq);
/* Create FIFO datastructure */
rc = kfifo_alloc(&ts_log_dev.fifo,
LOG_FIFO_SIZE, GFP_KERNEL);
if (rc)
return rc;
ts_log_dev.miscdev.minor = MISC_DYNAMIC_MINOR;
ts_log_dev.miscdev.name = GOODIX_LOG_DEVICE_NAME;
ts_log_dev.miscdev.fops = &log_device_fops;
rc = misc_register(&ts_log_dev.miscdev);
if (rc)
return rc;
return 0;
}
int goodix_log_capture_unregister_misc(void)
{
kfifo_free(&ts_log_dev.fifo);
misc_deregister(&ts_log_dev.miscdev);
return 0;
}

View file

@ -51,6 +51,13 @@ static ssize_t goodix_ts_sensitivity_store(struct device *dev,
static ssize_t goodix_ts_timestamp_show(struct device *dev,
struct device_attribute *attr, char *buf);
#endif
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
static ssize_t goodix_ts_log_trigger_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t goodix_ts_log_trigger_show(struct device *dev,
struct device_attribute *attr, char *buf);
#endif
static DEVICE_ATTR(edge, (S_IRUGO | S_IWUSR | S_IWGRP),
goodix_ts_edge_show, goodix_ts_edge_store);
@ -65,6 +72,10 @@ static DEVICE_ATTR(sensitivity, (S_IRUGO | S_IWUSR | S_IWGRP),
#ifdef CONFIG_GTP_LAST_TIME
static DEVICE_ATTR(timestamp, S_IRUGO, goodix_ts_timestamp_show, NULL);
#endif
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
static DEVICE_ATTR(log_trigger, (S_IRUGO | S_IWUSR | S_IWGRP),
goodix_ts_log_trigger_show, goodix_ts_log_trigger_store);
#endif
/* hal settings */
#define ROTATE_0 0
@ -122,6 +133,10 @@ static int goodix_ts_mmi_extend_attribute_group(struct device *dev, struct attri
ADD_ATTR(timestamp);
#endif
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
ADD_ATTR(log_trigger);
#endif
if (idx) {
ext_attributes[idx] = NULL;
*group = &ext_attr_group;
@ -698,6 +713,39 @@ static ssize_t goodix_ts_timestamp_show(struct device *dev,
}
#endif
#ifdef CONFIG_GTP_GHOST_LOG_CAPTURE
static ssize_t goodix_ts_log_trigger_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct platform_device *pdev;
struct goodix_ts_core *core_data;
dev = MMI_DEV_TO_TS_DEV(dev);
GET_GOODIX_DATA(dev);
if (!buf || count <= 0)
return 0;
clear_kfifo();
frame_log_capture_start(core_data);
return count;
}
static ssize_t goodix_ts_log_trigger_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev;
struct goodix_ts_core *core_data;
dev = MMI_DEV_TO_TS_DEV(dev);
GET_GOODIX_DATA(dev);
return scnprintf(buf, PAGE_SIZE, "0x%02x", 0x01);
}
#endif
static int goodix_ts_mmi_methods_get_vendor(struct device *dev, void *cdata) {
return scnprintf(TO_CHARP(cdata), TS_MMI_MAX_VENDOR_LEN, "%s", "goodix");
}