You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
kernel_samsung_sm7125/drivers/input/touchscreen/himax/hx831xx/himax_debug.c

2878 lines
74 KiB

/* SPDX-License-Identifier: GPL-2.0 */
/* Himax Android Driver Sample Code for debug nodes
*
* Copyright (C) 2019 Himax Corporation.
*
* 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 "himax_debug.h"
#include "himax_ic_core.h"
#ifdef HX_TP_PROC_2T2R
bool Is_2T2R;
EXPORT_SYMBOL(Is_2T2R);
int HX_RX_NUM_2;
int HX_TX_NUM_2;
#endif
uint8_t g_diag_arr_num;
int g_max_mutual;
int g_min_mutual = 0xFFFF;
int g_max_self;
int g_min_self = 0xFFFF;
/* moved from debug.h */
struct proc_dir_entry *himax_proc_vendor_file;
uint8_t byte_length;
uint8_t register_command[4];
uint8_t cfg_flag;
struct proc_dir_entry *himax_proc_stack_file;
struct proc_dir_entry *himax_proc_iir_file;
struct proc_dir_entry *himax_proc_dc_file;
struct proc_dir_entry *himax_proc_bank_file;
bool dsram_flag;
#ifdef HX_TP_PROC_2T2R
uint32_t *diag_mutual_2;
#endif
int32_t *diag_mutual;
int32_t *diag_mutual_new;
int32_t *diag_mutual_old;
uint8_t diag_max_cnt;
uint8_t hx_state_info[2];
uint8_t diag_coor[128];
int32_t diag_self[100];
int32_t diag_self_new[100];
int32_t diag_self_old[100];
struct proc_dir_entry *himax_proc_debug_file;
bool fw_update_complete;
int handshaking_result;
unsigned char debug_level_cmd;
uint8_t cmd_set[8];
uint8_t mutual_set_flag;
struct proc_dir_entry *himax_proc_flash_dump_file;
uint8_t *flash_buffer;
uint8_t g_flash_cmd;
uint8_t g_flash_progress;
bool g_flash_dump_rst; /*Fail = 0, Pass = 1*/
uint32_t **raw_data_array;
uint8_t X_NUM;
uint8_t Y_NUM;
uint8_t sel_type = 0x0D;
/* Moved from debug.h End */
char buf_tmp[BUF_SIZE] = {0};
uint8_t *reg_read_data;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
struct timespec64 timeStart, timeEnd, timeDelta;
#else
struct timespec timeStart, timeEnd, timeDelta;
#endif
int g_switch_mode;
/*
* Segment : Himax PROC Debug Function
*/
static ssize_t himax_crc_test_read(char *buf, size_t len)
{
ssize_t ret = 0;
uint8_t result = 0;
uint32_t size = 0;
g_core_fp.fp_sense_off(true);
msleep(20);
size = ic_data->flash_size;
result = g_core_fp.fp_calculateChecksum(false, size);
g_core_fp.fp_sense_on(0x01);
if (result)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CRC test is Pass!\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CRC test is Fail!\n");
return ret;
}
static ssize_t himax_vendor_read(struct file *file, char *buf,
size_t len, loff_t *pos)
{
ssize_t ret = 0;
if (!HX_PROC_SEND_FLAG) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "FW_VER = 0x%2.2X\n",
ic_data->vendor_fw_ver);
if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CONFIG_VER = 0x%2.2X\n",
ic_data->vendor_config_ver);
} else {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"TOUCH_VER = 0x%2.2X\n",
ic_data->vendor_touch_cfg_ver);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"DISPLAY_VER = 0x%2.2X\n",
ic_data->vendor_display_cfg_ver);
}
if (ic_data->vendor_cid_maj_ver < 0 &&
ic_data->vendor_cid_min_ver < 0) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CID_VER = NULL\n");
} else {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CID_VER = 0x%2.2X\n",
(ic_data->vendor_cid_maj_ver << 8 |
ic_data->vendor_cid_min_ver));
}
if (ic_data->vendor_panel_ver < 0) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"PANEL_VER = NULL\n");
} else {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"PANEL_VER = 0x%2.2X\n",
ic_data->vendor_panel_ver);
}
if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Cusomer = %s\n", ic_data->vendor_cus_info);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Project = %s\n", ic_data->vendor_proj_info);
}
#if defined(HX_AUTO_UPDATE_FW) || defined(HX_ZERO_FLASH)
#ifdef HX_EN_DYNAMIC_NAME
if (ic_data->vendor_semifac == 1) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"SEMI_FAC = UMC\n");
} else if (ic_data->vendor_semifac == 2) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"SEMI_FAC = PSC\n");
} else {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"SEMI_FAC = NULL\n");
}
#endif
#endif
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Himax Touch Driver Version:\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%s\n",
HIMAX_DRIVER_VER);
HX_PROC_SEND_FLAG = 1;
if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len))
I("%s,here:%d\n", __func__, __LINE__);
} else {
HX_PROC_SEND_FLAG = 0;
}
return ret;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_vendor_ops = {
.proc_read = himax_vendor_read,
};
#else
static const struct file_operations himax_proc_vendor_ops = {
.owner = THIS_MODULE,
.read = himax_vendor_read,
};
#endif
static ssize_t himax_attn_read(char *buf, size_t len)
{
ssize_t ret = 0;
struct himax_ts_data *ts_data;
ts_data = private_ts;
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "attn = %x\n",
himax_int_gpio_read(ts_data->pdata->gpio_irq));
return ret;
}
static ssize_t himax_int_en_read(char *buf, size_t len)
{
struct himax_ts_data *ts = private_ts;
size_t ret = 0;
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d\n",
ts->irq_enabled);
return ret;
}
static ssize_t himax_int_en_write(char *buf, size_t len)
{
struct himax_ts_data *ts = private_ts;
int ret = 0;
if (len >= 12) {
I("%s: no command exceeds 12 chars.\n", __func__);
return -EFAULT;
}
if (buf[0] == '0') {
himax_int_enable(0);
} else if (buf[0] == '1') {
himax_int_enable(1);
} else if (buf[0] == '2') {
himax_int_enable(0);
free_irq(ts->hx_irq, ts);
ts->irq_enabled = 0;
} else if (buf[0] == '3') {
ret = himax_int_en_set();
if (ret == 0) {
ts->irq_enabled = 1;
atomic_set(&ts->irq_state, 1);
}
} else
return -EINVAL;
return len;
}
static ssize_t himax_layout_read(char *buf, size_t len)
{
struct himax_ts_data *ts = private_ts;
size_t ret = 0;
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ",
ts->pdata->abs_x_min);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ",
ts->pdata->abs_x_max);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ",
ts->pdata->abs_y_min);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ",
ts->pdata->abs_y_max);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
return ret;
}
static ssize_t himax_layout_write(char *buf, size_t len)
{
struct himax_ts_data *ts = private_ts;
char buf_tmp[5] = {0};
int i = 0, j = 0, k = 0, ret;
unsigned long value;
int layout[4] = {0};
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
for (i = 0; i < 20; i++) {
if (buf[i] == ',' || buf[i] == '\n') {
memset(buf_tmp, 0x0, sizeof(buf_tmp));
if (i - j <= 5) {
memcpy(buf_tmp, buf + j, i - j);
} else {
I("buffer size is over 5 char\n");
return len;
}
j = i + 1;
if (k < 4) {
ret = kstrtoul(buf_tmp, 10, &value);
layout[k++] = value;
}
}
}
if (k == 4) {
ts->pdata->abs_x_min = layout[0];
ts->pdata->abs_x_max = (layout[1] - 1);
ts->pdata->abs_y_min = layout[2];
ts->pdata->abs_y_max = (layout[3] - 1);
I("%d, %d, %d, %d\n",
ts->pdata->abs_x_min, ts->pdata->abs_x_max,
ts->pdata->abs_y_min, ts->pdata->abs_y_max);
input_unregister_device(ts->input_dev);
if (ts->pdata->support_dex && ts->input_dev_pad)
input_unregister_device(ts->input_dev_pad);
ret = himax_dev_set(ts);
if (ret >= 0) {
himax_input_register(ts, ts->input_dev, INPUT_PROP_DIRECT);
if (ts->pdata->support_dex)
himax_input_register(ts, ts->input_dev_pad, INPUT_PROP_POINTER);
}
} else {
I("ERR@%d, %d, %d, %d\n",
ts->pdata->abs_x_min, ts->pdata->abs_x_max,
ts->pdata->abs_y_min, ts->pdata->abs_y_max);
}
return len;
}
static ssize_t himax_debug_level_read(char *buf, size_t len)
{
struct himax_ts_data *ts_data;
size_t ret = 0;
ts_data = private_ts;
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d\n",
ts_data->debug_log_level);
if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len))
I("%s,here:%d\n", __func__, __LINE__);
return ret;
}
static ssize_t himax_debug_level_write(char *buf, size_t len)
{
struct himax_ts_data *ts;
unsigned int i;
ts = private_ts;
if (len >= 12) {
I("%s: no command exceeds 12 chars.\n", __func__);
return -EFAULT;
}
ts->debug_log_level = 0;
for (i = 0; i < len; i++) {
if (buf[i] >= '0' && buf[i] <= '9')
ts->debug_log_level |= (buf[i] - '0');
else if (buf[i] >= 'A' && buf[i] <= 'F')
ts->debug_log_level |= (buf[i] - 'A' + 10);
else if (buf[i] >= 'a' && buf[i] <= 'f')
ts->debug_log_level |= (buf[i] - 'a' + 10);
if (i != len - 1)
ts->debug_log_level <<= 4;
}
I("Now debug level value=%d\n", ts->debug_log_level);
if (ts->debug_log_level & BIT(4)) {
I("Turn on/Enable Debug Mode for Inspection!\n");
goto END_FUNC;
}
if (ts->debug_log_level & BIT(3)) {
if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 &&
(ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 &&
(ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) {
ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)
/ (ts->pdata->abs_x_max - ts->pdata->abs_x_min);
ts->heightFactor =
(ts->pdata->screenHeight << SHIFTBITS) /
(ts->pdata->abs_y_max - ts->pdata->abs_y_min);
if (ts->widthFactor > 0 && ts->heightFactor > 0) {
ts->useScreenRes = 1;
} else {
ts->heightFactor = 0;
ts->widthFactor = 0;
ts->useScreenRes = 0;
}
} else {
I("Enable finger debug with raw position mode!\n");
}
} else {
ts->useScreenRes = 0;
ts->widthFactor = 0;
ts->heightFactor = 0;
}
END_FUNC:
return len;
}
static ssize_t himax_proc_register_read(char *buf, size_t len)
{
int ret = 0;
uint16_t loop_i;
memset(reg_read_data, 0x00, 128 * sizeof(uint8_t));
I("himax_register_show: %02X,%02X,%02X,%02X\n",
register_command[3], register_command[2],
register_command[1], register_command[0]);
g_core_fp.fp_register_read(register_command, 128, reg_read_data,
cfg_flag);
ret += snprintf(buf_tmp + ret, len - ret,
"command: %02X,%02X,%02X,%02X\n",
register_command[3], register_command[2],
register_command[1], register_command[0]);
for (loop_i = 0; loop_i < 128; loop_i++) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "0x%2.2X ",
reg_read_data[loop_i]);
if ((loop_i % 16) == 15)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
}
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
return ret;
}
static ssize_t himax_proc_register_write(char *buf, size_t len)
{
char buff_tmp[16] = {0};
uint8_t length = 0;
unsigned long result = 0;
uint8_t loop_i = 0;
uint16_t base = 2;
char *data_str = NULL;
uint8_t w_data[20] = {0};
uint8_t x_pos[20] = {0};
uint8_t count = 0;
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
memset(register_command, 0x0, sizeof(register_command));
I("himax %s\n", buf);
if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':' &&
buf[2] == 'x') {
length = strlen(buf);
/* I("%s: length = %d.\n", __func__,length); */
for (loop_i = 0; loop_i < length; loop_i++) {
/* find postion of 'x' */
if (buf[loop_i] == 'x') {
x_pos[count] = loop_i;
count++;
}
}
data_str = strrchr(buf, 'x');
I("%s: %s.\n", __func__, data_str);
length = strlen(data_str + 1);
switch (buf[0]) {
case 'r':
if (buf[3] == 'F' && buf[4] == 'E' && length == 4) {
length = length - base;
cfg_flag = 1;
memcpy(buff_tmp, data_str + base + 1, length);
} else {
cfg_flag = 0;
memcpy(buff_tmp, data_str + 1, length);
}
byte_length = length / 2;
if (!kstrtoul(buff_tmp, 16, &result)) {
for (loop_i = 0; loop_i < byte_length; loop_i++)
register_command[loop_i] =
(uint8_t)(result >> loop_i * 8);
}
if (strcmp(HX_85XX_H_SERIES_PWON,
private_ts->chip_name) == 0 && cfg_flag == 0)
cfg_flag = 2;
break;
case 'w':
if (buf[3] == 'F' && buf[4] == 'E') {
cfg_flag = 1;
memcpy(buff_tmp, buf + base + 3, length);
} else {
cfg_flag = 0;
memcpy(buff_tmp, buf + 3, length);
}
if (count < 3) {
byte_length = length / 2;
if (!kstrtoul(buff_tmp, 16, &result)) {
/* command */
for (loop_i = 0; loop_i < byte_length;
loop_i++) {
register_command[loop_i] =
(uint8_t)(result >> loop_i * 8);
}
}
if (!kstrtoul(data_str + 1, 16, &result)) {
/* data */
for (loop_i = 0; loop_i < byte_length;
loop_i++) {
w_data[loop_i] =
(uint8_t)(result >> loop_i * 8);
}
}
g_core_fp.fp_register_write(register_command,
byte_length, w_data, cfg_flag);
} else {
for (loop_i = 0; loop_i < count; loop_i++) {
/* parsing addr after 'x' */
memset(buff_tmp, 0x0, sizeof(buff_tmp));
if (cfg_flag != 0 && loop_i != 0)
byte_length = 2;
else
byte_length = x_pos[1] -
x_pos[0] - 2;/* original */
memcpy(buff_tmp, buf + x_pos[loop_i] + 1,
byte_length);
/* I("%s: buff_tmp = %s\n", __func__,
* buff_tmp);
*/
if (!kstrtoul(buff_tmp, 16, &result)) {
if (loop_i == 0) {
register_command[loop_i]
= (uint8_t)(result);
/* I("%s:
* register_command
* = %X\n", __func__,
* register_command[0]);
*/
} else {
w_data[loop_i - 1] =
(uint8_t)(result);
/* I("%s: w_data[%d] =
* %2X\n", __func__,
* loop_i - 1,
* w_data[loop_i - 1]);
*/
}
}
}
byte_length = count - 1;
if (strcmp(HX_85XX_H_SERIES_PWON,
private_ts->chip_name) == 0 && cfg_flag == 0)
cfg_flag = 2;
g_core_fp.fp_register_write(register_command,
byte_length, &w_data[0], cfg_flag);
}
break;
};
}
return len;
}
int32_t *getMutualBuffer(void)
{
return diag_mutual;
}
int32_t *getMutualNewBuffer(void)
{
return diag_mutual_new;
}
int32_t *getMutualOldBuffer(void)
{
return diag_mutual_old;
}
int32_t *getSelfBuffer(void)
{
return &diag_self[0];
}
int32_t *getSelfNewBuffer(void)
{
return &diag_self_new[0];
}
int32_t *getSelfOldBuffer(void)
{
return &diag_self_old[0];
}
void setMutualBuffer(uint8_t x_num, uint8_t y_num)
{
diag_mutual = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL);
}
void setMutualNewBuffer(uint8_t x_num, uint8_t y_num)
{
diag_mutual_new = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL);
}
void setMutualOldBuffer(uint8_t x_num, uint8_t y_num)
{
diag_mutual_old = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL);
}
#ifdef HX_TP_PROC_2T2R
int32_t *getMutualBuffer_2(void)
{
return diag_mutual_2;
}
void setMutualBuffer_2(uint8_t x_num_2, uint8_t y_num_2)
{
diag_mutual_2 =
kzalloc(x_num_2 * y_num_2 * sizeof(int32_t), GFP_KERNEL);
}
#endif
int himax_set_diag_cmd(struct himax_ic_data *ic_data,
struct himax_report_data *hx_touch_data)
{
struct himax_ts_data *ts = private_ts;
int32_t *mutual_data;
int32_t *self_data;
int mul_num;
int self_num;
/* int RawDataLen = 0; */
hx_touch_data->diag_cmd = ts->diag_cmd;
if (hx_touch_data->diag_cmd >= 1 && hx_touch_data->diag_cmd <= 7) {
/* Check event stack CRC */
if (!g_core_fp.fp_diag_check_sum(hx_touch_data))
goto bypass_checksum_failed_packet;
#ifdef HX_TP_PROC_2T2R
if (Is_2T2R && (hx_touch_data->diag_cmd >= 4 &&
hx_touch_data->diag_cmd <= 6)) {
mutual_data = getMutualBuffer_2();
self_data = getSelfBuffer();
/* initiallize the block number of mutual and self */
mul_num = ic_data->HX_RX_NUM_2 * ic_data->HX_TX_NUM_2;
#ifdef HX_EN_SEL_BUTTON
self_num = ic_data->HX_RX_NUM_2 +
ic_data->HX_TX_NUM_2 + ic_data->HX_BT_NUM;
#else
self_num = ic_data->HX_RX_NUM_2 + ic_data->HX_TX_NUM_2;
#endif
} else
#endif
{
mutual_data = getMutualBuffer();
self_data = getSelfBuffer();
/* initiallize the block number of mutual and self */
mul_num = ic_data->HX_RX_NUM * ic_data->HX_TX_NUM;
#ifdef HX_EN_SEL_BUTTON
self_num = ic_data->HX_RX_NUM +
ic_data->HX_TX_NUM + ic_data->HX_BT_NUM;
#else
self_num = ic_data->HX_RX_NUM + ic_data->HX_TX_NUM;
#endif
}
g_core_fp.fp_diag_parse_raw_data(hx_touch_data, mul_num,
self_num, hx_touch_data->diag_cmd, mutual_data,
self_data);
} else if (hx_touch_data->diag_cmd == 8) {
memset(diag_coor, 0x00, sizeof(diag_coor));
memcpy(&(diag_coor[0]), &hx_touch_data->hx_coord_buf[0],
hx_touch_data->touch_info_size);
}
/* assign state info data */
memcpy(&(hx_state_info[0]), &hx_touch_data->hx_state_info[0], 2);
return NO_ERR;
bypass_checksum_failed_packet:
return 1;
}
/* #if defined(HX_DEBUG_LEVEL) */
void himax_log_touch_data(int start)
{
int loop_i = 0;
int print_size = 0;
uint8_t *buf;
if (start == 1)
return; /* report data when end of ts_work*/
if (hx_touch_data->diag_cmd > 0) {
print_size = hx_touch_data->touch_all_size;
buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL);
memcpy(buf, hx_touch_data->hx_coord_buf,
hx_touch_data->touch_info_size);
memcpy(&buf[hx_touch_data->touch_info_size],
hx_touch_data->hx_rawdata_buf,
print_size - hx_touch_data->touch_info_size);
}
#if defined(HX_SMART_WAKEUP)
else if (private_ts->SMWP_enable > 0 && private_ts->suspended) {
print_size = hx_touch_data->event_size;
buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL);
memcpy(buf, hx_touch_data->hx_event_buf, print_size);
}
#endif
else if (hx_touch_data->diag_cmd == 0) {
print_size = hx_touch_data->touch_info_size;
buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL);
memcpy(buf, hx_touch_data->hx_coord_buf, print_size);
} else {
E("%s:cmd fault\n", __func__);
}
for (loop_i = 0; loop_i < print_size; loop_i += 8) {
if ((loop_i + 7) >= print_size) {
I("P %2d = 0x%2.2X P %2d = 0x%2.2X ",
loop_i, buf[loop_i], loop_i + 1, buf[loop_i + 1]);
I("P %2d = 0x%2.2X P %2d = 0x%2.2X\n",
loop_i + 2, buf[loop_i + 2], loop_i + 3, buf[loop_i + 3]);
break;
}
I("P %2d = 0x%2.2X P %2d = 0x%2.2X ",
loop_i, buf[loop_i], loop_i + 1, buf[loop_i + 1]);
I("P %2d = 0x%2.2X P %2d = 0x%2.2X ",
loop_i + 2, buf[loop_i + 2], loop_i + 3, buf[loop_i + 3]);
I("P %2d = 0x%2.2X P %2d = 0x%2.2X ",
loop_i + 4, buf[loop_i + 4], loop_i + 5, buf[loop_i + 5]);
I("P %2d = 0x%2.2X P %2d = 0x%2.2X ",
loop_i + 6, buf[loop_i + 6], loop_i + 7, buf[loop_i + 7]);
I("\n");
}
kfree(buf);
}
void himax_log_touch_event(struct himax_ts_data *ts, int start)
{
int loop_i = 0;
if (start == 1)
return; /*report data when end of ts_work*/
if (g_target_report_data->finger_on > 0 &&
g_target_report_data->finger_num > 0) {
for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
if (g_target_report_data->x[loop_i] >= 0
&& g_target_report_data->x[loop_i]
<= ts->pdata->abs_x_max
&& g_target_report_data->y[loop_i] >= 0
&& g_target_report_data->y[loop_i]
<= ts->pdata->abs_y_max) {
I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d,Int_Delay_Counter:%d\n",
loop_i + 1,
g_target_report_data->x[loop_i],
g_target_report_data->y[loop_i],
g_target_report_data->w[loop_i],
g_target_report_data->w[loop_i],
loop_i + 1,
g_target_report_data->ig_count);
}
}
} else if (g_target_report_data->finger_on == 0 &&
g_target_report_data->finger_num == 0) {
I("All Finger leave\n");
} else {
I("%s : wrong input!\n", __func__);
}
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
void himax_log_touch_int_devation(int touched)
{
if (touched == HX_FINGER_ON) {
ktime_get_real_ts64(&timeStart);
/* I(" Irq start time = %ld.%06ld s\n",
* timeStart.tv_sec, timeStart.tv_nsec/1000);
*/
} else if (touched == HX_FINGER_LEAVE) {
ktime_get_real_ts64(&timeEnd);
timeDelta.tv_nsec =
(timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) -
(timeStart.tv_sec * 1000000000 + timeStart.tv_nsec);
/* I("Irq finish time = %ld.%06ld s\n",
* timeEnd.tv_sec, timeEnd.tv_nsec/1000);
*/
I("Touch latency = %ld us\n", timeDelta.tv_nsec / 1000);
I("bus_speed = %d kHz\n", private_ts->bus_speed);
if (g_target_report_data->finger_on == 0 && g_target_report_data->finger_num == 0)
I("All Finger leave\n");
} else {
I("%s : wrong input!\n", __func__);
}
}
#else
void himax_log_touch_int_devation(int touched)
{
if (touched == HX_FINGER_ON) {
getnstimeofday(&timeStart);
/* I(" Irq start time = %ld.%06ld s\n",
* timeStart.tv_sec, timeStart.tv_nsec/1000);
*/
} else if (touched == HX_FINGER_LEAVE) {
getnstimeofday(&timeEnd);
timeDelta.tv_nsec =
(timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) -
(timeStart.tv_sec * 1000000000 + timeStart.tv_nsec);
/* I("Irq finish time = %ld.%06ld s\n",
* timeEnd.tv_sec, timeEnd.tv_nsec/1000);
*/
I("Touch latency = %ld us\n", timeDelta.tv_nsec / 1000);
I("bus_speed = %d kHz\n", private_ts->bus_speed);
if (g_target_report_data->finger_on == 0 && g_target_report_data->finger_num == 0)
I("All Finger leave\n");
} else {
I("%s : wrong input!\n", __func__);
}
}
#endif
#define RAW_DOWN_STATUS "status: Raw:F:%02d Down, X:%d, Y:%d, W:%d\n"
#define RAW_UP_STATUS "status: Raw:F:%02d Up, X:%d, Y:%d\n"
void himax_log_touch_event_detail(struct himax_ts_data *ts, int start)
{
int loop_i = 0;
if (start == HX_FINGER_LEAVE) {
for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
if (((ts->old_finger >> loop_i & 1) == 0) &&
((ts->pre_finger_mask >> loop_i & 1) == 1)) {
if (g_target_report_data->x[loop_i] >= 0
&& g_target_report_data->x[loop_i]
<= ts->pdata->abs_x_max
&& g_target_report_data->y[loop_i] >= 0
&& g_target_report_data->y[loop_i]
<= ts->pdata->abs_y_max) {
I(RAW_DOWN_STATUS,
loop_i + 1,
g_target_report_data->x[loop_i],
g_target_report_data->y[loop_i],
g_target_report_data->w[loop_i]);
}
} else if ((((ts->old_finger >> loop_i & 1) == 1) &&
((ts->pre_finger_mask >> loop_i & 1) == 0))) {
I(RAW_UP_STATUS,
loop_i + 1, ts->pre_finger_data[loop_i][0],
ts->pre_finger_data[loop_i][1]);
} else {
/* I("dbg hx_point_num=%d, old_finger=0x%02X,"
* " pre_finger_mask=0x%02X\n",
* ts->hx_point_num, ts->old_finger,
* ts->pre_finger_mask);
*/
}
}
}
}
void himax_ts_dbg_func(struct himax_ts_data *ts, int start)
{
if (ts->debug_log_level & BIT(0)) {
/* I("debug level 1\n"); */
himax_log_touch_data(start);
}
if (ts->debug_log_level & BIT(1)) {
/* I("debug level 2\n"); */
himax_log_touch_event(ts, start);
}
if (ts->debug_log_level & BIT(2)) {
/* I("debug level 4\n"); */
himax_log_touch_int_devation(start);
}
if (ts->debug_log_level & BIT(3)) {
/* I("debug level 8\n"); */
himax_log_touch_event_detail(ts, start);
}
}
static int himax_change_mode(uint8_t str_pw, uint8_t end_pw)
{
uint8_t data[4] = {0};
int count = 0;
/*sense off*/
g_core_fp.fp_sense_off(true);
/*mode change*/
data[1] = str_pw; data[0] = str_pw;
if (g_core_fp.fp_assign_sorting_mode != NULL)
g_core_fp.fp_assign_sorting_mode(data);
/*sense on*/
g_core_fp.fp_sense_on(1);
/*wait mode change*/
do {
if (g_core_fp.fp_check_sorting_mode != NULL)
g_core_fp.fp_check_sorting_mode(data);
if ((data[0] == end_pw) && (data[1] == end_pw))
return 0;
I("Now retry %d times!\n", count++);
msleep(50);
} while (count < 50);
return ERR_WORK_OUT;
}
static ssize_t himax_diag_cmd_write(char *buf, size_t len)
{
struct himax_ts_data *ts = private_ts;
char *dbg_map_str = "mode:";
char *str_ptr = NULL;
int str_len = 0;
int rst = 0;
uint8_t str_pw = 0;
uint8_t end_pw = 0;
switch (len) {
case 1:/*raw out select - diag,X*/
if (!kstrtoint(buf, 16, &rst)) {
ts->diag_cmd = rst;
I("%s: dsram_flag = %d\n", __func__, dsram_flag);
if (dsram_flag) {
/*Cancal work queue and return to stack*/
process_type = 0;
dsram_flag = false;
cancel_delayed_work(&ts->himax_diag_delay_wrok);
himax_int_enable(1);
g_core_fp.fp_return_event_stack();
}
g_core_fp.fp_diag_register_set(ts->diag_cmd, 0);
I("%s: Set raw out select 0x%X.\n", __func__, ts->diag_cmd);
}
if (!ts->diag_cmd) {
if (mode_flag) /*back to normal mode*/
himax_change_mode(0x00, 0x99);
}
break;
case 2:/*data processing + rawout select - diag,XY*/
if (!kstrtoint(buf, 16, &rst)) {
process_type = (rst >> 4) & 0xF;
ts->diag_cmd = rst & 0xF;
}
if (process_type <= 0 || ts->diag_cmd <= 0)
break;
else if (process_type > 0 && process_type <= 3) {
if (!dsram_flag) {
/*Start wrok queue*/
himax_int_enable(0);
g_core_fp.fp_diag_register_set(ts->diag_cmd, process_type);
queue_delayed_work(ts->himax_diag_wq,
&ts->himax_diag_delay_wrok, 2 * HZ / 100);
dsram_flag = true;
I("%s: Start get raw data in DSRAM\n", __func__);
} else {
g_core_fp.fp_diag_register_set(ts->diag_cmd, process_type);
}
}
break;
case 9:/*change mode - mode:XXYY(start PW,end PW)*/
str_ptr = strnstr(buf, dbg_map_str, len);
if (str_ptr) {
str_len = strlen(dbg_map_str);
if (!kstrtoint(buf + str_len, 16, &rst)) {
str_pw = (rst >> 8) & 0xFF;
end_pw = rst & 0xFF;
if (!himax_change_mode(str_pw, end_pw)) {
mode_flag = 1;
I("%s: change mode 0x%4X. str_pw = %2X, end_pw = %2X\n", __func__, rst, str_pw, end_pw);
} else
I("%s: change mode failed. str_pw = %2X, end_pw = %2X\n", __func__, str_pw, end_pw);
}
} else {
I("%s: Can't find string [%s].\n", __func__, dbg_map_str);
}
break;
default:
I("%s: Length is not correct.\n", __func__);
}
return len;
}
static ssize_t himax_diag_arrange_write(char *buf, size_t len)
{
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
g_diag_arr_num = buf[0] - '0';
I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num);
return len;
}
void himax_get_mutual_edge(void)
{
int i = 0;
for (i = 0; i < (ic_data->HX_RX_NUM * ic_data->HX_TX_NUM); i++) {
if (diag_mutual[i] > g_max_mutual)
g_max_mutual = diag_mutual[i];
if (diag_mutual[i] < g_min_mutual)
g_min_mutual = diag_mutual[i];
}
}
void himax_get_self_edge(void)
{
int i = 0;
for (i = 0; i < (ic_data->HX_RX_NUM + ic_data->HX_TX_NUM); i++) {
if (diag_self[i] > g_max_self)
g_max_self = diag_self[i];
if (diag_self[i] < g_min_self)
g_min_self = diag_self[i];
}
}
static void print_state_info(struct seq_file *s)
{
/* seq_printf(s, "State_info_2bytes:%3d, %3d\n",
* _state_info[0],hx_state_info[1]);
*/
#ifdef HX_NEW_EVENT_STACK_FORMAT
seq_printf(s, "ReCal = %d\t", hx_state_info[0] & 0x03);
seq_printf(s, "Base Line = %d\t", hx_state_info[0] >> 2 & 0x01);
seq_printf(s, "Palm = %d\t", hx_state_info[0] >> 3 & 0x01);
seq_printf(s, "Idle mode = %d\t", hx_state_info[0] >> 4 & 0x01);
seq_printf(s, "Water = %d\n", hx_state_info[0] >> 5 & 0x01);
seq_printf(s, "TX Hop = %d\t", hx_state_info[0] >> 6 & 0x01);
seq_printf(s, "AC mode = %d\t", hx_state_info[0] >> 7 & 0x01);
seq_printf(s, "High Sensitivity = %d\t", hx_state_info[1] & 0x01);
seq_printf(s, "Noise mode = %d\n", hx_state_info[1] >> 3 & 0x01);
seq_printf(s, "Lamp Noise mode = %d\n", hx_state_info[1] >> 4 & 0x01);
#else
seq_printf(s, "ReCal = %d\t", hx_state_info[0] & 0x01);
seq_printf(s, "Palm = %d\t", hx_state_info[0] >> 1 & 0x01);
seq_printf(s, "AC mode = %d\t", hx_state_info[0] >> 2 & 0x01);
seq_printf(s, "Water = %d\n", hx_state_info[0] >> 3 & 0x01);
seq_printf(s, "Glove = %d\t", hx_state_info[0] >> 4 & 0x01);
seq_printf(s, "TX Hop = %d\t", hx_state_info[0] >> 5 & 0x01);
seq_printf(s, "Base Line = %d\t", hx_state_info[0] >> 6 & 0x01);
seq_printf(s, "OSR Hop = %d\t", hx_state_info[1] >> 3 & 0x01);
seq_printf(s, "KEY = %d\n", hx_state_info[1] >> 4 & 0x0F);
#endif
}
static void himax_diag_arrange_print(struct seq_file *s, int i, int j,
int transpose)
{
if (transpose)
seq_printf(s, "%6d", diag_mutual[j + i * ic_data->HX_RX_NUM]);
else
seq_printf(s, "%6d", diag_mutual[i + j * ic_data->HX_RX_NUM]);
}
/* ready to print second step which is column*/
static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,
int out_init, bool transpose, int j)
{
int x_channel = ic_data->HX_RX_NUM;
int y_channel = ic_data->HX_TX_NUM;
int i;
int in_max = 0;
if (transpose)
in_max = y_channel;
else
in_max = x_channel;
if (in_init > 0) { /* bit0 = 1 */
for (i = in_init - 1; i >= 0; i--)
himax_diag_arrange_print(s, i, j, transpose);
if (transpose) {
if (out_init > 0)
seq_printf(s, " %5d\n", diag_self[j]);
else
seq_printf(s, " %5d\n",
diag_self[x_channel - j - 1]);
}
} else { /* bit0 = 0 */
for (i = 0; i < in_max; i++)
himax_diag_arrange_print(s, i, j, transpose);
if (transpose) {
if (out_init > 0)
seq_printf(s, " %5d\n",
diag_self[x_channel - j - 1]);
else
seq_printf(s, " %5d\n", diag_self[j]);
}
}
}
/* print first step which is row */
static void himax_diag_arrange_outloop(struct seq_file *s, int transpose,
int out_init, int in_init)
{
int j;
int x_channel = ic_data->HX_RX_NUM;
int y_channel = ic_data->HX_TX_NUM;
int out_max = 0;
int self_cnt = 0;
if (transpose)
out_max = x_channel;
else
out_max = y_channel;
if (out_init > 0) { /* bit1 = 1 */
self_cnt = 1;
for (j = out_init - 1; j >= 0; j--) {
seq_printf(s, "%3c%02d%c", '[', j + 1, ']');
himax_diag_arrange_inloop(s, in_init, out_init,
transpose, j);
if (!transpose) {
seq_printf(s, " %5d\n",
diag_self[y_channel + x_channel - self_cnt]);
self_cnt++;
}
}
} else { /* bit1 = 0 */
/* self_cnt = x_channel; */
for (j = 0; j < out_max; j++) {
seq_printf(s, "%3c%02d%c", '[', j + 1, ']');
himax_diag_arrange_inloop(s, in_init, out_init,
transpose, j);
if (!transpose) {
seq_printf(s, " %5d\n",
diag_self[j + x_channel]);
}
}
}
}
/* determin the output format of diag */
static void himax_diag_arrange(struct seq_file *s)
{
int x_channel = ic_data->HX_RX_NUM;
int y_channel = ic_data->HX_TX_NUM;
int bit2, bit1, bit0;
int i;
/* rotate bit */
bit2 = g_diag_arr_num >> 2;
/* reverse Y */
bit1 = g_diag_arr_num >> 1 & 0x1;
/* reverse X */
bit0 = g_diag_arr_num & 0x1;
if (g_diag_arr_num < 4) {
for (i = 0 ; i <= x_channel; i++)
seq_printf(s, "%3c%02d%c", '[', i, ']');
seq_puts(s, "\n");
himax_diag_arrange_outloop(s, bit2, bit1 * y_channel,
bit0 * x_channel);
seq_printf(s, "%6c", ' ');
if (bit0 == 1) {
for (i = x_channel - 1; i >= 0; i--)
seq_printf(s, "%6d", diag_self[i]);
} else {
for (i = 0; i < x_channel; i++)
seq_printf(s, "%6d", diag_self[i]);
}
} else {
for (i = 0 ; i <= y_channel; i++)
seq_printf(s, "%3c%02d%c", '[', i, ']');
seq_puts(s, "\n");
himax_diag_arrange_outloop(s, bit2, bit1 * x_channel,
bit0 * y_channel);
seq_printf(s, "%6c", ' ');
if (bit1 == 1) {
for (i = x_channel + y_channel - 1; i >= x_channel;
i--)
seq_printf(s, "%6d", diag_self[i]);
} else {
for (i = x_channel; i < x_channel + y_channel; i++)
seq_printf(s, "%6d", diag_self[i]);
}
}
}
static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos >= 1)
return NULL;
return (void *)((unsigned long) *pos + 1);
}
static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
return NULL;
}
static void himax_diag_seq_stop(struct seq_file *s, void *v)
{
kfree(v);
}
/* DSRAM thread */
bool himax_ts_diag_func(void)
{
int retry = 3;
int i = 0, j = 0;
unsigned int index = 0;
int x_channel = ic_data->HX_RX_NUM;
int y_channel = ic_data->HX_TX_NUM;
int total_size = (y_channel * x_channel + y_channel + x_channel) * 2;
uint8_t *info_data;
int32_t *mutual_data = NULL;
int32_t *mutual_data_new = NULL;
int32_t *mutual_data_old = NULL;
int32_t *self_data = NULL;
int32_t *self_data_new = NULL;
int32_t *self_data_old = NULL;
int32_t new_data;
/* 1:common dsram,2:100 frame Max,3:N-(N-1)frame */
int dsram_type = process_type;
info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL);
if (info_data == NULL)
return false;
memset(info_data, 0, total_size * sizeof(uint8_t));
I("%s: process type=%d!\n", __func__, process_type);
g_core_fp.fp_burst_enable(1);
if (dsram_type <= 2) {
mutual_data = getMutualBuffer();
self_data = getSelfBuffer();
} else if (dsram_type == 3) {
mutual_data = getMutualBuffer();
mutual_data_new = getMutualNewBuffer();
mutual_data_old = getMutualOldBuffer();
self_data = getSelfBuffer();
self_data_new = getSelfNewBuffer();
self_data_old = getSelfOldBuffer();
}
do {
if (retry <= 0) {
E("%s Get DSRAM data failed\n", __func__);
kfree(info_data);
return false;
}
if (g_core_fp.fp_get_DSRAM_data(info_data, dsram_flag))
break;
} while (retry-- > 0);
index = 0;
for (i = 0; i < y_channel; i++) { /*mutual data*/
for (j = 0; j < x_channel; j++) {
new_data = (((int8_t)info_data[index + 1] << 8) |
info_data[index]);
if (dsram_type <= 1) {
mutual_data[i * x_channel + j] = new_data;
} else if (dsram_type == 2) { /* Keep max data */
if (mutual_data[i * x_channel + j] < new_data)
mutual_data[i * x_channel + j] = new_data;
} else if (dsram_type == 3) {
/* Cal data for [N]-[N-1] frame */
mutual_data_new[i * x_channel + j] = new_data;
mutual_data[i * x_channel + j] =
mutual_data_new[i * x_channel + j] -
mutual_data_old[i * x_channel + j];
}
index += 2;
}
}
for (i = 0; i < x_channel + y_channel; i++) { /*self data*/
new_data = (info_data[index + 1] << 8 | info_data[index]);
if (dsram_type <= 1) {
self_data[i] = new_data;
} else if (dsram_type == 2) { /* Keep max data */
if (self_data[i] < new_data)
self_data[i] = new_data;
} else if (dsram_type == 3) { /* Cal data for [N]-[N-1] frame */
self_data_new[i] = new_data;
self_data[i] = self_data_new[i] - self_data_old[i];
}
index += 2;
}
kfree(info_data);
if (dsram_type == 3) {
memcpy(mutual_data_old, mutual_data_new,
x_channel * y_channel * sizeof(int32_t));
/* copy N data to N-1 array */
memcpy(self_data_old, self_data_new,
(x_channel + y_channel) * sizeof(int32_t));
/* copy N data to N-1 array */
}
diag_max_cnt++;
if (dsram_type >= 1 && dsram_type <= 3) {
queue_delayed_work(private_ts->himax_diag_wq,
&private_ts->himax_diag_delay_wrok, 1 / 10 * HZ);
}
return true;
}
static int himax_diag_print(struct seq_file *s, void *v)
{
int x_num = ic_data->HX_RX_NUM;
int y_num = ic_data->HX_TX_NUM;
size_t ret = 0;
uint16_t mutual_num, self_num, width;
mutual_num = x_num * y_num;
self_num = x_num + y_num;
/* don't add KEY_COUNT */
width = x_num;
seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_num, y_num);
/* start to show out the raw data in adb shell */
himax_diag_arrange(s);
seq_puts(s, "\n");
#ifdef HX_EN_SEL_BUTTON
seq_puts(s, "\n");
for (loop_i = 0; loop_i < ic_data->HX_BT_NUM; loop_i++)
seq_printf(s, "%6d", diag_self[ic_data->HX_RX_NUM +
ic_data->HX_TX_NUM + loop_i]);
#endif
seq_puts(s, "ChannelEnd");
seq_puts(s, "\n");
/* print Mutual/Slef Maximum and Minimum */
himax_get_mutual_edge();
himax_get_self_edge();
seq_printf(s, "Mutual Max:%3d, Min:%3d\n", g_max_mutual,
g_min_mutual);
seq_printf(s, "Self Max:%3d, Min:%3d\n", g_max_self,
g_min_self);
/* recovery status after print*/
g_max_mutual = 0;
g_min_mutual = 0xFFFF;
g_max_self = 0;
g_min_self = 0xFFFF;
/*pring state info*/
print_state_info(s);
if (s->count >= s->size)
overflow++;
return ret;
}
static int himax_diag_stack_read(struct seq_file *s, void *v)
{
struct himax_ts_data *ts = private_ts;
if (ts->diag_cmd)
himax_diag_print(s, v);
else
seq_puts(s, "Please set raw out select 'echo diag,X > debug'\n\n");
return 0;
}
static const struct seq_operations himax_diag_stack_ops = {
.start = himax_diag_seq_start,
.next = himax_diag_seq_next,
.stop = himax_diag_seq_stop,
.show = himax_diag_stack_read,
};
static int himax_diag_stack_open(struct inode *inode, struct file *file)
{
return seq_open(file, &himax_diag_stack_ops);
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_stack_ops = {
.proc_open = himax_diag_stack_open,
.proc_read = seq_read,
.proc_release = seq_release,
};
#else
static const struct file_operations himax_proc_stack_ops = {
.owner = THIS_MODULE,
.open = himax_diag_stack_open,
.read = seq_read,
.release = seq_release,
};
#endif
static int himax_sram_read(struct seq_file *s, void *v, uint8_t rs)
{
struct himax_ts_data *ts = private_ts;
int d_type = 0;
d_type = (!ts->diag_cmd)?rs:ts->diag_cmd;
if (!overflow) {
if (!process_type) {
himax_int_enable(0);
g_core_fp.fp_diag_register_set(d_type, 0);
if (!himax_ts_diag_func())
seq_puts(s, "Get sram data failed.");
else
himax_diag_print(s, v);
ts->diag_cmd = 0;
g_core_fp.fp_diag_register_set(0, 0);
himax_int_enable(1);
}
}
if ((process_type <= 3 && ts->diag_cmd && dsram_flag) || overflow) {
himax_diag_print(s, v);
overflow = 0;
}
return 0;
}
static int himax_diag_iir_read(struct seq_file *s, void *v)
{
return himax_sram_read(s, v, 0x09);
}
static const struct seq_operations himax_diag_iir_ops = {
.start = himax_diag_seq_start,
.next = himax_diag_seq_next,
.stop = himax_diag_seq_stop,
.show = himax_diag_iir_read,
};
static int himax_diag_iir_open(struct inode *inode, struct file *file)
{
return seq_open(file, &himax_diag_iir_ops);
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_iir_ops = {
.proc_open = himax_diag_iir_open,
.proc_read = seq_read,
.proc_release = seq_release,
};
#else
static const struct file_operations himax_proc_iir_ops = {
.owner = THIS_MODULE,
.open = himax_diag_iir_open,
.read = seq_read,
.release = seq_release,
};
#endif
static int himax_diag_dc_read(struct seq_file *s, void *v)
{
return himax_sram_read(s, v, 0x0A);
}
static const struct seq_operations himax_diag_dc_ops = {
.start = himax_diag_seq_start,
.next = himax_diag_seq_next,
.stop = himax_diag_seq_stop,
.show = himax_diag_dc_read,
};
static int himax_diag_dc_open(struct inode *inode, struct file *file)
{
return seq_open(file, &himax_diag_dc_ops);
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_dc_ops = {
.proc_open = himax_diag_dc_open,
.proc_read = seq_read,
.proc_release = seq_release,
};
#else
static const struct file_operations himax_proc_dc_ops = {
.owner = THIS_MODULE,
.open = himax_diag_dc_open,
.read = seq_read,
.release = seq_release,
};
#endif
static int himax_diag_bank_read(struct seq_file *s, void *v)
{
return himax_sram_read(s, v, 0x0B);
}
static const struct seq_operations himax_diag_bank_ops = {
.start = himax_diag_seq_start,
.next = himax_diag_seq_next,
.stop = himax_diag_seq_stop,
.show = himax_diag_bank_read,
};
static int himax_diag_bank_open(struct inode *inode, struct file *file)
{
return seq_open(file, &himax_diag_bank_ops);
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_bank_ops = {
.proc_open = himax_diag_bank_open,
.proc_read = seq_read,
.proc_release = seq_release,
};
#else
static const struct file_operations himax_proc_bank_ops = {
.owner = THIS_MODULE,
.open = himax_diag_bank_open,
.read = seq_read,
.release = seq_release,
};
#endif
static ssize_t himax_reset_write(char *buf, size_t len)
{
if (len >= 12) {
I("%s: no command exceeds 12 chars.\n", __func__);
return -EFAULT;
}
#ifdef HX_RST_PIN_FUNC
if (buf[0] == '1')
g_core_fp.fp_ic_reset(false, false);
else if (buf[0] == '2')
g_core_fp.fp_ic_reset(false, true);
else if (buf[0] == '3')
g_core_fp.fp_ic_reset(true, false);
else if (buf[0] == '4')
g_core_fp.fp_ic_reset(true, true);
/* else if (buf[0] == '5') */
/* ESD_HW_REST(); */
#endif
#ifdef HX_ZERO_FLASH
if (g_core_fp.fp_0f_reload_to_active)
g_core_fp.fp_0f_reload_to_active();
#endif
return len;
}
static ssize_t himax_proc_FW_debug_read(char *buf, size_t len)
{
ssize_t ret = 0;
uint8_t loop_i = 0;
uint8_t tmp_data[64] = {0};
cmd_set[0] = 0x01;
if (g_core_fp.fp_read_FW_status(cmd_set, tmp_data) == NO_ERR) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"0x%02X%02X%02X%02X :\t",
cmd_set[5], cmd_set[4], cmd_set[3], cmd_set[2]);
for (loop_i = 0; loop_i < cmd_set[1]; loop_i++)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"%5d\t", tmp_data[loop_i]);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
}
cmd_set[0] = 0x02;
if (g_core_fp.fp_read_FW_status(cmd_set, tmp_data) == NO_ERR) {
for (loop_i = 0; loop_i < cmd_set[1];
loop_i = loop_i + 2) {
if ((loop_i % 16) == 0)
ret += snprintf(buf_tmp + ret,
sizeof(buf_tmp) - ret, "0x%02X%02X%02X%02X :\t",
cmd_set[5], cmd_set[4],
cmd_set[3] +
(((cmd_set[2] + loop_i) >> 8) & 0xFF),
(cmd_set[2] + loop_i) & 0xFF);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"%5d\t", tmp_data[loop_i] +
(tmp_data[loop_i + 1] << 8));
if ((loop_i % 16) == 14)
ret += snprintf(buf_tmp + ret,
sizeof(buf_tmp) - ret, "\n");
}
}
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
return ret;
}
static ssize_t himax_proc_DD_debug_read(char *buf, size_t len)
{
ssize_t ret = 0;
uint8_t tmp_data[64] = {0};
uint8_t loop_i = 0;
if (mutual_set_flag == 1) {
if (g_core_fp.fp_read_DD_status(cmd_set, tmp_data) ==
NO_ERR) {
for (loop_i = 0; loop_i < cmd_set[0];
loop_i++) {
if ((loop_i % 8) == 0)
ret += snprintf(buf_tmp + ret,
sizeof(buf_tmp) - ret, "0x%02X : ", loop_i);
ret += snprintf(buf_tmp + ret,
sizeof(buf_tmp) - ret, "0x%02X ", tmp_data[loop_i]);
if ((loop_i % 8) == 7)
ret += snprintf(buf_tmp + ret,
sizeof(buf_tmp) - ret, "\n");
}
} else {
ret += snprintf(buf_tmp + ret,
sizeof(buf_tmp) - ret, "Get DD status falied!\n");
}
}
ret += snprintf(buf_tmp + ret, len - ret, "\n");
return ret;
}
#define STR_TO_UL_ERR "String to ul is fail in cnt = %d, buf_tmp2 = %s\n"
static ssize_t himax_proc_DD_debug_write(char *buf, size_t len)
{
uint8_t i = 0;
uint8_t cnt = 2;
unsigned long result = 0;
char buf_tmp2[4];
if (len >= 20) {
I("%s: no command exceeds 20 chars.\n", __func__);
return -EFAULT;
}
memset(buf_tmp2, 0x0, sizeof(buf_tmp2));
if (buf[2] == 'x' && buf[6] == 'x' && buf[10] == 'x') {
mutual_set_flag = 1;
for (i = 3; i < 12; i = i + 4) {
memcpy(buf_tmp2, buf + i, 2);
if (!kstrtoul(buf_tmp2, 16, &result))
cmd_set[cnt] = (uint8_t)result;
else
I(STR_TO_UL_ERR, cnt, buf_tmp2);
cnt--;
}
I("cmd_set[2] = %02X, cmd_set[1] = %02X, cmd_set[0] = %02X\n",
cmd_set[2], cmd_set[1], cmd_set[0]);
} else {
mutual_set_flag = 0;
}
return len;
}
void setFlashBuffer(void)
{
flash_buffer = kcalloc(ic_data->flash_size, sizeof(uint8_t), GFP_KERNEL);
}
void flash_dump_prog_set(uint8_t prog)
{
g_flash_progress = prog;
if (prog == ONGOING)
debug_data->flash_dump_going = ONGOING;
else
debug_data->flash_dump_going = START;
}
static int himax_proc_flash_read(struct seq_file *s, void *v)
{
ssize_t ret = 0;
int i;
uint8_t flash_progress = g_flash_progress;
uint8_t flash_cmd = g_flash_cmd;
bool flash_rst = g_flash_dump_rst;
I("flash_progress = %d\n", flash_progress);
if (!flash_rst) {
seq_puts(s, "FlashStart:Fail\n");
seq_puts(s, "FlashEnd\n");
return ret;
}
if (flash_progress == START)
seq_puts(s, "Flash dump - Start\n");
else if (flash_progress == ONGOING)
seq_puts(s, "Flash dump - On-going\n");
else if (flash_progress == FINISHED)
seq_puts(s, "Flash dump - Finished\n");
/*print flash dump data*/
if (flash_cmd == 1 && flash_progress == FINISHED) {
seq_puts(s, "Start to print flash dump data\n");
for (i = 0; i < ic_data->flash_size; i++) {
seq_printf(s, "0x%02X,", flash_buffer[i]);
if (i % 16 == 15)
seq_puts(s, "\n");
}
}
seq_puts(s, "FlashEnd\n");
return ret;
}
static ssize_t himax_proc_flash_write(struct file *filp,
const char __user *buff, size_t len, loff_t *data)
{
char buf[80] = {0};
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
if (copy_from_user(buf, buff, len))
return -EFAULT;
I("%s: buf = %s\n", __func__, buf);
if (g_flash_progress == ONGOING) {
E("%s: process is busy , return!\n", __func__);
return len;
}
/*1 : print flash to window, 2 : dump to sdcard*/
if (buf[0] == '1') {
/* 1_32,1_60,1_64,1_24,1_28 for flash size:
* 32k,60k,64k,124k,128k
*/
g_flash_cmd = 1;
flash_dump_prog_set(START);
g_flash_dump_rst = true;
queue_work(private_ts->flash_wq, &private_ts->flash_work);
} else if (buf[0] == '2') {
/* 2_32,2_60,2_64,2_24,2_28 for flash size:
* 32k,60k,64k,124k,128k
*/
g_flash_cmd = 2;
flash_dump_prog_set(START);
g_flash_dump_rst = true;
queue_work(private_ts->flash_wq, &private_ts->flash_work);
}
return len;
}
static void *himax_flash_dump_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos >= 1)
return NULL;
return (void *)((unsigned long) *pos + 1);
}
static void *himax_flash_dump_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
return NULL;
}
static void himax_flash_dump_seq_stop(struct seq_file *s, void *v)
{
}
static const struct seq_operations himax_flash_dump_seq_ops = {
.start = himax_flash_dump_seq_start,
.next = himax_flash_dump_seq_next,
.stop = himax_flash_dump_seq_stop,
.show = himax_proc_flash_read,
};
static int himax_flash_dump_proc_open(struct inode *inode, struct file *file)
{
return seq_open(file, &himax_flash_dump_seq_ops);
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_flash_ops = {
.proc_open = himax_flash_dump_proc_open,
.proc_read = seq_read,
.proc_write = himax_proc_flash_write,
};
#else
static const struct file_operations himax_proc_flash_ops = {
.owner = THIS_MODULE,
.open = himax_flash_dump_proc_open,
.read = seq_read,
.write = himax_proc_flash_write,
};
#endif
void himax_ts_flash_func(void)
{
uint8_t flash_command = g_flash_cmd;
himax_int_enable(0);
flash_dump_prog_set(ONGOING);
/*msleep(100);*/
I("%s: flash_command = %d enter.\n", __func__, flash_command);
if (flash_command == 1 || flash_command == 2) {
g_core_fp.fp_flash_dump_func(flash_command, ic_data->flash_size,
flash_buffer);
g_flash_dump_rst = true;
}
I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n");
/* if (flash_command == 2) {
* struct file *fn;
* struct filename *vts_name;
*
* vts_name = kp_getname_kernel(FLASH_DUMP_FILE);
* fn = kp_file_open_name(vts_name, O_CREAT | O_WRONLY, 0);
*
* if (!IS_ERR(fn)) {
* I("%s create file and ready to write\n", __func__);
* fn->f_op->write(fn, flash_buffer,
* Flash_Size * sizeof(uint8_t), &fn->f_pos);
* filp_close(fn, NULL);
* } else {
* E("%s Open file failed!\n", __func__);
* g_flash_dump_rst = false;
* }
* }
*/
himax_int_enable(1);
flash_dump_prog_set(FINISHED);
}
static ssize_t himax_sense_on_off_write(char *buf, size_t len)
{
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
if (buf[0] == '0') {
g_core_fp.fp_sense_off(true);
I("Sense off\n");
} else if (buf[0] == '1') {
if (buf[1] == 's') {
g_core_fp.fp_sense_on(0x00);
I("Sense on re-map on, run sram\n");
} else {
g_core_fp.fp_sense_on(0x01);
I("Sense on re-map off, run flash\n");
}
} else {
I("Do nothing\n");
}
return len;
}
#ifdef HX_ESD_RECOVERY
static ssize_t himax_esd_cnt_read(char *buf, size_t len)
{
size_t ret = 0;
I("%s: enter, %d\n", __func__, __LINE__);
ret += snprintf(buf_tmp + ret, len - ret,
"EB_cnt = %d, EC_cnt = %d, ED_cnt = %d\n",
hx_EB_event_flag, hx_EC_event_flag, hx_ED_event_flag);
return ret;
}
static ssize_t himax_esd_cnt_write(char *buf, size_t len)
{
int i = 0;
if (len >= 12) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
I("Clear ESD Flag\n");
if (buf[i] == '0') {
hx_EB_event_flag = 0;
hx_EC_event_flag = 0;
hx_ED_event_flag = 0;
}
return len;
}
#endif
static int printMat(char *temp_buf, size_t len, int max_size,
uint8_t *guest_str, int loc)
{
int ret = loc;
int i;
for (i = 0; i < max_size; i++) {
if ((i % 16) == 0 && i > 0)
ret += snprintf(temp_buf + ret, len - ret, "\n");
ret += snprintf(temp_buf + ret, len - ret, "0x%02X\t",
guest_str[i]);
}
return ret;
}
static int printUnit(char *temp_buf, size_t len, int max_size, char *info_item,
uint8_t *guest_str, int loc)
{
int ret = loc;
ret += snprintf(temp_buf + ret, len - ret, "%s:\n", info_item);
ret = printMat(temp_buf, len, max_size, guest_str, ret);
ret += snprintf(temp_buf + ret, len - ret, "\n");
return ret;
}
#ifdef HX_TP_PROC_GUEST_INFO
static ssize_t himax_proc_guest_info_read(char *buf, size_t len)
{
int ret = 0;
int j = 0;
int max_size = 128;
struct hx_guest_info *info = g_guest_info_data;
I("guest info progress\n");
if (g_core_fp.guest_info_get_status()) {
ret += snprintf(buf_tmp + ret, len - ret,
"Not Ready\n");
goto END_FUNCTION;
} else {
if (info->g_guest_info_type == 1) {
for (j = 0; j < 3; j++) {
ret = printUnit(buf_tmp, len, max_size,
g_guest_info_item[j],
info->g_guest_str[j], ret);
I("str[%d] %s\n", j,
info->g_guest_str[j]);
}
ret = printUnit(buf_tmp, len, max_size,
g_guest_info_item[8], info->g_guest_str[8],
ret);
I("str[8] %s\n",
info->g_guest_str[8]);
ret = printUnit(buf_tmp, len, max_size,
g_guest_info_item[9], info->g_guest_str[9],
ret);
I("str[9] %s\n",
info->g_guest_str[9]);
} else if (info->g_guest_info_type == 0) {
for (j = 0; j < 10; j++) {
if (j == 3)
j = 8;
ret += snprintf(buf_tmp + ret,
len - ret, "%s:\n",
g_guest_info_item[j]);
if (info->g_guest_data_type[j] == 0) {
ret += snprintf(buf_tmp + ret,
len - ret, "%s",
g_guest_info_data->g_guest_str_in_format[j]);
} else {
ret = printMat(buf_tmp, len,
info->g_guest_data_len[j],
g_guest_info_data->g_guest_str_in_format[j], ret);
}
ret += snprintf(buf_tmp + ret,
len - ret, "\n");
}
}
}
END_FUNCTION:
return ret;
}
static ssize_t himax_proc_guest_info_write(char *buf, size_t len)
{
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
I("%s: buf = %s\n", __func__, buf);
if (buf[0] == 'r') {
I("%s,Test to get", __func__);
queue_work(private_ts->guest_info_wq,
&private_ts->guest_info_work);
}
return len;
}
#endif
static ssize_t himax_debug_read(struct file *file, char *buf,
size_t len, loff_t *pos)
{
ssize_t ret = 0;
int i = 0;
if (!HX_PROC_SEND_FLAG) {
I("%s, Enter\n", __func__);
memset(buf_tmp, 0, sizeof(buf_tmp));
if (dbg_cmd_flag) {
if (dbg_func_ptr_r[dbg_cmd_flag])
ret += dbg_func_ptr_r[dbg_cmd_flag](buf, len);
else
goto END_FUNC_R;
}
if (debug_level_cmd == 't') {
if (fw_update_complete)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"FW Update Complete ");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"FW Update Fail ");
} else if (debug_level_cmd == 'h') {
if (handshaking_result == 0)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Handshaking Result = %d (MCU Running)\n",
handshaking_result);
else if (handshaking_result == 1)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Handshaking Result = %d (MCU Stop)\n",
handshaking_result);
else if (handshaking_result == 2)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Handshaking Result = %d (I2C Error)\n",
handshaking_result);
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Handshaking Result = error\n");
} else if (debug_level_cmd == 'v') {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"FW_VER = 0x%2.2X\n", ic_data->vendor_fw_ver);
if (private_ts->chip_cell_type == CHIP_IS_ON_CELL)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CONFIG_VER = 0x%2.2X\n",
ic_data->vendor_config_ver);
else {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"TOUCH_VER = 0x%2.2X\n",
ic_data->vendor_touch_cfg_ver);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"DISPLAY_VER = 0x%2.2X\n",
ic_data->vendor_display_cfg_ver);
}
if (ic_data->vendor_cid_maj_ver < 0 &&
ic_data->vendor_cid_min_ver < 0)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CID_VER = NULL\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"CID_VER = 0x%2.2X\n",
(ic_data->vendor_cid_maj_ver << 8 |
ic_data->vendor_cid_min_ver));
if (ic_data->vendor_panel_ver < 0)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"PANEL_VER = NULL\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"PANEL_VER = 0x%2.2X\n",
ic_data->vendor_panel_ver);
if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Cusomer = %s\n", ic_data->vendor_cus_info);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Project = %s\n", ic_data->vendor_proj_info);
}
#if defined(HX_AUTO_UPDATE_FW) || defined(HX_ZERO_FLASH)
#ifdef HX_EN_DYNAMIC_NAME
if (ic_data->vendor_semifac == 1)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"SEMI_FAC = UMC\n");
else if (ic_data->vendor_semifac == 2)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"SEMI_FAC = PSC\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"SEMI_FAC = NULL\n");
#endif
#endif
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Himax Touch Driver Version:\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"%s\n", HIMAX_DRIVER_VER);
} else if (debug_level_cmd == 'd') {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Himax Touch IC Information :\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"%s\n", private_ts->chip_name);
switch (IC_CHECKSUM) {
case HX_TP_BIN_CHECKSUM_SW:
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"IC Checksum : SW\n");
break;
case HX_TP_BIN_CHECKSUM_HW:
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"IC Checksum : HW\n");
break;
case HX_TP_BIN_CHECKSUM_CRC:
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"IC Checksum : CRC\n");
break;
default:
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"IC Checksum error.\n");
}
if (ic_data->HX_INT_IS_EDGE)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Driver register Interrupt : EDGE TIRGGER\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Driver register Interrupt : LEVEL TRIGGER\n");
if (private_ts->protocol_type == PROTOCOL_TYPE_A)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Protocol : TYPE_A\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Protocol : TYPE_B\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"RX Num : %d\n", ic_data->HX_RX_NUM);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"TX Num : %d\n", ic_data->HX_TX_NUM);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"BT Num : %d\n", ic_data->HX_BT_NUM);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"X Resolution : %d\n", ic_data->HX_X_RES);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Y Resolution : %d\n", ic_data->HX_Y_RES);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Max Point : %d\n", ic_data->HX_MAX_PT);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"XY reverse : %d\n", ic_data->HX_XY_REVERSE);
#ifdef HX_TP_PROC_2T2R
if (Is_2T2R) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"2T2R panel\n");
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"RX Num_2 : %d\n", HX_RX_NUM_2);
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"TX Num_2 : %d\n", HX_TX_NUM_2);
}
#endif
} else if (debug_level_cmd == 'i') {
if (g_core_fp.fp_read_i2c_status())
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"I2C communication is bad.\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"I2C communication is good.\n");
} else if (debug_level_cmd == 'n') {
/* Edgd = 1, Level = 0 */
if (g_core_fp.fp_read_ic_trigger_type() == 1)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"IC Interrupt type is edge trigger.\n");
else if (g_core_fp.fp_read_ic_trigger_type() == 0)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"IC Interrupt type is level trigger.\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Unkown IC trigger type.\n");
if (ic_data->HX_INT_IS_EDGE)
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Driver register Interrupt : EDGE TIRGGER\n");
else
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"Driver register Interrupt : LEVEL TRIGGER\n");
} else if (debug_level_cmd == 'l') {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"LotID : ");
for (i = 0; i < 13; i++) {
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"%02X", ic_data->vendor_ic_id[i]);
}
ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret,
"\n");
}
END_FUNC_R:
if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len))
I("%s,here:%d\n", __func__, __LINE__);
HX_PROC_SEND_FLAG = 1;
} else {
HX_PROC_SEND_FLAG = 0;
}
return ret;
}
static ssize_t himax_debug_write(struct file *file, const char *buff,
size_t len, loff_t *pos)
{
char fileName[128];
char buf[80] = {0};
int result = 0;
#ifndef HX_ZERO_FLASH
int fw_type = 0;
const struct firmware *fw = NULL;
#endif
char *str_ptr = NULL;
int str_len = 0;
int i = 0;
if (len >= 80) {
I("%s: no command exceeds 80 chars.\n", __func__);
return -EFAULT;
}
if (copy_from_user(buf, buff, len))
return -EFAULT;
str_len = len;
buf[str_len - 1] = 0; /*remove \n*/
while (dbg_cmd_str[i]) {
str_ptr = strnstr(buf, dbg_cmd_str[i], len);
if (str_ptr) {
str_len = strlen(dbg_cmd_str[i]);
dbg_cmd_flag = i + 1;
debug_level_cmd = 0;
I("Cmd is correct :%s, dbg_cmd = %d\n", str_ptr, dbg_cmd_flag);
break;
}
i++;
}
if (!str_ptr) {
I("Cmd is not correct\n");
dbg_cmd_flag = 0;
}
if (buf[str_len] == ',') {
dbg_cmd_par = buf + str_len + 1;
if (dbg_func_ptr_w[dbg_cmd_flag])
dbg_func_ptr_w[dbg_cmd_flag](dbg_cmd_par, len - str_len - 2);/* 2 => '/n' + ','*/
I("string of paremeter is %s, dbg_cmd_par = %s\n", buf + str_len + 1, dbg_cmd_par);
} else
I("No paremeter of this cmd\n");
if (dbg_cmd_flag)
return len;
if (buf[0] == 'h') { /* handshaking */
debug_level_cmd = buf[0];
himax_int_enable(0);
/* 0:Running, 1:Stop, 2:I2C Fail */
handshaking_result = g_core_fp.fp_hand_shaking();
himax_int_enable(1);
return len;
} else if (buf[0] == 'v') { /* firmware version */
himax_int_enable(0);
#ifdef HX_RST_PIN_FUNC
g_core_fp.fp_ic_reset(false, false);
#endif
debug_level_cmd = buf[0];
g_core_fp.fp_read_FW_ver();
#ifdef HX_RST_PIN_FUNC
g_core_fp.fp_ic_reset(true, false);
#else
g_core_fp.fp_system_reset();
#endif
#ifdef HX_ZERO_FLASH
if (g_core_fp.fp_0f_reload_to_active)
g_core_fp.fp_0f_reload_to_active();
#endif
himax_int_enable(1);
/* himax_check_chip_version(); */
return len;
} else if (buf[0] == 'd') { /* ic information */
debug_level_cmd = buf[0];
return len;
} else if (buf[0] == 't') {
if (buf[1] == 's' &&
buf[2] == 'd' &&
buf[3] == 'b' &&
buf[4] == 'g'
) {
if (buf[5] == '1') {
I("Open Ts Debug!\n");
g_ts_dbg = 1;
} else if (buf[5] == '0') {
I("Close Ts Debug!\n");
g_ts_dbg = 0;
} else {
E("Parameter fault for ts debug\n");
}
goto ENDFUCTION;
}
himax_int_enable(0);
debug_level_cmd = buf[0];
fw_update_complete = false;
memset(fileName, 0, 128);
/* parse the file name */
snprintf(fileName, len - 2, "%s", &buf[2]);
#ifdef HX_ZERO_FLASH
I("NOW Running Zero flash update!\n");
I("%s: upgrade from file(%s) start!\n", __func__, fileName);
result = g_core_fp.fp_0f_op_file_dirly(fileName);
if (result) {
fw_update_complete = false;
I("Zero flash update fail!\n");
goto ENDFUCTION;
} else {
fw_update_complete = true;
I("Zero flash update complete!\n");
}
goto firmware_upgrade_done;
#else
I("NOW Running common flow update!\n");
I("%s: upgrade from file(%s) start!\n", __func__, fileName);
result = request_firmware(&fw, fileName, private_ts->dev);
if (result < 0) {
I("fail to request_firmware fwpath: %s (ret:%d)\n",
fileName, result);
return result;
}
I("%s: FW image: %02X, %02X, %02X, %02X\n", __func__,
fw->data[0], fw->data[1], fw->data[2], fw->data[3]);
fw_type = (fw->size) / 1024;
/* start to upgrade */
himax_int_enable(0);
I("Now FW size is : %dk\n", fw_type);
switch (fw_type) {
case 32:
if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k(
(unsigned char *)fw->data, fw->size, false) == 0) {
E("%s: TP upgrade error, line: %d\n",
__func__, __LINE__);
fw_update_complete = false;
} else {
I("%s: TP upgrade OK, line: %d\n",
__func__, __LINE__);
fw_update_complete = true;
}
break;
case 60:
if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k(
(unsigned char *)fw->data, fw->size, false) == 0) {
E("%s: TP upgrade error, line: %d\n",
__func__, __LINE__);
fw_update_complete = false;
} else {
I("%s: TP upgrade OK, line: %d\n",
__func__, __LINE__);
fw_update_complete = true;
}
break;
case 64:
if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k(
(unsigned char *)fw->data, fw->size, false) == 0) {
E("%s: TP upgrade error, line: %d\n",
__func__, __LINE__);
fw_update_complete = false;
} else {
I("%s: TP upgrade OK, line: %d\n",
__func__, __LINE__);
fw_update_complete = true;
}
break;
case 124:
if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k(
(unsigned char *)fw->data, fw->size, false) == 0) {
E("%s: TP upgrade error, line: %d\n",
__func__, __LINE__);
fw_update_complete = false;
} else {
I("%s: TP upgrade OK, line: %d\n",
__func__, __LINE__);
fw_update_complete = true;
}
break;
case 128:
if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k(
(unsigned char *)fw->data, fw->size, false) == 0) {
E("%s: TP upgrade error, line: %d\n",
__func__, __LINE__);
fw_update_complete = false;
} else {
I("%s: TP upgrade OK, line: %d\n",
__func__, __LINE__);
fw_update_complete = true;
}
break;
case 255:
if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_255k(
(unsigned char *)fw->data, fw->size, false) == 0) {
E("%s: TP upgrade error, line: %d\n",
__func__, __LINE__);
fw_update_complete = false;
} else {
I("%s: TP upgrade OK, line: %d\n",
__func__, __LINE__);
fw_update_complete = true;
}
break;
default:
E("%s: Flash command fail: %d\n", __func__, __LINE__);
fw_update_complete = false;
break;
}
release_firmware(fw);
goto firmware_upgrade_done;
#endif
} else if (buf[0] == 'i' && buf[1] == '2' && buf[2] == 'c') {
/* i2c communication */
debug_level_cmd = 'i';
return len;
} else if (buf[0] == 'i' && buf[1] == 'n' && buf[2] == 't') {
/* INT trigger */
debug_level_cmd = 'n';
return len;
#ifdef HX_ZERO_FLASH
} else if (buf[0] == 'z') {
result = buf[1] - '0';
I("check type = %d\n", result);
g_core_fp.fp_0f_operation_check(result);
return len;
} else if (buf[0] == 'p') {
I("NOW debug echo r!\n");
/* himax_program_sram(); */
private_ts->himax_0f_update_wq =
create_singlethread_workqueue("HMX_update_0f_reuqest_write");
if (!private_ts->himax_0f_update_wq)
E(" allocate syn_update_wq failed\n");
INIT_DELAYED_WORK(&private_ts->work_0f_update,
g_core_fp.fp_0f_operation);
queue_delayed_work(private_ts->himax_0f_update_wq,
&private_ts->work_0f_update, msecs_to_jiffies(100));
return len;
} else if (buf[0] == 'x') {
g_core_fp.fp_system_reset();
#ifdef HX_ZERO_FLASH
if (g_core_fp.fp_0f_reload_to_active)
g_core_fp.fp_0f_reload_to_active();
#endif
return len;
#endif
} else if (buf[0] == 'l' && buf[1] == 'o' && buf[2] == 't') {
debug_level_cmd = buf[0];
g_core_fp.fp_sense_off(true);
g_core_fp.fp_ic_id_read();
g_core_fp.fp_sense_on(0x01);
return len;
}
/* others,do nothing */
debug_level_cmd = 0;
return len;
firmware_upgrade_done:
g_core_fp.fp_reload_disable(0);
g_core_fp.fp_read_FW_ver();
g_core_fp.fp_touch_information();
#ifdef HX_RST_PIN_FUNC
g_core_fp.fp_ic_reset(true, false);
#ifdef HX_ZERO_FLASH
if (g_core_fp.fp_0f_reload_to_active)
g_core_fp.fp_0f_reload_to_active();
#endif
#else
g_core_fp.fp_sense_on(0x00);
#endif
himax_int_enable(1);
/* todo himax_chip->tp_firmware_upgrade_proceed = 0;
* todo himax_chip->suspend_state = 0;
* todo enable_irq(himax_chip->irq);
*/
ENDFUCTION:
return len;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static const struct proc_ops himax_proc_debug_ops = {
.proc_read = himax_debug_read,
.proc_write = himax_debug_write,
};
#else
static const struct file_operations himax_proc_debug_ops = {
.owner = THIS_MODULE,
.read = himax_debug_read,
.write = himax_debug_write,
};
#endif
static void himax_himax_data_init(void)
{
debug_data->fp_ts_dbg_func = himax_ts_dbg_func;
debug_data->fp_set_diag_cmd = himax_set_diag_cmd;
debug_data->flash_dump_going = false;
}
static void himax_ts_flash_work_func(struct work_struct *work)
{
himax_ts_flash_func();
}
#ifdef HX_TP_PROC_GUEST_INFO
static void himax_ts_guest_info_work_func(struct work_struct *work)
{
g_core_fp.read_guest_info();
}
#endif
static void himax_ts_diag_work_func(struct work_struct *work)
{
himax_ts_diag_func();
}
void dbg_func_ptr_init(void)
{
/*debug function ptr init*/
dbg_func_ptr_r[1] = himax_crc_test_read;
dbg_func_ptr_r[2] = himax_proc_FW_debug_read;
dbg_func_ptr_r[3] = himax_attn_read;
dbg_func_ptr_r[4] = himax_layout_read;
dbg_func_ptr_w[4] = himax_layout_write;
dbg_func_ptr_r[5] = himax_proc_DD_debug_read;
dbg_func_ptr_w[5] = himax_proc_DD_debug_write;
#ifdef HX_ESD_RECOVERY
dbg_func_ptr_r[6] = himax_esd_cnt_read;
dbg_func_ptr_w[6] = himax_esd_cnt_write;
#endif
dbg_func_ptr_w[7] = himax_sense_on_off_write;
dbg_func_ptr_r[8] = himax_debug_level_read;
dbg_func_ptr_w[8] = himax_debug_level_write;
#ifdef HX_TP_PROC_GUEST_INFO
dbg_func_ptr_r[9] = himax_proc_guest_info_read;
dbg_func_ptr_w[9] = himax_proc_guest_info_write;
#endif
dbg_func_ptr_r[10] = himax_int_en_read;
dbg_func_ptr_w[10] = himax_int_en_write;
dbg_func_ptr_w[11] = himax_proc_register_write;
dbg_func_ptr_r[11] = himax_proc_register_read;
dbg_func_ptr_w[12] = himax_reset_write;
dbg_func_ptr_w[13] = himax_diag_arrange_write;
dbg_func_ptr_w[14] = himax_diag_cmd_write;
}
int himax_touch_proc_init(void)
{
himax_proc_diag_dir = proc_mkdir(HIMAX_PROC_DIAG_FOLDER, himax_touch_proc_dir);
if (himax_proc_diag_dir == NULL) {
E(" %s: himax_proc_diag_dir file create failed!\n", __func__);
return -ENOMEM;
}
himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, 0444,
himax_touch_proc_dir, &himax_proc_vendor_ops);
if (himax_proc_vendor_file == NULL) {
E(" %s: proc vendor file create failed!\n", __func__);
goto fail_1;
}
himax_proc_stack_file = proc_create(HIMAX_PROC_STACK_FILE, 0444,
himax_proc_diag_dir, &himax_proc_stack_ops);
if (himax_proc_stack_file == NULL) {
E(" %s: proc stack file create failed!\n", __func__);
goto fail_2_1;
}
himax_proc_iir_file = proc_create(HIMAX_PROC_IIR_FILE, 0444,
himax_proc_diag_dir, &himax_proc_iir_ops);
if (himax_proc_iir_file == NULL) {
E(" %s: proc iir file create failed!\n", __func__);
goto fail_2_2;
}
himax_proc_dc_file = proc_create(HIMAX_PROC_DC_FILE, 0444,
himax_proc_diag_dir, &himax_proc_dc_ops);
if (himax_proc_dc_file == NULL) {
E(" %s: proc dc file create failed!\n", __func__);
goto fail_2_3;
}
himax_proc_bank_file = proc_create(HIMAX_PROC_BANK_FILE, 0444,
himax_proc_diag_dir, &himax_proc_bank_ops);
if (himax_proc_bank_file == NULL) {
E(" %s: proc bank file create failed!\n", __func__);
goto fail_2_4;
}
himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE,
0644, himax_touch_proc_dir,
&himax_proc_debug_ops);
if (himax_proc_debug_file == NULL) {
E(" %s: proc debug file create failed!\n", __func__);
goto fail_3;
}
dbg_func_ptr_init();
himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE,
0644, himax_touch_proc_dir,
&himax_proc_flash_ops);
if (himax_proc_flash_dump_file == NULL) {
E(" %s: proc flash dump file create failed!\n", __func__);
goto fail_4;
}
return 0;
fail_4: remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir);
fail_3: remove_proc_entry(HIMAX_PROC_BANK_FILE, himax_proc_diag_dir);
fail_2_4: remove_proc_entry(HIMAX_PROC_DC_FILE, himax_proc_diag_dir);
fail_2_3: remove_proc_entry(HIMAX_PROC_IIR_FILE, himax_proc_diag_dir);
fail_2_2: remove_proc_entry(HIMAX_PROC_STACK_FILE, himax_proc_diag_dir);
fail_2_1: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir);
fail_1: remove_proc_entry(HIMAX_PROC_DIAG_FOLDER, himax_touch_proc_dir);
return -ENOMEM;
}
void himax_touch_proc_deinit(void)
{
remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir);
remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir);
remove_proc_entry(HIMAX_PROC_BANK_FILE, himax_proc_diag_dir);
remove_proc_entry(HIMAX_PROC_DC_FILE, himax_proc_diag_dir);
remove_proc_entry(HIMAX_PROC_IIR_FILE, himax_proc_diag_dir);
remove_proc_entry(HIMAX_PROC_STACK_FILE, himax_proc_diag_dir);
remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir);
}
int hx_set_stack_raw(int set_val)
{
int ret = NO_ERR;
if (dsram_flag) {
/*Cancal work queue and return to stack*/
process_type = 0;
dsram_flag = false;
cancel_delayed_work(&private_ts->himax_diag_delay_wrok);
himax_int_enable(1);
g_core_fp.fp_return_event_stack();
}
// if (set_val) {
private_ts->diag_cmd = set_val;
g_core_fp.fp_diag_register_set(private_ts->diag_cmd, 0);
// } else {
// private_ts->diag_cmd = 0;
// g_core_fp.fp_diag_register_set(private_ts->diag_cmd, 0);
// }
return ret;
}
int himax_debug_init(void)
{
struct himax_ts_data *ts = private_ts;
I("%s:Enter\n", __func__);
if (ts == NULL) {
E("%s: ts struct is NULL\n", __func__);
return -EPROBE_DEFER;
}
reg_read_data = kzalloc(128 * sizeof(uint8_t), GFP_KERNEL);
if (reg_read_data == NULL) {
goto err_alloc_reg_read_data_fail;
}
debug_data = kzalloc(sizeof(struct himax_debug), GFP_KERNEL);
if (debug_data == NULL) { /*Allocate debug data space*/
goto err_alloc_debug_data_fail;
}
himax_himax_data_init();
ts->flash_wq = create_singlethread_workqueue("himax_flash_wq");
if (!ts->flash_wq) {
E("%s: create flash workqueue failed\n", __func__);
goto err_create_flash_dump_wq_failed;
}
INIT_WORK(&ts->flash_work, himax_ts_flash_work_func);
g_flash_progress = START;
setFlashBuffer();
if (flash_buffer == NULL) {
E("%s: flash buffer allocate fail failed\n", __func__);
goto err_flash_buf_alloc_failed;
}
#ifdef HX_TP_PROC_GUEST_INFO
if (g_guest_info_data == NULL) {
g_guest_info_data = kzalloc(sizeof(struct hx_guest_info),
GFP_KERNEL);
if (g_guest_info_data == NULL)
goto err_guest_info_alloc_failed;
g_guest_info_data->g_guest_info_ongoing = 0;
g_guest_info_data->g_guest_info_type = 0;
}
ts->guest_info_wq =
create_singlethread_workqueue("himax_guest_info_wq");
if (!ts->guest_info_wq) {
E("%s: create guest info workqueue failed\n", __func__);
goto err_create_guest_info_wq_failed;
}
INIT_WORK(&ts->guest_info_work, himax_ts_guest_info_work_func);
#endif
ts->himax_diag_wq = create_singlethread_workqueue("himax_diag");
if (!ts->himax_diag_wq) {
E("%s: create diag workqueue failed\n", __func__);
goto err_create_diag_wq_failed;
}
INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func);
setMutualBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM);
if (getMutualBuffer() == NULL) {
E("%s: mutual buffer allocate fail failed\n", __func__);
goto err_mut_buf_alloc_failed;
}
setMutualNewBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM);
if (getMutualNewBuffer() == NULL) {
E("%s: mutual new buffer allocate fail failed\n", __func__);
goto err_mut_new_alloc_failed;
}
setMutualOldBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM);
if (getMutualOldBuffer() == NULL) {
E("%s: mutual old buffer allocate fail failed\n", __func__);
goto err_mut_old_alloc_failed;
}
#ifdef HX_TP_PROC_2T2R
if (Is_2T2R) {
setMutualBuffer_2(ic_data->HX_RX_NUM_2, ic_data->HX_TX_NUM_2);
if (getMutualBuffer_2() == NULL) {
E("%s: mutual buffer 2 allocate fail failed\n",
__func__);
goto err_mut_buf2_alloc_failed;
}
}
#endif
if (himax_touch_proc_init())
goto err_proc_init_failed;
return 0;
err_proc_init_failed:
#if defined(HX_TP_PROC_2T2R)
kfree(diag_mutual_2);
diag_mutual_2 = NULL;
err_mut_buf2_alloc_failed:
#endif
kfree(diag_mutual_old);
diag_mutual_old = NULL;
err_mut_old_alloc_failed:
kfree(diag_mutual_new);
diag_mutual_new = NULL;
err_mut_new_alloc_failed:
kfree(diag_mutual);
diag_mutual = NULL;
err_mut_buf_alloc_failed:
cancel_delayed_work_sync(&ts->himax_diag_delay_wrok);
destroy_workqueue(ts->himax_diag_wq);
err_create_diag_wq_failed:
#ifdef HX_TP_PROC_GUEST_INFO
err_create_guest_info_wq_failed:
destroy_workqueue(ts->guest_info_wq);
if (g_guest_info_data != NULL) {
kfree(g_guest_info_data);
g_guest_info_data = NULL;
}
err_guest_info_alloc_failed:
#endif
kfree(flash_buffer);
flash_buffer = NULL;
err_flash_buf_alloc_failed:
destroy_workqueue(ts->flash_wq);
err_create_flash_dump_wq_failed:
kfree(debug_data);
debug_data = NULL;
err_alloc_debug_data_fail:
kfree(reg_read_data);
reg_read_data = NULL;
err_alloc_reg_read_data_fail:
return -ENOMEM;
}
EXPORT_SYMBOL(himax_debug_init);
int himax_debug_remove(void)
{
struct himax_ts_data *ts = private_ts;
himax_touch_proc_deinit();
cancel_delayed_work_sync(&ts->himax_diag_delay_wrok);
#ifdef HX_TP_PROC_GUEST_INFO
destroy_workqueue(ts->guest_info_wq);
if (g_guest_info_data != NULL)
kfree(g_guest_info_data);
#endif
destroy_workqueue(ts->himax_diag_wq);
destroy_workqueue(ts->flash_wq);
if (debug_data != NULL)
kfree(debug_data);
if (reg_read_data != NULL)
kfree(reg_read_data);
return 0;
}
EXPORT_SYMBOL(himax_debug_remove);