diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/Android.mk b/drivers/input/touchscreen/goodix_berlin_mmi/Android.mk index 9abbb250c8d4..007d0de0ba66 100644 --- a/drivers/input/touchscreen/goodix_berlin_mmi/Android.mk +++ b/drivers/input/touchscreen/goodix_berlin_mmi/Android.mk @@ -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 diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/Kbuild b/drivers/input/touchscreen/goodix_berlin_mmi/Kbuild index b57c1851ba73..b8178fde323d 100644 --- a/drivers/input/touchscreen/goodix_berlin_mmi/Kbuild +++ b/drivers/input/touchscreen/goodix_berlin_mmi/Kbuild @@ -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 diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_brl_hw.c b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_brl_hw.c index 892847fe2ae7..8dcf87819bd1 100644 --- a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_brl_hw.c +++ b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_brl_hw.c @@ -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; diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.c b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.c index e365eeed242e..4639cef18511 100644 --- a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.c +++ b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.c @@ -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(); diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.h b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.h index 88d6b067d4a2..00015d6c4854 100644 --- a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.h +++ b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_core.h @@ -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 diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_log_capture.c b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_log_capture.c new file mode 100644 index 000000000000..b9e586146299 --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_log_capture.c @@ -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 +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_mmi.c b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_mmi.c index ee21d44599c8..5f8bc4733e53 100644 --- a/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_mmi.c +++ b/drivers/input/touchscreen/goodix_berlin_mmi/goodix_ts_mmi.c @@ -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"); }