From bb4e7d1ddcacb4b7488ea9c9ce12e92729e97fb7 Mon Sep 17 00:00:00 2001 From: dengwei1 Date: Tue, 31 Jul 2018 17:37:18 +0800 Subject: [PATCH] channel input: update nova touch to module Change-Id: I34ce49924af03475968fbdcbe76ae0c4f2dd36fc Signed-off-by: dengwei1 Reviewed-on: https://gerrit.mot.com/1218188 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key --- .../touchscreen/nova_36525_mmi/Android.mk | 14 + .../input/touchscreen/nova_36525_mmi/Kbuild | 13 + .../input/touchscreen/nova_36525_mmi/Makefile | 10 + .../touchscreen/nova_36525_mmi/nt36xxx.c | 1782 +++++++++++++++ .../touchscreen/nova_36525_mmi/nt36xxx.h | 190 ++ .../nova_36525_mmi/nt36xxx_ext_proc.c | 694 ++++++ .../nova_36525_mmi/nt36xxx_fw_update.c | 1387 ++++++++++++ .../nova_36525_mmi/nt36xxx_mem_map.h | 208 ++ .../nova_36525_mmi/nt36xxx_mp_ctrlram.c | 1901 +++++++++++++++++ .../nova_36525_mmi/nt36xxx_mp_ctrlram.h | 719 +++++++ 10 files changed, 6918 insertions(+) create mode 100644 drivers/input/touchscreen/nova_36525_mmi/Android.mk create mode 100644 drivers/input/touchscreen/nova_36525_mmi/Kbuild create mode 100644 drivers/input/touchscreen/nova_36525_mmi/Makefile create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx.c create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx.h create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx_ext_proc.c create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx_fw_update.c create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mem_map.h create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.c create mode 100644 drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.h diff --git a/drivers/input/touchscreen/nova_36525_mmi/Android.mk b/drivers/input/touchscreen/nova_36525_mmi/Android.mk new file mode 100644 index 000000000000..edc91035fb5e --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/Android.mk @@ -0,0 +1,14 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true) +NOVA_MMI_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/ +else +NOVA_MMI_MODULE_PATH := $(KERNEL_MODULES_OUT) +endif + +include $(CLEAR_VARS) +LOCAL_MODULE := nova_36525_mmi.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(NOVA_MMI_MODULE_PATH) +include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/input/touchscreen/nova_36525_mmi/Kbuild b/drivers/input/touchscreen/nova_36525_mmi/Kbuild new file mode 100644 index 000000000000..01a63f95fff6 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/Kbuild @@ -0,0 +1,13 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \ + -I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/nova_36525_mmi + +ifeq ($(filter m y, $(CONFIG_TOUCHSCREEN_NOVATEK_CHIPSET)),) + obj-m := nova_36525_mmi.o +endif + +nova_36525_mmi-objs += nt36xxx.o +nova_36525_mmi-objs += nt36xxx_ext_proc.o +nova_36525_mmi-objs += nt36xxx_fw_update.o +nova_36525_mmi-objs += nt36xxx_mp_ctrlram.o diff --git a/drivers/input/touchscreen/nova_36525_mmi/Makefile b/drivers/input/touchscreen/nova_36525_mmi/Makefile new file mode 100644 index 000000000000..4191dea22679 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/Makefile @@ -0,0 +1,10 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx.c b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx.c new file mode 100644 index 000000000000..86f05df7ff32 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx.c @@ -0,0 +1,1782 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 23175 $ + * $Date: 2018-02-12 16:26:21 +0800 (Mon, 12 Feb 2018) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#include "nt36xxx.h" +#if NVT_TOUCH_ESD_PROTECT +#include +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + +#if NVT_TOUCH_ESD_PROTECT +static struct delayed_work nvt_esd_check_work; +static struct workqueue_struct *nvt_esd_check_wq; +static unsigned long irq_timer; +uint8_t esd_check; +uint8_t esd_retry; +uint8_t esd_retry_max = 5; +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + +#if NVT_TOUCH_EXT_PROC +extern int32_t nvt_extra_proc_init(void); +#endif + +#if NVT_TOUCH_FW +extern int32_t nvt_fw_sysfs_init(void); +extern int32_t nvt_fw_sysfs_deinit(void); +#endif + +#if NVT_TOUCH_MP +extern int32_t nvt_mp_proc_init(void); +#endif + +struct nvt_ts_data *ts; + +static struct workqueue_struct *nvt_wq; + +#if BOOT_UPDATE_FIRMWARE +static struct workqueue_struct *nvt_fwu_wq; +extern void Boot_Update_Firmware(struct work_struct *work); +#endif + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void nvt_ts_early_suspend(struct early_suspend *h); +static void nvt_ts_late_resume(struct early_suspend *h); +#endif + +#if TOUCH_KEY_NUM > 0 +const uint16_t touch_key_array[TOUCH_KEY_NUM] = { + KEY_BACK, + KEY_HOME, + KEY_MENU +}; +#endif + +#if WAKEUP_GESTURE +const uint16_t gesture_key_array[] = { + KEY_POWER, //GESTURE_WORD_C + KEY_POWER, //GESTURE_WORD_W + KEY_POWER, //GESTURE_WORD_V + KEY_POWER, //GESTURE_DOUBLE_CLICK + KEY_POWER, //GESTURE_WORD_Z + KEY_POWER, //GESTURE_WORD_M + KEY_POWER, //GESTURE_WORD_O + KEY_POWER, //GESTURE_WORD_e + KEY_POWER, //GESTURE_WORD_S + KEY_POWER, //GESTURE_SLIDE_UP + KEY_POWER, //GESTURE_SLIDE_DOWN + KEY_POWER, //GESTURE_SLIDE_LEFT + KEY_POWER, //GESTURE_SLIDE_RIGHT +}; +#endif + +static uint8_t bTouchIsAwake; + +/******************************************************* +Description: + Novatek touchscreen i2c read function. + +return: + Executive outcomes. 2---succeed. -5---I/O error +*******************************************************/ +int32_t CTP_I2C_READ(struct i2c_client *client, uint16_t address, uint8_t *buf, uint16_t len) +{ + struct i2c_msg msgs[2]; + int32_t ret = -1; + int32_t retries = 0; + + msgs[0].flags = !I2C_M_RD; + msgs[0].addr = address; + msgs[0].len = 1; + msgs[0].buf = &buf[0]; + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = address; + msgs[1].len = len - 1; + msgs[1].buf = &buf[1]; + + while (retries < 5) { + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret == 2) + break; + retries++; + } + + if (unlikely(retries == 5)) { + NVT_ERR("error, ret=%d\n", ret); + ret = -EIO; + } + + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen i2c write function. + +return: + Executive outcomes. 1---succeed. -5---I/O error +*******************************************************/ +int32_t CTP_I2C_WRITE(struct i2c_client *client, uint16_t address, uint8_t *buf, uint16_t len) +{ + struct i2c_msg msg; + int32_t ret = -1; + int32_t retries = 0; + + msg.flags = !I2C_M_RD; + msg.addr = address; + msg.len = len; + msg.buf = buf; + + while (retries < 5) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + break; + retries++; + } + + if (unlikely(retries == 5)) { + NVT_ERR("error, ret=%d\n", ret); + ret = -EIO; + } + + return ret; +} + + +/******************************************************* +Description: + Novatek touchscreen reset MCU then into idle mode + function. + +return: + n.a. +*******************************************************/ +void nvt_sw_reset_idle(void) +{ + uint8_t buf[4] = {0}; + + //---write i2c cmds to reset idle--- + buf[0] = 0x00; + buf[1] = 0xA5; + CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + + msleep(15); +} + +/******************************************************* +Description: + Novatek touchscreen reset MCU (boot) function. + +return: + n.a. +*******************************************************/ +void nvt_bootloader_reset(void) +{ + uint8_t buf[8] = {0}; + NVT_LOG("enter %s start\n", __func__); + //---write i2c cmds to reset--- + buf[0] = 0x00; + buf[1] = 0x69; + CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + + // need 35ms delay after bootloader reset + msleep(35); + NVT_LOG("exit %s end\n", __func__); +} + +/******************************************************* +Description: + Novatek touchscreen clear FW status function. + +return: + Executive outcomes. 0---succeed. -1---fail. +*******************************************************/ +int32_t nvt_clear_fw_status(void) +{ + uint8_t buf[8] = {0}; + int32_t i = 0; + const int32_t retry = 20; + + for (i = 0; i < retry; i++) { + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---clear fw status--- + buf[0] = EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE; + buf[1] = 0x00; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 2); + + //---read fw status--- + buf[0] = EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE; + buf[1] = 0xFF; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 2); + + if (buf[1] == 0x00) + break; + + msleep(10); + } + + if (i >= retry) { + NVT_ERR("failed, i=%d, buf[1]=0x%02X\n", i, buf[1]); + return -EPERM; + } else { + return 0; + } +} + +/******************************************************* +Description: + Novatek touchscreen check FW status function. + +return: + Executive outcomes. 0---succeed. -1---failed. +*******************************************************/ +int32_t nvt_check_fw_status(void) +{ + uint8_t buf[8] = {0}; + int32_t i = 0; + const int32_t retry = 50; + + for (i = 0; i < retry; i++) { + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read fw status--- + buf[0] = EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE; + buf[1] = 0x00; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 2); + + if ((buf[1] & 0xF0) == 0xA0) + break; + + msleep(10); + } + + if (i >= retry) { + NVT_ERR("failed, i=%d, buf[1]=0x%02X\n", i, buf[1]); + return -EPERM; + } else { + return 0; + } +} + +/******************************************************* +Description: + Novatek touchscreen check FW reset state function. + +return: + Executive outcomes. 0---succeed. -1---failed. +*******************************************************/ +int32_t nvt_check_fw_reset_state(RST_COMPLETE_STATE check_reset_state) +{ + uint8_t buf[8] = {0}; + int32_t ret = 0; + int32_t retry = 0; + NVT_LOG("enter %s start\n", __func__); + + while (1) { + msleep(10); + + //---read reset state--- + buf[0] = EVENT_MAP_RESET_COMPLETE; + buf[1] = 0x00; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 6); + + if ((buf[1] >= check_reset_state) && (buf[1] <= RESET_STATE_MAX)) { + ret = 0; + break; + } + + retry++; + if (check_reset_state <= RESET_STATE_REK) { + if (unlikely(retry > 50)) { + NVT_ERR("error,retry = %d, buf[1] = 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", retry, buf[1], buf[2], buf[3], buf[4], buf[5]); + ret = -1; + break; + } + } else { + if (unlikely(retry > 100)) { + NVT_ERR("error, retry=%d, buf[1]=0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", retry, buf[1], buf[2], buf[3], buf[4], buf[5]); + ret = -1; + break; + } + } + } + NVT_LOG("exit %s end\n", __func__); + + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen get novatek project id information + function. + +return: + Executive outcomes. 0---success. -1---fail. +*******************************************************/ +int32_t nvt_read_pid(void) +{ + uint8_t buf[3] = {0}; + int32_t ret = 0; + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read project id--- + buf[0] = EVENT_MAP_PROJECTID; + buf[1] = 0x00; + buf[2] = 0x00; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 3); + + ts->nvt_pid = (buf[2] << 8) + buf[1]; + + NVT_LOG("PID=%04X\n", ts->nvt_pid); + + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen get firmware related information + function. + +return: + Executive outcomes. 0---success. -1---fail. +*******************************************************/ +int32_t nvt_get_fw_info(void) +{ + uint8_t buf[64] = {0}; + uint32_t retry_count = 0; + int32_t ret = 0; + NVT_LOG("enter %s start\n", __func__); + +info_retry: + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read fw info--- + buf[0] = EVENT_MAP_FWINFO; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 17); + ts->fw_ver = buf[1]; + ts->x_num = buf[3]; + ts->y_num = buf[4]; + ts->abs_x_max = (uint16_t)((buf[5] << 8) | buf[6]); + ts->abs_y_max = (uint16_t)((buf[7] << 8) | buf[8]); + ts->max_button_num = buf[11]; + + //---clear x_num, y_num if fw info is broken--- + if ((buf[1] + buf[2]) != 0xFF) { + NVT_ERR("FW info is broken! fw_ver=0x%02X, ~fw_ver=0x%02X\n", buf[1], buf[2]); + ts->fw_ver = 0; + ts->x_num = 18; + ts->y_num = 32; + ts->abs_x_max = TOUCH_DEFAULT_MAX_WIDTH; + ts->abs_y_max = TOUCH_DEFAULT_MAX_HEIGHT; + ts->max_button_num = TOUCH_KEY_NUM; + + if (retry_count < 3) { + retry_count++; + NVT_ERR("retry_count=%d\n", retry_count); + goto info_retry; + } else { + NVT_ERR("Set default fw_ver=%d, x_num=%d, y_num=%d, \ + abs_x_max=%d, abs_y_max=%d, max_button_num=%d!\n", + ts->fw_ver, ts->x_num, ts->y_num, + ts->abs_x_max, ts->abs_y_max, ts->max_button_num); + ret = -1; + } + } else { + ret = 0; + } + + //---Get Novatek PID--- + nvt_read_pid(); + NVT_LOG("exit %s end\n", __func__); + + return ret; +} + +/******************************************************* + Create Device Node (Proc Entry) +*******************************************************/ +#if NVT_TOUCH_PROC +static struct proc_dir_entry *NVT_proc_entry; +#define DEVICE_NAME "NVTflash" + +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash read function. + +return: + Executive outcomes. 2---succeed. -5,-14---failed. +*******************************************************/ +static ssize_t nvt_flash_read(struct file *file, char __user *buff, size_t count, loff_t *offp) +{ + uint8_t str[68] = {0}; + int32_t ret = -1; + int32_t retries = 0; + int8_t i2c_wr = 0; + + if (count > sizeof(str)) { + NVT_ERR("error count=%zu\n", count); + return -EFAULT; + } + + if (copy_from_user(str, buff, count)) { + NVT_ERR("copy from user error\n"); + return -EFAULT; + } + +#if NVT_TOUCH_ESD_PROTECT + /* + * stop esd check work to avoid case that 0x77 report righ after here to enable esd check again + * finally lead to trigger esd recovery bootloader reset + */ + cancel_delayed_work_sync(&nvt_esd_check_work); + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + i2c_wr = str[0] >> 7; + + if (i2c_wr == 0) { //I2C write + while (retries < 20) { + ret = CTP_I2C_WRITE(ts->client, (str[0] & 0x7F), &str[2], str[1]); + if (ret == 1) + break; + else + NVT_ERR("error, retries=%d, ret=%d\n", retries, ret); + + retries++; + } + + if (unlikely(retries == 20)) { + NVT_ERR("error, ret = %d\n", ret); + return -EIO; + } + + return ret; + } else if (i2c_wr == 1) { //I2C read + while (retries < 20) { + ret = CTP_I2C_READ(ts->client, (str[0] & 0x7F), &str[2], str[1]); + if (ret == 2) + break; + else + NVT_ERR("error, retries=%d, ret=%d\n", retries, ret); + + retries++; + } + + // copy buff to user if i2c transfer + if (retries < 20) { + if (copy_to_user(buff, str, count)) + return -EFAULT; + } + + if (unlikely(retries == 20)) { + NVT_ERR("error, ret = %d\n", ret); + return -EIO; + } + + return ret; + } else { + NVT_ERR("Call error, str[0]=%d\n", str[0]); + return -EFAULT; + } +} + +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash open function. + +return: + Executive outcomes. 0---succeed. -12---failed. +*******************************************************/ +static int32_t nvt_flash_open(struct inode *inode, struct file *file) +{ + struct nvt_flash_data *dev; + + dev = kmalloc(sizeof(struct nvt_flash_data), GFP_KERNEL); + if (dev == NULL) { + NVT_ERR("Failed to allocate memory for nvt flash data\n"); + return -ENOMEM; + } + + rwlock_init(&dev->lock); + file->private_data = dev; + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash close function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_flash_close(struct inode *inode, struct file *file) +{ + struct nvt_flash_data *dev = file->private_data; + + if (dev) + kfree(dev); + + return 0; +} + +static const struct file_operations nvt_flash_fops = { + .owner = THIS_MODULE, + .open = nvt_flash_open, + .release = nvt_flash_close, + .read = nvt_flash_read, +}; + +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash initial function. + +return: + Executive outcomes. 0---succeed. -12---failed. +*******************************************************/ +static int32_t nvt_flash_proc_init(void) +{ + NVT_proc_entry = proc_create(DEVICE_NAME, 0444, NULL, &nvt_flash_fops); + if (NVT_proc_entry == NULL) { + NVT_ERR("Failed!\n"); + return -ENOMEM; + } else { + NVT_LOG("Succeeded!\n"); + } + + NVT_LOG("============================================================\n"); + NVT_LOG("Create /proc/NVTflash\n"); + NVT_LOG("============================================================\n"); + + return 0; +} +#endif + +#if WAKEUP_GESTURE +#define GESTURE_WORD_C 12 +#define GESTURE_WORD_W 13 +#define GESTURE_WORD_V 14 +#define GESTURE_DOUBLE_CLICK 15 +#define GESTURE_WORD_Z 16 +#define GESTURE_WORD_M 17 +#define GESTURE_WORD_O 18 +#define GESTURE_WORD_e 19 +#define GESTURE_WORD_S 20 +#define GESTURE_SLIDE_UP 21 +#define GESTURE_SLIDE_DOWN 22 +#define GESTURE_SLIDE_LEFT 23 +#define GESTURE_SLIDE_RIGHT 24 +/* customized gesture id */ +#define DATA_PROTOCOL 30 + +/* function page definition */ +#define FUNCPAGE_GESTURE 1 + +#define NVT_TS_HOLD_TIME 5000 +static struct wakeup_source gestrue_wakelock; + + +/******************************************************* +Description: + Novatek touchscreen wake up gesture key report function. + +return: + n.a. +*******************************************************/ +void nvt_ts_wakeup_gesture_report(uint8_t gesture_id, uint8_t *data) +{ + uint32_t keycode = 0; + uint8_t func_type = data[2]; + uint8_t func_id = data[3]; + + /* support fw specifal data protocol */ + if ((gesture_id == DATA_PROTOCOL) && (func_type == FUNCPAGE_GESTURE)) { + gesture_id = func_id; + } else if (gesture_id > DATA_PROTOCOL) { + NVT_ERR("gesture_id %d is invalid, func_type=%d, func_id=%d\n", gesture_id, func_type, func_id); + return; + } + + NVT_LOG("gesture_id = %d\n", gesture_id); + + switch (gesture_id) { + case GESTURE_WORD_C: + NVT_LOG("Gesture : Word-C.\n"); + keycode = gesture_key_array[0]; + break; + case GESTURE_WORD_W: + NVT_LOG("Gesture : Word-W.\n"); + keycode = gesture_key_array[1]; + break; + case GESTURE_WORD_V: + NVT_LOG("Gesture : Word-V.\n"); + keycode = gesture_key_array[2]; + break; + case GESTURE_DOUBLE_CLICK: + NVT_LOG("Gesture : Double Click.\n"); + keycode = gesture_key_array[3]; + break; + case GESTURE_WORD_Z: + NVT_LOG("Gesture : Word-Z.\n"); + keycode = gesture_key_array[4]; + break; + case GESTURE_WORD_M: + NVT_LOG("Gesture : Word-M.\n"); + keycode = gesture_key_array[5]; + break; + case GESTURE_WORD_O: + NVT_LOG("Gesture : Word-O.\n"); + keycode = gesture_key_array[6]; + break; + case GESTURE_WORD_e: + NVT_LOG("Gesture : Word-e.\n"); + keycode = gesture_key_array[7]; + break; + case GESTURE_WORD_S: + NVT_LOG("Gesture : Word-S.\n"); + keycode = gesture_key_array[8]; + break; + case GESTURE_SLIDE_UP: + NVT_LOG("Gesture : Slide UP.\n"); + keycode = gesture_key_array[9]; + break; + case GESTURE_SLIDE_DOWN: + NVT_LOG("Gesture : Slide DOWN.\n"); + keycode = gesture_key_array[10]; + break; + case GESTURE_SLIDE_LEFT: + NVT_LOG("Gesture : Slide LEFT.\n"); + keycode = gesture_key_array[11]; + break; + case GESTURE_SLIDE_RIGHT: + NVT_LOG("Gesture : Slide RIGHT.\n"); + keycode = gesture_key_array[12]; + break; + default: + break; + } + + if (keycode > 0) { + input_report_key(ts->input_dev, keycode, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, keycode, 0); + input_sync(ts->input_dev); + } +} +#endif + +/******************************************************* +Description: + Novatek touchscreen parse device tree function. + +return: + n.a. +*******************************************************/ +#ifdef CONFIG_OF +static void nvt_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + NVT_LOG("enter %s start\n", __func__); + +#if NVT_TOUCH_SUPPORT_HW_RST + ts->reset_gpio = of_get_named_gpio_flags(np, "novatek,reset-gpio", 0, &ts->reset_flags); + NVT_LOG("novatek,reset-gpio=%d\n", ts->reset_gpio); +#endif + ts->irq_gpio = of_get_named_gpio_flags(np, "novatek,irq-gpio", 0, &ts->irq_flags); + NVT_LOG("novatek,irq-gpio=%d\n", ts->irq_gpio); + NVT_LOG("exit %s end\n", __func__); +} +#else +static void nvt_parse_dt(struct device *dev) +{ +#if NVT_TOUCH_SUPPORT_HW_RST + ts->reset_gpio = NVTTOUCH_RST_PIN; +#endif + ts->irq_gpio = NVTTOUCH_INT_PIN; +} +#endif + +/******************************************************* +Description: + Novatek touchscreen config and request gpio + +return: + Executive outcomes. 0---succeed. not 0---failed. +*******************************************************/ +static int nvt_gpio_config(struct nvt_ts_data *ts) +{ + int32_t ret = 0; + NVT_LOG("enter %s start\n", __func__); +#if NVT_TOUCH_SUPPORT_HW_RST + /* request RST-pin (Output/High) */ + if (gpio_is_valid(ts->reset_gpio)) { + ret = gpio_request_one(ts->reset_gpio, GPIOF_OUT_INIT_HIGH, "NVT-tp-rst"); + if (ret) { + NVT_ERR("Failed to request NVT-tp-rst GPIO\n"); + goto err_request_reset_gpio; + } + } +#endif + + /* request INT-pin (Input) */ + if (gpio_is_valid(ts->irq_gpio)) { + ret = gpio_request_one(ts->irq_gpio, GPIOF_IN, "NVT-int"); + if (ret) { + NVT_ERR("Failed to request NVT-int GPIO\n"); + goto err_request_irq_gpio; + } + } + NVT_LOG("exit %s end\n", __func__); + + return ret; + +err_request_irq_gpio: +#if NVT_TOUCH_SUPPORT_HW_RST + if (gpio_is_valid(ts->reset_gpio)) + gpio_free(ts->reset_gpio); +err_request_reset_gpio: +#endif + NVT_LOG("exit %s abnormal end\n", __func__); + + return ret; +} + +#if NVT_TOUCH_ESD_PROTECT +void nvt_esd_check_enable(uint8_t enable) +{ + /* enable/disable esd check flag */ + esd_check = enable; + /* update interrupt timer */ + irq_timer = jiffies; + /* clear esd_retry counter, if protect function is enabled */ + esd_retry = enable ? 0 : esd_retry; +} + +static uint8_t nvt_fw_recovery(uint8_t *point_data) +{ + uint8_t i = 0; + uint8_t detected = true; + + /* check pattern */ + for (i = 1; i < 7; i++) { + if (point_data[i] != 0x77) { + detected = false; + break; + } + } + + return detected; +} + +static void nvt_esd_check_func(struct work_struct *work) +{ + unsigned int timer = jiffies_to_msecs(jiffies - irq_timer); + + //NVT_ERR("esd_check = %d (retry %d/%d)\n", esd_check, esd_retry, esd_retry_max); //DEBUG + + if (esd_retry >= esd_retry_max) + nvt_esd_check_enable(false); + + if ((timer > NVT_TOUCH_ESD_CHECK_PERIOD) && esd_check) { + NVT_ERR("do ESD recovery, timer = %d, retry = %d\n", timer, esd_retry); + /* do esd recovery, bootloader reset */ + nvt_bootloader_reset(); + /* update interrupt timer */ + irq_timer = jiffies; + /* update esd_retry counter */ + esd_retry++; + } + + queue_delayed_work(nvt_esd_check_wq, &nvt_esd_check_work, + msecs_to_jiffies(NVT_TOUCH_ESD_CHECK_PERIOD)); +} +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + +#define POINT_DATA_LEN 65 +/******************************************************* +Description: + Novatek touchscreen work function. + +return: + n.a. +*******************************************************/ +static void nvt_ts_work_func(struct work_struct *work) +{ + int32_t ret = -1; + uint8_t point_data[POINT_DATA_LEN + 1] = {0}; + uint32_t position = 0; + uint32_t input_x = 0; + uint32_t input_y = 0; + uint32_t input_w = 0; + uint32_t input_p = 0; + uint8_t input_id = 0; +#if MT_PROTOCOL_B + uint8_t press_id[TOUCH_MAX_FINGER_NUM] = {0}; +#endif /* MT_PROTOCOL_B */ + int32_t i = 0; + int32_t finger_cnt = 0; + + mutex_lock(&ts->lock); + + ret = CTP_I2C_READ(ts->client, I2C_FW_Address, point_data, POINT_DATA_LEN + 1); + if (ret < 0) { + NVT_ERR("CTP_I2C_READ failed.(%d)\n", ret); + goto XFER_ERROR; + } +/* + //--- dump I2C buf --- + for (i = 0; i < 10; i++) { + printk("%02X %02X %02X %02X %02X %02X ", point_data[1+i*6], point_data[2+i*6], point_data[3+i*6], point_data[4+i*6], point_data[5+i*6], point_data[6+i*6]); + } + printk("\n"); +*/ + +#if NVT_TOUCH_ESD_PROTECT + if (nvt_fw_recovery(point_data)) { + nvt_esd_check_enable(true); + goto XFER_ERROR; + } +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + +#if WAKEUP_GESTURE + if (bTouchIsAwake == 0) { + input_id = (uint8_t)(point_data[1] >> 3); + nvt_ts_wakeup_gesture_report(input_id, point_data); + enable_irq(ts->client->irq); + mutex_unlock(&ts->lock); + return; + } +#endif + + finger_cnt = 0; + + for (i = 0; i < ts->max_touch_num; i++) { + position = 1 + 6 * i; + input_id = (uint8_t)(point_data[position + 0] >> 3); + if ((input_id == 0) || (input_id > ts->max_touch_num)) + continue; + + if (((point_data[position] & 0x07) == 0x01) || ((point_data[position] & 0x07) == 0x02)) { //finger down (enter & moving) +#if NVT_TOUCH_ESD_PROTECT + /* update interrupt timer */ + irq_timer = jiffies; +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + input_x = (uint32_t)(point_data[position + 1] << 4) + (uint32_t) (point_data[position + 3] >> 4); + input_y = (uint32_t)(point_data[position + 2] << 4) + (uint32_t) (point_data[position + 3] & 0x0F); + if ((input_x < 0) || (input_y < 0)) + continue; + if ((input_x > ts->abs_x_max) || (input_y > ts->abs_y_max)) + continue; + input_w = (uint32_t)(point_data[position + 4]); + if (input_w == 0) + input_w = 1; + if (i < 2) { + input_p = (uint32_t)(point_data[position + 5]) + (uint32_t)(point_data[i + 63] << 8); + if (input_p > TOUCH_FORCE_NUM) + input_p = TOUCH_FORCE_NUM; + } else { + input_p = (uint32_t)(point_data[position + 5]); + } + if (input_p == 0) + input_p = 1; + +#if MT_PROTOCOL_B + press_id[input_id - 1] = 1; + input_mt_slot(ts->input_dev, input_id - 1); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); +#else /* MT_PROTOCOL_B */ + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, input_id - 1); + input_report_key(ts->input_dev, BTN_TOUCH, 1); +#endif /* MT_PROTOCOL_B */ + + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, input_p); + +#if MT_PROTOCOL_B +#else /* MT_PROTOCOL_B */ + input_mt_sync(ts->input_dev); +#endif /* MT_PROTOCOL_B */ + + finger_cnt++; + } + } + +#if MT_PROTOCOL_B + for (i = 0; i < ts->max_touch_num; i++) { + if (press_id[i] != 1) { + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); + } + } + + input_report_key(ts->input_dev, BTN_TOUCH, (finger_cnt > 0)); +#else /* MT_PROTOCOL_B */ + if (finger_cnt == 0) { + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_mt_sync(ts->input_dev); + } +#endif /* MT_PROTOCOL_B */ + +#if TOUCH_KEY_NUM > 0 + if (point_data[61] == 0xF8) { + for (i = 0; i < ts->max_button_num; i++) { + input_report_key(ts->input_dev, touch_key_array[i], ((point_data[62] >> i) & 0x01)); + } + } else { + for (i = 0; i < ts->max_button_num; i++) { + input_report_key(ts->input_dev, touch_key_array[i], 0); + } + } +#endif + + input_sync(ts->input_dev); + +XFER_ERROR: + enable_irq(ts->client->irq); + + mutex_unlock(&ts->lock); +} + +/******************************************************* +Description: + External interrupt service routine. + +return: + irq execute status. +*******************************************************/ +static irqreturn_t nvt_ts_irq_handler(int32_t irq, void *dev_id) +{ + disable_irq_nosync(ts->client->irq); + +#if WAKEUP_GESTURE + if (bTouchIsAwake == 0) { + __pm_wakeup_event(&gestrue_wakelock, NVT_TS_HOLD_TIME); + } +#endif + + queue_work(nvt_wq, &ts->nvt_work); + + return IRQ_HANDLED; +} + +/******************************************************* +Description: + Novatek touchscreen check and stop crc reboot loop. + +return: + n.a. +*******************************************************/ +void nvt_stop_crc_reboot(void) +{ + uint8_t buf[8] = {0}; + int32_t retry = 0; + + //read dummy buffer to check CRC fail reboot is happening or not + + //---change I2C index to prevent geting 0xFF, but not 0xFC--- + buf[0] = 0xFF; + buf[1] = 0x01; + buf[2] = 0xF6; + CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + + //---read to check if buf is 0xFC which means IC is in CRC reboot --- + buf[0] = 0x4E; + CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 4); + + if (((buf[1] == 0xFC) && (buf[2] == 0xFC) && (buf[3] == 0xFC)) || + ((buf[1] == 0xFF) && (buf[2] == 0xFF) && (buf[3] == 0xFF))) { + + //IC is in CRC fail reboot loop, needs to be stopped! + for (retry = 5; retry > 0; retry--) { + + //---write i2c cmds to reset idle : 1st--- + buf[0] = 0x00; + buf[1] = 0xA5; + CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + + //---write i2c cmds to reset idle : 2rd--- + buf[0] = 0x00; + buf[1] = 0xA5; + CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + msleep(1); + + //---clear CRC_ERR_FLAG--- + buf[0] = 0xFF; + buf[1] = 0x03; + buf[2] = 0xF1; + CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + + buf[0] = 0x35; + buf[1] = 0xA5; + CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 2); + + //---check CRC_ERR_FLAG--- + buf[0] = 0xFF; + buf[1] = 0x03; + buf[2] = 0xF1; + CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + + buf[0] = 0x35; + buf[1] = 0x00; + CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 2); + + if (buf[1] == 0xA5) + break; + } + if (retry == 0) + NVT_ERR("CRC auto reboot is not able to be stopped! buf[1]=0x%02X\n", buf[1]); + } + + return; +} + +/******************************************************* +Description: + Novatek touchscreen check chip version trim function. + +return: + Executive outcomes. 0---NVT IC. -1---not NVT IC. +*******************************************************/ +static int8_t nvt_ts_check_chip_ver_trim(void) +{ + uint8_t buf[8] = {0}; + int32_t retry = 0; + int32_t list = 0; + int32_t i = 0; + int32_t found_nvt_chip = 0; + int32_t ret = -1; + NVT_LOG("enter %s start\n", __func__); + + nvt_bootloader_reset(); // NOT in retry loop + + //---Check for 5 times--- + for (retry = 5; retry > 0; retry--) { + nvt_sw_reset_idle(); + + buf[0] = 0x00; + buf[1] = 0x35; + CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + msleep(10); + + buf[0] = 0xFF; + buf[1] = 0x01; + buf[2] = 0xF6; + CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + + buf[0] = 0x4E; + buf[1] = 0x00; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x00; + CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 7); + NVT_LOG("buf[1]=0x%02X, buf[2]=0x%02X, buf[3]=0x%02X, buf[4]=0x%02X, buf[5]=0x%02X, buf[6]=0x%02X\n", + buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + // compare read chip id on supported list + for (list = 0; list < (sizeof(trim_id_table) / sizeof(struct nvt_ts_trim_id_table)); list++) { + found_nvt_chip = 0; + + // compare each byte + for (i = 0; i < NVT_ID_BYTE_MAX; i++) { + if (trim_id_table[list].mask[i]) { + if (buf[i + 1] != trim_id_table[list].id[i]) + break; + } + } + + if (i == NVT_ID_BYTE_MAX) { + found_nvt_chip = 1; + } + + if (found_nvt_chip) { + NVT_LOG("This is NVT touch IC\n"); +#if NVT_TOUCH_FW + if (list == 0) { + snprintf(ts->product_id, sizeof(ts->product_id), "NT36672A"); + } else if (list == 9) { + snprintf(ts->product_id, sizeof(ts->product_id), "NT36525"); + } else if (list == 10) { + snprintf(ts->product_id, sizeof(ts->product_id), "NT36870"); + } else if (list == 11) { + snprintf(ts->product_id, sizeof(ts->product_id), "NT36676F"); + } else { + snprintf(ts->product_id, sizeof(ts->product_id), "NT36772"); + } +#endif + ts->mmap = trim_id_table[list].mmap; + ts->carrier_system = trim_id_table[list].carrier_system; + ret = 0; + goto out; + } else { + ts->mmap = NULL; + ret = -1; + } + } + + //---Stop CRC check to prevent IC auto reboot--- + if (((buf[1] == 0xFC) && (buf[2] == 0xFC) && (buf[3] == 0xFC)) || + ((buf[1] == 0xFF) && (buf[2] == 0xFF) && (buf[3] == 0xFF))) { + nvt_stop_crc_reboot(); + } + + msleep(10); + } + +out: + NVT_LOG("exit %s end\n", __func__); + return ret; +} +/******************************************************* +Description: + Novatek touchscreen driver probe function. + +return: + Executive outcomes. 0---succeed. negative---failed +*******************************************************/ +static int32_t nvt_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int32_t ret = 0; +#if ((TOUCH_KEY_NUM > 0) || WAKEUP_GESTURE) + int32_t retry = 0; +#endif + + NVT_LOG("enter %s start\n", __func__); + //---check i2c func.--- + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + NVT_ERR("i2c_check_functionality failed. (no I2C_FUNC_I2C)\n"); + ret = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kmalloc(sizeof(struct nvt_ts_data), GFP_KERNEL); + if (ts == NULL) { + NVT_ERR("failed to allocated memory for nvt ts data\n"); + return -ENOMEM; + } + + ts->client = client; + i2c_set_clientdata(client, ts); + + //---parse dts--- + nvt_parse_dt(&client->dev); + + + //---request and config GPIOs--- + ret = nvt_gpio_config(ts); + if (ret) { + NVT_ERR("gpio config error!\n"); + goto err_gpio_config_failed; + } + + // need 10ms delay after POR(power on reset) + msleep(10); + //---check chip version trim--- + ret = nvt_ts_check_chip_ver_trim(); + if (ret) { + NVT_ERR("chip is not identified\n"); + ret = -EINVAL; + goto err_chipvertrim_failed; + } + + mutex_init(&ts->lock); + + mutex_lock(&ts->lock); + nvt_bootloader_reset(); + nvt_check_fw_reset_state(RESET_STATE_INIT); + nvt_get_fw_info(); + mutex_unlock(&ts->lock); + + //---create workqueue--- + nvt_wq = create_workqueue("nvt_wq"); + if (!nvt_wq) { + NVT_ERR("nvt_wq create workqueue failed\n"); + ret = -ENOMEM; + goto err_create_nvt_wq_failed; + } + INIT_WORK(&ts->nvt_work, nvt_ts_work_func); + + + //---allocate input device--- + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + NVT_ERR("allocate input device failed\n"); + ret = -ENOMEM; + goto err_input_dev_alloc_failed; + } + + ts->max_touch_num = TOUCH_MAX_FINGER_NUM; + +#if TOUCH_KEY_NUM > 0 + ts->max_button_num = TOUCH_KEY_NUM; +#endif + + ts->int_trigger_type = INT_TRIGGER_TYPE; + + + //---set input device info.--- + ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; + ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + ts->input_dev->propbit[0] = BIT(INPUT_PROP_DIRECT); + +#if MT_PROTOCOL_B + input_mt_init_slots(ts->input_dev, ts->max_touch_num, 0); +#endif + + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, TOUCH_FORCE_NUM, 0, 0); //pressure = TOUCH_FORCE_NUM + +#if TOUCH_MAX_FINGER_NUM > 1 + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); //area = 255 + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0); +#if MT_PROTOCOL_B + // no need to set ABS_MT_TRACKING_ID, input_mt_init_slots() already set it +#else + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, ts->max_touch_num, 0, 0); +#endif //MT_PROTOCOL_B +#endif //TOUCH_MAX_FINGER_NUM > 1 + +#if TOUCH_KEY_NUM > 0 + for (retry = 0; retry < ts->max_button_num; retry++) { + input_set_capability(ts->input_dev, EV_KEY, touch_key_array[retry]); + } +#endif + +#if WAKEUP_GESTURE + for (retry = 0; retry < (sizeof(gesture_key_array) / sizeof(gesture_key_array[0])); retry++) { + input_set_capability(ts->input_dev, EV_KEY, gesture_key_array[retry]); + } + wakeup_source_init(&gestrue_wakelock, "gestrue-wake-lock"); +#endif + + snprintf(ts->phys, 9, "input/ts"); + ts->input_dev->name = NVT_TS_NAME; + ts->input_dev->phys = ts->phys; + ts->input_dev->id.bustype = BUS_I2C; + + //---register input device--- + ret = input_register_device(ts->input_dev); + if (ret) { + NVT_ERR("register input device (%s) failed. ret=%d\n", ts->input_dev->name, ret); + goto err_input_register_device_failed; + } + + //---set int-pin & request irq--- + client->irq = gpio_to_irq(ts->irq_gpio); + if (client->irq) { + NVT_LOG("int_trigger_type=%d\n", ts->int_trigger_type); + +#if WAKEUP_GESTURE + ret = request_irq(client->irq, nvt_ts_irq_handler, ts->int_trigger_type | IRQF_NO_SUSPEND, client->name, ts); +#else + ret = request_irq(client->irq, nvt_ts_irq_handler, ts->int_trigger_type, client->name, ts); +#endif + if (ret != 0) { + NVT_ERR("request irq failed. ret=%d\n", ret); + goto err_int_request_failed; + } else { + disable_irq(client->irq); + NVT_LOG("request irq %d succeed\n", client->irq); + } + } + +#if BOOT_UPDATE_FIRMWARE + nvt_fwu_wq = create_singlethread_workqueue("nvt_fwu_wq"); + if (!nvt_fwu_wq) { + NVT_ERR("nvt_fwu_wq create workqueue failed\n"); + ret = -ENOMEM; + goto err_create_nvt_fwu_wq_failed; + } + INIT_DELAYED_WORK(&ts->nvt_fwu_work, Boot_Update_Firmware); + // please make sure boot update start after display reset(RESX) sequence + queue_delayed_work(nvt_fwu_wq, &ts->nvt_fwu_work, msecs_to_jiffies(14000)); +#endif + +#if NVT_TOUCH_ESD_PROTECT + INIT_DELAYED_WORK(&nvt_esd_check_work, nvt_esd_check_func); + nvt_esd_check_wq = create_workqueue("nvt_esd_check_wq"); + queue_delayed_work(nvt_esd_check_wq, &nvt_esd_check_work, + msecs_to_jiffies(NVT_TOUCH_ESD_CHECK_PERIOD)); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + //---set device node--- +#if NVT_TOUCH_PROC + ret = nvt_flash_proc_init(); + if (ret != 0) { + NVT_ERR("nvt flash proc init failed. ret=%d\n", ret); + goto err_init_NVT_ts; + } +#endif + +#if NVT_TOUCH_EXT_PROC + ret = nvt_extra_proc_init(); + if (ret != 0) { + NVT_ERR("nvt extra proc init failed. ret=%d\n", ret); + goto err_init_NVT_ts; + } +#endif + +#if NVT_TOUCH_FW + ts->suspended = 0; + ts->force_reflash = 0; + ts->loading_fw = 0; + + ret = nvt_fw_sysfs_init(); + if (ret != 0) { + NVT_ERR("nvt fw class init failed. ret=%d\n", ret); + goto err_init_NVT_ts; + } +#endif + +#if NVT_TOUCH_MP + ret = nvt_mp_proc_init(); + if (ret != 0) { + NVT_ERR("nvt mp proc init failed. ret=%d\n", ret); + goto err_init_NVT_ts; + } +#endif + +#if defined(CONFIG_FB) + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) { + NVT_ERR("register fb_notifier failed. ret=%d\n", ret); + goto err_register_fb_notif_failed; + } +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = nvt_ts_early_suspend; + ts->early_suspend.resume = nvt_ts_late_resume; + ret = register_early_suspend(&ts->early_suspend); + if (ret) { + NVT_ERR("register early suspend failed. ret=%d\n", ret); + goto err_register_early_suspend_failed; + } +#endif + + bTouchIsAwake = 1; + NVT_LOG("exit %s normal end\n", __func__); + + enable_irq(client->irq); + + return 0; + +#if defined(CONFIG_FB) +err_register_fb_notif_failed: +#elif defined(CONFIG_HAS_EARLYSUSPEND) +err_register_early_suspend_failed: +#endif +#if (NVT_TOUCH_PROC || NVT_TOUCH_EXT_PROC || NVT_TOUCH_MP) +err_init_NVT_ts: +#endif +#if BOOT_UPDATE_FIRMWARE + err_create_nvt_fwu_wq_failed: +#endif + free_irq(client->irq, ts); +err_int_request_failed: +err_input_register_device_failed: + input_free_device(ts->input_dev); +err_input_dev_alloc_failed: +err_create_nvt_wq_failed: + mutex_destroy(&ts->lock); +err_chipvertrim_failed: +#if NVT_TOUCH_SUPPORT_HW_RST + if (gpio_is_valid(ts->reset_gpio)) + gpio_free(ts->reset_gpio); +#endif + if (gpio_is_valid(ts->irq_gpio)) + gpio_free(ts->irq_gpio); +err_gpio_config_failed: + i2c_set_clientdata(client, NULL); + kfree(ts); +err_check_functionality_failed: + + NVT_LOG("exit %s abnormal end\n", __func__); + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen driver release function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_ts_remove(struct i2c_client *client) +{ + //struct nvt_ts_data *ts = i2c_get_clientdata(client); + +#if defined(CONFIG_FB) + if (fb_unregister_client(&ts->fb_notif)) + NVT_ERR("Error occurred while unregistering fb_notifier.\n"); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + +#if NVT_TOUCH_FW + nvt_fw_sysfs_deinit(); +#endif + + mutex_destroy(&ts->lock); + + NVT_LOG("Removing driver...\n"); + + free_irq(client->irq, ts); + input_unregister_device(ts->input_dev); + i2c_set_clientdata(client, NULL); + kfree(ts); + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen driver suspend function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_ts_suspend(struct device *dev) +{ + uint8_t buf[4] = {0}; +#if MT_PROTOCOL_B + uint32_t i = 0; +#endif + + if (!bTouchIsAwake) { + NVT_LOG("Touch is already suspend\n"); + return 0; + } + + mutex_lock(&ts->lock); + + NVT_LOG("start\n"); +#if NVT_TOUCH_FW + ts->suspended = 1; +#endif + bTouchIsAwake = 0; + +#if NVT_TOUCH_ESD_PROTECT + cancel_delayed_work_sync(&nvt_esd_check_work); + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + +#if WAKEUP_GESTURE + //---write i2c command to enter "wakeup gesture mode"--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0x13; +#if 0 // Do not set 0xFF first, ToDo + buf[2] = 0xFF; + buf[3] = 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 4); +#else + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 2); +#endif + + enable_irq_wake(ts->client->irq); + + NVT_LOG("Enabled touch wakeup gesture\n"); + +#else // WAKEUP_GESTURE + disable_irq(ts->client->irq); + + //---write i2c command to enter "deep sleep mode"--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0x11; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 2); +#endif // WAKEUP_GESTURE + + /* release all touches */ +#if MT_PROTOCOL_B + for (i = 0; i < ts->max_touch_num; i++) { + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + input_report_key(ts->input_dev, BTN_TOUCH, 0); +#if !MT_PROTOCOL_B + input_mt_sync(ts->input_dev); +#endif + input_sync(ts->input_dev); + + msleep(50); + + mutex_unlock(&ts->lock); + + NVT_LOG("end\n"); + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen driver resume function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_ts_resume(struct device *dev) +{ + if (bTouchIsAwake) { + NVT_LOG("Touch is already resume\n"); + return 0; + } + + mutex_lock(&ts->lock); + + NVT_LOG("start\n"); + + // please make sure display reset(RESX) sequence and mipi dsi cmds sent before this +#if NVT_TOUCH_SUPPORT_HW_RST + if (gpio_is_valid(ts->reset_gpio)) + gpio_set_value(ts->reset_gpio, 1); +#endif + nvt_bootloader_reset(); + nvt_check_fw_reset_state(RESET_STATE_REK); + +#if !WAKEUP_GESTURE + enable_irq(ts->client->irq); +#endif + +#if NVT_TOUCH_ESD_PROTECT + queue_delayed_work(nvt_esd_check_wq, &nvt_esd_check_work, + msecs_to_jiffies(NVT_TOUCH_ESD_CHECK_PERIOD)); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + bTouchIsAwake = 1; +#if NVT_TOUCH_FW + ts->suspended = 0; +#endif + + mutex_unlock(&ts->lock); + + NVT_LOG("end\n"); + + return 0; +} + + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct nvt_ts_data *ts = + container_of(self, struct nvt_ts_data, fb_notif); + + if (evdata && evdata->data && event == FB_EARLY_EVENT_BLANK) { + blank = evdata->data; + if (*blank == FB_BLANK_POWERDOWN) { + nvt_ts_suspend(&ts->client->dev); + } + } else if (evdata && evdata->data && event == FB_EVENT_BLANK) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK || + (*blank == FB_BLANK_NORMAL && 0 == bTouchIsAwake)) { + nvt_ts_resume(&ts->client->dev); + } + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) +/******************************************************* +Description: + Novatek touchscreen driver early suspend function. + +return: + n.a. +*******************************************************/ +static void nvt_ts_early_suspend(struct early_suspend *h) +{ + nvt_ts_suspend(ts->client, PMSG_SUSPEND); +} + +/******************************************************* +Description: + Novatek touchscreen driver late resume function. + +return: + n.a. +*******************************************************/ +static void nvt_ts_late_resume(struct early_suspend *h) +{ + nvt_ts_resume(ts->client); +} +#endif + +#if 0 +static const struct dev_pm_ops nvt_ts_dev_pm_ops = { + .suspend = nvt_ts_suspend, + .resume = nvt_ts_resume, +}; +#endif + +static const struct i2c_device_id nvt_ts_id[] = { + { NVT_I2C_NAME, 0 }, + { } +}; + +#ifdef CONFIG_OF +static struct of_device_id nvt_match_table[] = { + { .compatible = "novatek,NVT-ts",}, + { }, +}; +#endif +/* +static struct i2c_board_info __initdata nvt_i2c_boardinfo[] = { + { + I2C_BOARD_INFO(NVT_I2C_NAME, I2C_FW_Address), + }, +}; +*/ + +static struct i2c_driver nvt_i2c_driver = { + .probe = nvt_ts_probe, + .remove = nvt_ts_remove, +// .suspend = nvt_ts_suspend, +// .resume = nvt_ts_resume, + .id_table = nvt_ts_id, + .driver = { + .name = NVT_I2C_NAME, + .owner = THIS_MODULE, +#if 0 +#ifdef CONFIG_PM + .pm = &nvt_ts_dev_pm_ops, +#endif +#endif +#ifdef CONFIG_OF + .of_match_table = nvt_match_table, +#endif + }, +}; + +/******************************************************* +Description: + Driver Install function. + +return: + Executive Outcomes. 0---succeed. not 0---failed. +********************************************************/ +static int32_t __init nvt_driver_init(void) +{ + int32_t ret = 0; + + NVT_LOG("start\n"); + //---add i2c driver--- + ret = i2c_add_driver(&nvt_i2c_driver); + if (ret) { + pr_err("%s: failed to add i2c driver", __func__); + goto err_driver; + } + + pr_info("%s: finished\n", __func__); + +err_driver: + return ret; +} + +/******************************************************* +Description: + Driver uninstall function. + +return: + n.a. +********************************************************/ +static void __exit nvt_driver_exit(void) +{ + i2c_del_driver(&nvt_i2c_driver); + + if (nvt_wq) + destroy_workqueue(nvt_wq); + +#if BOOT_UPDATE_FIRMWARE + if (nvt_fwu_wq) + destroy_workqueue(nvt_fwu_wq); +#endif + +#if NVT_TOUCH_ESD_PROTECT + if (nvt_esd_check_wq) + destroy_workqueue(nvt_esd_check_wq); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ +} + +//late_initcall(nvt_driver_init); +module_init(nvt_driver_init); +module_exit(nvt_driver_exit); + +MODULE_DESCRIPTION("Novatek Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx.h b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx.h new file mode 100644 index 000000000000..262fa85a420e --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22429 $ + * $Date: 2018-01-30 19:42:59 +0800 (Tue, 30 Jan 2018) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + */ +#ifndef _LINUX_NVT_TOUCH_H +#define _LINUX_NVT_TOUCH_H + +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include "nt36xxx_mem_map.h" + +#define NVT_DEBUG 0 + +//---GPIO number--- +#define NVTTOUCH_RST_PIN 980 +#define NVTTOUCH_INT_PIN 943 + + +//---INT trigger mode--- +//#define IRQ_TYPE_EDGE_RISING 1 +//#define IRQ_TYPE_EDGE_FALLING 2 +#define INT_TRIGGER_TYPE IRQ_TYPE_EDGE_RISING + + +//---I2C driver info.--- +#define NVT_I2C_NAME "NVT-ts" +#define I2C_BLDR_Address 0x01 +#define I2C_FW_Address 0x01 +#define I2C_HW_Address 0x62 + +#if NVT_DEBUG +#define NVT_LOG(fmt, args...) pr_err("[%s] %s %d: " fmt, NVT_I2C_NAME, __func__, __LINE__, ##args) +#else +#define NVT_LOG(fmt, args...) pr_info("[%s] %s %d: " fmt, NVT_I2C_NAME, __func__, __LINE__, ##args) +#endif +#define NVT_ERR(fmt, args...) pr_err("[%s] %s %d: " fmt, NVT_I2C_NAME, __func__, __LINE__, ##args) + +//---Input device info.--- +#define NVT_TS_NAME "NVTCapacitiveTouchScreen" + + +//---Touch info.--- +#define TOUCH_DEFAULT_MAX_WIDTH 720 +#define TOUCH_DEFAULT_MAX_HEIGHT 1512 +#define TOUCH_MAX_FINGER_NUM 10 +#define TOUCH_KEY_NUM 0 +#if TOUCH_KEY_NUM > 0 +extern const uint16_t touch_key_array[TOUCH_KEY_NUM]; +#endif +#define TOUCH_FORCE_NUM 1000 + +/* Enable only when module have tp reset pin and connected to host */ +#define NVT_TOUCH_SUPPORT_HW_RST 1 + +//---Customerized func.--- +#define NVT_TOUCH_PROC 1 +#define NVT_TOUCH_EXT_PROC 1 +#define NVT_TOUCH_FW 1 +#define NVT_TOUCH_MP 1 +#define NVT_TOUCH_MP_LENOVO 1 +#define MT_PROTOCOL_B 1 +#define WAKEUP_GESTURE 0 +#if WAKEUP_GESTURE +extern const uint16_t gesture_key_array[]; +#endif +#define BOOT_UPDATE_FIRMWARE 0 +#define BOOT_UPDATE_FIRMWARE_NAME "novatek_ts_fw.bin" + +//---ESD Protect.--- +#define NVT_TOUCH_ESD_PROTECT 1 +#define NVT_TOUCH_ESD_CHECK_PERIOD 2000 /* ms */ + +struct nvt_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct nvt_work; + struct delayed_work nvt_fwu_work; + uint16_t addr; + int8_t phys[32]; +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + uint8_t fw_ver; + uint8_t x_num; + uint8_t y_num; + uint16_t abs_x_max; + uint16_t abs_y_max; + uint8_t max_touch_num; + uint8_t max_button_num; + uint32_t int_trigger_type; + int32_t irq_gpio; + uint32_t irq_flags; + int32_t reset_gpio; + uint32_t reset_flags; + struct mutex lock; + const struct nvt_ts_mem_map *mmap; + uint8_t carrier_system; + uint16_t nvt_pid; +#if NVT_TOUCH_FW + int8_t product_id[10]; + uint8_t suspended; + uint8_t force_reflash; + uint8_t loading_fw; +#endif +}; + +#if NVT_TOUCH_FW +#define FW_NAME_MAX_LEN 80 +#define VENDOR_NAME "novatek_ts" +#endif + +#if NVT_TOUCH_PROC +struct nvt_flash_data{ + rwlock_t lock; + struct i2c_client *client; +}; +#endif + +typedef enum { + RESET_STATE_INIT = 0xA0,// IC reset + RESET_STATE_REK, // ReK baseline + RESET_STATE_REK_FINISH, // baseline is ready + RESET_STATE_NORMAL_RUN, // normal run + RESET_STATE_MAX = 0xAF +} RST_COMPLETE_STATE; + +typedef enum { + EVENT_MAP_HOST_CMD = 0x50, + EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE = 0x51, + EVENT_MAP_RESET_COMPLETE = 0x60, + EVENT_MAP_FWINFO = 0x78, + EVENT_MAP_PROJECTID = 0x9A, + EVENT_MAP_FWDATE = 0x9C, +} I2C_EVENT_MAP; + +#if NVT_TOUCH_MP_LENOVO +typedef enum { + MP_RESULT_SHIFT_SHORT = 0x00, + MP_RESULT_SHIFT_SHORT_DIFF, + MP_RESULT_SHIFT_SHORT_BASE, + MP_RESULT_SHIFT_OPEN, + MP_RESULT_SHIFT_RAWDATA, + MP_RESULT_SHIFT_CC, + MP_RESULT_SHIFT_CC_I, + MP_RESULT_SHIFT_CC_Q, + MP_RESULT_SHIFT_NOISE, + MP_RESULT_SHIFT_DIFF_MAX, + MP_RESULT_SHIFT_DIFF_MIN, +/* MP_RESULT_SHIFT_READFAIL,*/ +} MP_TEST_RESULT; +#endif + +//---extern structures--- +extern struct nvt_ts_data *ts; + +//---extern functions--- +extern int32_t CTP_I2C_READ(struct i2c_client *client, uint16_t address, uint8_t *buf, uint16_t len); +extern int32_t CTP_I2C_WRITE(struct i2c_client *client, uint16_t address, uint8_t *buf, uint16_t len); +extern void nvt_bootloader_reset(void); +extern void nvt_sw_reset_idle(void); +extern int32_t nvt_check_fw_reset_state(RST_COMPLETE_STATE check_reset_state); +extern int32_t nvt_get_fw_info(void); +extern int32_t nvt_clear_fw_status(void); +extern int32_t nvt_check_fw_status(void); +#if NVT_TOUCH_ESD_PROTECT +extern void nvt_esd_check_enable(uint8_t enable); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ +extern void nvt_stop_crc_reboot(void); + +#endif /* _LINUX_NVT_TOUCH_H */ diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_ext_proc.c b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_ext_proc.c new file mode 100644 index 000000000000..9ec4d20d69ce --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_ext_proc.c @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 20251 $ + * $Date: 2017-12-13 17:41:29 +0800 (Wed, 13 Dec 2017) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + + +#include +#include +#include + +#include "nt36xxx.h" + +#if NVT_TOUCH_EXT_PROC +#define NVT_FW_VERSION "nvt_fw_version" +#define NVT_BASELINE "nvt_baseline" +#define NVT_RAW "nvt_raw" +#define NVT_DIFF "nvt_diff" + +#define I2C_TANSFER_LENGTH 64 + +#define NORMAL_MODE 0x00 +#define TEST_MODE_1 0x21 +#define TEST_MODE_2 0x22 +#define HANDSHAKING_HOST_READY 0xBB + +#define XDATA_SECTOR_SIZE 256 +#define XDATA_BUF_SIZE 2048 + +static uint8_t xdata_tmp[XDATA_BUF_SIZE] = {0}; +static int32_t xdata[XDATA_BUF_SIZE] = {0}; +static int32_t xdata_i[XDATA_BUF_SIZE] = {0}; +static int32_t xdata_q[XDATA_BUF_SIZE] = {0}; + +static struct proc_dir_entry *NVT_proc_fw_version_entry; +static struct proc_dir_entry *NVT_proc_baseline_entry; +static struct proc_dir_entry *NVT_proc_raw_entry; +static struct proc_dir_entry *NVT_proc_diff_entry; + +/******************************************************* +Description: + Novatek touchscreen change mode function. + +return: + n.a. +*******************************************************/ +void nvt_change_mode(uint8_t mode) +{ + uint8_t buf[8] = {0}; + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---set mode--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = mode; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 2); + + if (mode == NORMAL_MODE) { + buf[0] = EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE; + buf[1] = HANDSHAKING_HOST_READY; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 2); + msleep(20); + } +} + +/******************************************************* +Description: + Novatek touchscreen get firmware pipe function. + +return: + Executive outcomes. 0---pipe 0. 1---pipe 1. +*******************************************************/ +uint8_t nvt_get_fw_pipe(void) +{ + uint8_t buf[8] = {0}; + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read fw status--- + buf[0] = EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE; + buf[1] = 0x00; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 2); + + //NVT_LOG("FW pipe=%d, buf[1]=0x%02X\n", (buf[1]&0x01), buf[1]); + + return (buf[1] & 0x01); +} + +/******************************************************* +Description: + Novatek touchscreen read mass data function. + +return: + n.a. +*******************************************************/ +int32_t nvt_read_mass_data(uint8_t i2c_addr, uint8_t *temp_buf, uint32_t count) +{ + int32_t i = 0; + int32_t j = 0; + int32_t k = 0; + uint8_t i2c_buf[I2C_TANSFER_LENGTH + 1] = {0}; + uint32_t xdata_addr = 0; + uint32_t head_addr = 0; + int32_t dummy_len = 0; + int32_t data_len = 0; + int32_t residual_len = 0; + + xdata_addr = (temp_buf[3] << 24) + (temp_buf[4] << 16) + (temp_buf[5] << 8) + temp_buf[6]; + head_addr = xdata_addr - (xdata_addr % XDATA_SECTOR_SIZE); + dummy_len = xdata_addr - head_addr; + data_len = (int32_t)((temp_buf[1] << 8) + temp_buf[2]); + residual_len = (head_addr + dummy_len + data_len) % XDATA_SECTOR_SIZE; + + if (data_len > XDATA_BUF_SIZE) + return -EINVAL; + + for (i = 0; i < ((dummy_len + data_len) / XDATA_SECTOR_SIZE); i++) { + i2c_buf[0] = 0xFF; + i2c_buf[1] = ((head_addr + XDATA_SECTOR_SIZE * i) >> 16) & 0xFF; + i2c_buf[2] = ((head_addr + XDATA_SECTOR_SIZE * i) >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, (uint16_t)i2c_addr, i2c_buf, 3); + for (j = 0; j < (XDATA_SECTOR_SIZE / I2C_TANSFER_LENGTH); j++) { + i2c_buf[0] = I2C_TANSFER_LENGTH * j; + CTP_I2C_READ(ts->client, (uint16_t)i2c_addr, i2c_buf, I2C_TANSFER_LENGTH + 1); + for (k = 0; k < I2C_TANSFER_LENGTH; k++) { + xdata_tmp[XDATA_SECTOR_SIZE * i + I2C_TANSFER_LENGTH * j + k] = i2c_buf[k + 1]; + } + } + } + + if (residual_len != 0) { + i2c_buf[0] = 0xFF; + i2c_buf[1] = ((xdata_addr + data_len - residual_len) >> 16) & 0xFF; + i2c_buf[2] = ((xdata_addr + data_len - residual_len) >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, (uint16_t)i2c_addr, i2c_buf, 3); + for (j = 0; j < (residual_len / I2C_TANSFER_LENGTH + 1); j++) { + i2c_buf[0] = I2C_TANSFER_LENGTH * j; + CTP_I2C_READ(ts->client, (uint16_t)i2c_addr, i2c_buf, I2C_TANSFER_LENGTH + 1); + for (k = 0; k < I2C_TANSFER_LENGTH; k++) { + xdata_tmp[(dummy_len + data_len - residual_len) + I2C_TANSFER_LENGTH * j + k] = i2c_buf[k + 1]; + } + } + } + + i2c_buf[0] = 0xFF; + i2c_buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + i2c_buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, (uint16_t)i2c_addr, i2c_buf, 3); + + for (i = 0; i < data_len; i++) { + *(temp_buf + i) = xdata_tmp[dummy_len + i]; + } + + return data_len; +} + +/******************************************************* +Description: + Novatek touchscreen read meta data function. + +return: + n.a. +*******************************************************/ +void nvt_read_mdata(uint32_t xdata_addr, uint32_t xdata_btn_addr) +{ + int32_t i = 0; + int32_t j = 0; + int32_t k = 0; + uint8_t buf[I2C_TANSFER_LENGTH + 1] = {0}; + uint32_t head_addr = 0; + int32_t dummy_len = 0; + int32_t data_len = 0; + int32_t residual_len = 0; + + //---set xdata sector address & length--- + head_addr = xdata_addr - (xdata_addr % XDATA_SECTOR_SIZE); + dummy_len = xdata_addr - head_addr; + data_len = ts->x_num * ts->y_num * 2; + residual_len = (head_addr + dummy_len + data_len) % XDATA_SECTOR_SIZE; + + //printk("head_addr=0x%05X, dummy_len=0x%05X, data_len=0x%05X, residual_len=0x%05X\n", head_addr, dummy_len, data_len, residual_len); + + //read xdata : step 1 + for (i = 0; i < ((dummy_len + data_len) / XDATA_SECTOR_SIZE); i++) { + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = ((head_addr + XDATA_SECTOR_SIZE * i) >> 16) & 0xFF; + buf[2] = ((head_addr + XDATA_SECTOR_SIZE * i) >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read xdata by I2C_TANSFER_LENGTH + for (j = 0; j < (XDATA_SECTOR_SIZE / I2C_TANSFER_LENGTH); j++) { + //---read data--- + buf[0] = I2C_TANSFER_LENGTH * j; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, I2C_TANSFER_LENGTH + 1); + + //---copy buf to xdata_tmp--- + for (k = 0; k < I2C_TANSFER_LENGTH; k++) { + xdata_tmp[XDATA_SECTOR_SIZE * i + I2C_TANSFER_LENGTH * j + k] = buf[k + 1]; + //printk("0x%02X, 0x%04X\n", buf[k+1], (XDATA_SECTOR_SIZE*i + I2C_TANSFER_LENGTH*j + k)); + } + } + //printk("addr=0x%05X\n", (head_addr+XDATA_SECTOR_SIZE*i)); + } + + //read xdata : step2 + if (residual_len != 0) { + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = ((xdata_addr + data_len - residual_len) >> 16) & 0xFF; + buf[2] = ((xdata_addr + data_len - residual_len) >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read xdata by I2C_TANSFER_LENGTH + for (j = 0; j < (residual_len / I2C_TANSFER_LENGTH + 1); j++) { + //---read data--- + buf[0] = I2C_TANSFER_LENGTH * j; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, I2C_TANSFER_LENGTH + 1); + + //---copy buf to xdata_tmp--- + for (k = 0; k < I2C_TANSFER_LENGTH; k++) { + xdata_tmp[(dummy_len + data_len - residual_len) + I2C_TANSFER_LENGTH * j + k] = buf[k + 1]; + //printk("0x%02X, 0x%04x\n", buf[k+1], ((dummy_len+data_len-residual_len) + I2C_TANSFER_LENGTH*j + k)); + } + } + //printk("addr=0x%05X\n", (xdata_addr+data_len-residual_len)); + } + + //---remove dummy data and 2bytes-to-1data--- + for (i = 0; i < (data_len / 2); i++) { + xdata[i] = (int16_t)(xdata_tmp[dummy_len + i * 2] + 256 * xdata_tmp[dummy_len + i * 2 + 1]); + } + +#if TOUCH_KEY_NUM > 0 + //read button xdata : step3 + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (xdata_btn_addr >> 16) & 0xFF; + buf[2] = ((xdata_btn_addr >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read data--- + buf[0] = (xdata_btn_addr & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, (TOUCH_KEY_NUM * 2 + 1)); + + //---2bytes-to-1data--- + for (i = 0; i < TOUCH_KEY_NUM; i++) { + xdata[ts->x_num * ts->y_num + i] = (int16_t)(buf[1 + i * 2] + 256 * buf[1 + i * 2 + 1]); + } +#endif + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); +} + +/******************************************************* +Description: + Novatek touchscreen read meta data from IQ to rss function. + +return: + n.a. +*******************************************************/ +void nvt_read_mdata_rss(uint32_t xdata_i_addr, uint32_t xdata_q_addr, uint32_t xdata_btn_i_addr, uint32_t xdata_btn_q_addr) +{ + int i = 0; + + nvt_read_mdata(xdata_i_addr, xdata_btn_i_addr); + memcpy(xdata_i, xdata, ((ts->x_num * ts->y_num + TOUCH_KEY_NUM) * sizeof(int32_t))); + + nvt_read_mdata(xdata_q_addr, xdata_btn_q_addr); + memcpy(xdata_q, xdata, ((ts->x_num * ts->y_num + TOUCH_KEY_NUM) * sizeof(int32_t))); + + for (i = 0; i < (ts->x_num * ts->y_num + TOUCH_KEY_NUM); i++) { + xdata[i] = (int32_t)int_sqrt((unsigned long)(xdata_i[i] * xdata_i[i]) + (unsigned long)(xdata_q[i] * xdata_q[i])); + } +} + +/******************************************************* +Description: + Novatek touchscreen get meta data function. + +return: + n.a. +*******************************************************/ +void nvt_get_mdata(int32_t *buf, uint8_t *m_x_num, uint8_t *m_y_num) +{ + *m_x_num = ts->x_num; + *m_y_num = ts->y_num; + memcpy(buf, xdata, ((ts->x_num * ts->y_num + TOUCH_KEY_NUM) * sizeof(int32_t))); +} + +/******************************************************* +Description: + Novatek touchscreen firmware version show function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t c_fw_version_show(struct seq_file *m, void *v) +{ + seq_printf(m, "fw_ver=%d, x_num=%d, y_num=%d, button_num=%d\n", ts->fw_ver, ts->x_num, ts->y_num, ts->max_button_num); + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen xdata sequence print show + function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t c_show(struct seq_file *m, void *v) +{ + int32_t i = 0; + int32_t j = 0; + + for (i = 0; i < ts->y_num; i++) { + for (j = 0; j < ts->x_num; j++) { + seq_printf(m, "%5d, ", xdata[i * ts->x_num + j]); + } + seq_puts(m, "\n"); + } + +#if TOUCH_KEY_NUM > 0 + for (i = 0; i < TOUCH_KEY_NUM; i++) { + seq_printf(m, "%5d, ", xdata[ts->x_num * ts->y_num + i]); + } + seq_puts(m, "\n"); +#endif + + seq_printf(m, "\n\n"); + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen xdata sequence print start + function. + +return: + Executive outcomes. 1---call next function. + NULL---not call next function and sequence loop + stop. +*******************************************************/ +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +/******************************************************* +Description: + Novatek touchscreen xdata sequence print next + function. + +return: + Executive outcomes. NULL---no next and call sequence + stop function. +*******************************************************/ +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +/******************************************************* +Description: + Novatek touchscreen xdata sequence print stop + function. + +return: + n.a. +*******************************************************/ +static void c_stop(struct seq_file *m, void *v) +{ + return; +} + +const struct seq_operations nvt_fw_version_seq_ops = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_fw_version_show +}; + +const struct seq_operations nvt_seq_ops = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show +}; + +/******************************************************* +Description: + Novatek touchscreen /proc/nvt_fw_version open + function. + +return: + n.a. +*******************************************************/ +static int32_t nvt_fw_version_open(struct inode *inode, struct file *file) +{ + if (mutex_lock_interruptible(&ts->lock)) { + return -ERESTARTSYS; + } + + NVT_LOG("++\n"); + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + if (nvt_get_fw_info()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + mutex_unlock(&ts->lock); + + NVT_LOG("--\n"); + + return seq_open(file, &nvt_fw_version_seq_ops); +} + +static const struct file_operations nvt_fw_version_fops = { + .owner = THIS_MODULE, + .open = nvt_fw_version_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/******************************************************* +Description: + Novatek touchscreen /proc/nvt_baseline open function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_baseline_open(struct inode *inode, struct file *file) +{ + if (mutex_lock_interruptible(&ts->lock)) { + return -ERESTARTSYS; + } + + NVT_LOG("++\n"); + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + if (nvt_clear_fw_status()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + nvt_change_mode(TEST_MODE_2); + + if (nvt_check_fw_status()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + if (nvt_get_fw_info()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + if (ts->carrier_system) { + nvt_read_mdata_rss(ts->mmap->BASELINE_ADDR, ts->mmap->BASELINE_Q_ADDR, + ts->mmap->BASELINE_BTN_ADDR, ts->mmap->BASELINE_BTN_Q_ADDR); + } else { + nvt_read_mdata(ts->mmap->BASELINE_ADDR, ts->mmap->BASELINE_BTN_ADDR); + } + + nvt_change_mode(NORMAL_MODE); + + mutex_unlock(&ts->lock); + + NVT_LOG("--\n"); + + return seq_open(file, &nvt_seq_ops); +} + +static const struct file_operations nvt_baseline_fops = { + .owner = THIS_MODULE, + .open = nvt_baseline_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/******************************************************* +Description: + Novatek touchscreen /proc/nvt_raw open function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_raw_open(struct inode *inode, struct file *file) +{ + if (mutex_lock_interruptible(&ts->lock)) { + return -ERESTARTSYS; + } + + NVT_LOG("++\n"); + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + if (nvt_clear_fw_status()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + nvt_change_mode(TEST_MODE_2); + + if (nvt_check_fw_status()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + if (nvt_get_fw_info()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + if (ts->carrier_system) { + if (nvt_get_fw_pipe() == 0) + nvt_read_mdata_rss(ts->mmap->RAW_PIPE0_ADDR, ts->mmap->RAW_PIPE0_Q_ADDR, + ts->mmap->RAW_BTN_PIPE0_ADDR, ts->mmap->RAW_BTN_PIPE0_Q_ADDR); + else + nvt_read_mdata_rss(ts->mmap->RAW_PIPE1_ADDR, ts->mmap->RAW_PIPE1_Q_ADDR, + ts->mmap->RAW_BTN_PIPE1_ADDR, ts->mmap->RAW_BTN_PIPE1_Q_ADDR); + } else { + if (nvt_get_fw_pipe() == 0) + nvt_read_mdata(ts->mmap->RAW_PIPE0_ADDR, ts->mmap->RAW_BTN_PIPE0_ADDR); + else + nvt_read_mdata(ts->mmap->RAW_PIPE1_ADDR, ts->mmap->RAW_BTN_PIPE1_ADDR); + } + + nvt_change_mode(NORMAL_MODE); + + mutex_unlock(&ts->lock); + + NVT_LOG("--\n"); + + return seq_open(file, &nvt_seq_ops); +} + +static const struct file_operations nvt_raw_fops = { + .owner = THIS_MODULE, + .open = nvt_raw_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/******************************************************* +Description: + Novatek touchscreen /proc/nvt_diff open function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +static int32_t nvt_diff_open(struct inode *inode, struct file *file) +{ + if (mutex_lock_interruptible(&ts->lock)) { + return -ERESTARTSYS; + } + + NVT_LOG("++\n"); + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + if (nvt_clear_fw_status()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + nvt_change_mode(TEST_MODE_2); + + if (nvt_check_fw_status()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + if (nvt_get_fw_info()) { + mutex_unlock(&ts->lock); + return -EAGAIN; + } + + if (ts->carrier_system) { + if (nvt_get_fw_pipe() == 0) + nvt_read_mdata_rss(ts->mmap->DIFF_PIPE0_ADDR, ts->mmap->DIFF_PIPE0_Q_ADDR, + ts->mmap->DIFF_BTN_PIPE0_ADDR, ts->mmap->DIFF_BTN_PIPE0_Q_ADDR); + else + nvt_read_mdata_rss(ts->mmap->DIFF_PIPE1_ADDR, ts->mmap->DIFF_PIPE1_Q_ADDR, + ts->mmap->DIFF_BTN_PIPE1_ADDR, ts->mmap->DIFF_BTN_PIPE1_Q_ADDR); + } else { + if (nvt_get_fw_pipe() == 0) + nvt_read_mdata(ts->mmap->DIFF_PIPE0_ADDR, ts->mmap->DIFF_BTN_PIPE0_ADDR); + else + nvt_read_mdata(ts->mmap->DIFF_PIPE1_ADDR, ts->mmap->DIFF_BTN_PIPE1_ADDR); + } + + nvt_change_mode(NORMAL_MODE); + + mutex_unlock(&ts->lock); + + NVT_LOG("--\n"); + + return seq_open(file, &nvt_seq_ops); +} + +static const struct file_operations nvt_diff_fops = { + .owner = THIS_MODULE, + .open = nvt_diff_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/******************************************************* +Description: + Novatek touchscreen extra function proc. file node + initial function. + +return: + Executive outcomes. 0---succeed. -12---failed. +*******************************************************/ +int32_t nvt_extra_proc_init(void) +{ + NVT_proc_fw_version_entry = proc_create(NVT_FW_VERSION, 0444, NULL, &nvt_fw_version_fops); + if (NVT_proc_fw_version_entry == NULL) { + NVT_ERR("create proc/nvt_fw_version Failed!\n"); + return -ENOMEM; + } else { + NVT_LOG("create proc/nvt_fw_version Succeeded!\n"); + } + + NVT_proc_baseline_entry = proc_create(NVT_BASELINE, 0444, NULL, &nvt_baseline_fops); + if (NVT_proc_baseline_entry == NULL) { + NVT_ERR("create proc/nvt_baseline Failed!\n"); + return -ENOMEM; + } else { + NVT_LOG("create proc/nvt_baseline Succeeded!\n"); + } + + NVT_proc_raw_entry = proc_create(NVT_RAW, 0444, NULL, &nvt_raw_fops); + if (NVT_proc_raw_entry == NULL) { + NVT_ERR("create proc/nvt_raw Failed!\n"); + return -ENOMEM; + } else { + NVT_LOG("create proc/nvt_raw Succeeded!\n"); + } + + NVT_proc_diff_entry = proc_create(NVT_DIFF, 0444, NULL, &nvt_diff_fops); + if (NVT_proc_diff_entry == NULL) { + NVT_ERR("create proc/nvt_diff Failed!\n"); + return -ENOMEM; + } else { + NVT_LOG("create proc/nvt_diff Succeeded!\n"); + } + + return 0; +} +#endif diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_fw_update.c b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_fw_update.c new file mode 100644 index 000000000000..ba75fc516e44 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_fw_update.c @@ -0,0 +1,1387 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 20544 $ + * $Date: 2017-12-20 11:08:15 +0800 (Wed, 20 Dec 2017) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include + +#include "nt36xxx.h" + +#if (BOOT_UPDATE_FIRMWARE || NVT_TOUCH_FW) + +#define FW_BIN_SIZE_116KB 118784 +#define FW_BIN_SIZE FW_BIN_SIZE_116KB +#define FW_BIN_VER_OFFSET 0x1A000 +#define FW_BIN_VER_BAR_OFFSET 0x1A001 +#define FLASH_SECTOR_SIZE 4096 +#define SIZE_64KB 65536 +#define BLOCK_64KB_NUM 4 + +const struct firmware *fw_entry; + +/******************************************************* +Description: + Novatek touchscreen request update firmware function. + +return: + Executive outcomes. 0---succeed. -1,-22---failed. +*******************************************************/ +int32_t update_firmware_request(char *filename) +{ + int32_t ret = 0; + + if (NULL == filename) { + return -EPERM; + } + + NVT_LOG("filename is %s\n", filename); + + ret = request_firmware(&fw_entry, filename, &ts->client->dev); + if (ret) { + NVT_ERR("firmware load failed, ret=%d\n", ret); + return ret; + } + + // check bin file size (116kb) + if (fw_entry->size != FW_BIN_SIZE) { + NVT_ERR("bin file size not match. (%zu)\n", fw_entry->size); + return -EINVAL; + } + + // check if FW version add FW version bar equals 0xFF + if (*(fw_entry->data + FW_BIN_VER_OFFSET) + *(fw_entry->data + FW_BIN_VER_BAR_OFFSET) != 0xFF) { + NVT_ERR("bin file FW_VER + FW_VER_BAR should be 0xFF!\n"); + NVT_ERR("FW_VER=0x%02X, FW_VER_BAR=0x%02X\n", *(fw_entry->data+FW_BIN_VER_OFFSET), *(fw_entry->data+FW_BIN_VER_BAR_OFFSET)); + return -EINVAL; + } + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen release update firmware function. + +return: + n.a. +*******************************************************/ +void update_firmware_release(void) +{ + if (fw_entry) { + release_firmware(fw_entry); + } + fw_entry = NULL; +} + +/******************************************************* +Description: + Novatek touchscreen check firmware version function. + +return: + Executive outcomes. 0---need update. 1---need not + update. +*******************************************************/ +int32_t Check_FW_Ver(void) +{ + uint8_t buf[16] = {0}; + int32_t ret = 0; + + //write i2c index to EVENT BUF ADDR + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("i2c write error!(%d)\n", ret); + return ret; + } + + //read Firmware Version + buf[0] = EVENT_MAP_FWINFO; + buf[1] = 0x00; + buf[2] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("i2c read error!(%d)\n", ret); + return ret; + } + + NVT_LOG("IC FW Ver = 0x%02X, FW Ver Bar = 0x%02X\n", buf[1], buf[2]); + NVT_LOG("Bin FW Ver = 0x%02X, FW ver Bar = 0x%02X\n", + fw_entry->data[FW_BIN_VER_OFFSET], fw_entry->data[FW_BIN_VER_BAR_OFFSET]); + + // check IC FW_VER + FW_VER_BAR equals 0xFF or not, need to update if not + if ((buf[1] + buf[2]) != 0xFF) { + NVT_ERR("IC FW_VER + FW_VER_BAR not equals to 0xFF!\n"); + return 0; + } + + // compare IC and binary FW version + if (buf[1] == fw_entry->data[FW_BIN_VER_OFFSET]) + return 1; + else + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen resume from deep power down function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +int32_t Resume_PD(void) +{ + uint8_t buf[8] = {0}; + int32_t ret = 0; + int32_t retry = 0; + + // Resume Command + buf[0] = 0x00; + buf[1] = 0xAB; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Write Enable error!!(%d)\n", ret); + return ret; + } + + // Check 0xAA (Resume Command) + retry = 0; + while (1) { + msleep(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Resume Command) error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Resume Command) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + } + msleep(10); + + NVT_LOG("Resume PD OK\n"); + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen check firmware checksum function. + +return: + Executive outcomes. 0---checksum not match. + 1---checksum match. -1--- checksum read failed. +*******************************************************/ +int32_t Check_CheckSum(void) +{ + uint8_t buf[64] = {0}; + uint32_t XDATA_Addr = ts->mmap->READ_FLASH_CHECKSUM_ADDR; + int32_t ret = 0; + int32_t i = 0; + int32_t k = 0; + uint16_t WR_Filechksum[BLOCK_64KB_NUM] = {0}; + uint16_t RD_Filechksum[BLOCK_64KB_NUM] = {0}; + size_t fw_bin_size = 0; + size_t len_in_blk = 0; + int32_t retry = 0; + + if (Resume_PD()) { + NVT_ERR("Resume PD error!!\n"); + return -EPERM; + } + + fw_bin_size = fw_entry->size; + + for (i = 0; i < BLOCK_64KB_NUM; i++) { + if (fw_bin_size > (i * SIZE_64KB)) { + // Calculate WR_Filechksum of each 64KB block + len_in_blk = min(fw_bin_size - i * SIZE_64KB, (size_t)SIZE_64KB); + WR_Filechksum[i] = i + 0x00 + 0x00 + (((len_in_blk - 1) >> 8) & 0xFF) + ((len_in_blk - 1) & 0xFF); + for (k = 0; k < len_in_blk; k++) { + WR_Filechksum[i] += fw_entry->data[k + i * SIZE_64KB]; + } + WR_Filechksum[i] = 65535 - WR_Filechksum[i] + 1; + + // Fast Read Command + buf[0] = 0x00; + buf[1] = 0x07; + buf[2] = i; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = ((len_in_blk - 1) >> 8) & 0xFF; + buf[6] = (len_in_blk - 1) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 7); + if (ret < 0) { + NVT_ERR("Fast Read Command error!!(%d)\n", ret); + return ret; + } + // Check 0xAA (Fast Read Command) + retry = 0; + while (1) { + msleep(80); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Fast Read Command) error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 5)) { + NVT_ERR("Check 0xAA (Fast Read Command) failed, buf[1]=0x%02X, retry=%d\n", buf[1], retry); + return -EPERM; + } + } + // Read Checksum (write addr high byte & middle byte) + buf[0] = 0xFF; + buf[1] = XDATA_Addr >> 16; + buf[2] = (XDATA_Addr >> 8) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Read Checksum (write addr high byte & middle byte) error!!(%d)\n", ret); + return ret; + } + // Read Checksum + buf[0] = (XDATA_Addr) & 0xFF; + buf[1] = 0x00; + buf[2] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Read Checksum error!!(%d)\n", ret); + return ret; + } + + RD_Filechksum[i] = (uint16_t)((buf[2] << 8) | buf[1]); + if (WR_Filechksum[i] != RD_Filechksum[i]) { + NVT_ERR("RD_Filechksum[%d]=0x%04X, WR_Filechksum[%d]=0x%04X\n", i, RD_Filechksum[i], i, WR_Filechksum[i]); + NVT_ERR("firmware checksum not match!!\n"); + return 0; + } + } + } + + NVT_LOG("firmware checksum match\n"); + return 1; +} + +/******************************************************* +Description: + Novatek touchscreen initial bootloader and flash + block function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +int32_t Init_BootLoader(void) +{ + uint8_t buf[64] = {0}; + int32_t ret = 0; + int32_t retry = 0; + + // SW Reset & Idle + nvt_sw_reset_idle(); + + // Initiate Flash Block + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = I2C_FW_Address; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Inittial Flash Block error!!(%d)\n", ret); + return ret; + } + + // Check 0xAA (Initiate Flash Block) + retry = 0; + while (1) { + msleep(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Inittial Flash Block) error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Inittial Flash Block) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + } + + NVT_LOG("Init OK \n"); + msleep(20); + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen erase flash sectors function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +int32_t Erase_Flash(void) +{ + uint8_t buf[64] = {0}; + int32_t ret = 0; + int32_t count = 0; + int32_t i = 0; + int32_t Flash_Address = 0; + int32_t retry = 0; + + // Write Enable + buf[0] = 0x00; + buf[1] = 0x06; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Write Enable (for Write Status Register) error!!(%d)\n", ret); + return ret; + } + // Check 0xAA (Write Enable) + retry = 0; + while (1) { + mdelay(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Write Enable for Write Status Register) error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Write Enable for Write Status Register) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + } + + // Write Status Register + buf[0] = 0x00; + buf[1] = 0x01; + buf[2] = 0x00; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Write Status Register error!!(%d)\n", ret); + return ret; + } + // Check 0xAA (Write Status Register) + retry = 0; + while (1) { + mdelay(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Write Status Register) error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Write Status Register) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + } + + // Read Status + retry = 0; + while (1) { + mdelay(5); + buf[0] = 0x00; + buf[1] = 0x05; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Read Status (for Write Status Register) error!!(%d)\n", ret); + return ret; + } + + // Check 0xAA (Read Status) + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Check 0xAA (Read Status for Write Status Register) error!!(%d)\n", ret); + return ret; + } + if ((buf[1] == 0xAA) && (buf[2] == 0x00)) { + break; + } + retry++; + if (unlikely(retry > 100)) { + NVT_ERR("Check 0xAA (Read Status for Write Status Register) failed, buf[1]=0x%02X, buf[2]=0x%02X, retry=%d\n", buf[1], buf[2], retry); + return -EPERM; + } + } + + if (fw_entry->size % FLASH_SECTOR_SIZE) + count = fw_entry->size / FLASH_SECTOR_SIZE + 1; + else + count = fw_entry->size / FLASH_SECTOR_SIZE; + + for (i = 0; i < count; i++) { + // Write Enable + buf[0] = 0x00; + buf[1] = 0x06; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Write Enable error!!(%d,%d)\n", ret, i); + return ret; + } + // Check 0xAA (Write Enable) + retry = 0; + while (1) { + mdelay(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Write Enable) error!!(%d,%d)\n", ret, i); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Write Enable) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + } + + Flash_Address = i * FLASH_SECTOR_SIZE; + + // Sector Erase + buf[0] = 0x00; + buf[1] = 0x20; // Command : Sector Erase + buf[2] = ((Flash_Address >> 16) & 0xFF); + buf[3] = ((Flash_Address >> 8) & 0xFF); + buf[4] = (Flash_Address & 0xFF); + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 5); + if (ret < 0) { + NVT_ERR("Sector Erase error!!(%d,%d)\n", ret, i); + return ret; + } + // Check 0xAA (Sector Erase) + retry = 0; + while (1) { + mdelay(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Sector Erase) error!!(%d,%d)\n", ret, i); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Sector Erase) failed, buf[1]=0x%02X, retry=%d\n", buf[1], retry); + return -EPERM; + } + } + + // Read Status + retry = 0; + while (1) { + mdelay(5); + buf[0] = 0x00; + buf[1] = 0x05; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Read Status error!!(%d,%d)\n", ret, i); + return ret; + } + + // Check 0xAA (Read Status) + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Check 0xAA (Read Status) error!!(%d,%d)\n", ret, i); + return ret; + } + if ((buf[1] == 0xAA) && (buf[2] == 0x00)) { + break; + } + retry++; + if (unlikely(retry > 100)) { + NVT_ERR("Check 0xAA (Read Status) failed, buf[1]=0x%02X, buf[2]=0x%02X, retry=%d\n", buf[1], buf[2], retry); + return -EPERM; + } + } + } + + NVT_LOG("Erase OK \n"); + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen write flash sectors function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +int32_t Write_Flash(void) +{ + uint8_t buf[64] = {0}; + uint32_t XDATA_Addr = ts->mmap->RW_FLASH_DATA_ADDR; + uint32_t Flash_Address = 0; + int32_t i = 0, j = 0, k = 0; + uint8_t tmpvalue = 0; + int32_t count = 0; + int32_t ret = 0; + int32_t retry = 0; + + // change I2C buffer index + buf[0] = 0xFF; + buf[1] = XDATA_Addr >> 16; + buf[2] = (XDATA_Addr >> 8) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("change I2C buffer index error!!(%d)\n", ret); + return ret; + } + + if (fw_entry->size % 256) + count = fw_entry->size / 256 + 1; + else + count = fw_entry->size / 256; + + for (i = 0; i < count; i++) { + Flash_Address = i * 256; + + // Write Enable + buf[0] = 0x00; + buf[1] = 0x06; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Write Enable error!!(%d)\n", ret); + return ret; + } + // Check 0xAA (Write Enable) + retry = 0; + while (1) { + udelay(100); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Write Enable) error!!(%d,%d)\n", ret, i); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Write Enable) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + } + + // Write Page : 256 bytes + for (j = 0; j < min(fw_entry->size - i * 256, (size_t)256); j += 32) { + buf[0] = (XDATA_Addr + j) & 0xFF; + for (k = 0; k < 32; k++) { + buf[1 + k] = fw_entry->data[Flash_Address + j + k]; + } + ret = CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 33); + if (ret < 0) { + NVT_ERR("Write Page error!!(%d), j=%d\n", ret, j); + return ret; + } + } + if (fw_entry->size - Flash_Address >= 256) + tmpvalue = (Flash_Address >> 16) + ((Flash_Address >> 8) & 0xFF) + (Flash_Address & 0xFF) + 0x00 + (255); + else + tmpvalue = (Flash_Address >> 16) + ((Flash_Address >> 8) & 0xFF) + (Flash_Address & 0xFF) + 0x00 + (fw_entry->size - Flash_Address - 1); + + for (k = 0; k < min(fw_entry->size - Flash_Address, (size_t)256); k++) + tmpvalue += fw_entry->data[Flash_Address + k]; + + tmpvalue = 255 - tmpvalue + 1; + + // Page Program + buf[0] = 0x00; + buf[1] = 0x02; + buf[2] = ((Flash_Address >> 16) & 0xFF); + buf[3] = ((Flash_Address >> 8) & 0xFF); + buf[4] = (Flash_Address & 0xFF); + buf[5] = 0x00; + buf[6] = min(fw_entry->size - Flash_Address, (size_t)256) - 1; + buf[7] = tmpvalue; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 8); + if (ret < 0) { + NVT_ERR("Page Program error!!(%d), i=%d\n", ret, i); + return ret; + } + // Check 0xAA (Page Program) + retry = 0; + while (1) { + mdelay(1); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Page Program error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA || buf[1] == 0xEA) { + break; + } + retry++; + if (unlikely(retry > 20)) { + NVT_ERR("Check 0xAA (Page Program) failed, buf[1]=0x%02X, retry=%d\n", buf[1], retry); + return -EPERM; + } + } + if (buf[1] == 0xEA) { + NVT_ERR("Page Program error!! i=%d\n", i); + return -ESRCH; + } + + // Read Status + retry = 0; + while (1) { + mdelay(5); + buf[0] = 0x00; + buf[1] = 0x05; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Read Status error!!(%d)\n", ret); + return ret; + } + + // Check 0xAA (Read Status) + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Check 0xAA (Read Status) error!!(%d)\n", ret); + return ret; + } + if (((buf[1] == 0xAA) && (buf[2] == 0x00)) || (buf[1] == 0xEA)) { + break; + } + retry++; + if (unlikely(retry > 100)) { + NVT_ERR("Check 0xAA (Read Status) failed, buf[1]=0x%02X, buf[2]=0x%02X, retry=%d\n", buf[1], buf[2], retry); + return -EPERM; + } + } + if (buf[1] == 0xEA) { + NVT_ERR("Page Program error!! i=%d\n", i); + return -EINTR; + } + + NVT_LOG("Programming...%2d%%\r", ((i * 100) / count)); + } + + NVT_LOG("Programming...%2d%%\r", 100); + NVT_LOG("Program OK \n"); + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen verify checksum of written + flash function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +int32_t Verify_Flash(void) +{ + uint8_t buf[64] = {0}; + uint32_t XDATA_Addr = ts->mmap->READ_FLASH_CHECKSUM_ADDR; + int32_t ret = 0; + int32_t i = 0; + int32_t k = 0; + uint16_t WR_Filechksum[BLOCK_64KB_NUM] = {0}; + uint16_t RD_Filechksum[BLOCK_64KB_NUM] = {0}; + size_t fw_bin_size = 0; + size_t len_in_blk = 0; + int32_t retry = 0; + + fw_bin_size = fw_entry->size; + + for (i = 0; i < BLOCK_64KB_NUM; i++) { + if (fw_bin_size > (i * SIZE_64KB)) { + // Calculate WR_Filechksum of each 64KB block + len_in_blk = min(fw_bin_size - i * SIZE_64KB, (size_t)SIZE_64KB); + WR_Filechksum[i] = i + 0x00 + 0x00 + (((len_in_blk - 1) >> 8) & 0xFF) + ((len_in_blk - 1) & 0xFF); + for (k = 0; k < len_in_blk; k++) { + WR_Filechksum[i] += fw_entry->data[k + i * SIZE_64KB]; + } + WR_Filechksum[i] = 65535 - WR_Filechksum[i] + 1; + + // Fast Read Command + buf[0] = 0x00; + buf[1] = 0x07; + buf[2] = i; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = ((len_in_blk - 1) >> 8) & 0xFF; + buf[6] = (len_in_blk - 1) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 7); + if (ret < 0) { + NVT_ERR("Fast Read Command error!!(%d)\n", ret); + return ret; + } + // Check 0xAA (Fast Read Command) + retry = 0; + while (1) { + msleep(80); + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Fast Read Command) error!!(%d)\n", ret); + return ret; + } + if (buf[1] == 0xAA) { + break; + } + retry++; + if (unlikely(retry > 5)) { + NVT_ERR("Check 0xAA (Fast Read Command) failed, buf[1]=0x%02X, retry=%d\n", buf[1], retry); + return -EPERM; + } + } + // Read Checksum (write addr high byte & middle byte) + buf[0] = 0xFF; + buf[1] = XDATA_Addr >> 16; + buf[2] = (XDATA_Addr >> 8) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Read Checksum (write addr high byte & middle byte) error!!(%d)\n", ret); + return ret; + } + // Read Checksum + buf[0] = (XDATA_Addr) & 0xFF; + buf[1] = 0x00; + buf[2] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("Read Checksum error!!(%d)\n", ret); + return ret; + } + + RD_Filechksum[i] = (uint16_t)((buf[2] << 8) | buf[1]); + if (WR_Filechksum[i] != RD_Filechksum[i]) { + NVT_ERR("Verify Fail%d!!\n", i); + NVT_ERR("RD_Filechksum[%d]=0x%04X, WR_Filechksum[%d]=0x%04X\n", i, RD_Filechksum[i], i, WR_Filechksum[i]); + return -EPERM; + } + } + } + + NVT_LOG("Verify OK \n"); + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen update firmware function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +int32_t Update_Firmware(void) +{ + int32_t ret = 0; + NVT_LOG("enter %s start\n", __func__); + //---Stop CRC check to prevent IC auto reboot--- + nvt_stop_crc_reboot(); + + // Step 1 : initial bootloader + ret = Init_BootLoader(); + if (ret) { + return ret; + } + + // Step 2 : Resume PD + ret = Resume_PD(); + if (ret) { + return ret; + } + + // Step 3 : Erase + ret = Erase_Flash(); + if (ret) { + return ret; + } + + // Step 4 : Program + ret = Write_Flash(); + if (ret) { + return ret; + } + + // Step 5 : Verify + ret = Verify_Flash(); + if (ret) { + return ret; + } + + //Step 6 : Bootloader Reset + nvt_bootloader_reset(); + nvt_check_fw_reset_state(RESET_STATE_INIT); + NVT_LOG("exit %s end\n", __func__); + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen check flash end flag function. + +return: + Executive outcomes. 0---succeed. 1,negative---failed. +*******************************************************/ +#define NVT_FLASH_END_FLAG_LEN 3 +#define NVT_FLASH_END_FLAG_ADDR 0x1AFFD +int32_t nvt_check_flash_end_flag(void) +{ + uint8_t buf[8] = {0}; + uint8_t nvt_end_flag[NVT_FLASH_END_FLAG_LEN + 1] = {0}; + int32_t ret = 0; + + // Step 1 : initial bootloader + ret = Init_BootLoader(); + if (ret) { + return ret; + } + + // Step 2 : Resume PD + ret = Resume_PD(); + if (ret) { + return ret; + } + + // Step 3 : unlock + buf[0] = 0x00; + buf[1] = 0x35; + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("write unlock error!!(%d)\n", ret); + return ret; + } + msleep(10); + + //Step 4 : Flash Read Command + buf[0] = 0x00; + buf[1] = 0x03; + buf[2] = (NVT_FLASH_END_FLAG_ADDR >> 16) & 0xFF; //Addr_H + buf[3] = (NVT_FLASH_END_FLAG_ADDR >> 8) & 0xFF; //Addr_M + buf[4] = NVT_FLASH_END_FLAG_ADDR & 0xFF; //Addr_L + buf[5] = (NVT_FLASH_END_FLAG_LEN >> 8) & 0xFF; //Len_H + buf[6] = NVT_FLASH_END_FLAG_LEN & 0xFF; //Len_L + ret = CTP_I2C_WRITE(ts->client, I2C_HW_Address, buf, 7); + if (ret < 0) { + NVT_ERR("write Read Command error!!(%d)\n", ret); + return ret; + } + msleep(10); + + // Check 0xAA (Read Command) + buf[0] = 0x00; + buf[1] = 0x00; + ret = CTP_I2C_READ(ts->client, I2C_HW_Address, buf, 2); + if (ret < 0) { + NVT_ERR("Check 0xAA (Read Command) error!!(%d)\n", ret); + return ret; + } + if (buf[1] != 0xAA) { + NVT_ERR("Check 0xAA (Read Command) error!! status=0x%02X\n", buf[1]); + return -EPERM; + } + + msleep(10); + + //Step 5 : Read Flash Data + buf[0] = 0xFF; + buf[1] = (ts->mmap->READ_FLASH_CHECKSUM_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->READ_FLASH_CHECKSUM_ADDR >> 8) & 0xFF; + ret = CTP_I2C_WRITE(ts->client, I2C_BLDR_Address, buf, 3); + if (ret < 0) { + NVT_ERR("change index error!! (%d)\n", ret); + return ret; + } + msleep(10); + + // Read Back + buf[0] = ts->mmap->READ_FLASH_CHECKSUM_ADDR & 0xFF; + ret = CTP_I2C_READ(ts->client, I2C_BLDR_Address, buf, 6); + if (ret < 0) { + NVT_ERR("Read Back error!! (%d)\n", ret); + return ret; + } + + //buf[3:5] => NVT End Flag + strlcpy(nvt_end_flag, &buf[3], sizeof(nvt_end_flag)); + NVT_LOG("nvt_end_flag=%s (%02X %02X %02X)\n", nvt_end_flag, buf[3], buf[4], buf[5]); + + if (strncmp(nvt_end_flag, "NVT", 3) == 0) { + return 0; + } else { + NVT_ERR("\"NVT\" end flag not found!\n"); + return 1; + } +} + +/******************************************************* +Description: + Novatek touchscreen update firmware when booting + function. + +return: + n.a. +*******************************************************/ +void Boot_Update_Firmware(struct work_struct *work) +{ + int32_t ret = 0; + + char firmware_name[256] = ""; + snprintf(firmware_name, sizeof(firmware_name), BOOT_UPDATE_FIRMWARE_NAME); + + // request bin file in "/etc/firmware" + ret = update_firmware_request(firmware_name); + if (ret) { + NVT_ERR("update_firmware_request failed. (%d)\n", ret); + return; + } + NVT_LOG("firmware name :%s\n", firmware_name); + mutex_lock(&ts->lock); + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ +#if NVT_TOUCH_FW + ts->loading_fw = 1; +#endif + + nvt_sw_reset_idle(); + + ret = Check_CheckSum(); + + if (ret < 0) { // read firmware checksum failed + NVT_ERR("read firmware checksum failed\n"); + Update_Firmware(); + } else if ((ret == 0) && (Check_FW_Ver() == 0)) { // (fw checksum not match) && (bin fw version >= ic fw version) + NVT_LOG("firmware version not match\n"); + Update_Firmware(); + } else if (nvt_check_flash_end_flag()) { + NVT_LOG("check flash end flag failed\n"); + Update_Firmware(); + } else { + // Bootloader Reset + nvt_bootloader_reset(); + nvt_check_fw_reset_state(RESET_STATE_INIT); + } + +#if NVT_TOUCH_FW + ts->loading_fw = 0; +#endif + mutex_unlock(&ts->lock); + + update_firmware_release(); +} +#endif /* BOOT_UPDATE_FIRMWARE */ + +#if NVT_TOUCH_FW +static ssize_t nvt_poweron_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool val; + + mutex_lock(&ts->lock); + val = ts->suspended; + mutex_unlock(&ts->lock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + val == 0); +} + +static DEVICE_ATTR(poweron, 0444, nvt_poweron_show, NULL); + +static ssize_t nvt_ic_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "[FW]%02x,[IC]NT36525\n", + ts->fw_ver); +} + +static DEVICE_ATTR(ic_ver, 0444, nvt_ic_ver_show, NULL); + +static ssize_t nvt_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +/* Update script use as $touch_product_id in fw name ==> (chip id from Lenovo&script) OR (vendor name from Focaltech) OR (project ID from Longcheer&Himax) + Project ID ?? ( - Jeter - Hannah) + Chip ID ?? (NVT-ts or NVTCapacitiveTouchScreen or NT36xxx) */ + return scnprintf(buf, PAGE_SIZE, "%s\n", + ts->product_id); +} + +static DEVICE_ATTR(productinfo, 0444, nvt_productinfo_show, NULL); + +static ssize_t nvt_force_reflash_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + ts->force_reflash = (input == 0) ? false : true; + + return count; +} + +static DEVICE_ATTR(forcereflash, 0220, NULL, nvt_force_reflash_store); + +static ssize_t nvt_flashprog_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", + (ts->loading_fw) ? 1 : 0); +} + +static DEVICE_ATTR(flashprog, 0444, nvt_flashprog_show, NULL); + +static ssize_t nvt_do_reflash_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + char prefix[FW_NAME_MAX_LEN] = VENDOR_NAME; + char template[FW_NAME_MAX_LEN]; + char firmware_name[256] = ""; + + if (count > FW_NAME_MAX_LEN) { + NVT_ERR("FW filename is too long\n"); + retval = -EINVAL; + goto exit; + } + + if (ts->suspended) { + NVT_ERR("In suspend state, try again later\n"); + retval = -EINVAL; + goto exit; + } + + if (ts->loading_fw) { + NVT_ERR("In FW flashing state, try again later\n"); + retval = -EINVAL; + goto exit; + } + + if (!ts->force_reflash) { + if (strncmp(buf, prefix, + strnlen(prefix, sizeof(prefix)))) { + NVT_ERR("FW does not belong to Novatek\n"); + retval = -EINVAL; + goto exit; + } + + snprintf(template, sizeof(template), "-%s-", + ts->product_id); + if (!strnstr(buf + strnlen(prefix, sizeof(prefix)), template, + count)) { + NVT_ERR("FW does not belong to %s\n", ts->product_id); + retval = -EINVAL; + goto exit; + } + } + + strlcpy(firmware_name, buf, count); + NVT_LOG("FW filename: %s\n", firmware_name); + + retval = update_firmware_request(firmware_name); + if (retval) { + NVT_ERR("update_firmware_request failed. (%d)\n", retval); + goto exit; + } + + mutex_lock(&ts->lock); +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif + ts->loading_fw = 1; + nvt_sw_reset_idle(); + + retval = Check_CheckSum(); + + if (retval < 0) { + NVT_ERR("read firmware checksum failed\n"); + Update_Firmware(); + } else if ((retval == 0) && (Check_FW_Ver() == 0)) { + NVT_LOG("firmware version not match\n"); + Update_Firmware(); + } else if (nvt_check_flash_end_flag()) { + NVT_LOG("check flash end flag failed\n"); + Update_Firmware(); + } else { + /* Bootloader Reset */ + nvt_bootloader_reset(); + nvt_check_fw_reset_state(RESET_STATE_INIT); + } + + ts->loading_fw = 0; + mutex_unlock(&ts->lock); + + update_firmware_release(); + + retval = count; +exit: + return retval; +} + +static DEVICE_ATTR(doreflash, 0220, NULL, nvt_do_reflash_store); + +static ssize_t nvt_build_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +/* Update script use for comparing $str_cfg_id_latest in fw name */ + uint8_t tmp_buf[4] = {0}; + uint8_t fw_version = 0; + uint8_t date_Y = 0; + uint8_t date_M = 0; + uint8_t date_D = 0; + + tmp_buf[0] = 0xFF; + tmp_buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + tmp_buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, tmp_buf, 3); + + tmp_buf[0] = EVENT_MAP_FWINFO; + CTP_I2C_READ(ts->client, I2C_FW_Address, tmp_buf, 2); + fw_version = tmp_buf[1]; + + tmp_buf[0] = EVENT_MAP_FWDATE; + CTP_I2C_READ(ts->client, I2C_FW_Address, tmp_buf, 4); + date_Y = tmp_buf[1]; + date_M = tmp_buf[2]; + date_D = tmp_buf[3]; + + return scnprintf(buf, PAGE_SIZE, "%02x-%02d%02d%02d\n", + fw_version, date_Y, date_M, date_D); +} + +static DEVICE_ATTR(buildid, 0444, nvt_build_id_show, NULL); + + +#include +#include +#include + +/* Attribute: path (RO) */ +static ssize_t path_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t blen; + const char *path; + + path = kobject_get_path(&ts->client->dev.kobj, GFP_KERNEL); + blen = scnprintf(buf, PAGE_SIZE, "%s", path ? path : "na"); + kfree(path); + return blen; +} + +/* Attribute: vendor (RO) */ +static ssize_t vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, VENDOR_NAME); +} + +static struct device_attribute touchscreen_attributes[] = { + __ATTR_RO(path), + __ATTR_RO(vendor), + __ATTR_NULL +}; + +#define TSDEV_MINOR_BASE 128 +#define TSDEV_MINOR_MAX 32 + +/******************************************************* +Description: + Novatek touchscreen FW function class. file node + initial function. + +return: + Executive outcomes. 0---succeed. -1---failed. +*******************************************************/ +int32_t nvt_fw_class_init(bool create) +{ + struct device_attribute *attrs = touchscreen_attributes; + int i, error = 0; + static struct class *touchscreen_class; + static struct device *ts_class_dev; + static int minor; + + if (create) { + minor = input_get_new_minor(ts->client->addr, + 1, false); + if (minor < 0) + minor = input_get_new_minor(TSDEV_MINOR_BASE, + TSDEV_MINOR_MAX, true); + NVT_LOG("assigned minor %d\n", minor); + + touchscreen_class = class_create(THIS_MODULE, "touchscreen"); + if (IS_ERR(touchscreen_class)) { + error = PTR_ERR(touchscreen_class); + touchscreen_class = NULL; + return error; + } + + ts_class_dev = device_create(touchscreen_class, NULL, + MKDEV(INPUT_MAJOR, minor), + ts, NVT_I2C_NAME); + if (IS_ERR(ts_class_dev)) { + error = PTR_ERR(ts_class_dev); + ts_class_dev = NULL; + return error; + } + + for (i = 0; attrs[i].attr.name != NULL; ++i) { + error = device_create_file(ts_class_dev, &attrs[i]); + if (error) + break; + } + + if (error) + goto device_destroy; + else + NVT_LOG("create /sys/class/touchscreen/%s Succeeded!\n", NVT_I2C_NAME); + } else { + if (!touchscreen_class || !ts_class_dev) + return -ENODEV; + + for (i = 0; attrs[i].attr.name != NULL; ++i) + device_remove_file(ts_class_dev, &attrs[i]); + + device_unregister(ts_class_dev); + class_unregister(touchscreen_class); + } + + return 0; + +device_destroy: + for (--i; i >= 0; --i) + device_remove_file(ts_class_dev, &attrs[i]); + device_destroy(touchscreen_class, MKDEV(INPUT_MAJOR, minor)); + ts_class_dev = NULL; + class_unregister(touchscreen_class); + NVT_ERR("error creating touchscreen class\n"); + + return -ENODEV; +} + +int nvt_fw_sysfs_init(void) +{ + int ret; + struct i2c_client *client = ts->client; + + ret = nvt_fw_class_init(true); + if (ret != 0) { + NVT_ERR("fw class init failed. ret=%d\n", ret); + return ret; + } + + ret = device_create_file(&client->dev, &dev_attr_forcereflash); + if (ret) { + NVT_ERR("create_file dev_attr_forcereflash failed\n"); + return ret; + } + + ret = device_create_file(&client->dev, &dev_attr_flashprog); + if (ret) { + NVT_ERR("create_file dev_attr_flashprog failed\n"); + return ret; + } + ret = device_create_file(&client->dev, &dev_attr_doreflash); + if (ret) { + NVT_ERR("create_file dev_attr_doreflash failed\n"); + return ret; + } + + ret = device_create_file(&client->dev, &dev_attr_buildid); + if (ret) { + NVT_ERR("create_file dev_attr_buildid failed\n"); + return ret; + } + + ret = device_create_file(&client->dev, &dev_attr_productinfo); + if (ret) { + NVT_ERR("create_file dev_attr_productinfo failed\n"); + return ret; + } + + ret = device_create_file(&client->dev, &dev_attr_poweron); + if (ret) { + NVT_ERR("create_file dev_attr_poweron failed\n"); + return ret; + } + + ret = device_create_file(&client->dev, &dev_attr_ic_ver); + if (ret) { + NVT_ERR("create_file dev_attr_ic_ver failed\n"); + return ret; + } + + return 0; +} + +void nvt_fw_sysfs_deinit(void) +{ + struct i2c_client *client = ts->client; + device_remove_file(&client->dev, &dev_attr_forcereflash); + device_remove_file(&client->dev, &dev_attr_flashprog); + device_remove_file(&client->dev, &dev_attr_doreflash); + device_remove_file(&client->dev, &dev_attr_buildid); + device_remove_file(&client->dev, &dev_attr_productinfo); + device_remove_file(&client->dev, &dev_attr_poweron); + device_remove_file(&client->dev, &dev_attr_ic_ver); + nvt_fw_class_init(false); +} +#endif diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mem_map.h b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mem_map.h new file mode 100644 index 000000000000..90d62dd70a08 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mem_map.h @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 20544 $ + * $Date: 2017-12-20 11:08:15 +0800 (Wed, 20 Dec 2017) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + */ + +struct nvt_ts_mem_map { + uint32_t EVENT_BUF_ADDR; + uint32_t RAW_PIPE0_ADDR; + uint32_t RAW_PIPE0_Q_ADDR; + uint32_t RAW_PIPE1_ADDR; + uint32_t RAW_PIPE1_Q_ADDR; + uint32_t BASELINE_ADDR; + uint32_t BASELINE_Q_ADDR; + uint32_t BASELINE_BTN_ADDR; + uint32_t BASELINE_BTN_Q_ADDR; + uint32_t DIFF_PIPE0_ADDR; + uint32_t DIFF_PIPE0_Q_ADDR; + uint32_t DIFF_PIPE1_ADDR; + uint32_t DIFF_PIPE1_Q_ADDR; + uint32_t RAW_BTN_PIPE0_ADDR; + uint32_t RAW_BTN_PIPE0_Q_ADDR; + uint32_t RAW_BTN_PIPE1_ADDR; + uint32_t RAW_BTN_PIPE1_Q_ADDR; + uint32_t DIFF_BTN_PIPE0_ADDR; + uint32_t DIFF_BTN_PIPE0_Q_ADDR; + uint32_t DIFF_BTN_PIPE1_ADDR; + uint32_t DIFF_BTN_PIPE1_Q_ADDR; + uint32_t READ_FLASH_CHECKSUM_ADDR; + uint32_t RW_FLASH_DATA_ADDR; +}; + +static const struct nvt_ts_mem_map NT36672A_memory_map = { + .EVENT_BUF_ADDR = 0x21C00, + .RAW_PIPE0_ADDR = 0x20000, + .RAW_PIPE0_Q_ADDR = 0, + .RAW_PIPE1_ADDR = 0x23000, + .RAW_PIPE1_Q_ADDR = 0, + .BASELINE_ADDR = 0x20BFC, + .BASELINE_Q_ADDR = 0, + .BASELINE_BTN_ADDR = 0x23BFC, + .BASELINE_BTN_Q_ADDR = 0, + .DIFF_PIPE0_ADDR = 0x206DC, + .DIFF_PIPE0_Q_ADDR = 0, + .DIFF_PIPE1_ADDR = 0x236DC, + .DIFF_PIPE1_Q_ADDR = 0, + .RAW_BTN_PIPE0_ADDR = 0x20510, + .RAW_BTN_PIPE0_Q_ADDR = 0, + .RAW_BTN_PIPE1_ADDR = 0x23510, + .RAW_BTN_PIPE1_Q_ADDR = 0, + .DIFF_BTN_PIPE0_ADDR = 0x20BF0, + .DIFF_BTN_PIPE0_Q_ADDR = 0, + .DIFF_BTN_PIPE1_ADDR = 0x23BF0, + .DIFF_BTN_PIPE1_Q_ADDR = 0, + .READ_FLASH_CHECKSUM_ADDR = 0x24000, + .RW_FLASH_DATA_ADDR = 0x24002, +}; + +static const struct nvt_ts_mem_map NT36772_memory_map = { + .EVENT_BUF_ADDR = 0x11E00, + .RAW_PIPE0_ADDR = 0x10000, + .RAW_PIPE0_Q_ADDR = 0, + .RAW_PIPE1_ADDR = 0x12000, + .RAW_PIPE1_Q_ADDR = 0, + .BASELINE_ADDR = 0x10E70, + .BASELINE_Q_ADDR = 0, + .BASELINE_BTN_ADDR = 0x12E70, + .BASELINE_BTN_Q_ADDR = 0, + .DIFF_PIPE0_ADDR = 0x10830, + .DIFF_PIPE0_Q_ADDR = 0, + .DIFF_PIPE1_ADDR = 0x12830, + .DIFF_PIPE1_Q_ADDR = 0, + .RAW_BTN_PIPE0_ADDR = 0x10E60, + .RAW_BTN_PIPE0_Q_ADDR = 0, + .RAW_BTN_PIPE1_ADDR = 0x12E60, + .RAW_BTN_PIPE1_Q_ADDR = 0, + .DIFF_BTN_PIPE0_ADDR = 0x10E68, + .DIFF_BTN_PIPE0_Q_ADDR = 0, + .DIFF_BTN_PIPE1_ADDR = 0x12E68, + .DIFF_BTN_PIPE1_Q_ADDR = 0, + .READ_FLASH_CHECKSUM_ADDR = 0x14000, + .RW_FLASH_DATA_ADDR = 0x14002, +}; + +static const struct nvt_ts_mem_map NT36525_memory_map = { + .EVENT_BUF_ADDR = 0x11A00, + .RAW_PIPE0_ADDR = 0x10000, + .RAW_PIPE0_Q_ADDR = 0, + .RAW_PIPE1_ADDR = 0x12000, + .RAW_PIPE1_Q_ADDR = 0, + .BASELINE_ADDR = 0x10B08, + .BASELINE_Q_ADDR = 0, + .BASELINE_BTN_ADDR = 0x12B08, + .BASELINE_BTN_Q_ADDR = 0, + .DIFF_PIPE0_ADDR = 0x1064C, + .DIFF_PIPE0_Q_ADDR = 0, + .DIFF_PIPE1_ADDR = 0x1264C, + .DIFF_PIPE1_Q_ADDR = 0, + .RAW_BTN_PIPE0_ADDR = 0x10634, + .RAW_BTN_PIPE0_Q_ADDR = 0, + .RAW_BTN_PIPE1_ADDR = 0x12634, + .RAW_BTN_PIPE1_Q_ADDR = 0, + .DIFF_BTN_PIPE0_ADDR = 0x10AFC, + .DIFF_BTN_PIPE0_Q_ADDR = 0, + .DIFF_BTN_PIPE1_ADDR = 0x12AFC, + .DIFF_BTN_PIPE1_Q_ADDR = 0, + .READ_FLASH_CHECKSUM_ADDR = 0x14000, + .RW_FLASH_DATA_ADDR = 0x14002, +}; + +static const struct nvt_ts_mem_map NT36870_memory_map = { + .EVENT_BUF_ADDR = 0x25000, + .RAW_PIPE0_ADDR = 0x20000, + .RAW_PIPE0_Q_ADDR = 0x204C8, + .RAW_PIPE1_ADDR = 0x23000, + .RAW_PIPE1_Q_ADDR = 0x234C8, + .BASELINE_ADDR = 0x21350, + .BASELINE_Q_ADDR = 0x21818, + .BASELINE_BTN_ADDR = 0x24350, + .BASELINE_BTN_Q_ADDR = 0x24358, + .DIFF_PIPE0_ADDR = 0x209B0, + .DIFF_PIPE0_Q_ADDR = 0x20E78, + .DIFF_PIPE1_ADDR = 0x239B0, + .DIFF_PIPE1_Q_ADDR = 0x23E78, + .RAW_BTN_PIPE0_ADDR = 0x20990, + .RAW_BTN_PIPE0_Q_ADDR = 0x20998, + .RAW_BTN_PIPE1_ADDR = 0x23990, + .RAW_BTN_PIPE1_Q_ADDR = 0x23998, + .DIFF_BTN_PIPE0_ADDR = 0x21340, + .DIFF_BTN_PIPE0_Q_ADDR = 0x21348, + .DIFF_BTN_PIPE1_ADDR = 0x24340, + .DIFF_BTN_PIPE1_Q_ADDR = 0x24348, + .READ_FLASH_CHECKSUM_ADDR = 0x24000, + .RW_FLASH_DATA_ADDR = 0x24002, +}; + +static const struct nvt_ts_mem_map NT36676F_memory_map = { + .EVENT_BUF_ADDR = 0x11A00, + .RAW_PIPE0_ADDR = 0x10000, + .RAW_PIPE0_Q_ADDR = 0, + .RAW_PIPE1_ADDR = 0x12000, + .RAW_PIPE1_Q_ADDR = 0, + .BASELINE_ADDR = 0x10B08, + .BASELINE_Q_ADDR = 0, + .BASELINE_BTN_ADDR = 0x12B08, + .BASELINE_BTN_Q_ADDR = 0, + .DIFF_PIPE0_ADDR = 0x1064C, + .DIFF_PIPE0_Q_ADDR = 0, + .DIFF_PIPE1_ADDR = 0x1264C, + .DIFF_PIPE1_Q_ADDR = 0, + .RAW_BTN_PIPE0_ADDR = 0x10634, + .RAW_BTN_PIPE0_Q_ADDR = 0, + .RAW_BTN_PIPE1_ADDR = 0x12634, + .RAW_BTN_PIPE1_Q_ADDR = 0, + .DIFF_BTN_PIPE0_ADDR = 0x10AFC, + .DIFF_BTN_PIPE0_Q_ADDR = 0, + .DIFF_BTN_PIPE1_ADDR = 0x12AFC, + .DIFF_BTN_PIPE1_Q_ADDR = 0, + .READ_FLASH_CHECKSUM_ADDR = 0x14000, + .RW_FLASH_DATA_ADDR = 0x14002, +}; + +#define NVT_ID_BYTE_MAX 6 +struct nvt_ts_trim_id_table { + uint8_t id[NVT_ID_BYTE_MAX]; + uint8_t mask[NVT_ID_BYTE_MAX]; + const struct nvt_ts_mem_map *mmap; + uint8_t carrier_system; +}; + +static const struct nvt_ts_trim_id_table trim_id_table[] = { + {.id = {0x0A, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1}, + .mmap = &NT36672A_memory_map, .carrier_system = 0}, + {.id = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0x55, 0x72, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xAA, 0x00, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xAA, 0x72, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xFF, 0xFF, 0xFF, 0x72, 0x67, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xFF, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xFF, 0xFF, 0xFF, 0x70, 0x67, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xFF, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36772_memory_map, .carrier_system = 0}, + {.id = {0xFF, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36525_memory_map, .carrier_system = 0}, + {.id = {0xFF, 0xFF, 0xFF, 0x70, 0x68, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36870_memory_map, .carrier_system = 1}, + {.id = {0xFF, 0xFF, 0xFF, 0x76, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1}, + .mmap = &NT36676F_memory_map, .carrier_system = 0} +}; diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.c b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.c new file mode 100644 index 000000000000..0c05b865c783 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.c @@ -0,0 +1,1901 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 21288 $ + * $Date: 2018-01-05 11:38:47 +0800 (Fri, 05 Jan 2018) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include + +#include "nt36xxx.h" +#include "nt36xxx_mp_ctrlram.h" + +#if NVT_TOUCH_MP + +#define NORMAL_MODE 0x00 +#define TEST_MODE_1 0x21 +#define TEST_MODE_2 0x22 +#define MP_MODE_CC 0x41 +#define FREQ_HOP_DISABLE 0x66 +#define FREQ_HOP_ENABLE 0x65 + +#define SHORT_TEST_CSV_FILE "/data/local/tmp/ShortTest.csv" +#define OPEN_TEST_CSV_FILE "/data/local/tmp/OpenTest.csv" +#define FW_RAWDATA_CSV_FILE "/data/local/tmp/FWMutualTest.csv" +#define FW_CC_CSV_FILE "/data/local/tmp/FWCCTest.csv" +#define NOISE_TEST_CSV_FILE "/data/local/tmp/NoiseTest.csv" + +#define nvt_mp_seq_printf(m, fmt, args...) do { \ + seq_printf(m, fmt, ##args); \ + if (!nvt_mp_test_result_printed) \ + printk(fmt, ##args); \ +} while (0) + +static uint8_t *RecordResult_Short; +static uint8_t *RecordResult_Short_Diff; +static uint8_t *RecordResult_Short_Base; +static uint8_t *RecordResult_Open; +static uint8_t *RecordResult_FWMutual; +static uint8_t *RecordResult_FW_CC; +static uint8_t *RecordResult_FW_CC_I; +static uint8_t *RecordResult_FW_CC_Q; +static uint8_t *RecordResult_FW_DiffMax; +static uint8_t *RecordResult_FW_DiffMin; + +static int32_t TestResult_Short; +static int32_t TestResult_Short_Diff; +static int32_t TestResult_Short_Base; +static int32_t TestResult_Open; +static int32_t TestResult_FW_Rawdata; +static int32_t TestResult_FWMutual; +static int32_t TestResult_FW_CC; +static int32_t TestResult_FW_CC_I; +static int32_t TestResult_FW_CC_Q; +static int32_t TestResult_Noise; +static int32_t TestResult_FW_DiffMax; +static int32_t TestResult_FW_DiffMin; + +static int32_t *RawData_Short; +static int32_t *RawData_Short_Diff; +static int32_t *RawData_Short_Base; +static int32_t *RawData_Open; +static int32_t *RawData_Diff; +static int32_t *RawData_Diff_Min; +static int32_t *RawData_Diff_Max; +static int32_t *RawData_FWMutual; +static int32_t *RawData_FW_CC; +static int32_t *RawData_FW_CC_I; +static int32_t *RawData_FW_CC_Q; + +static struct proc_dir_entry *NVT_proc_selftest_entry; +#if NVT_TOUCH_MP_LENOVO +static struct proc_dir_entry *NVT_proc_selftest_read_data; +#endif +static int8_t nvt_mp_test_result_printed; + +extern void nvt_change_mode(uint8_t mode); +extern uint8_t nvt_get_fw_pipe(void); +extern void nvt_read_mdata(uint32_t xdata_addr, uint32_t xdata_btn_addr); +extern void nvt_get_mdata(int32_t *buf, uint8_t *m_x_num, uint8_t *m_y_num); +void nvt_mp_parse_dt(struct device_node *root, const char *node_compatible); +extern int32_t nvt_read_mass_data(uint32_t xdata_addr, uint8_t *temp_buf, uint32_t len); + +/******************************************************* +Description: + Novatek touchscreen allocate buffer for mp selftest. + +return: + Executive outcomes. 0---succeed. -12---Out of memory +*******************************************************/ +static int nvt_mp_buffer_init(void) +{ + size_t RecordResult_BufSize = IC_X_CFG_SIZE * IC_Y_CFG_SIZE + IC_KEY_CFG_SIZE; + size_t RawData_BufSize = (IC_X_CFG_SIZE * IC_Y_CFG_SIZE + IC_KEY_CFG_SIZE) * sizeof(int32_t); + + RecordResult_Short = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_Short) { + NVT_ERR("kzalloc for RecordResult_Short failed!\n"); + return -ENOMEM; + } + + RecordResult_Short_Diff = RecordResult_Short; + + RecordResult_Short_Base = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_Short_Base) { + NVT_ERR("kzalloc for RecordResult_Short_Base failed!\n"); + return -ENOMEM; + } + + RecordResult_Open = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_Open) { + NVT_ERR("kzalloc for RecordResult_Open failed!\n"); + return -ENOMEM; + } + + RecordResult_FWMutual = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_FWMutual) { + NVT_ERR("kzalloc for RecordResult_FWMutual failed!\n"); + return -ENOMEM; + } + + RecordResult_FW_CC = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_FW_CC) { + NVT_ERR("kzalloc for RecordResult_FW_CC failed!\n"); + return -ENOMEM; + } + + RecordResult_FW_CC_I = RecordResult_FW_CC; + + RecordResult_FW_CC_Q = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_FW_CC_Q) { + NVT_ERR("kzalloc for RecordResult_FW_CC_Q failed!\n"); + return -ENOMEM; + } + + RecordResult_FW_DiffMax = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_FW_DiffMax) { + NVT_ERR("kzalloc for RecordResult_FW_DiffMax failed!\n"); + return -ENOMEM; + } + + RecordResult_FW_DiffMin = (uint8_t *)kzalloc(RecordResult_BufSize, GFP_KERNEL); + if (!RecordResult_FW_DiffMin) { + NVT_ERR("kzalloc for RecordResult_FW_DiffMin failed!\n"); + return -ENOMEM; + } + + RawData_Short = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_Short) { + NVT_ERR("kzalloc for RawData_Short failed!\n"); + return -ENOMEM; + } + + RawData_Short_Diff = RawData_Short; + + RawData_Short_Base = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_Short_Base) { + NVT_ERR("kzalloc for RawData_Short_Base failed!\n"); + return -ENOMEM; + } + + RawData_Open = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_Open) { + NVT_ERR("kzalloc for RawData_Open failed!\n"); + return -ENOMEM; + } + + RawData_Diff = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_Diff) { + NVT_ERR("kzalloc for RawData_Diff failed!\n"); + return -ENOMEM; + } + + RawData_Diff_Min = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_Diff_Min) { + NVT_ERR("kzalloc for RawData_Diff_Min failed!\n"); + return -ENOMEM; + } + + RawData_Diff_Max = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_Diff_Max) { + NVT_ERR("kzalloc for RawData_Diff_Max failed!\n"); + return -ENOMEM; + } + + RawData_FWMutual = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_FWMutual) { + NVT_ERR("kzalloc for RawData_FWMutual failed!\n"); + return -ENOMEM; + } + + RawData_FW_CC = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_FW_CC) { + NVT_ERR("kzalloc for RawData_FW_CC failed!\n"); + return -ENOMEM; + } + + RawData_FW_CC_I = RawData_FW_CC; + + RawData_FW_CC_Q = (int32_t *)kzalloc(RawData_BufSize, GFP_KERNEL); + if (!RawData_FW_CC_Q) { + NVT_ERR("kzalloc for RawData_FW_CC_Q failed!\n"); + return -ENOMEM; + } + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen self-test criteria print function. + +return: + n.a. +*******************************************************/ +static void nvt_print_lmt_array(int32_t *array, int32_t x_ch, int32_t y_ch) +{ + int32_t i = 0; + int32_t j = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + + for (j = 0; j < y_ch; j++) { + for (i = 0; i < x_ch; i++) { + printk("%5d, ", array[j * x_ch + i]); + } + printk("\n"); + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + printk("%5d, ", array[y_ch * x_ch + k]); + } + printk("\n"); +#endif /* #if TOUCH_KEY_NUM > 0 */ +} + +static void nvt_print_criteria(void) +{ + NVT_LOG("++\n"); + + if (ts->carrier_system) { + //---PS_Config_Lmt_Short_Diff--- + printk("PS_Config_Lmt_Short_Diff_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Short_Diff_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_Short_Diff_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Short_Diff_N, X_Channel, Y_Channel); + //---PS_Config_Lmt_Short_Base--- + printk("PS_Config_Lmt_Short_Base_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Short_Base_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_Short_Base_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Short_Base_N, X_Channel, Y_Channel); + } else { + //---PS_Config_Lmt_Short_Rawdata--- + printk("PS_Config_Lmt_Short_Rawdata_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Short_Rawdata_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_Short_Rawdata_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Short_Rawdata_N, X_Channel, Y_Channel); + } + + //---PS_Config_Lmt_Open_Rawdata--- + printk("PS_Config_Lmt_Open_Rawdata_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Open_Rawdata_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_Open_Rawdata_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_Open_Rawdata_N, X_Channel, Y_Channel); + + //---PS_Config_Lmt_FW_Rawdata--- + printk("PS_Config_Lmt_FW_Rawdata_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_Rawdata_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_FW_Rawdata_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_Rawdata_N, X_Channel, Y_Channel); + + if (ts->carrier_system) { + //---PS_Config_Lmt_FW_CC_I--- + printk("PS_Config_Lmt_FW_CC_I_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_CC_I_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_FW_CC_I_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_CC_I_N, X_Channel, Y_Channel); + //---PS_Config_Lmt_FW_CC_Q--- + printk("PS_Config_Lmt_FW_CC_Q_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_CC_Q_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_FW_CC_Q_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_CC_Q_N, X_Channel, Y_Channel); + } else { + //---PS_Config_Lmt_FW_CC--- + printk("PS_Config_Lmt_FW_CC_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_CC_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_FW_CC_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_CC_N, X_Channel, Y_Channel); + } + + //---PS_Config_Lmt_FW_Diff--- + printk("PS_Config_Lmt_FW_Diff_P:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_Diff_P, X_Channel, Y_Channel); + printk("PS_Config_Lmt_FW_Diff_N:\n"); + nvt_print_lmt_array(PS_Config_Lmt_FW_Diff_N, X_Channel, Y_Channel); + + NVT_LOG("--\n"); +} + +static int32_t nvt_save_rawdata_to_csv(int32_t *rawdata, uint8_t x_ch, uint8_t y_ch, const char *file_path, uint32_t offset) +{ + int32_t x = 0; + int32_t y = 0; + int32_t iArrayIndex = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + + printk("%s:++%s\n", __func__, file_path); + + for (y = 0; y < y_ch; y++) { + for (x = 0; x < x_ch; x++) { + iArrayIndex = y * x_ch + x; + printk("%5d, ", rawdata[iArrayIndex]); + } + printk("\n"); + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = y_ch * x_ch + k; + printk("%5d, ", rawdata[iArrayIndex]); + } + printk("\n"); +#endif /* #if TOUCH_KEY_NUM > 0 */ + printk("%s:--\n", __func__); + return 0; +} + +static int32_t nvt_polling_hand_shake_status(void) +{ + uint8_t buf[8] = {0}; + int32_t i = 0; + const int32_t retry = 50; + + for (i = 0; i < retry; i++) { + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---read fw status--- + buf[0] = EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE; + buf[1] = 0x00; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 2); + + if ((buf[1] == 0xA0) || (buf[1] == 0xA1)) + break; + + msleep(10); + } + + if (i >= retry) { + NVT_ERR("polling hand shake status failed, buf[1]=0x%02X\n", buf[1]); + + // Read back 5 bytes from offset EVENT_MAP_HOST_CMD for debug check + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0x00; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 6); + NVT_ERR("Read back 5 bytes from offset EVENT_MAP_HOST_CMD: 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", buf[1], buf[2], buf[3], buf[4], buf[5]); + + return -EPERM; + } else { + return 0; + } +} + +static int8_t nvt_switch_FreqHopEnDis(uint8_t FreqHopEnDis) +{ + uint8_t buf[8] = {0}; + uint8_t retry = 0; + int8_t ret = 0; + + NVT_LOG("++\n"); + + for (retry = 0; retry < 20; retry++) { + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---switch FreqHopEnDis--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = FreqHopEnDis; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 2); + + msleep(35); + + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0xFF; + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, 2); + + if (buf[1] == 0x00) + break; + } + + if (unlikely(retry == 20)) { + NVT_ERR("switch FreqHopEnDis 0x%02X failed, buf[1]=0x%02X\n", FreqHopEnDis, buf[1]); + ret = -1; + } + + NVT_LOG("--\n"); + + return ret; +} + +static int32_t nvt_read_baseline(int32_t *xdata) +{ + uint8_t x_num = 0; + uint8_t y_num = 0; + uint32_t x = 0; + uint32_t y = 0; + int32_t iArrayIndex = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + + NVT_LOG("++\n"); + + nvt_read_mdata(ts->mmap->BASELINE_ADDR, ts->mmap->BASELINE_BTN_ADDR); + + nvt_get_mdata(xdata, &x_num, &y_num); + + for (y = 0; y < y_num; y++) { + for (x = 0; x < x_num; x++) { + iArrayIndex = y * x_num + x; + if (ts->carrier_system) { + xdata[iArrayIndex] = (uint16_t)xdata[iArrayIndex]; + } else { + xdata[iArrayIndex] = (int16_t)xdata[iArrayIndex]; + } + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = Y_Channel * X_Channel + k; + if (ts->carrier_system) { + xdata[iArrayIndex] = (uint16_t)xdata[iArrayIndex]; + } else { + xdata[iArrayIndex] = (int16_t)xdata[iArrayIndex]; + } + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + printk("%s:\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(xdata, X_Channel, Y_Channel, FW_RAWDATA_CSV_FILE, 0) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + + NVT_LOG("--\n"); + + return 0; +} + +static int32_t nvt_read_CC(int32_t *xdata) +{ + uint8_t x_num = 0; + uint8_t y_num = 0; + uint32_t x = 0; + uint32_t y = 0; + int32_t iArrayIndex = 0; + int32_t xdata_tmp = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + uint32_t rawdata_cc_q_offset = 0; + + NVT_LOG("++\n"); + + if (nvt_get_fw_pipe() == 0) + nvt_read_mdata(ts->mmap->DIFF_PIPE1_ADDR, ts->mmap->DIFF_BTN_PIPE1_ADDR); + else + nvt_read_mdata(ts->mmap->DIFF_PIPE0_ADDR, ts->mmap->DIFF_BTN_PIPE0_ADDR); + + nvt_get_mdata(xdata, &x_num, &y_num); + + for (y = 0; y < y_num; y++) { + for (x = 0; x < x_num; x++) { + iArrayIndex = y * x_num + x; + if (ts->carrier_system) { + xdata_tmp = xdata[iArrayIndex]; + RawData_FW_CC_I[iArrayIndex] = (uint8_t)(xdata_tmp & 0xFF); + RawData_FW_CC_Q[iArrayIndex] = (uint8_t)((xdata_tmp >> 8) & 0xFF); + } else { + xdata[iArrayIndex] = (int16_t)xdata[iArrayIndex]; + } + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = Y_Channel * X_Channel + k; + if (ts->carrier_system) { + xdata_tmp = xdata[iArrayIndex]; + RawData_FW_CC_I[iArrayIndex] = (uint8_t)(xdata_tmp & 0xFF); + RawData_FW_CC_Q[iArrayIndex] = (uint8_t)((xdata_tmp >> 8) & 0xFF); + } else { + xdata[iArrayIndex] = (int16_t)xdata[iArrayIndex]; + } + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + printk("%s:\n", __func__); + if (ts->carrier_system) { + printk("%s:RawData_CC_I:\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(RawData_FW_CC_I, X_Channel, Y_Channel, FW_CC_CSV_FILE, 0) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } +#if TOUCH_KEY_NUM > 0 + rawdata_cc_q_offset = Y_Channel * X_Channel * 7 + Y_Channel * 2 + Key_Channel * 7 + 2; +#else + rawdata_cc_q_offset = Y_Channel * X_Channel * 7 + Y_Channel * 2; +#endif /* #if TOUCH_KEY_NUM > 0 */ + printk("%s:RawData_CC_Q:\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(RawData_FW_CC_Q, X_Channel, Y_Channel, FW_CC_CSV_FILE, rawdata_cc_q_offset) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + } else { + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(xdata, X_Channel, Y_Channel, FW_CC_CSV_FILE, 0) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + } + + NVT_LOG("--\n"); + + return 0; +} + +static void nvt_enable_noise_collect(int32_t frame_num) +{ + uint8_t buf[8] = {0}; + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---enable noise collect--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0x47; + buf[2] = 0xAA; + buf[3] = frame_num; + buf[4] = 0x00; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 5); +} + +static int32_t nvt_read_fw_noise(int32_t *xdata) +{ + uint8_t x_num = 0; + uint8_t y_num = 0; + uint32_t x = 0; + uint32_t y = 0; + int32_t iArrayIndex = 0; + int32_t frame_num = 0; + uint32_t rawdata_diff_min_offset = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + + NVT_LOG("++\n"); + + //---Enter Test Mode--- + if (nvt_clear_fw_status()) { + return -EAGAIN; + } + + frame_num = PS_Config_Diff_Test_Frame / 10; + if (frame_num <= 0) + frame_num = 1; + printk("%s: frame_num=%d\n", __func__, frame_num); + nvt_enable_noise_collect(frame_num); + // need wait PS_Config_Diff_Test_Frame * 8.3ms + msleep(frame_num * 83); + + if (nvt_polling_hand_shake_status()) { + return -EAGAIN; + } + + if (nvt_get_fw_info()) { + return -EAGAIN; + } + + if (nvt_get_fw_pipe() == 0) + nvt_read_mdata(ts->mmap->DIFF_PIPE0_ADDR, ts->mmap->DIFF_BTN_PIPE0_ADDR); + else + nvt_read_mdata(ts->mmap->DIFF_PIPE1_ADDR, ts->mmap->DIFF_BTN_PIPE1_ADDR); + + nvt_get_mdata(xdata, &x_num, &y_num); + + for (y = 0; y < y_num; y++) { + for (x = 0; x < x_num; x++) { + iArrayIndex = y * x_num + x; + if (ts->carrier_system) { + RawData_Diff_Max[iArrayIndex] = (uint16_t)xdata[iArrayIndex]; + RawData_Diff_Min[iArrayIndex] = 0; + } else { + RawData_Diff_Max[iArrayIndex] = (int8_t)((xdata[iArrayIndex] >> 8) & 0xFF); + RawData_Diff_Min[iArrayIndex] = (int8_t)(xdata[iArrayIndex] & 0xFF); + } + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = Y_Channel * X_Channel + k; + if (ts->carrier_system) { + RawData_Diff_Max[iArrayIndex] = (uint16_t)xdata[iArrayIndex]; + RawData_Diff_Min[iArrayIndex] = 0; + } else { + RawData_Diff_Max[iArrayIndex] = (int8_t)((xdata[iArrayIndex] >> 8) & 0xFF); + RawData_Diff_Min[iArrayIndex] = (int8_t)(xdata[iArrayIndex] & 0xFF); + } + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + //---Leave Test Mode--- + nvt_change_mode(NORMAL_MODE); + + printk("%s:RawData_Diff_Max:\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(RawData_Diff_Max, X_Channel, Y_Channel, NOISE_TEST_CSV_FILE, 0) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + + if (!ts->carrier_system) { +#if TOUCH_KEY_NUM > 0 + rawdata_diff_min_offset = Y_Channel * X_Channel * 7 + Y_Channel * 2 + Key_Channel * 7 + 2; +#else + rawdata_diff_min_offset = Y_Channel * X_Channel * 7 + Y_Channel * 2; +#endif /* #if TOUCH_KEY_NUM > 0 */ + printk("%s:RawData_Diff_Min:\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(RawData_Diff_Min, X_Channel, Y_Channel, NOISE_TEST_CSV_FILE, rawdata_diff_min_offset) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + } + + NVT_LOG("--\n"); + + return 0; +} + +static void nvt_enable_open_test(void) +{ + uint8_t buf[8] = {0}; + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---enable open test--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0x45; + buf[2] = 0xAA; + buf[3] = 0x02; + buf[4] = 0x00; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 5); +} + +static void nvt_enable_short_test(void) +{ + uint8_t buf[8] = {0}; + + //---set xdata index to EVENT BUF ADDR--- + buf[0] = 0xFF; + buf[1] = (ts->mmap->EVENT_BUF_ADDR >> 16) & 0xFF; + buf[2] = (ts->mmap->EVENT_BUF_ADDR >> 8) & 0xFF; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + + //---enable short test--- + buf[0] = EVENT_MAP_HOST_CMD; + buf[1] = 0x43; + buf[2] = 0xAA; + buf[3] = 0x02; + buf[4] = 0x00; + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 5); +} + +static int32_t nvt_read_fw_open(int32_t *xdata) +{ + uint32_t raw_pipe_addr = 0; + uint8_t *rawdata_buf = NULL; + uint32_t x = 0; + uint32_t y = 0; + uint8_t buf[128] = {0}; +#if TOUCH_KEY_NUM > 0 + uint32_t raw_btn_pipe_addr = 0; + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + + NVT_LOG("++\n"); + + //---Enter Test Mode--- + if (nvt_clear_fw_status()) { + return -EAGAIN; + } + + nvt_enable_open_test(); + + if (nvt_polling_hand_shake_status()) { + return -EAGAIN; + } + +#if TOUCH_KEY_NUM > 0 + rawdata_buf = (uint8_t *)kzalloc((IC_X_CFG_SIZE * IC_Y_CFG_SIZE + IC_KEY_CFG_SIZE) * 2, GFP_KERNEL); +#else + rawdata_buf = (uint8_t *)kzalloc(IC_X_CFG_SIZE * IC_Y_CFG_SIZE * 2, GFP_KERNEL); +#endif /* #if TOUCH_KEY_NUM > 0 */ + if (!rawdata_buf) { + NVT_ERR("kzalloc for rawdata_buf failed!\n"); + return -ENOMEM; + } + + if (nvt_get_fw_pipe() == 0) + raw_pipe_addr = ts->mmap->RAW_PIPE0_ADDR; + else + raw_pipe_addr = ts->mmap->RAW_PIPE1_ADDR; + + for (y = 0; y < IC_Y_CFG_SIZE; y++) { + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (uint8_t)(((raw_pipe_addr + y * IC_X_CFG_SIZE * 2) >> 16) & 0xFF); + buf[2] = (uint8_t)(((raw_pipe_addr + y * IC_X_CFG_SIZE * 2) >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + buf[0] = (uint8_t)((raw_pipe_addr + y * IC_X_CFG_SIZE * 2) & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, IC_X_CFG_SIZE * 2 + 1); + memcpy(rawdata_buf + y * IC_X_CFG_SIZE * 2, buf + 1, IC_X_CFG_SIZE * 2); + } +#if TOUCH_KEY_NUM > 0 + if (nvt_get_fw_pipe() == 0) + raw_btn_pipe_addr = ts->mmap->RAW_BTN_PIPE0_ADDR; + else + raw_btn_pipe_addr = ts->mmap->RAW_BTN_PIPE1_ADDR; + + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (uint8_t)((raw_btn_pipe_addr >> 16) & 0xFF); + buf[2] = (uint8_t)((raw_btn_pipe_addr >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + buf[0] = (uint8_t)(raw_btn_pipe_addr & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, IC_KEY_CFG_SIZE * 2 + 1); + memcpy(rawdata_buf + IC_Y_CFG_SIZE * IC_X_CFG_SIZE * 2, buf + 1, IC_KEY_CFG_SIZE * 2); +#endif /* #if TOUCH_KEY_NUM > 0 */ + + for (y = 0; y < IC_Y_CFG_SIZE; y++) { + for (x = 0; x < IC_X_CFG_SIZE; x++) { + if ((AIN_Y[y] != 0xFF) && (AIN_X[x] != 0xFF)) { + xdata[AIN_Y[y] * X_Channel + AIN_X[x]] = (int16_t)((rawdata_buf[(y * IC_X_CFG_SIZE + x) * 2] + 256 * rawdata_buf[(y * IC_X_CFG_SIZE + x) * 2 + 1])); + } + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < IC_KEY_CFG_SIZE; k++) { + if (AIN_KEY[k] != 0xFF) + xdata[Y_Channel * X_Channel + AIN_KEY[k]] = (int16_t)(rawdata_buf[(IC_Y_CFG_SIZE * IC_X_CFG_SIZE + k) * 2] + 256 * rawdata_buf[(IC_Y_CFG_SIZE * IC_X_CFG_SIZE + k) * 2 + 1]); + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + if (rawdata_buf) { + kfree(rawdata_buf); + rawdata_buf = NULL; + } + + //---Leave Test Mode--- + nvt_change_mode(NORMAL_MODE); + + + printk("%s:RawData_Open\n", __func__); + // Save RawData to CSV file + if (nvt_save_rawdata_to_csv(xdata, X_Channel, Y_Channel, OPEN_TEST_CSV_FILE, 0) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + + NVT_LOG("--\n"); + + return 0; +} + +static int32_t nvt_read_fw_short(int32_t *xdata) +{ + uint32_t raw_pipe_addr = 0; + uint8_t *rawdata_buf = NULL; + uint32_t x = 0; + uint32_t y = 0; + uint8_t buf[128] = {0}; + int32_t iArrayIndex = 0; +#if TOUCH_KEY_NUM > 0 + uint32_t raw_btn_pipe_addr = 0; + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + uint32_t rawdata_short_base_offset = 0; + + NVT_LOG("++\n"); + + //---Enter Test Mode--- + if (nvt_clear_fw_status()) { + return -EAGAIN; + } + + nvt_enable_short_test(); + + if (nvt_polling_hand_shake_status()) { + return -EAGAIN; + } + +#if TOUCH_KEY_NUM > 0 + rawdata_buf = (uint8_t *)kzalloc((X_Channel * Y_Channel + Key_Channel) * 2, GFP_KERNEL); +#else + rawdata_buf = (uint8_t *)kzalloc(X_Channel * Y_Channel * 2, GFP_KERNEL); +#endif /* #if TOUCH_KEY_NUM > 0 */ + if (!rawdata_buf) { + NVT_ERR("kzalloc for rawdata_buf failed!\n"); + return -ENOMEM; + } + + if (ts->carrier_system) { + // to get short diff rawdata at pipe0 + raw_pipe_addr = ts->mmap->RAW_PIPE0_ADDR; + } else { + if (nvt_get_fw_pipe() == 0) + raw_pipe_addr = ts->mmap->RAW_PIPE0_ADDR; + else + raw_pipe_addr = ts->mmap->RAW_PIPE1_ADDR; + } + + for (y = 0; y < Y_Channel; y++) { + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (uint8_t)(((raw_pipe_addr + y * X_Channel * 2) >> 16) & 0xFF); + buf[2] = (uint8_t)(((raw_pipe_addr + y * X_Channel * 2) >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + buf[0] = (uint8_t)((raw_pipe_addr + y * X_Channel * 2) & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, X_Channel * 2 + 1); + memcpy(rawdata_buf + y * X_Channel * 2, buf + 1, X_Channel * 2); + } +#if TOUCH_KEY_NUM > 0 + if (ts->carrier_system) { + // to get button short diff rawdata at pipe0 + raw_btn_pipe_addr = ts->mmap->RAW_BTN_PIPE0_ADDR; + } else { + if (nvt_get_fw_pipe() == 0) + raw_btn_pipe_addr = ts->mmap->RAW_BTN_PIPE0_ADDR; + else + raw_btn_pipe_addr = ts->mmap->RAW_BTN_PIPE1_ADDR; + } + + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (uint8_t)((raw_btn_pipe_addr >> 16) & 0xFF); + buf[2] = (uint8_t)((raw_btn_pipe_addr >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + buf[0] = (uint8_t)(raw_btn_pipe_addr & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, Key_Channel * 2 + 1); + memcpy(rawdata_buf + Y_Channel * X_Channel * 2, buf + 1, Key_Channel * 2); +#endif /* #if TOUCH_KEY_NUM > 0 */ + + for (y = 0; y < Y_Channel; y++) { + for (x = 0; x < X_Channel; x++) { + iArrayIndex = y * X_Channel + x; + xdata[iArrayIndex] = (int16_t)(rawdata_buf[iArrayIndex * 2] + 256 * rawdata_buf[iArrayIndex * 2 + 1]); + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = Y_Channel * X_Channel + k; + xdata[iArrayIndex] = (int16_t)(rawdata_buf[iArrayIndex * 2] + 256 * rawdata_buf[iArrayIndex * 2 + 1]); + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + // for carrier sensing system to get short baseline rawdata + if (ts->carrier_system) { + // to get short baseline rawdata at pipe1 + raw_pipe_addr = ts->mmap->RAW_PIPE1_ADDR; + + for (y = 0; y < Y_Channel; y++) { + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (uint8_t)(((raw_pipe_addr + y * X_Channel * 2) >> 16) & 0xFF); + buf[2] = (uint8_t)(((raw_pipe_addr + y * X_Channel * 2) >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + buf[0] = (uint8_t)((raw_pipe_addr + y * X_Channel * 2) & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, X_Channel * 2 + 1); + memcpy(rawdata_buf + y * X_Channel * 2, buf + 1, X_Channel * 2); + } +#if TOUCH_KEY_NUM > 0 + // to get button short baseline rawdata at pipe1 + raw_btn_pipe_addr = ts->mmap->RAW_BTN_PIPE1_ADDR; + + //---change xdata index--- + buf[0] = 0xFF; + buf[1] = (uint8_t)((raw_btn_pipe_addr >> 16) & 0xFF); + buf[2] = (uint8_t)((raw_btn_pipe_addr >> 8) & 0xFF); + CTP_I2C_WRITE(ts->client, I2C_FW_Address, buf, 3); + buf[0] = (uint8_t)(raw_btn_pipe_addr & 0xFF); + CTP_I2C_READ(ts->client, I2C_FW_Address, buf, Key_Channel * 2 + 1); + memcpy(rawdata_buf + Y_Channel * X_Channel * 2, buf + 1, Key_Channel * 2); +#endif /* #if TOUCH_KEY_NUM > 0 */ + + for (y = 0; y < Y_Channel; y++) { + for (x = 0; x < X_Channel; x++) { + iArrayIndex = y * X_Channel + x; + RawData_Short_Base[iArrayIndex] = (int16_t)(rawdata_buf[iArrayIndex * 2] + 256 * rawdata_buf[iArrayIndex * 2 + 1]); + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = Y_Channel * X_Channel + k; + RawData_Short_Base[iArrayIndex] = (int16_t)(rawdata_buf[iArrayIndex * 2] + 256 * rawdata_buf[iArrayIndex * 2 + 1]); + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + } + + if (rawdata_buf) { + kfree(rawdata_buf); + rawdata_buf = NULL; + } + + //---Leave Test Mode--- + nvt_change_mode(NORMAL_MODE); + + if (ts->carrier_system) + printk("%s:RawData_Short_Diff:\n", __func__); + else + printk("%s:RawData_Short\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(xdata, X_Channel, Y_Channel, SHORT_TEST_CSV_FILE, 0) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + if (ts->carrier_system) { +#if TOUCH_KEY_NUM > 0 + rawdata_short_base_offset = Y_Channel * X_Channel * 7 + Y_Channel * 2 + Key_Channel * 7 + 2; +#else + rawdata_short_base_offset = Y_Channel * X_Channel * 7 + Y_Channel * 2; +#endif /* #if TOUCH_KEY_NUM > 0 */ + printk("%s:RawData_Short_Base:\n", __func__); + // Save Rawdata to CSV file + if (nvt_save_rawdata_to_csv(RawData_Short_Base, X_Channel, Y_Channel, SHORT_TEST_CSV_FILE, rawdata_short_base_offset) < 0) { + NVT_ERR("save rawdata to CSV file failed\n"); + return -EAGAIN; + } + } + + NVT_LOG("--\n"); + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen raw data test for each single point function. + +return: + Executive outcomes. 0---passed. negative---failed. +*******************************************************/ +static int32_t RawDataTest_SinglePoint_Sub(int32_t rawdata[], uint8_t RecordResult[], uint8_t x_ch, uint8_t y_ch, int32_t Rawdata_Limit_Postive[], int32_t Rawdata_Limit_Negative[]) +{ + int32_t i = 0; + int32_t j = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + int32_t iArrayIndex = 0; + bool isPass = true; + + for (j = 0; j < y_ch; j++) { + for (i = 0; i < x_ch; i++) { + iArrayIndex = j * x_ch + i; + + RecordResult[iArrayIndex] = 0x00; // default value for PASS + + if (rawdata[iArrayIndex] > Rawdata_Limit_Postive[iArrayIndex]) + RecordResult[iArrayIndex] |= 0x01; + + if (rawdata[iArrayIndex] < Rawdata_Limit_Negative[iArrayIndex]) + RecordResult[iArrayIndex] |= 0x02; + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = y_ch * x_ch + k; + + RecordResult[iArrayIndex] = 0x00; // default value for PASS + + if (rawdata[iArrayIndex] > Rawdata_Limit_Postive[iArrayIndex]) + RecordResult[iArrayIndex] |= 0x01; + + if (rawdata[iArrayIndex] < Rawdata_Limit_Negative[iArrayIndex]) + RecordResult[iArrayIndex] |= 0x02; + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + //---Check RecordResult--- + for (j = 0; j < y_ch; j++) { + for (i = 0; i < x_ch; i++) { + if (RecordResult[j * x_ch + i] != 0) { + isPass = false; + break; + } + } + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = y_ch * x_ch + k; + if (RecordResult[iArrayIndex] != 0) { + isPass = false; + break; + } + } +#endif /* #if TOUCH_KEY_NUM > 0 */ + + if (isPass == false) { + return -EPERM; + } else { + return 0; + } +} + +/******************************************************* +Description: + Novatek touchscreen print self-test result function. + +return: + n.a. +*******************************************************/ +void print_selftest_result(struct seq_file *m, int32_t TestResult, uint8_t RecordResult[], int32_t rawdata[], uint8_t x_len, uint8_t y_len) +{ + int32_t i = 0; + int32_t j = 0; + int32_t iArrayIndex = 0; +#if TOUCH_KEY_NUM > 0 + int32_t k = 0; +#endif /* #if TOUCH_KEY_NUM > 0 */ + + switch (TestResult) { + case 0: + nvt_mp_seq_printf(m, " PASS!\n"); + break; + + case 1: + nvt_mp_seq_printf(m, " ERROR! Read Data FAIL!\n"); + break; + + case -1: + nvt_mp_seq_printf(m, " FAIL!\n"); + nvt_mp_seq_printf(m, "RecordResult:\n"); + for (i = 0; i < y_len; i++) { + for (j = 0; j < x_len; j++) { + iArrayIndex = i * x_len + j; + nvt_mp_seq_printf(m, "0x%02X, ", RecordResult[iArrayIndex]); + } + nvt_mp_seq_printf(m, "\n"); + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = y_len * x_len + k; + nvt_mp_seq_printf(m, "0x%02X, ", RecordResult[iArrayIndex]); + } + nvt_mp_seq_printf(m, "\n"); +#endif /* #if TOUCH_KEY_NUM > 0 */ + nvt_mp_seq_printf(m, "ReadData:\n"); + for (i = 0; i < y_len; i++) { + for (j = 0; j < x_len; j++) { + iArrayIndex = i * x_len + j; + nvt_mp_seq_printf(m, "%5d, ", rawdata[iArrayIndex]); + } + nvt_mp_seq_printf(m, "\n"); + } +#if TOUCH_KEY_NUM > 0 + for (k = 0; k < Key_Channel; k++) { + iArrayIndex = y_len * x_len + k; + nvt_mp_seq_printf(m, "%5d, ", rawdata[iArrayIndex]); + } + nvt_mp_seq_printf(m, "\n"); +#endif /* #if TOUCH_KEY_NUM > 0 */ + break; + } + nvt_mp_seq_printf(m, "\n"); +} + +/******************************************************* +Description: + Novatek touchscreen self-test sequence print show + function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t c_show_selftest(struct seq_file *m, void *v) +{ +#if NVT_TOUCH_MP_LENOVO + MP_TEST_RESULT mp_result = 0; +#endif + + NVT_LOG("++\n"); +#if !NVT_TOUCH_MP_LENOVO + nvt_mp_seq_printf(m, "FW Version: %d\n\n", ts->fw_ver); + + nvt_mp_seq_printf(m, "Short Test"); + if ((TestResult_Short == 0) || (TestResult_Short == 1)) { + print_selftest_result(m, TestResult_Short, RecordResult_Short, RawData_Short, X_Channel, Y_Channel); + } else { // TestResult_Short is -1 + if (ts->carrier_system) { + nvt_mp_seq_printf(m, " FAIL!\n"); + if (TestResult_Short_Diff == -1) { + nvt_mp_seq_printf(m, "Short Diff"); + print_selftest_result(m, TestResult_Short_Diff, RecordResult_Short_Diff, RawData_Short_Diff, X_Channel, Y_Channel); + } + if (TestResult_Short_Base == -1) { + nvt_mp_seq_printf(m, "Short Base"); + print_selftest_result(m, TestResult_Short_Base, RecordResult_Short_Base, RawData_Short_Base, X_Channel, Y_Channel); + } + } else { + print_selftest_result(m, TestResult_Short, RecordResult_Short, RawData_Short, X_Channel, Y_Channel); + } + } + + nvt_mp_seq_printf(m, "Open Test"); + print_selftest_result(m, TestResult_Open, RecordResult_Open, RawData_Open, X_Channel, Y_Channel); + + nvt_mp_seq_printf(m, "FW Rawdata Test"); + if ((TestResult_FW_Rawdata == 0) || (TestResult_FW_Rawdata == 1)) { + print_selftest_result(m, TestResult_FWMutual, RecordResult_FWMutual, RawData_FWMutual, X_Channel, Y_Channel); + } else { // TestResult_FW_Rawdata is -1 + nvt_mp_seq_printf(m, " FAIL!\n"); + if (TestResult_FWMutual == -1) { + nvt_mp_seq_printf(m, "FW Mutual"); + print_selftest_result(m, TestResult_FWMutual, RecordResult_FWMutual, RawData_FWMutual, X_Channel, Y_Channel); + } + if (TestResult_FW_CC == -1) { + if (ts->carrier_system) { + if (TestResult_FW_CC_I == -1) { + nvt_mp_seq_printf(m, "FW CC_I"); + print_selftest_result(m, TestResult_FW_CC_I, RecordResult_FW_CC_I, RawData_FW_CC_I, X_Channel, Y_Channel); + } + if (TestResult_FW_CC_Q == -1) { + nvt_mp_seq_printf(m, "FW CC_Q"); + print_selftest_result(m, TestResult_FW_CC_Q, RecordResult_FW_CC_Q, RawData_FW_CC_Q, X_Channel, Y_Channel); + } + } else { + nvt_mp_seq_printf(m, "FW CC"); + print_selftest_result(m, TestResult_FW_CC, RecordResult_FW_CC, RawData_FW_CC, X_Channel, Y_Channel); + } + } + } + + nvt_mp_seq_printf(m, "Noise Test"); + if ((TestResult_Noise == 0) || (TestResult_Noise == 1)) { + print_selftest_result(m, TestResult_FW_DiffMax, RecordResult_FW_DiffMax, RawData_Diff_Max, X_Channel, Y_Channel); + } else { // TestResult_Noise is -1 + nvt_mp_seq_printf(m, " FAIL!\n"); + + if (TestResult_FW_DiffMax == -1) { + nvt_mp_seq_printf(m, "FW Diff Max"); + print_selftest_result(m, TestResult_FW_DiffMax, RecordResult_FW_DiffMax, RawData_Diff_Max, X_Channel, Y_Channel); + } + if (TestResult_FW_DiffMin == -1) { + nvt_mp_seq_printf(m, "FW Diff Min"); + print_selftest_result(m, TestResult_FW_DiffMin, RecordResult_FW_DiffMin, RawData_Diff_Min, X_Channel, Y_Channel); + } + } +#else + /* short */ + if (TestResult_Short >= 0) + mp_result |= (!!TestResult_Short << MP_RESULT_SHIFT_SHORT); + else { + if (ts->carrier_system) { + mp_result |= (!!TestResult_Short_Diff << MP_RESULT_SHIFT_SHORT_DIFF); + mp_result |= (!!TestResult_Short_Base << MP_RESULT_SHIFT_SHORT_BASE); + } else { + mp_result |= (!!TestResult_Short << MP_RESULT_SHIFT_SHORT); + } + } + + /* open */ + mp_result |= (!!TestResult_Open << MP_RESULT_SHIFT_OPEN); + + /* raw data & cc */ + if (TestResult_FW_Rawdata >= 0) + mp_result |= (!!TestResult_FWMutual << MP_RESULT_SHIFT_RAWDATA); + else { + if (TestResult_FWMutual == -1) { + mp_result |= (!!TestResult_FWMutual << MP_RESULT_SHIFT_RAWDATA); + } + if (TestResult_FW_CC == -1) { + if (ts->carrier_system) { + mp_result |= (!!TestResult_FW_CC_I << MP_RESULT_SHIFT_CC_I); + mp_result |= (!!TestResult_FW_CC_Q << MP_RESULT_SHIFT_CC_Q); + } else { + mp_result |= (!!TestResult_FW_CC << MP_RESULT_SHIFT_CC); + } + } + } + + /* noise */ + if (TestResult_Noise >= 0) + mp_result |= (!!TestResult_FW_DiffMax << MP_RESULT_SHIFT_DIFF_MAX); + else { + if (TestResult_FW_DiffMax == -1) { + mp_result |= (!!TestResult_FW_DiffMax << MP_RESULT_SHIFT_DIFF_MAX); + } + if (TestResult_FW_DiffMin == -1) { + mp_result |= (!!TestResult_FW_DiffMin << MP_RESULT_SHIFT_DIFF_MIN); + } + } + + nvt_mp_seq_printf(m, "%d", mp_result); +#endif + nvt_mp_test_result_printed = 1; + + NVT_LOG("--\n"); + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen self-test sequence print start + function. + +return: + Executive outcomes. 1---call next function. + NULL---not call next function and sequence loop + stop. +*******************************************************/ +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +/******************************************************* +Description: + Novatek touchscreen self-test sequence print next + function. + +return: + Executive outcomes. NULL---no next and call sequence + stop function. +*******************************************************/ +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +/******************************************************* +Description: + Novatek touchscreen self-test sequence print stop + function. + +return: + n.a. +*******************************************************/ +static void c_stop(struct seq_file *m, void *v) +{ + return; +} + +const struct seq_operations nvt_selftest_seq_ops = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show_selftest +}; + +/******************************************************* +Description: + Novatek touchscreen /proc/nvt_selftest open function. + +return: + Executive outcomes. 0---succeed. negative---failed. +*******************************************************/ +static int32_t nvt_selftest_open(struct inode *inode, struct file *file) +{ + struct device_node *np = ts->client->dev.of_node; + unsigned char mpcriteria[32] = {0}; //novatek-mp-criteria-default + + TestResult_Short = 0; + TestResult_Short_Diff = 0; + TestResult_Short_Base = 0; + TestResult_Open = 0; + TestResult_FW_Rawdata = 0; + TestResult_FWMutual = 0; + TestResult_FW_CC = 0; + TestResult_FW_CC_I = 0; + TestResult_FW_CC_Q = 0; + TestResult_Noise = 0; + TestResult_FW_DiffMax = 0; + TestResult_FW_DiffMin = 0; + + NVT_LOG("++\n"); + + if (mutex_lock_interruptible(&ts->lock)) { + return -ERESTARTSYS; + } + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif /* #if NVT_TOUCH_ESD_PROTECT */ + + if (nvt_get_fw_info()) { + mutex_unlock(&ts->lock); + NVT_ERR("get fw info failed!\n"); + return -EAGAIN; + } + + /* Parsing criteria from dts */ + if (of_property_read_bool(np, "novatek,mp-support-dt")) { + /* + * Parsing Criteria by Novatek PID + * The string rule is "novatek-mp-criteria-" + * nvt_pid is 2 bytes (show hex). + * + * Ex. nvt_pid = 500A + * mpcriteria = "novatek-mp-criteria-500A" + */ + snprintf(mpcriteria, PAGE_SIZE, "novatek-mp-criteria-%04X", ts->nvt_pid); + + nvt_mp_parse_dt(np, mpcriteria); + } else { + NVT_LOG("Not found novatek,mp-support-dt, use default setting\n"); + //---Print Test Criteria--- + nvt_print_criteria(); + } + + if (nvt_switch_FreqHopEnDis(FREQ_HOP_DISABLE)) { + mutex_unlock(&ts->lock); + NVT_ERR("switch frequency hopping disable failed!\n"); + return -EAGAIN; + } + + if (nvt_check_fw_reset_state(RESET_STATE_NORMAL_RUN)) { + mutex_unlock(&ts->lock); + NVT_ERR("check fw reset state failed!\n"); + return -EAGAIN; + } + + msleep(100); + + //---Enter Test Mode--- + if (nvt_clear_fw_status()) { + mutex_unlock(&ts->lock); + NVT_ERR("clear fw status failed!\n"); + return -EAGAIN; + } + + nvt_change_mode(MP_MODE_CC); + + if (nvt_check_fw_status()) { + mutex_unlock(&ts->lock); + NVT_ERR("check fw status failed!\n"); + return -EAGAIN; + } + + //---FW Rawdata Test--- + if (nvt_read_baseline(RawData_FWMutual) != 0) { + TestResult_FWMutual = 1; + } else { + TestResult_FWMutual = RawDataTest_SinglePoint_Sub(RawData_FWMutual, RecordResult_FWMutual, X_Channel, Y_Channel, + PS_Config_Lmt_FW_Rawdata_P, PS_Config_Lmt_FW_Rawdata_N); + } + if (nvt_read_CC(RawData_FW_CC) != 0) { + TestResult_FW_CC = 1; + if (ts->carrier_system) { + TestResult_FW_CC_I = 1; + TestResult_FW_CC_Q = 1; + } + } else { + if (ts->carrier_system) { + TestResult_FW_CC_I = RawDataTest_SinglePoint_Sub(RawData_FW_CC_I, RecordResult_FW_CC_I, X_Channel, Y_Channel, + PS_Config_Lmt_FW_CC_I_P, PS_Config_Lmt_FW_CC_I_N); + TestResult_FW_CC_Q = RawDataTest_SinglePoint_Sub(RawData_FW_CC_Q, RecordResult_FW_CC_Q, X_Channel, Y_Channel, + PS_Config_Lmt_FW_CC_Q_P, PS_Config_Lmt_FW_CC_Q_N); + if ((TestResult_FW_CC_I == -1) || (TestResult_FW_CC_Q == -1)) + TestResult_FW_CC = -1; + else + TestResult_FW_CC = 0; + } else { + TestResult_FW_CC = RawDataTest_SinglePoint_Sub(RawData_FW_CC, RecordResult_FW_CC, X_Channel, Y_Channel, + PS_Config_Lmt_FW_CC_P, PS_Config_Lmt_FW_CC_N); + } + } + + if ((TestResult_FWMutual == 1) || (TestResult_FW_CC == 1)) { + TestResult_FW_Rawdata = 1; + } else { + if ((TestResult_FWMutual == -1) || (TestResult_FW_CC == -1)) + TestResult_FW_Rawdata = -1; + else + TestResult_FW_Rawdata = 0; + } + + //---Leave Test Mode--- + nvt_change_mode(NORMAL_MODE); + + //---Noise Test--- + if (nvt_read_fw_noise(RawData_Diff) != 0) { + TestResult_Noise = 1; // 1: ERROR + TestResult_FW_DiffMax = 1; + TestResult_FW_DiffMin = 1; + } else { + TestResult_FW_DiffMax = RawDataTest_SinglePoint_Sub(RawData_Diff_Max, RecordResult_FW_DiffMax, X_Channel, Y_Channel, + PS_Config_Lmt_FW_Diff_P, PS_Config_Lmt_FW_Diff_N); + + // for carrier sensing system, only positive noise data + if (ts->carrier_system) { + TestResult_FW_DiffMin = 0; + } else { + TestResult_FW_DiffMin = RawDataTest_SinglePoint_Sub(RawData_Diff_Min, RecordResult_FW_DiffMin, X_Channel, Y_Channel, + PS_Config_Lmt_FW_Diff_P, PS_Config_Lmt_FW_Diff_N); + } + + if ((TestResult_FW_DiffMax == -1) || (TestResult_FW_DiffMin == -1)) + TestResult_Noise = -1; + else + TestResult_Noise = 0; + } + + //--Short Test--- + if (nvt_read_fw_short(RawData_Short) != 0) { + TestResult_Short = 1; // 1:ERROR + if (ts->carrier_system) { + TestResult_Short_Diff = 1; + TestResult_Short_Base = 1; + } + } else { + //---Self Test Check --- // 0:PASS, -1:FAIL + if (ts->carrier_system) { + TestResult_Short_Diff = RawDataTest_SinglePoint_Sub(RawData_Short_Diff, RecordResult_Short_Diff, X_Channel, Y_Channel, + PS_Config_Lmt_Short_Diff_P, PS_Config_Lmt_Short_Diff_N); + TestResult_Short_Base = RawDataTest_SinglePoint_Sub(RawData_Short_Base, RecordResult_Short_Base, X_Channel, Y_Channel, + PS_Config_Lmt_Short_Base_P, PS_Config_Lmt_Short_Base_N); + + if ((TestResult_Short_Diff == -1) || (TestResult_Short_Base == -1)) + TestResult_Short = -1; + else + TestResult_Short = 0; + } else { + TestResult_Short = RawDataTest_SinglePoint_Sub(RawData_Short, RecordResult_Short, X_Channel, Y_Channel, + PS_Config_Lmt_Short_Rawdata_P, PS_Config_Lmt_Short_Rawdata_N); + } + } + + //---Open Test--- + if (nvt_read_fw_open(RawData_Open) != 0) { + TestResult_Open = 1; // 1:ERROR + } else { + //---Self Test Check --- // 0:PASS, -1:FAIL + TestResult_Open = RawDataTest_SinglePoint_Sub(RawData_Open, RecordResult_Open, X_Channel, Y_Channel, + PS_Config_Lmt_Open_Rawdata_P, PS_Config_Lmt_Open_Rawdata_N); + } + + //---Reset IC--- + nvt_bootloader_reset(); + + mutex_unlock(&ts->lock); + + NVT_LOG("--\n"); + + nvt_mp_test_result_printed = 0; + + return seq_open(file, &nvt_selftest_seq_ops); +} + +static const struct file_operations nvt_selftest_fops = { + .owner = THIS_MODULE, + .open = nvt_selftest_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#if NVT_TOUCH_MP_LENOVO +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash read function. + +return: + Executive outcomes. 2---succeed. -5,-14---failed. +*******************************************************/ +static ssize_t nvt_data_read(struct file *file, char __user *buff, size_t count, loff_t *offp) +{ + uint8_t *str; + int32_t ret = -1; + int32_t retries = 0; + int8_t i2c_wr = 0; + uint8_t i2c_addr = 0; + uint32_t data_len = 0; + + NVT_LOG("++\n"); + + if (count > (40 * (40 + 4) * 2 + 7)) { + NVT_ERR("error count=%zu\n", count); + return -EFAULT; + } + + str = kmalloc(40 * (40 + 4) * 2 + 7, GFP_KERNEL); + if (str == NULL) { + NVT_ERR("failed to allocated memory for input data\n"); + return -ENOMEM; + } + + if (copy_from_user(str, buff, count)) { + NVT_ERR("copy from user error\n"); + return -EFAULT; + } + +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif + + i2c_wr = str[0] >> 7; + i2c_addr = str[0] & 0x7F; + data_len = (int32_t)((str[1] << 8) + str[2]); + + if (i2c_wr == 0) { + return -ENOTSUPP; + } else if (i2c_wr == 1) { + while (retries < 20) { + ret = nvt_read_mass_data(i2c_addr, str, data_len); + if (ret == data_len) + break; + else + NVT_ERR("error, retries=%d, ret=%d, data_len=%d\n", retries, ret, data_len); + + retries++; + } + + if (retries < 20) { + ret = copy_to_user(buff, str, data_len); + if (ret) { + NVT_ERR("error, copy_to_user, ret=%d, data_len=%d\n", ret, data_len); + return -EFAULT; + } + } + + if (unlikely(retries == 20)) { + NVT_ERR("error, ret = %d\n", ret); + return -EIO; + } + } else { + NVT_ERR("Call error, str[0]=%d\n", str[0]); + return -EFAULT; + } + + kfree(str); + NVT_LOG("--\n"); + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash open function. + +return: + Executive outcomes. 0---succeed. -12---failed. +*******************************************************/ +static int32_t nvt_data_open(struct inode *inode, struct file *file) +{ + struct nvt_flash_data *dev; + + dev = kmalloc(sizeof(struct nvt_flash_data), GFP_KERNEL); + if (dev == NULL) { + NVT_ERR("Failed to allocate memory for nvt flash data\n"); + return -ENOMEM; + } + + rwlock_init(&dev->lock); + file->private_data = dev; + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen /proc/NVTflash close function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +static int32_t nvt_data_close(struct inode *inode, struct file *file) +{ + struct nvt_flash_data *dev = file->private_data; + + if (dev) + kfree(dev); + + return 0; +} + +static const struct file_operations nvt_read_data_fops = { + .owner = THIS_MODULE, + .open = nvt_data_open, + .release = nvt_data_close, + .read = nvt_data_read, +}; +#endif + +#ifdef CONFIG_OF +/******************************************************* +Description: + Novatek touchscreen parse AIN setting for array type. + +return: + n.a. +*******************************************************/ +void nvt_mp_parse_ain(struct device_node *np, const char *name, uint8_t *array, int32_t size) +{ + struct property *data; + int32_t len, ret; + int32_t tmp[40]; + int32_t i; + + data = of_find_property(np, name, &len); + len /= sizeof(u32); + if ((!data) || (!len) || (len != size)) { + NVT_ERR("error find %s. len=%d\n", name, len); + } else { + NVT_LOG("%s. len=%d\n", name, len); + ret = of_property_read_u32_array(np, name, tmp, len); + if (ret) { + NVT_ERR("error reading %s. ret=%d\n", name, ret); + return; + } + + for (i = 0; i < len; i++) + array[i] = tmp[i]; + +#if NVT_DEBUG + printk("[NVT-ts] %s = ", name); + for (i = 0; i < len; i++) { + printk("%02d ", array[i]); + } + printk("\n"); +#endif + } +} + +/******************************************************* +Description: + Novatek touchscreen parse criterion for u32 type. + +return: + n.a. +*******************************************************/ +void nvt_mp_parse_u32(struct device_node *np, const char *name, int32_t *para) +{ + int32_t ret; + + ret = of_property_read_u32(np, name, para); + if (ret) + NVT_ERR("error reading %s. ret=%d\n", name, ret); + else { +#if NVT_DEBUG + NVT_LOG("%s=%d\n", name, *para); +#endif + } +} + +/******************************************************* +Description: + Novatek touchscreen parse criterion for array type. + +return: + n.a. +*******************************************************/ +void nvt_mp_parse_array(struct device_node *np, const char *name, int32_t *array, + int32_t size) +{ + struct property *data; + int32_t len, ret; +#if NVT_DEBUG + int32_t i, j, iArrayIndex = 0; +#endif + + data = of_find_property(np, name, &len); + len /= sizeof(u32); + if ((!data) || (!len) || (len < size)) { + NVT_ERR("error find %s. len=%d\n", name, len); + } else { + NVT_LOG("%s. len=%d\n", name, len); + ret = of_property_read_u32_array(np, name, array, len); + if (ret) { + NVT_ERR("error reading %s. ret=%d\n", name, ret); + return; + } + +#if NVT_DEBUG + NVT_LOG("%s =\n", name); + for (j = 0; j < Y_Channel; j++) { + printk("[NVT-ts] "); + for (i = 0; i < X_Channel; i++) { + iArrayIndex = j * X_Channel + i; + printk("%5d, ", array[iArrayIndex]); + } + printk("\n"); + } +#if TOUCH_KEY_NUM > 0 + printk("[NVT-ts] "); + for (i = 0; i < Key_Channel; i++) { + iArrayIndex++; + printk("%5d, ", array[iArrayIndex]); + } + printk("\n"); +#endif +#endif + } +} + +/******************************************************* +Description: + Novatek touchscreen parse device tree mp function. + +return: + n.a. +*******************************************************/ +void nvt_mp_parse_dt(struct device_node *root, const char *node_compatible) +{ + struct device_node *np = root; + struct device_node *child = NULL; + + NVT_LOG("Parse mp criteria for node %s\n", node_compatible); + + /* find each MP sub-nodes */ + for_each_child_of_node(root, child) { + /* find the specified node */ + if (of_device_is_compatible(child, node_compatible)) { + NVT_LOG("found child node %s\n", node_compatible); + np = child; + break; + } + } + if (child == NULL) { + NVT_ERR("Not found compatible node %s, use default setting!\n", node_compatible); + return; + } + + /* MP Config*/ + nvt_mp_parse_u32(np, "IC_X_CFG_SIZE", &IC_X_CFG_SIZE); + + nvt_mp_parse_u32(np, "IC_Y_CFG_SIZE", &IC_Y_CFG_SIZE); + +#if TOUCH_KEY_NUM > 0 + nvt_mp_parse_u32(np, "IC_KEY_CFG_SIZE", &IC_KEY_CFG_SIZE); +#endif + + nvt_mp_parse_u32(np, "X_Channel", &X_Channel); + + nvt_mp_parse_u32(np, "Y_Channel", &Y_Channel); + + nvt_mp_parse_ain(np, "AIN_X", AIN_X, IC_X_CFG_SIZE); + + nvt_mp_parse_ain(np, "AIN_Y", AIN_Y, IC_Y_CFG_SIZE); + +#if TOUCH_KEY_NUM > 0 + nvt_mp_parse_ain(np, "AIN_KEY", AIN_KEY, IC_KEY_CFG_SIZE); +#endif + + /* MP Criteria */ + if (ts->carrier_system) { + nvt_mp_parse_array(np, "PS_Config_Lmt_Short_Diff_P", PS_Config_Lmt_Short_Diff_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_Short_Diff_N", PS_Config_Lmt_Short_Diff_N, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_Short_Base_P", PS_Config_Lmt_Short_Base_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_Short_Base_N", PS_Config_Lmt_Short_Base_N, + X_Channel * Y_Channel + Key_Channel); + } else { + nvt_mp_parse_array(np, "PS_Config_Lmt_Short_Rawdata_P", PS_Config_Lmt_Short_Rawdata_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_Short_Rawdata_N", PS_Config_Lmt_Short_Rawdata_N, + X_Channel * Y_Channel + Key_Channel); + } + + nvt_mp_parse_array(np, "PS_Config_Lmt_Open_Rawdata_P", PS_Config_Lmt_Open_Rawdata_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_Open_Rawdata_N", PS_Config_Lmt_Open_Rawdata_N, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_Rawdata_P", PS_Config_Lmt_FW_Rawdata_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_Rawdata_N", PS_Config_Lmt_FW_Rawdata_N, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_CC_P", PS_Config_Lmt_FW_CC_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_CC_N", PS_Config_Lmt_FW_CC_N, + X_Channel * Y_Channel + Key_Channel); + + if (ts->carrier_system) { + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_CC_I_P", PS_Config_Lmt_FW_CC_I_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_CC_I_N", PS_Config_Lmt_FW_CC_I_N, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_CC_Q_P", PS_Config_Lmt_FW_CC_Q_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_CC_Q_N", PS_Config_Lmt_FW_CC_Q_N, + X_Channel * Y_Channel + Key_Channel); + } + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_Diff_P", PS_Config_Lmt_FW_Diff_P, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_array(np, "PS_Config_Lmt_FW_Diff_N", PS_Config_Lmt_FW_Diff_N, + X_Channel * Y_Channel + Key_Channel); + + nvt_mp_parse_u32(np, "PS_Config_Diff_Test_Frame", &PS_Config_Diff_Test_Frame); + + NVT_LOG("Parse mp criteria done!\n"); +} +#endif /* #ifdef CONFIG_OF */ + +/******************************************************* +Description: + Novatek touchscreen MP function proc. file node + initial function. + +return: + Executive outcomes. 0---succeed. -1---failed. +*******************************************************/ +int32_t nvt_mp_proc_init(void) +{ + int32_t ret = 0; + + NVT_proc_selftest_entry = proc_create("nvt_selftest", 0444, NULL, &nvt_selftest_fops); + if (NVT_proc_selftest_entry == NULL) { + NVT_ERR("create /proc/nvt_selftest Failed!\n"); + ret = -1; + } else { + if (nvt_mp_buffer_init()) { + NVT_ERR("Allocate mp memory failed\n"); + ret = -1; + } else { + NVT_LOG("create /proc/nvt_selftest Succeeded!\n"); + } + ret = 0; + } +#if NVT_TOUCH_MP_LENOVO + if (ret == 0) { + NVT_proc_selftest_read_data = proc_create("nvt_read_data", 0444, NULL, &nvt_read_data_fops); + if (NVT_proc_selftest_read_data == NULL) { + NVT_ERR("create /proc/nvt_read_data Failed!\n"); + ret = -1; + } else { + NVT_LOG("create /proc/nvt_read_data Succeeded!\n"); + } + } +#endif + + return ret; +} + +#endif /* #if NVT_TOUCH_MP */ diff --git a/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.h b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.h new file mode 100644 index 000000000000..ed068d741d48 --- /dev/null +++ b/drivers/input/touchscreen/nova_36525_mmi/nt36xxx_mp_ctrlram.h @@ -0,0 +1,719 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 19587 $ + * $Date: 2017-11-28 21:00:30 +0800 (Tue, 28 Nov 2017) $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + */ + +#if NVT_TOUCH_MP + +static uint32_t IC_X_CFG_SIZE = 18; +static uint32_t IC_Y_CFG_SIZE = 32; +static uint32_t IC_KEY_CFG_SIZE = 4; +static uint32_t X_Channel = 18; +static uint32_t Y_Channel = 32; +static uint32_t Key_Channel = TOUCH_KEY_NUM; +static uint8_t AIN_X[40] = {17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; +static uint8_t AIN_Y[40] = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; +#if TOUCH_KEY_NUM > 0 +static uint8_t AIN_KEY[8] = {0, 1, 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +#endif /* #if TOUCH_KEY_NUM > 0 */ + +static int32_t PS_Config_Lmt_Short_Rawdata_P[40 * 40] = { + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, +#if TOUCH_KEY_NUM > 0 + 20000, 20000, 20000, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Short_Rawdata_N[40 * 40] = { + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, + 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, 11550, +#if TOUCH_KEY_NUM > 0 + 11550, 11550, 11550, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Short_Diff_P[40 * 40] = { + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, + 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, +#if TOUCH_KEY_NUM > 0 + 6300, 6300, 6300, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Short_Diff_N[40 * 40] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if TOUCH_KEY_NUM > 0 + 0, 0, 0, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Short_Base_P[40 * 40] = { + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, +#if TOUCH_KEY_NUM > 0 + 2000, 2000, 2000, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Short_Base_N[40 * 40] = { + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, + -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, -2000, +#if TOUCH_KEY_NUM > 0 + -2000, -2000, -2000, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Open_Rawdata_P[40 * 40] = { + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, + 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, 13000, +#if TOUCH_KEY_NUM > 0 + 13000, 13000, 13000, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Open_Rawdata_N[40 * 40] = { + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, + 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, +#if TOUCH_KEY_NUM > 0 + 6500, 6500, 6500, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_Rawdata_P[40 * 40] = { + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, +#if TOUCH_KEY_NUM > 0 + 2000, 2000, 2000, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_Rawdata_N[40 * 40] = { + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, +#if TOUCH_KEY_NUM > 0 + 400, 400, 400, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_CC_P[40 * 40] = { + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, +#if TOUCH_KEY_NUM > 0 + 38, 38, 38, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_CC_N[40 * 40] = { + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, +#if TOUCH_KEY_NUM > 0 + 9, 9, 9, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_CC_I_P[40 * 40] = { + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +#if TOUCH_KEY_NUM > 0 + 25, 25, 25, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_CC_I_N[40 * 40] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if TOUCH_KEY_NUM > 0 + 0, 0, 0, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_CC_Q_P[40 * 40] = { + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +#if TOUCH_KEY_NUM > 0 + 25, 25, 25, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_CC_Q_N[40 * 40] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if TOUCH_KEY_NUM > 0 + 0, 0, 0, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_Diff_P[40 * 40] = { + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, +#if TOUCH_KEY_NUM > 0 + 35, 35, 35, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_FW_Diff_N[40 * 40] = { + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, +#if TOUCH_KEY_NUM > 0 + -35, -35, -35, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Diff_Test_Frame = 50; + +#endif /* #if NVT_TOUCH_MP */