/* Himax Android Driver Sample Code for debug nodes * * Copyright (C) 2021 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.h" #include "himax_debug.h" #include "himax_ic_core.h" static ssize_t himax_crc_test_read(struct himax_ts_data *ts, char *buf, size_t len) { ssize_t ret = 0; uint8_t result = 0; uint32_t size = 0; ts->core_fp.fp_sense_off(ts, true); msleep(20); size = FW_SIZE_128k; result = ts->core_fp.fp_calculateChecksum(ts, false, size); ts->core_fp.fp_sense_on(ts, 0x01); if (result) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CRC test is Pass!\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.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) { struct himax_ts_data *ts = PDE_DATA(file_inode(file)); ssize_t ret = 0; ts->core_fp.fp_reload_disable(ts, 0); ts->core_fp.fp_power_on_init(ts); ts->core_fp.fp_read_FW_ver(ts); ts->core_fp.fp_touch_information(ts); if (!ts->hx_proc_send_flag) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC = %s\n", ts->chip_name); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Architecture Version = 0x%2.2X\n", ts->ic_data->vendor_arch_ver); if (ts->chip_cell_type == CHIP_IS_ON_CELL) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CONFIG_VER = 0x%2.2X\n", ts->ic_data->vendor_config_ver); } else { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Touch Config. Version = 0x%2.2X\n", ts->ic_data->vendor_touch_cfg_ver); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Display Config. Version = 0x%2.2X\n", ts->ic_data->vendor_display_cfg_ver); } if (ts->ic_data->vendor_cid_maj_ver < 0 && ts->ic_data->vendor_cid_min_ver < 0) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CID = NULL\n"); } else { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CID = 0x%2.2X\n", (ts->ic_data->vendor_cid_maj_ver << 8 | ts->ic_data->vendor_cid_min_ver)); } if (ts->ic_data->vendor_panel_ver < 0) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Panel Version = NULL\n"); } else { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Panel Version = 0x%2.2X\n", ts->ic_data->vendor_panel_ver); } if (ts->chip_cell_type == CHIP_IS_IN_CELL) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Cusomer = %s\n", ts->ic_data->vendor_cus_info); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Project Name = %s\n", ts->ic_data->vendor_proj_info); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Config. Date = %s\n", ts->ic_data->vendor_config_date); } ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Himax Touch Driver Version:\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%s\n", HIMAX_DRIVER_VER); ts->hx_proc_send_flag = 1; if (copy_to_user(buf, ts->debug.buf_tmp, (len > BUF_SIZE) ? BUF_SIZE : len)) I("%s,here:%d\n", __func__, __LINE__); } else { ts->hx_proc_send_flag = 0; } return ret; } static const struct proc_ops himax_proc_vendor_ops = { .proc_read = himax_vendor_read, }; static ssize_t himax_attn_read(struct himax_ts_data *ts, char *buf, size_t len) { ssize_t ret = 0; ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "attn = %x\n", himax_int_gpio_read(ts->pdata->gpio_irq)); return ret; } static ssize_t himax_int_en_read(struct himax_ts_data *ts, char *buf, size_t len) { size_t ret = 0; ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%d\n", ts->irq_enabled); return ret; } static ssize_t himax_int_en_write(struct himax_ts_data *ts, char *buf, size_t len) { int ret = 0; if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (buf[0] == '0') { himax_int_enable(ts, 0); } else if (buf[0] == '1') { himax_int_enable(ts, 1); } else if (buf[0] == '2') { himax_int_enable(ts, 0); free_irq(ts->hx_irq, ts); ts->irq_enabled = 0; } else if (buf[0] == '3') { ret = himax_int_en_set(ts); if (ret == 0) { ts->irq_enabled = 1; atomic_set(&ts->irq_state, 1); } } else return -EINVAL; return len; } static ssize_t himax_layout_read(struct himax_ts_data *ts, char *buf, size_t len) { size_t ret = 0; ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%d ", ts->pdata->abs_x_min); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%d ", ts->pdata->abs_x_max); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%d ", ts->pdata->abs_y_min); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%d ", ts->pdata->abs_y_max); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "\n"); return ret; } static ssize_t himax_layout_write(struct himax_ts_data *ts, char *buf, size_t len) { 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); I("%s failed to get value, ret:%d\n", __func__, ret); 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); himax_input_register(ts); } 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(struct himax_ts_data *ts, char *buf, size_t len) { size_t ret = 0; ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%u\n", ts->debug_log_level); if (copy_to_user(buf, ts->debug.buf_tmp, (len > BUF_SIZE) ? BUF_SIZE : len)) I("%s,here:%d\n", __func__, __LINE__); return ret; } static ssize_t himax_debug_level_write(struct himax_ts_data *ts, char *buf, size_t len) { int i; 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(struct himax_ts_data *ts, char *buf, size_t len) { int ret = 0; uint16_t loop_i; memset(ts->debug.reg_read_data, 0x00, 128 * sizeof(uint8_t)); I("himax_register_show: %02X,%02X,%02X,%02X\n", ts->debug.reg_cmd[3], ts->debug.reg_cmd[2], ts->debug.reg_cmd[1], ts->debug.reg_cmd[0]); himax_mcu_register_read(ts, ts->debug.reg_cmd, 128, ts->debug.reg_read_data, ts->debug.cfg_flag); ret += snprintf(ts->debug.buf_tmp + ret, len - ret, "command: %02X,%02X,%02X,%02X\n", ts->debug.reg_cmd[3], ts->debug.reg_cmd[2], ts->debug.reg_cmd[1], ts->debug.reg_cmd[0]); for (loop_i = 0; loop_i < 128; loop_i++) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "0x%2.2X ", ts->debug.reg_read_data[loop_i]); if ((loop_i % 16) == 15) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "\n"); } ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "\n"); return ret; } static ssize_t himax_proc_register_write(struct himax_ts_data *ts, 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(ts->debug.reg_cmd, 0x0, sizeof(ts->debug.reg_cmd)); 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; ts->debug.cfg_flag = 1; memcpy(buff_tmp, data_str + base + 1, length); } else { ts->debug.cfg_flag = 0; memcpy(buff_tmp, data_str + 1, length); } ts->debug.byte_length = length / 2; if (!kstrtoul(buff_tmp, 16, &result)) { for (loop_i = 0; loop_i < ts->debug.byte_length; loop_i++) ts->debug.reg_cmd[loop_i] = (uint8_t)(result >> loop_i * 8); } break; case 'w': if (buf[3] == 'F' && buf[4] == 'E') { ts->debug.cfg_flag = 1; memcpy(buff_tmp, buf + base + 3, length); } else { ts->debug.cfg_flag = 0; memcpy(buff_tmp, buf + 3, length); } if (count < 3) { ts->debug.byte_length = length / 2; if (!kstrtoul(buff_tmp, 16, &result)) { /* command */ for (loop_i = 0; loop_i < ts->debug.byte_length; loop_i++) { ts->debug.reg_cmd[loop_i] = (uint8_t)(result >> loop_i * 8); } } if (!kstrtoul(data_str + 1, 16, &result)) { /* data */ for (loop_i = 0; loop_i < ts->debug.byte_length; loop_i++) { w_data[loop_i] = (uint8_t)(result >> loop_i * 8); } } himax_mcu_register_write(ts, ts->debug.reg_cmd, ts->debug.byte_length, w_data, ts->debug.cfg_flag); } else { for (loop_i = 0; loop_i < count; loop_i++) { /* parsing addr after 'x' */ memset(buff_tmp, 0x0, sizeof(buff_tmp)); if (ts->debug.cfg_flag != 0 && loop_i != 0) ts->debug.byte_length = 2; else ts->debug.byte_length = x_pos[1] - x_pos[0] - 2; /* original */ memcpy(buff_tmp, buf + x_pos[loop_i] + 1, ts->debug.byte_length); /* I("%s: buff_tmp = %s\n",*/ /* __func__, buff_tmp);*/ if (!kstrtoul(buff_tmp, 16, &result)) { if (loop_i == 0) ts->debug.reg_cmd[loop_i] = (uint8_t)(result); /* I("%s: * reg_cmd * = %X\n", __func__, * reg_cmd[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]); */ } } ts->debug.byte_length = count - 1; himax_mcu_register_write(ts, ts->debug.reg_cmd, ts->debug.byte_length, &w_data[0], ts->debug.cfg_flag); } break; }; } return len; } static void himax_burn_GMA_to_flash(struct himax_ts_data *ts, uint8_t *gma_buf, uint8_t type) { uint16_t CFG_4k_SIZE = 0x1000; uint32_t start_addr; uint8_t tmp_addr[4]; switch (type) { case 'V': /*Start to flash VCOM*/ start_addr = 0x28000; I("Item : VCOM\n"); break; case 'A': /*Start to flash Analog GMA*/ start_addr = 0x29000; I("Item : AGMA\n"); break; case 'D': /*Start to flash Digital GMA*/ start_addr = 0x2A000; I("Item : DGMA\n"); break; default: I("Input cmd is incorrect.\n"); return; } if (start_addr < 0x100) { tmp_addr[3] = 0x00; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = (uint8_t)start_addr; } else if (start_addr >= 0x100 && start_addr < 0x10000) { tmp_addr[3] = 0x00; tmp_addr[2] = 0x00; tmp_addr[1] = (uint8_t)(start_addr >> 8); tmp_addr[0] = (uint8_t)start_addr; } else if (start_addr >= 0x10000 && start_addr < 0x1000000) { tmp_addr[3] = 0x00; tmp_addr[2] = (uint8_t)(start_addr >> 16); tmp_addr[1] = (uint8_t)(start_addr >> 8); tmp_addr[0] = (uint8_t)start_addr; } ts->core_fp.fp_sector_erase(ts, start_addr, CFG_4k_SIZE); ts->core_fp.fp_flash_programming(ts, gma_buf, start_addr, CFG_4k_SIZE); if (ts->core_fp.fp_check_CRC(ts, tmp_addr, CFG_4k_SIZE) == 0) I("Burn GMA Success!\n"); else E("Burn GMA FAIL!\n"); } static uint8_t himax_convert_char2int(uint8_t src) { uint8_t result; if ((src <= '9') && (src >= '0')) { result = src - '0'; } else if ((src <= 'F') && (src >= 'A')) { result = src - 'A' + 0x0a; } else if ((src <= 'f') && (src >= 'a')) { result = src - 'a' + 0x0a; } else { result = 0xFF; } return result; } static uint8_t *himax_convert_GMA_data(struct himax_ts_data *ts, uint8_t *data, size_t data_size) { uint8_t HEX_check[3]; uint8_t GMA_content = 0; uint16_t CFG_4k_SIZE = 0x1000; uint32_t i = 0; uint32_t GMA_length = 0; uint32_t crc_value = 0; ts->debug.gma_buf = kcalloc(CFG_4k_SIZE, sizeof(uint8_t), GFP_KERNEL); memset(HEX_check, 0xFF, 3); memset(ts->debug.gma_buf, 0x00, CFG_4k_SIZE * sizeof(uint8_t)); while (i < data_size) { if (data[i] == ',') { memset(HEX_check, 0xFF, 3); goto next_interation; } else if (data[i] == 'x') { if (HEX_check[1] == 0xFF) { HEX_check[1] = data[i]; goto next_interation; } } else if (data[i] == '0') { if (HEX_check[0] == 0xFF) { HEX_check[0] = data[i]; goto next_interation; } } else if (himax_convert_char2int(data[i]) == 0xFF) { goto next_interation; } if ((HEX_check[1] == 'x') && (HEX_check[0] == '0')) { if (HEX_check[2] == 0xFF) { HEX_check[2] = data[i]; GMA_content = himax_convert_char2int(data[i]); } else { GMA_content = (GMA_content << 4) + himax_convert_char2int(data[i]); ts->debug.gma_buf[8 + GMA_length] = GMA_content; ++GMA_length; } } next_interation: i++; } ts->debug.gma_buf[0] = (GMA_length) % 0x100; ts->debug.gma_buf[1] = (GMA_length >> 8) % 0x100; ts->debug.gma_buf[2] = (GMA_length >> 16) % 0x100; ts->debug.gma_buf[3] = (GMA_length >> 24) % 0x100; crc_value = ts->core_fp.fp_Calculate_CRC_with_AP(ts, ts->debug.gma_buf, 0, CFG_4k_SIZE - 4); ts->debug.gma_buf[CFG_4k_SIZE - 4] = (crc_value) % 0x100; ts->debug.gma_buf[CFG_4k_SIZE - 3] = (crc_value >> 8) % 0x100; ts->debug.gma_buf[CFG_4k_SIZE - 2] = (crc_value >> 16) % 0x100; ts->debug.gma_buf[CFG_4k_SIZE - 1] = (crc_value >> 24) % 0x100; return ts->debug.gma_buf; } static ssize_t himax_GMA_cmd_write(struct himax_ts_data *ts, char *buf, size_t len) { char *fileName = NULL; const struct firmware *fw = NULL; if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } I("himax %s\n", buf); if ((buf[0] == 'A' && buf[1] == 'G' && buf[2] == 'M' && buf[3] == 'A') || (buf[0] == 'V' && buf[1] == 'C' && buf[2] == 'O' && buf[3] == 'M') || (buf[0] == 'D' && buf[1] == 'G' && buf[2] == 'M' && buf[3] == 'A')) { switch (buf[0]) { case 'A': fileName = "AGMA.txt"; break; case 'V': fileName = "VCOM.txt"; break; case 'D': fileName = "DGMA.txt"; break; }; } request_firmware(&fw, fileName, ts->dev); if (fw) himax_convert_GMA_data(ts, (uint8_t *)fw->data, fw->size); himax_burn_GMA_to_flash(ts, ts->debug.gma_buf, buf[0]); kfree(ts->debug.gma_buf); if (fw) kfree(fw); return len; } static int32_t *getMutualBuffer(struct himax_ts_data *ts) { return ts->debug.diag_mutual; } static int32_t *getMutualNewBuffer(struct himax_ts_data *ts) { return ts->debug.diag_mutual_new; } static int32_t *getMutualOldBuffer(struct himax_ts_data *ts) { return ts->debug.diag_mutual_old; } static int32_t *getSelfBuffer(struct himax_ts_data *ts) { return ts->debug.diag_self; } static int32_t *getSelfNewBuffer(struct himax_ts_data *ts) { return ts->debug.diag_self_new; } static int32_t *getSelfOldBuffer(struct himax_ts_data *ts) { return ts->debug.diag_self_old; } static void setMutualBuffer(struct himax_ts_data *ts, uint8_t x_num, uint8_t y_num) { ts->debug.diag_mutual = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); } static void setMutualNewBuffer(struct himax_ts_data *ts, uint8_t x_num, uint8_t y_num) { ts->debug.diag_mutual_new = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); } static void setMutualOldBuffer(struct himax_ts_data *ts, uint8_t x_num, uint8_t y_num) { ts->debug.diag_mutual_old = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); } static void setSelfBuffer(struct himax_ts_data *ts, uint8_t x_num, uint8_t y_num) { ts->debug.diag_self = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); } static void setSelfNewBuffer(struct himax_ts_data *ts, uint8_t x_num, uint8_t y_num) { ts->debug.diag_self_new = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); } static void setSelfOldBuffer(struct himax_ts_data *ts, uint8_t x_num, uint8_t y_num) { ts->debug.diag_self_old = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); } #if defined(HX_TP_PROC_2T2R) static int32_t *getMutualBuffer_2(struct himax_ts_data *ts) { return ts->debug.diag_mutual_2; } static void setMutualBuffer_2(struct himax_ts_data *ts, uint8_t x_num_2, uint8_t y_num_2) { ts->debug.diag_mutual_2 = kzalloc(x_num_2 * y_num_2 * sizeof(int32_t), GFP_KERNEL); } #endif static int himax_set_diag_cmd(struct himax_ts_data *ts, struct himax_ic_data *ic_data, struct himax_report_data *hx_touch_data) { 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 (!ts->core_fp.fp_diag_check_sum(ts, hx_touch_data)) goto bypass_checksum_failed_packet; #if defined(HX_TP_PROC_2T2R) if (ts->debug.is_2t2r && (hx_touch_data->diag_cmd >= 4 && hx_touch_data->diag_cmd <= 6)) { mutual_data = getMutualBuffer_2(ts); self_data = getSelfBuffer(ts); /* initiallize the block number of mutual and self */ mul_num = ic_data->HX_RX_NUM_2 * ic_data->HX_TX_NUM_2; self_num = ic_data->HX_RX_NUM_2 + ic_data->HX_TX_NUM_2; } else #endif { mutual_data = getMutualBuffer(ts); self_data = getSelfBuffer(ts); /* initiallize the block number of mutual and self */ mul_num = ic_data->HX_RX_NUM * ic_data->HX_TX_NUM; self_num = ic_data->HX_RX_NUM + ic_data->HX_TX_NUM; } ts->core_fp.fp_diag_parse_raw_data(ts, 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(ts->debug.diag_coor, 0x00, sizeof(ts->debug.diag_coor)); memcpy(&(ts->debug.diag_coor[0]), &hx_touch_data->hx_coord_buf[0], hx_touch_data->touch_info_size); } /* assign state info data */ memcpy(&(ts->debug.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) */ static void himax_log_touch_data(struct himax_ts_data *ts, int start) { int loop_i = 0; int print_size = 0; uint8_t *buf = NULL; if (start == 1) return; /* report data when end of ts_work*/ if (ts->hx_touch_data->diag_cmd > 0) { print_size = ts->hx_touch_data->touch_all_size; buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); if (buf == NULL) { E("%s, Failed to allocate memory\n", __func__); return; } memcpy(buf, ts->hx_touch_data->hx_coord_buf, ts->hx_touch_data->touch_info_size); memcpy(&buf[ts->hx_touch_data->touch_info_size], ts->hx_touch_data->hx_rawdata_buf, print_size - ts->hx_touch_data->touch_info_size); } else if (ts->hx_touch_data->diag_cmd == 0) { print_size = ts->hx_touch_data->touch_info_size; buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); if (buf == NULL) { E("%s, Failed to allocate memory\n", __func__); return; } memcpy(buf, ts->hx_touch_data->hx_coord_buf, print_size); } else { E("%s:cmd fault\n", __func__); return; } 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); } #define PRT_LOG "Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, Int_Delay_Cnt:%d\n" static 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 (ts->target_report_data->finger_on > 0 && ts->target_report_data->finger_num > 0) { for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { if (ts->target_report_data->x[loop_i] >= 0 && ts->target_report_data->x[loop_i] <= ts->pdata->abs_x_max && ts->target_report_data->y[loop_i] >= 0 && ts->target_report_data->y[loop_i] <= ts->pdata->abs_y_max) { I(PRT_LOG, loop_i + 1, ts->target_report_data->x[loop_i], ts->target_report_data->y[loop_i], ts->target_report_data->w[loop_i], ts->target_report_data->w[loop_i], loop_i + 1, ts->target_report_data->ig_count); } } } else if (ts->target_report_data->finger_on == 0 && ts->target_report_data->finger_num == 0) { I("All Finger leave\n"); } else { I("%s : wrong input!\n", __func__); } } static void himax_log_touch_int_devation(struct himax_ts_data *ts, int touched) { if (touched == HX_FINGER_ON) { ktime_get_real_ts64(&ts->debug.time_start); /* I(" Irq start time = %ld.%06ld s\n", * time_start.tv_sec, time_start.tv_nsec/1000); */ } else if (touched == HX_FINGER_LEAVE) { ktime_get_real_ts64(&ts->debug.time_end); ts->debug.time_delta.tv_nsec = (ts->debug.time_end.tv_sec * 1000000000 + ts->debug.time_end.tv_nsec) - (ts->debug.time_start.tv_sec * 1000000000 + ts->debug.time_start.tv_nsec); /* I("Irq finish time = %ld.%06ld s\n", * time_end.tv_sec, time_end.tv_nsec/1000); */ I("Touch latency = %ld us\n", ts->debug.time_delta.tv_nsec / 1000); I("bus_speed = %d kHz\n", ts->bus_speed); if (ts->target_report_data->finger_on == 0 && ts->target_report_data->finger_num == 0) I("All Finger leave\n"); } else { I("%s : wrong input!\n", __func__); } } #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" static 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 (ts->target_report_data->x[loop_i] >= 0 && ts->target_report_data->x[loop_i] <= ts->pdata->abs_x_max && ts->target_report_data->y[loop_i] >= 0 && ts->target_report_data->y[loop_i] <= ts->pdata->abs_y_max) { I(RAW_DOWN_STATUS, loop_i + 1, ts->target_report_data->x[loop_i], ts->target_report_data->y[loop_i], ts->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); */ } } } } static 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(ts, 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(ts, 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(struct himax_ts_data *ts, uint8_t str_pw, uint8_t end_pw) { uint8_t data[4] = { 0 }; int count = 0; /*sense off*/ ts->core_fp.fp_sense_off(ts, true); /*mode change*/ data[1] = str_pw; data[0] = str_pw; if (ts->core_fp.fp_assign_sorting_mode != NULL) ts->core_fp.fp_assign_sorting_mode(ts, data); /*sense on*/ ts->core_fp.fp_sense_on(ts, 0x01); /*wait mode change*/ do { if (ts->core_fp.fp_check_sorting_mode != NULL) ts->core_fp.fp_check_sorting_mode(ts, data); if ((data[0] == end_pw) && (data[1] == end_pw)) return 0; I("Now retry %d times!\n", count); count++; msleep(50); } while (count < 50); return ERR_WORK_OUT; } #define PRT_OK_LOG "%s: change mode 0x%4X. str_pw = %2X, end_pw = %2X\n" #define PRT_FAIL_LOG "%s: change mode failed. str_pw = %2X, end_pw = %2X\n" static ssize_t himax_diag_cmd_write(struct himax_ts_data *ts, char *buf, size_t len) { 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__, ts->debug.dsram_flag); if (ts->debug.dsram_flag) { /*Cancal work queue and return to stack*/ ts->debug.process_type = 0; ts->debug.dsram_flag = false; cancel_delayed_work(&ts->himax_diag_delay_wrok); himax_int_enable(ts, 1); ts->core_fp.fp_return_event_stack(ts); } ts->core_fp.fp_diag_register_set(ts, ts->diag_cmd, 0, false); I("%s: Set raw out select 0x%X.\n", __func__, ts->diag_cmd); } if (!ts->diag_cmd) { if (ts->debug.mode_flag) /*back to normal mode*/ himax_change_mode(ts, 0x00, 0x99); } break; case 2: /*data processing + rawout select - diag,XY*/ if (!kstrtoint(buf, 16, &rst)) { ts->debug.process_type = (rst >> 4) & 0xF; ts->diag_cmd = rst & 0xF; } if (ts->diag_cmd == 0) break; else if (ts->debug.process_type > 0 && ts->debug.process_type <= 3) { if (!ts->debug.dsram_flag) { /*Start wrok queue*/ himax_int_enable(ts, 0); ts->core_fp.fp_diag_register_set(ts, ts->diag_cmd, ts->debug.process_type, false); queue_delayed_work(ts->himax_diag_wq, &ts->himax_diag_delay_wrok, 2 * HZ / 100); ts->debug.dsram_flag = true; I("%s: Start get raw data in DSRAM\n", __func__); } else { ts->core_fp.fp_diag_register_set(ts, ts->diag_cmd, ts->debug.process_type, false); } } break; case 4: /*data processing + rawout select - diag,XXYY*/ /*ex:XXYY=010A=dsram rawdata*/ I("%s, now case 4\n", __func__); if (!kstrtoint(buf, 16, &rst)) { ts->debug.process_type = (rst >> 8) & 0xFF; ts->diag_cmd = rst & 0xFF; I("%s:process_type=0x%02X, diag_cmd=0x%02X\n", __func__, ts->debug.process_type, ts->diag_cmd); } if (ts->debug.process_type <= 0 || ts->diag_cmd <= 0) break; else if (ts->debug.process_type > 0 && ts->debug.process_type <= 3) { if (!ts->debug.dsram_flag) { /*Start wrok queue*/ himax_int_enable(ts, 0); ts->core_fp.fp_diag_register_set(ts, ts->diag_cmd, ts->debug.process_type, true); queue_delayed_work(ts->himax_diag_wq, &ts->himax_diag_delay_wrok, 2 * HZ / 100); ts->debug.dsram_flag = true; I("%s: Start get raw data in DSRAM\n", __func__); } else { ts->core_fp.fp_diag_register_set(ts, ts->diag_cmd, ts->debug.process_type, true); } } 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(ts, str_pw, end_pw)) { ts->debug.mode_flag = 1; I(PRT_OK_LOG, __func__, rst, str_pw, end_pw); } else I(PRT_FAIL_LOG, __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(struct himax_ts_data *ts, char *buf, size_t len) { if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } ts->debug.diag_arr_num = buf[0] - '0'; I("%s: diag_arr_num = %d\n", __func__, ts->debug.diag_arr_num); return len; } static void himax_get_mutual_edge(struct himax_ts_data *ts) { int i = 0; for (i = 0; i < (ts->ic_data->HX_RX_NUM * ts->ic_data->HX_TX_NUM); i++) { if (ts->debug.diag_mutual[i] > ts->debug.max_mutual) ts->debug.max_mutual = ts->debug.diag_mutual[i]; if (ts->debug.diag_mutual[i] < ts->debug.min_mutual) ts->debug.min_mutual = ts->debug.diag_mutual[i]; } } static void himax_get_self_edge(struct himax_ts_data *ts) { int i = 0; for (i = 0; i < (ts->ic_data->HX_RX_NUM + ts->ic_data->HX_TX_NUM); i++) { if (ts->debug.diag_self[i] > ts->debug.max_self) ts->debug.max_self = ts->debug.diag_self[i]; if (ts->debug.diag_self[i] < ts->debug.min_self) ts->debug.min_self = ts->debug.diag_self[i]; } } static void print_state_info(struct seq_file *s) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); /* seq_printf(s, "State_info_2bytes:%3d, %3d\n", * _state_info[0],hx_state_info[1]); */ seq_printf(s, "ReCal = %d\t", ts->debug.hx_state_info[0] & 0x01); seq_printf(s, "Palm = %d\t", ts->debug.hx_state_info[0] >> 1 & 0x01); seq_printf(s, "AC mode = %d\t", ts->debug.hx_state_info[0] >> 2 & 0x01); seq_printf(s, "Water = %d\n", ts->debug.hx_state_info[0] >> 3 & 0x01); seq_printf(s, "Glove = %d\t", ts->debug.hx_state_info[0] >> 4 & 0x01); seq_printf(s, "TX Hop = %d\t", ts->debug.hx_state_info[0] >> 5 & 0x01); seq_printf(s, "Base Line = %d\t", ts->debug.hx_state_info[0] >> 6 & 0x01); seq_printf(s, "OSR Hop = %d\t", ts->debug.hx_state_info[1] >> 3 & 0x01); seq_printf(s, "KEY = %d\n", ts->debug.hx_state_info[1] >> 4 & 0x0F); } static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); if (transpose) seq_printf(s, "%6d", ts->debug.diag_mutual[j + i * ts->ic_data->HX_RX_NUM]); else seq_printf(s, "%6d", ts->debug.diag_mutual[i + j * ts->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) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); int x_channel = ts->ic_data->HX_RX_NUM; int y_channel = ts->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", ts->debug.diag_self[j]); else seq_printf(s, " %5d\n", ts->debug.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", ts->debug.diag_self[x_channel - j - 1]); else seq_printf(s, " %5d\n", ts->debug.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) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); int j; int x_channel = ts->ic_data->HX_RX_NUM; int y_channel = ts->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", ts->debug.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", ts->debug.diag_self[j + x_channel]); } } } } /* determin the output format of diag */ static void himax_diag_arrange(struct seq_file *s) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); int x_channel = ts->ic_data->HX_RX_NUM; int y_channel = ts->ic_data->HX_TX_NUM; int bit2, bit1, bit0; int i; /* rotate bit */ bit2 = ts->debug.diag_arr_num >> 2; /* reverse Y */ bit1 = ts->debug.diag_arr_num >> 1 & 0x1; /* reverse X */ bit0 = ts->debug.diag_arr_num & 0x1; if (ts->debug.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", ts->debug.diag_self[i]); } else { for (i = 0; i < x_channel; i++) seq_printf(s, "%6d", ts->debug.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", ts->debug.diag_self[i]); } else { for (i = x_channel; i < x_channel + y_channel; i++) seq_printf(s, "%6d", ts->debug.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 */ static bool himax_ts_diag_func(struct himax_ts_data *ts) { int retry = 3; int i = 0, j = 0; unsigned int index = 0; int x_channel = ts->ic_data->HX_RX_NUM; int y_channel = ts->ic_data->HX_TX_NUM; int total_size = (y_channel * x_channel + y_channel + x_channel) * 2; uint8_t *info_data = NULL; 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 = ts->debug.process_type; info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); if (info_data == NULL) { E("%s: Failed to allocate memory\n", __func__); return false; } memset(info_data, 0, total_size * sizeof(uint8_t)); I("%s: process type=%d!\n", __func__, ts->debug.process_type); ts->core_fp.fp_burst_enable(ts, 1); if (dsram_type <= 2) { mutual_data = getMutualBuffer(ts); self_data = getSelfBuffer(ts); } else if (dsram_type == 3) { mutual_data = getMutualBuffer(ts); mutual_data_new = getMutualNewBuffer(ts); mutual_data_old = getMutualOldBuffer(ts); self_data = getSelfBuffer(ts); self_data_new = getSelfNewBuffer(ts); self_data_old = getSelfOldBuffer(ts); } do { if (ts->core_fp.fp_get_DSRAM_data(ts, info_data, ts->debug.dsram_flag)) break; } while (retry-- > 0); if (retry <= 0) { E("%s: Get DSRAM data failed\n", __func__); kfree(info_data); return false; } 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 = (((int8_t)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 */ } ts->debug.diag_max_cnt++; if (dsram_type >= 1 && dsram_type <= 3) { queue_delayed_work(ts->himax_diag_wq, &ts->himax_diag_delay_wrok, 1 / 10 * HZ); } return true; } static int himax_diag_print(struct seq_file *s, void *v) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); int x_num = ts->ic_data->HX_RX_NUM; int y_num = ts->ic_data->HX_TX_NUM; size_t ret = 0; /* don't add KEY_COUNT */ 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"); seq_puts(s, "ChannelEnd"); seq_puts(s, "\n"); /* print Mutual/Slef Maximum and Minimum */ himax_get_mutual_edge(ts); himax_get_self_edge(ts); seq_printf(s, "Mutual Max:%3d, Min:%3d\n", ts->debug.max_mutual, ts->debug.min_mutual); seq_printf(s, "Self Max:%3d, Min:%3d\n", ts->debug.max_self, ts->debug.min_self); /* recovery status after print*/ ts->debug.max_mutual = 0; ts->debug.min_mutual = 0xFFFF; ts->debug.max_self = 0; ts->debug.min_self = 0xFFFF; /*pring state info*/ print_state_info(s); if (s->count >= s->size) ts->debug.h_overflow++; return ret; } static int himax_diag_stack_read(struct seq_file *s, void *v) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); 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); }; static const struct proc_ops himax_proc_stack_ops = { //.owner = THIS_MODULE, .proc_open = himax_diag_stack_open, .proc_read = seq_read, .proc_release = seq_release, }; static int himax_sram_read(struct seq_file *s, void *v, uint8_t rs) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); int d_type = 0; d_type = (!ts->diag_cmd) ? rs : ts->diag_cmd; if (!ts->debug.h_overflow) { if (!ts->debug.process_type) { himax_int_enable(ts, 0); ts->core_fp.fp_diag_register_set(ts, d_type, 0, false); if (!himax_ts_diag_func(ts)) seq_puts(s, "Get sram data failed."); else himax_diag_print(s, v); ts->diag_cmd = 0; ts->core_fp.fp_diag_register_set(ts, 0, 0, false); himax_int_enable(ts, 1); } } if ((ts->debug.process_type <= 3 && ts->diag_cmd && ts->debug.dsram_flag) || ts->debug.h_overflow) { himax_diag_print(s, v); ts->debug.h_overflow = 0; } return 0; } static int himax_diag_delta_read(struct seq_file *s, void *v) { return himax_sram_read(s, v, 0x09); } static const struct seq_operations himax_diag_delta_ops = { .start = himax_diag_seq_start, .next = himax_diag_seq_next, .stop = himax_diag_seq_stop, .show = himax_diag_delta_read, }; static int himax_diag_delta_open(struct inode *inode, struct file *file) { return seq_open(file, &himax_diag_delta_ops); }; static const struct proc_ops himax_proc_delta_ops = { //.owner = THIS_MODULE, .proc_open = himax_diag_delta_open, .proc_read = seq_read, .proc_release = seq_release, }; 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); }; static const struct proc_ops himax_proc_dc_ops = { //.owner = THIS_MODULE, .proc_open = himax_diag_dc_open, .proc_read = seq_read, .proc_release = seq_release, }; static int himax_diag_baseline_read(struct seq_file *s, void *v) { return himax_sram_read(s, v, 0x0B); } static const struct seq_operations himax_diag_baseline_ops = { .start = himax_diag_seq_start, .next = himax_diag_seq_next, .stop = himax_diag_seq_stop, .show = himax_diag_baseline_read, }; static int himax_diag_baseline_open(struct inode *inode, struct file *file) { return seq_open(file, &himax_diag_baseline_ops); }; static const struct proc_ops himax_proc_baseline_ops = { //.owner = THIS_MODULE, .proc_open = himax_diag_baseline_open, .proc_read = seq_read, .proc_release = seq_release, }; static ssize_t himax_reset_write(struct himax_ts_data *ts, char *buf, size_t len) { if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } #if defined(HX_RST_PIN_FUNC) if (buf[0] == '1') ts->core_fp.fp_ic_reset(ts, false, false); else if (buf[0] == '2') ts->core_fp.fp_ic_reset(ts, false, true); else if (buf[0] == '3') ts->core_fp.fp_ic_reset(ts, true, false); else if (buf[0] == '4') ts->core_fp.fp_ic_reset(ts, true, true); /* else if (buf[0] == '5') */ /* ESD_HW_REST(); */ #endif return len; } static ssize_t himax_proc_FW_debug_read(struct himax_ts_data *ts, char *buf, size_t len) { ssize_t ret = 0; uint8_t i = 0; uint8_t addr[4] = { 0 }; uint8_t data[4] = { 0 }; len = (size_t)(sizeof(himax_dbg_reg_ary) / sizeof(uint32_t)); for (i = 0; i < len; i++) { himax_parse_assign_cmd(himax_dbg_reg_ary[i], addr, 4); himax_mcu_register_read(ts, addr, DATA_LEN_4, data, 0); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", himax_dbg_reg_ary[i], data[0], data[1], data[2], data[3]); I("reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", himax_dbg_reg_ary[i], data[0], data[1], data[2], data[3]); } return ret; } static void setFlashBuffer(struct himax_ts_data *ts) { ts->debug.flash_buffer = kcalloc(ts->debug.flash_size, sizeof(uint8_t), GFP_KERNEL); } static void flash_dump_prog_set(struct himax_ts_data *ts, uint8_t prog) { ts->debug.flash_progress = prog; if (prog == ONGOING) ts->debug.flash_dump_going = ONGOING; else ts->debug.flash_dump_going = START; } static int himax_proc_flash_read(struct seq_file *s, void *v) { struct himax_ts_data *ts = PDE_DATA(file_inode(s->file)); ssize_t ret = 0; int i; uint8_t flash_progress = ts->debug.flash_progress; uint8_t flash_cmd = ts->debug.flash_cmd; bool flash_rst = ts->debug.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 < ts->debug.flash_size; i++) { seq_printf(s, "0x%02X,", ts->debug.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) { struct himax_ts_data *ts = PDE_DATA(file_inode(filp)); 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 (ts->debug.flash_progress == ONGOING) { E("%s: process is busy , return!\n", __func__); return len; } if ((buf[1] == '_') && (buf[2] == '6')) { if (buf[3] == '4') ts->debug.flash_size = FW_SIZE_64k; } else if ((buf[1] == '_') && (buf[2] == '2')) { if (buf[3] == '8') ts->debug.flash_size = FW_SIZE_128k; } /*1 : print flash to window, 2 : dump to sdcard*/ if (buf[0] == '1') { /* 1_64,1_28 for flash size: * 64k,128k */ ts->debug.flash_cmd = 1; flash_dump_prog_set(ts, START); ts->debug.flash_dump_rst = true; queue_work(ts->flash_wq, &ts->flash_work); } else if (buf[0] == '2') { /* 2_64,2_28 for flash size: * 64k,128k */ ts->debug.flash_cmd = 2; flash_dump_prog_set(ts, START); ts->debug.flash_dump_rst = true; queue_work(ts->flash_wq, &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); }; static const struct proc_ops himax_proc_flash_ops = { //.owner = THIS_MODULE, .proc_open = himax_flash_dump_proc_open, .proc_read = seq_read, .proc_write = himax_proc_flash_write, }; static void himax_ts_flash_func(struct himax_ts_data *ts) { uint8_t flash_command = ts->debug.flash_cmd; himax_int_enable(ts, 0); flash_dump_prog_set(ts, ONGOING); /*msleep(100);*/ I("%s: flash_command = %d enter.\n", __func__, flash_command); if (flash_command == 1 || flash_command == 2) { ts->core_fp.fp_flash_dump_func(ts, flash_command, ts->debug.flash_size, ts->debug.flash_buffer); ts->debug.flash_dump_rst = true; } I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); /* if (flash_command == 2) { * struct file *fn; * struct filename *vts_name; * * vts_name = getname_kernel(FLASH_DUMP_FILE); * fn = 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(ts, 1); flash_dump_prog_set(ts, FINISHED); } static ssize_t himax_sense_on_off_write(struct himax_ts_data *ts, char *buf, size_t len) { if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (buf[0] == '0') { ts->core_fp.fp_sense_off(ts, true); I("Sense off\n"); } else if (buf[0] == '1') { if (buf[1] == 's') { ts->core_fp.fp_sense_on(ts, 0x00); I("Sense on re-map on, run sram\n"); } else { ts->core_fp.fp_sense_on(ts, 0x01); I("Sense on re-map off, run flash\n"); } } else { I("Do nothing\n"); } return len; } static ssize_t himax_debug_read(struct file *file, char *buf, size_t len, loff_t *pos) { struct himax_ts_data *ts = PDE_DATA(file_inode(file)); ssize_t ret = 0; int i = 0; if (!ts->hx_proc_send_flag) { I("%s, Enter\n", __func__); memset(ts->debug.buf_tmp, 0, sizeof(ts->debug.buf_tmp)); if (dbg_cmd_flag) { if (dbg_func_ptr_r[dbg_cmd_flag]) ret += dbg_func_ptr_r[dbg_cmd_flag](ts, buf, len); else goto END_FUNC_R; } if (ts->debug.debug_level_cmd == 't') { if (!ts->debug.fw_update_going) { if (ts->debug.fw_update_complete) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Update Complete "); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Update Fail "); } else { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Update Ongoing "); } } else if (ts->debug.debug_level_cmd == 'h') { if (ts->debug.handshaking_result == 0) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Handshaking Result = %d (MCU Running)\n", ts->debug.handshaking_result); else if (ts->debug.handshaking_result == 1) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Handshaking Result = %d (MCU Stop)\n", ts->debug.handshaking_result); else if (ts->debug.handshaking_result == 2) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Handshaking Result = %d (I2C Error)\n", ts->debug.handshaking_result); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Handshaking Result = error\n"); } else if (ts->debug.debug_level_cmd == 'v') { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Architecture Version = 0x%2.2X\n", ts->ic_data->vendor_arch_ver); if (ts->chip_cell_type == CHIP_IS_ON_CELL) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CONFIG_VER = 0x%2.2X\n", ts->ic_data->vendor_config_ver); else { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Touch Config. Version = 0x%2.2X\n", ts->ic_data->vendor_touch_cfg_ver); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "FW Display Config. Version = 0x%2.2X\n", ts->ic_data->vendor_display_cfg_ver); } if (ts->ic_data->vendor_cid_maj_ver < 0 && ts->ic_data->vendor_cid_min_ver < 0) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CID = NULL\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "CID = 0x%2.2X\n", (ts->ic_data->vendor_cid_maj_ver << 8 | ts->ic_data->vendor_cid_min_ver)); if (ts->ic_data->vendor_panel_ver < 0) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Panel Version = NULL\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Panel Version = 0x%2.2X\n", ts->ic_data->vendor_panel_ver); if (ts->chip_cell_type == CHIP_IS_IN_CELL) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Cusomer = %s\n", ts->ic_data->vendor_cus_info); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Project Name = %s\n", ts->ic_data->vendor_proj_info); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Config. Date = %s\n", ts->ic_data->vendor_config_date); } ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Himax Touch Driver Version:\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%s\n", HIMAX_DRIVER_VER); } else if (ts->debug.debug_level_cmd == 'd') { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Himax Touch IC Information :\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%s\n", ts->chip_name); switch (ts->ic_checksum) { case HX_TP_BIN_CHECKSUM_SW: ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC Checksum : SW\n"); break; case HX_TP_BIN_CHECKSUM_HW: ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC Checksum : HW\n"); break; case HX_TP_BIN_CHECKSUM_CRC: ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC Checksum : CRC\n"); break; default: ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC Checksum error.\n"); } if (ts->ic_data->HX_INT_IS_EDGE) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Driver register Interrupt : EDGE TIRGGER\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Driver register Interrupt : LEVEL TRIGGER\n"); if (ts->protocol_type == PROTOCOL_TYPE_A) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Protocol : TYPE_A\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Protocol : TYPE_B\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "RX Num : %d\n", ts->ic_data->HX_RX_NUM); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "TX Num : %d\n", ts->ic_data->HX_TX_NUM); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "BT Num : %d\n", ts->ic_data->HX_BT_NUM); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "X Resolution : %d\n", ts->ic_data->HX_X_RES); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Y Resolution : %d\n", ts->ic_data->HX_Y_RES); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Max Point : %d\n", ts->ic_data->HX_MAX_PT); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "XY reverse : %d\n", ts->ic_data->HX_XY_REVERSE); #if defined(HX_TP_PROC_2T2R) if (ts->debug.is_2t2r) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "2T2R panel\n"); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "RX Num_2 : %d\n", ts->debug.hx_rx_num_2); ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "TX Num_2 : %d\n", ts->debug.hx_tx_num_2); } #endif } else if (ts->debug.debug_level_cmd == 'n') { /* Edgd = 1, Level = 0 */ if (ts->core_fp.fp_read_ic_trigger_type(ts) == 1) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC Interrupt type is edge trigger.\n"); else if (ts->core_fp.fp_read_ic_trigger_type(ts) == 0) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "IC Interrupt type is level trigger.\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Unkown IC trigger type.\n"); if (ts->ic_data->HX_INT_IS_EDGE) ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Driver register Interrupt : EDGE TIRGGER\n"); else ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "Driver register Interrupt : LEVEL TRIGGER\n"); } else if (ts->debug.debug_level_cmd == 'l') { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "LotID : "); for (i = 0; i < 13; i++) { ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "%02X", ts->ic_data->vendor_ic_id[i]); } ret += snprintf(ts->debug.buf_tmp + ret, sizeof(ts->debug.buf_tmp) - ret, "\n"); } END_FUNC_R: if (copy_to_user(buf, ts->debug.buf_tmp, (len > BUF_SIZE) ? BUF_SIZE : len)) I("%s,here:%d\n", __func__, __LINE__); ts->hx_proc_send_flag = 1; } else { ts->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) { struct himax_ts_data *ts = PDE_DATA(file_inode(file)); char fileName[128]; char buf[80] = "\0"; int result = 0; int fw_type = 0; const struct firmware *fw = NULL; 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; ts->debug.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]) /* 2 => '/n' + ','*/ dbg_func_ptr_w[dbg_cmd_flag](ts, dbg_cmd_par, len - str_len - 2); 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] == 'v') { /* firmware version */ himax_int_enable(ts, 0); ts->debug.debug_level_cmd = buf[0]; ts->core_fp.fp_reload_disable(ts, 0); ts->core_fp.fp_power_on_init(ts); ts->core_fp.fp_read_FW_ver(ts); himax_int_enable(ts, 1); return len; } else if (buf[0] == 'd') { /* ic information */ ts->debug.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"); ts->ts_dbg = 1; } else if (buf[5] == '0') { I("Close Ts Debug!\n"); ts->ts_dbg = 0; } else { E("Parameter fault for ts debug\n"); } goto ENDFUCTION; } himax_int_enable(ts, 0); ts->debug.debug_level_cmd = buf[0]; ts->debug.fw_update_complete = false; ts->debug.fw_update_going = true; memset(fileName, 0, 128); /* parse the file name */ snprintf(fileName, len - 2, "%s", &buf[2]); I("NOW Running common flow update!\n"); I("%s: upgrade from file(%s) start!\n", __func__, fileName); result = request_firmware(&fw, fileName, 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(ts, 0); I("Now FW size is : %dk\n", fw_type); switch (fw_type) { case 64: if (ts->core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k( ts, (unsigned char *)fw->data, fw->size, false) == 0) { E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); ts->debug.fw_update_complete = false; } else { I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); ts->debug.fw_update_complete = true; } break; case 128: if (ts->core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k( ts, (unsigned char *)fw->data, fw->size, false) == 0) { E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); ts->debug.fw_update_complete = false; } else { I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); ts->debug.fw_update_complete = true; } break; default: E("%s: Flash command fail: %d\n", __func__, __LINE__); ts->debug.fw_update_complete = false; break; } release_firmware(fw); goto firmware_upgrade_done; } else if (buf[0] == 'i' && buf[1] == 'n' && buf[2] == 't') { /* INT trigger */ ts->debug.debug_level_cmd = 'n'; return len; } else if (buf[0] == 'l' && buf[1] == 'o' && buf[2] == 't') { ts->debug.debug_level_cmd = buf[0]; ts->core_fp.fp_sense_off(ts, true); ts->core_fp.fp_ic_id_read(ts); ts->core_fp.fp_sense_on(ts, 0x01); return len; } /* others,do nothing */ ts->debug.debug_level_cmd = 0; return len; firmware_upgrade_done: ts->debug.fw_update_going = false; ts->core_fp.fp_reload_disable(ts, 0); ts->core_fp.fp_reload_disable(ts, 0); ts->core_fp.fp_power_on_init(ts); /* need to be review with FW update flow */ result = himax_mcu_WP_BP_enable(ts); if (result < 0) { I("%s: WP BP enable fail\n", __func__); } ts->core_fp.fp_read_FW_ver(ts); ts->core_fp.fp_touch_information(ts); himax_int_enable(ts, 1); /* todo himax_chip->tp_firmware_upgrade_proceed = 0; * todo himax_chip->suspend_state = 0; * todo enable_irq(himax_chip->irq); */ ENDFUCTION: return len; } static const struct proc_ops himax_proc_debug_ops = { .proc_read = himax_debug_read, .proc_write = himax_debug_write, }; static void himax_himax_data_init(struct himax_ts_data *ts) { ts->debug.ops.fp_ts_dbg_func = himax_ts_dbg_func; ts->debug.ops.fp_set_diag_cmd = himax_set_diag_cmd; ts->debug.flash_dump_going = false; } static void himax_ts_flash_work_func(struct work_struct *work) { struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); himax_ts_flash_func(ts); } static void himax_ts_diag_work_func(struct work_struct *work) { struct himax_ts_data *ts = container_of(work, struct himax_ts_data, himax_diag_delay_wrok.work); himax_ts_diag_func(ts); } static 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_w[5] = himax_sense_on_off_write; dbg_func_ptr_r[6] = himax_debug_level_read; dbg_func_ptr_w[6] = himax_debug_level_write; dbg_func_ptr_r[7] = himax_int_en_read; dbg_func_ptr_w[7] = himax_int_en_write; dbg_func_ptr_w[8] = himax_proc_register_write; dbg_func_ptr_r[8] = himax_proc_register_read; dbg_func_ptr_w[9] = himax_reset_write; dbg_func_ptr_w[10] = himax_diag_arrange_write; dbg_func_ptr_w[11] = himax_diag_cmd_write; dbg_func_ptr_w[12] = himax_GMA_cmd_write; } int himax_touch_proc_init(struct himax_ts_data *ts) { ts->debug.procfs.diag_dir = proc_mkdir(HIMAX_PROC_DIAG_FOLDER, ts->debug.procfs.proc_dir); if (ts->debug.procfs.diag_dir == NULL) { E(" %s: diag_dir file create failed!\n", __func__); return -ENOMEM; } ts->debug.procfs.vendor = proc_create_data(HIMAX_PROC_VENDOR_FILE, 0444, ts->debug.procfs.proc_dir, &himax_proc_vendor_ops, ts); if (ts->debug.procfs.vendor == NULL) { E(" %s: proc vendor file create failed!\n", __func__); goto fail_1; } ts->debug.procfs.stack = proc_create_data( HIMAX_PROC_STACK_FILE, 0444, ts->debug.procfs.diag_dir, &himax_proc_stack_ops, ts); if (ts->debug.procfs.stack == NULL) { E(" %s: proc stack file create failed!\n", __func__); goto fail_2_1; } ts->debug.procfs.delta = proc_create_data( HIMAX_PROC_DELTA_FILE, 0444, ts->debug.procfs.diag_dir, &himax_proc_delta_ops, ts); if (ts->debug.procfs.delta == NULL) { E(" %s: proc delta file create failed!\n", __func__); goto fail_2_2; } ts->debug.procfs.dc = proc_create_data(HIMAX_PROC_DC_FILE, 0444, ts->debug.procfs.diag_dir, &himax_proc_dc_ops, ts); if (ts->debug.procfs.dc == NULL) { E(" %s: proc dc file create failed!\n", __func__); goto fail_2_3; } ts->debug.procfs.baseline = proc_create_data(HIMAX_PROC_BASELINE_FILE, 0444, ts->debug.procfs.diag_dir, &himax_proc_baseline_ops, ts); if (ts->debug.procfs.baseline == NULL) { E(" %s: proc baseline file create failed!\n", __func__); goto fail_2_4; } ts->debug.procfs.debug = proc_create_data( HIMAX_PROC_DEBUG_FILE, 0644, ts->debug.procfs.proc_dir, &himax_proc_debug_ops, ts); if (ts->debug.procfs.debug == NULL) { E(" %s: proc debug file create failed!\n", __func__); goto fail_3; } dbg_func_ptr_init(); ts->debug.procfs.flash_dump = proc_create_data(HIMAX_PROC_FLASH_DUMP_FILE, 0644, ts->debug.procfs.proc_dir, &himax_proc_flash_ops, ts); if (ts->debug.procfs.flash_dump == NULL) { E(" %s: proc flash dump file create failed!\n", __func__); goto fail_4; } return 0; /* remove_proc_entry(HIMAX_PROC_PEN_POS_FILE, ts->debug.procfs.proc_dir); */ fail_4: remove_proc_entry(HIMAX_PROC_DEBUG_FILE, ts->debug.procfs.proc_dir); fail_3: remove_proc_entry(HIMAX_PROC_BASELINE_FILE, ts->debug.procfs.diag_dir); fail_2_4: remove_proc_entry(HIMAX_PROC_DC_FILE, ts->debug.procfs.diag_dir); fail_2_3: remove_proc_entry(HIMAX_PROC_DELTA_FILE, ts->debug.procfs.diag_dir); fail_2_2: remove_proc_entry(HIMAX_PROC_STACK_FILE, ts->debug.procfs.diag_dir); fail_2_1: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, ts->debug.procfs.proc_dir); fail_1: return -ENOMEM; } void himax_touch_proc_deinit(struct himax_ts_data *ts) { remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, ts->debug.procfs.proc_dir); remove_proc_entry(HIMAX_PROC_DEBUG_FILE, ts->debug.procfs.proc_dir); remove_proc_entry(HIMAX_PROC_BASELINE_FILE, ts->debug.procfs.diag_dir); remove_proc_entry(HIMAX_PROC_DC_FILE, ts->debug.procfs.diag_dir); remove_proc_entry(HIMAX_PROC_DELTA_FILE, ts->debug.procfs.diag_dir); remove_proc_entry(HIMAX_PROC_STACK_FILE, ts->debug.procfs.diag_dir); remove_proc_entry(HIMAX_PROC_VENDOR_FILE, ts->debug.procfs.proc_dir); } int himax_debug_init(struct himax_ts_data *ts) { I("%s:Enter\n", __func__); if (ts == NULL) { E("%s: ts struct is NULL\n", __func__); return -EPROBE_DEFER; } ts->debug.min_mutual = 0xFFFF; ts->debug.min_self = 0xFFFF; ts->debug.flash_size = 0x2B000; /*0x20000;*/ ts->debug.reg_read_data = kzalloc(128 * sizeof(uint8_t), GFP_KERNEL); if (ts->debug.reg_read_data == NULL) { E("%s: reg_read_data allocate failed\n", __func__); goto err_alloc_reg_read_data_fail; } himax_himax_data_init(ts); 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); ts->debug.flash_progress = START; setFlashBuffer(ts); if (ts->debug.flash_buffer == NULL) { E("%s: flash buffer allocate fail failed\n", __func__); goto err_flash_buf_alloc_failed; } 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); setSelfBuffer(ts, ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM); if (getSelfBuffer(ts) == NULL) { E("%s: self buffer allocate failed\n", __func__); goto err_self_buf_alloc_failed; } setSelfNewBuffer(ts, ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM); if (getSelfNewBuffer(ts) == NULL) { E("%s: self new buffer allocate failed\n", __func__); goto err_self_new_alloc_failed; } setSelfOldBuffer(ts, ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM); if (getSelfOldBuffer(ts) == NULL) { E("%s: self old buffer allocate failed\n", __func__); goto err_self_old_alloc_failed; } setMutualBuffer(ts, ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM); if (getMutualBuffer(ts) == NULL) { E("%s: mutual buffer allocate failed\n", __func__); goto err_mut_buf_alloc_failed; } setMutualNewBuffer(ts, ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM); if (getMutualNewBuffer(ts) == NULL) { E("%s: mutual new buffer allocate failed\n", __func__); goto err_mut_new_alloc_failed; } setMutualOldBuffer(ts, ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM); if (getMutualOldBuffer(ts) == NULL) { E("%s: mutual old buffer allocate failed\n", __func__); goto err_mut_old_alloc_failed; } #if defined(HX_TP_PROC_2T2R) if (ts->debug.is_2t2r) { setMutualBuffer_2(ts, ts->ic_data->HX_RX_NUM_2, ts->ic_data->HX_TX_NUM_2); if (getMutualBuffer_2(ts) == NULL) { E("%s: mutual buffer 2 allocate failed\n", __func__); goto err_mut_buf2_alloc_failed; } } #endif if (himax_touch_proc_init(ts)) goto err_proc_init_failed; return 0; err_proc_init_failed: #if defined(HX_TP_PROC_2T2R) kfree(ts->debug.diag_mutual_2); ts->debug.diag_mutual_2 = NULL; err_mut_buf2_alloc_failed: #endif kfree(ts->debug.diag_mutual_old); ts->debug.diag_mutual_old = NULL; err_mut_old_alloc_failed: kfree(ts->debug.diag_mutual_new); ts->debug.diag_mutual_new = NULL; err_mut_new_alloc_failed: kfree(ts->debug.diag_mutual); ts->debug.diag_mutual = NULL; err_mut_buf_alloc_failed: kfree(ts->debug.diag_self_old); ts->debug.diag_self_old = NULL; err_self_old_alloc_failed: kfree(ts->debug.diag_self_new); ts->debug.diag_self_new = NULL; err_self_new_alloc_failed: kfree(ts->debug.diag_self); ts->debug.diag_self = NULL; err_self_buf_alloc_failed: cancel_delayed_work_sync(&ts->himax_diag_delay_wrok); destroy_workqueue(ts->himax_diag_wq); err_create_diag_wq_failed: kfree(ts->debug.flash_buffer); ts->debug.flash_buffer = NULL; err_flash_buf_alloc_failed: destroy_workqueue(ts->flash_wq); err_create_flash_dump_wq_failed: kfree(ts->debug.reg_read_data); ts->debug.reg_read_data = NULL; err_alloc_reg_read_data_fail: return -ENOMEM; } EXPORT_SYMBOL(himax_debug_init); int himax_debug_remove(struct himax_ts_data *ts) { himax_touch_proc_deinit(ts); cancel_delayed_work_sync(&ts->himax_diag_delay_wrok); destroy_workqueue(ts->himax_diag_wq); destroy_workqueue(ts->flash_wq); if (ts->debug.reg_read_data != NULL) kfree(ts->debug.reg_read_data); return 0; } EXPORT_SYMBOL(himax_debug_remove);