mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 05:39:54 -04:00
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:
parent
b1ba34da62
commit
529e12857d
7 changed files with 354 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue