From ad8ab62c3fb8460762d72c421804d111a0dd8098 Mon Sep 17 00:00:00 2001 From: lijilai Date: Tue, 10 Jul 2018 10:10:38 +0800 Subject: [PATCH] BSP: add nt36xxx touch driver [9609][WING] touch: add nt36xxx touch driver Bug:HQ00000000 Workaround:no Change-Id: I2364fb4f434aae658ff3196b4ff5858fe1daa39c Signed-off-by: Youngmin Nam Signed-off-by: lijilai --- drivers/input/touchscreen/nt36672a/Kconfig | 11 + drivers/input/touchscreen/nt36672a/Makefile | 7 + drivers/input/touchscreen/nt36672a/nt36xxx.c | 1760 +++++++++++++++ drivers/input/touchscreen/nt36672a/nt36xxx.h | 190 ++ .../touchscreen/nt36672a/nt36xxx_ext_proc.c | 716 +++++++ .../touchscreen/nt36672a/nt36xxx_fw_update.c | 1385 ++++++++++++ .../touchscreen/nt36672a/nt36xxx_mem_map.h | 208 ++ .../touchscreen/nt36672a/nt36xxx_mp_ctrlram.c | 1902 +++++++++++++++++ .../touchscreen/nt36672a/nt36xxx_mp_ctrlram.h | 740 +++++++ 9 files changed, 6919 insertions(+) create mode 100755 drivers/input/touchscreen/nt36672a/Kconfig create mode 100755 drivers/input/touchscreen/nt36672a/Makefile create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx.c create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx.h create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx_ext_proc.c create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx_fw_update.c create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx_mem_map.h create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx_mp_ctrlram.c create mode 100755 drivers/input/touchscreen/nt36672a/nt36xxx_mp_ctrlram.h diff --git a/drivers/input/touchscreen/nt36672a/Kconfig b/drivers/input/touchscreen/nt36672a/Kconfig new file mode 100755 index 000000000000..ad074627aacc --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/Kconfig @@ -0,0 +1,11 @@ +# +# Novatek NT36xxx touchscreen driver configuration +# +config TOUCHSCREEN_NT36xxx + bool "Novatek NT36xxx" + default y + help + Say Y here if you have a Novatek NT36xxx touchscreen connected + to your system. + + If unsure, say N. diff --git a/drivers/input/touchscreen/nt36672a/Makefile b/drivers/input/touchscreen/nt36672a/Makefile new file mode 100755 index 000000000000..88c95a96ae42 --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Novatek NT36xxx touchscreen driver. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_TOUCHSCREEN_NT36xxx) += nt36xxx.o nt36xxx_fw_update.o nt36xxx_ext_proc.o nt36xxx_mp_ctrlram.o diff --git a/drivers/input/touchscreen/nt36672a/nt36xxx.c b/drivers/input/touchscreen/nt36672a/nt36xxx.c new file mode 100755 index 000000000000..2103fdec0a55 --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx.c @@ -0,0 +1,1760 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22971 $ + * $Date: 2018-02-08 16:05:40 +0800 (週四, 08 二月 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 +#include + +#if defined(CONFIG_HQ_DEV_INFO) +#include +#endif + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#include "nt36xxx.h" + +#if NVT_TOUCH_ESD_PROTECT +#include + +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 = false; +uint8_t esd_retry = 0; +uint8_t esd_retry_max = 5; +#endif + +#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 = 0; + +/******************************************************* +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_ERR("xlixiang---enter-%s\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); +} + +/******************************************************* +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 -1; + } 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 -1; + } 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_ERR("xlixiang---enter-%s\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; + } + } + } + + 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; + +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(); + + 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 + + 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 + +static struct wake_lock 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; + +#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); + +} +#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; + +#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; + } + } + + return ret; + +err_request_irq_gpio: +#if NVT_TOUCH_SUPPORT_HW_RST + gpio_free(ts->reset_gpio); +err_request_reset_gpio: +#endif + 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); + + + 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); + printk("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 + +#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; + } + +#if NVT_TOUCH_ESD_PROTECT + + if (nvt_fw_recovery(point_data)) { + nvt_esd_check_enable(true); + goto XFER_ERROR; + } +#endif + +#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)) { +#if NVT_TOUCH_ESD_PROTECT + /* update interrupt timer */ + irq_timer = jiffies; +#endif + 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) { + wake_lock_timeout(&gestrue_wakelock, msecs_to_jiffies(5000)); + } +#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_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: + 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("start\n"); + + 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; + } + + //---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; + } + + // 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]); + } + wake_lock_init(&gestrue_wakelock, WAKE_LOCK_SUSPEND, "poll-wake-lock"); +#endif + + sprintf(ts->phys, "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 + //---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("end\n"); + + 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 + free_irq(client->irq, ts); +#if BOOT_UPDATE_FIRMWARE +err_create_nvt_fwu_wq_failed: +#endif +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: +err_check_functionality_failed: + gpio_free(ts->irq_gpio); +err_gpio_config_failed: + i2c_set_clientdata(client, NULL); + kfree(ts); + 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 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) +{ + int res = 0; + + if (bTouchIsAwake) { + NVT_LOG("Touch is already resume\n"); + return 0; + } + + msleep(10); + + 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 + gpio_set_value(ts->reset_gpio, 1); +#endif + nvt_bootloader_reset(); + res = nvt_check_fw_reset_state(RESET_STATE_REK); + + NVT_ERR("xlixiang---enter-%s-----res=%d\n", __func__, res); + +#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 + 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 + +} + +//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/nt36672a/nt36xxx.h b/drivers/input/touchscreen/nt36672a/nt36xxx.h new file mode 100755 index 000000000000..0c17bf3951e4 --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22971 $ + * $Date: 2018-02-08 16:05:40 +0800 (週四, 08 二月 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 1 + +//---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 1080 +#define TOUCH_DEFAULT_MAX_HEIGHT 2246 +#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, + 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 +extern void nvt_stop_crc_reboot(void); + +#endif /* _LINUX_NVT_TOUCH_H */ diff --git a/drivers/input/touchscreen/nt36672a/nt36xxx_ext_proc.c b/drivers/input/touchscreen/nt36672a/nt36xxx_ext_proc.c new file mode 100755 index 000000000000..00ee7b6604f6 --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx_ext_proc.c @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22971 $ + * $Date: 2018-02-08 16:05:40 +0800 (週四, 08 二月 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 "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_info_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_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_info_proc_fops = { + .owner = THIS_MODULE, + .open = nvt_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +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_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_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_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_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/nt36672a/nt36xxx_fw_update.c b/drivers/input/touchscreen/nt36672a/nt36xxx_fw_update.c new file mode 100755 index 000000000000..a4bdeb2aa53d --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx_fw_update.c @@ -0,0 +1,1385 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22971 $ + * $Date: 2018-02-08 16:05:40 +0800 (週四, 08 二月 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 "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 = NULL; + +/******************************************************* +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 -1; + } + + 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 -1; + } + } + 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 -1; + } + + 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 -1; + } + } + // 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 -1; + } + } + + 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 -1; + } + } + + // 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 -1; + } + } + + // 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 -1; + } + } + + 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 -1; + } + } + + 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 -1; + } + } + + // 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 -1; + } + } + } + + 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 -1; + } + } + + // 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 -1; + } + } + if (buf[1] == 0xEA) { + NVT_ERR("Page Program error!! i=%d\n", i); + return -3; + } + + // 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 -1; + } + } + if (buf[1] == 0xEA) { + NVT_ERR("Page Program error!! i=%d\n", i); + return -4; + } + + 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 -1; + } + } + // 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 -1; + } + } + } + + 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; + + //---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); + + 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 -1; + } + + 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 + strncpy(nvt_end_flag, &buf[3], NVT_FLASH_END_FLAG_LEN); + 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; + } +} +#endif + +#if BOOT_UPDATE_FIRMWARE +/******************************************************* +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] = ""; + sprintf(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; + } + + mutex_lock(&ts->lock); +#if NVT_TOUCH_ESD_PROTECT + nvt_esd_check_enable(false); +#endif +#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/nt36672a/nt36xxx_mem_map.h b/drivers/input/touchscreen/nt36672a/nt36xxx_mem_map.h new file mode 100755 index 000000000000..723c67353b40 --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx_mem_map.h @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22971 $ + * $Date: 2018-02-08 16:05:40 +0800 (週四, 08 二月 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. + * + */ + +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/nt36672a/nt36xxx_mp_ctrlram.c b/drivers/input/touchscreen/nt36672a/nt36xxx_mp_ctrlram.c new file mode 100755 index 000000000000..bd8f7572c785 --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx_mp_ctrlram.c @@ -0,0 +1,1902 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 23067 $ + * $Date: 2018-02-09 11:39:27 +0800 (週五, 09 二月 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 = NULL; +static uint8_t *RecordResult_Short_Diff = NULL; +static uint8_t *RecordResult_Short_Base = NULL; +static uint8_t *RecordResult_Open = NULL; +static uint8_t *RecordResult_FWMutual = NULL; +static uint8_t *RecordResult_FW_CC = NULL; +static uint8_t *RecordResult_FW_CC_I = NULL; +static uint8_t *RecordResult_FW_CC_Q = NULL; +static uint8_t *RecordResult_FW_DiffMax = NULL; +static uint8_t *RecordResult_FW_DiffMin = NULL; + +static int32_t TestResult_Short = 0; +static int32_t TestResult_Short_Diff = 0; +static int32_t TestResult_Short_Base = 0; +static int32_t TestResult_Open = 0; +static int32_t TestResult_FW_Rawdata = 0; +static int32_t TestResult_FWMutual = 0; +static int32_t TestResult_FW_CC = 0; +static int32_t TestResult_FW_CC_I = 0; +static int32_t TestResult_FW_CC_Q = 0; +static int32_t TestResult_Noise = 0; +static int32_t TestResult_FW_DiffMax = 0; +static int32_t TestResult_FW_DiffMin = 0; + +static int32_t *RawData_Short = NULL; +static int32_t *RawData_Short_Diff = NULL; +static int32_t *RawData_Short_Base = NULL; +static int32_t *RawData_Open = NULL; +static int32_t *RawData_Diff = NULL; +static int32_t *RawData_Diff_Min = NULL; +static int32_t *RawData_Diff_Max = NULL; +static int32_t *RawData_FWMutual = NULL; +static int32_t *RawData_FW_CC = NULL; +static int32_t *RawData_FW_CC_I = NULL; +static int32_t *RawData_FW_CC_Q = NULL; + +static struct proc_dir_entry *NVT_proc_selftest_entry = NULL; +#if NVT_TOUCH_MP_LENOVO +static struct proc_dir_entry *NVT_proc_selftest_read_data = NULL; +#endif +static int8_t nvt_mp_test_result_printed = 0; + +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 -1; + } 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 -1; // FAIL + } else { + return 0; // PASS + } +} + +/******************************************************* +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_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 + +/******************************************************* +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/nt36672a/nt36xxx_mp_ctrlram.h b/drivers/input/touchscreen/nt36672a/nt36xxx_mp_ctrlram.h new file mode 100755 index 000000000000..bd9f949c444d --- /dev/null +++ b/drivers/input/touchscreen/nt36672a/nt36xxx_mp_ctrlram.h @@ -0,0 +1,740 @@ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * + * $Revision: 22971 $ + * $Date: 2018-02-08 16:05:40 +0800 (週四, 08 二月 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. + * + */ + +#if NVT_TOUCH_MP + +static uint32_t IC_X_CFG_SIZE = 18; +static uint32_t IC_Y_CFG_SIZE = 36; +static uint32_t IC_KEY_CFG_SIZE = 4; +static uint32_t X_Channel = 18; +static uint32_t Y_Channel = 34; +static uint32_t Key_Channel = TOUCH_KEY_NUM; +static uint8_t AIN_X[40] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; +static uint8_t AIN_Y[40] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 0xFF, 0xFF}; +#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] = { + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500, + 6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,6500,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 + 20000,20000,20000, +#endif /* #if TOUCH_KEY_NUM > 0 */ +}; + +static int32_t PS_Config_Lmt_Short_Rawdata_N[40 * 40] = { + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, + 4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500,4500, +#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] = { + 5830,2470,3134,2675,6215, 590, 616, 542, 600,2505,2447,2511,2488,6273,4533,3227,2617,6119, + 2967,3669,3098,6069,5039,4702,4552,4654,4525,2545,2653,2584,2695,3051,3680,5123,5934,3186, + 2831,3440,2926,3081,2920,3067,2910,3055,2916,2883,3046,2916,3049,2907,3448,2893,3039,2908, + 2762,3353,2877,3020,2873,3008,2865,2999,2872,2813,2961,2871,2990,2862,3389,2846,2979,2861, + 2815,3410,2895,3040,2892,3031,2886,3023,2891,2863,3015,2890,3012,2881,3408,2865,3000,2881, + 2773,3357,2846,2980,2844,2974,2840,2967,2846,2817,2958,2843,2952,2832,3347,2816,2942,2838, + 2775,3362,2822,2953,2846,2975,2846,2970,2851,2825,2966,2823,2929,2838,3353,2823,2943,2838, + 2730,3176,2803,2925,2797,2898,2800,2914,2807,2778,2906,2804,2901,2787,3160,2772,2879,2788, + 2741,2939,2813,2938,2807,2909,2814,2930,2817,2791,2922,2815,2914,2798,2913,2784,2893,2801, + 2691,2875,2761,2878,2758,2849,2767,2869,2765,2756,2857,2764,2863,2745,2849,2734,2830,2748, + 2684,2861,2750,2862,2724,2812,2758,2859,2757,2750,2843,2759,2855,2714,2809,2726,2821,2743, + 2714,2871,2768,2868,2771,2852,2785,2881,2788,2787,2867,2786,2866,2759,2844,2743,2830,2768, + 2725,2885,2781,2884,2781,2871,2803,2901,2799,2804,2881,2798,2877,2770,2863,2755,2849,2780, + 2554,2710,2612,2700,2616,2690,2607,2683,2624,2629,2676,2623,2693,2604,2680,2569,2649,2614, + 2558,2712,2615,2703,2620,2697,2638,2717,2629,2634,2683,2627,2694,2607,2684,2598,2688,2621, + 2487,2628,2541,2619,2548,2616,2567,2626,2554,2560,2605,2553,2607,2534,2599,2525,2611,2548, + 2492,2625,2538,2616,2545,2617,2567,2618,2531,2561,2605,2552,2605,2531,2598,2524,2615,2527, + 2399,2515,2447,2508,2450,2506,2476,2508,2461,2466,2499,2461,2494,2437,2491,2433,2508,2457, + 2393,2510,2442,2501,2446,2503,2471,2502,2469,2465,2507,2458,2489,2433,2489,2430,2513,2450, + 2316,2419,2363,2414,2372,2418,2394,2413,2387,2386,2414,2377,2399,2354,2399,2352,2432,2370, + 2287,2391,2354,2404,2369,2415,2387,2407,2373,2360,2374,2365,2389,2344,2391,2342,2431,2363, + 2214,2303,2260,2294,2276,2306,2296,2295,2278,2286,2300,2272,2276,2251,2284,2252,2316,2270, + 2283,2365,2323,2419,2345,2376,2370,2379,2355,2360,2374,2341,2338,2316,2349,2317,2447,2344, + 2225,2304,2245,2634,2280,2300,2303,2304,2284,2278,2285,2254,2257,2247,2265,2262,2684,2285, + 2099,2175,2147,2528,2158,2167,2175,2165,2146,2149,2154,2145,2143,2128,2141,2145,2553,2157, + 2005,2144,2065,2312,2074,2119,2085,2137,2057,2055,2112,2055,2113,2044,2112,2059,2337,2060, + 1970,2107,2031,2273,2042,2082,2052,2081,2028,2018,2074,2021,2072,2011,2072,2029,2301,2026, + 1894,2019,1958,2188,1958,1983,1977,1992,1954,1938,1978,1940,1980,1924,1971,1954,2213,1948, + 1840,1957,1908,2127,1918,1929,1925,1929,1895,1888,1917,1891,1919,1886,1925,1907,2154,1896, + 1767,1872,1837,2045,1846,1845,1854,1844,1822,1813,1827,1815,1834,1814,1842,1836,2067,1818, + 1726,1830,1800,2004,1810,1802,1813,1791,1784,1772,1779,1776,1791,1776,1798,1796,2021,1777, + 1658,1750,1733,1929,1741,1722,1750,1719,1709,1701,1695,1704,1713,1709,1724,1737,1948,1706, + 1499,2086,1889,1954,1768,1745,1774,1735,1732,1720,1710,1724,1735,1732,1748,1762,1975,1461, + 3326,3789,3764,1741,1713,1721,1704,1695,1703,1796,1816,1835,1821,1834,2028,1708,1674,1383, +#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] = { + 3139,1330,1688,1440,3346, 317, 332, 292, 323,1349,1318,1352,1340,3378,2441,1738,1409,3295, + 1597,1975,1668,3268,2714,2532,2451,2506,2437,1371,1428,1391,1451,1643,1981,2759,3195,1715, + 1525,1852,1575,1659,1572,1652,1567,1645,1570,1552,1640,1570,1642,1565,1857,1558,1636,1566, + 1487,1806,1549,1626,1547,1620,1543,1615,1547,1514,1595,1546,1610,1541,1825,1532,1604,1541, + 1516,1836,1559,1637,1557,1632,1554,1628,1557,1541,1623,1556,1622,1551,1835,1543,1616,1551, + 1493,1808,1532,1605,1531,1601,1529,1597,1532,1517,1593,1531,1590,1525,1802,1516,1584,1528, + 1494,1810,1520,1590,1532,1602,1533,1599,1535,1521,1597,1520,1577,1528,1805,1520,1585,1528, + 1470,1710,1509,1575,1506,1560,1508,1569,1511,1496,1565,1510,1562,1501,1702,1493,1550,1501, + 1476,1583,1515,1582,1512,1567,1515,1578,1517,1503,1573,1516,1569,1507,1568,1499,1558,1508, + 1449,1548,1487,1550,1485,1534,1490,1545,1489,1484,1539,1489,1542,1478,1534,1472,1524,1480, + 1445,1541,1481,1541,1467,1514,1485,1539,1485,1481,1531,1485,1537,1461,1513,1468,1519,1477, + 1461,1546,1490,1544,1492,1536,1499,1551,1501,1501,1544,1500,1543,1486,1532,1477,1524,1491, + 1467,1553,1498,1553,1498,1546,1509,1562,1507,1510,1551,1507,1549,1492,1541,1483,1534,1497, + 1375,1459,1406,1454,1409,1448,1404,1445,1413,1416,1441,1413,1450,1402,1443,1383,1426,1407, + 1378,1460,1408,1455,1411,1452,1420,1463,1416,1418,1445,1414,1451,1404,1445,1399,1448,1411, + 1339,1415,1368,1410,1372,1409,1382,1414,1375,1379,1403,1375,1404,1365,1399,1360,1406,1372, + 1342,1414,1367,1408,1370,1409,1382,1410,1363,1379,1402,1374,1403,1363,1399,1359,1408,1361, + 1292,1354,1318,1350,1319,1349,1333,1350,1325,1328,1346,1325,1343,1312,1341,1310,1351,1323, + 1289,1351,1315,1347,1317,1348,1330,1347,1329,1327,1350,1324,1340,1310,1340,1308,1353,1319, + 1247,1302,1272,1300,1277,1302,1289,1299,1285,1285,1300,1280,1292,1267,1292,1266,1309,1276, + 1232,1288,1267,1295,1276,1300,1286,1296,1278,1271,1278,1274,1286,1262,1287,1261,1309,1272, + 1192,1240,1217,1235,1225,1242,1236,1236,1226,1231,1239,1224,1226,1212,1230,1213,1247,1222, + 1229,1273,1251,1302,1263,1279,1276,1281,1268,1271,1278,1261,1259,1247,1265,1248,1318,1262, + 1198,1241,1209,1418,1228,1239,1240,1241,1230,1227,1230,1214,1215,1210,1220,1218,1445,1231, + 1130,1171,1156,1361,1162,1167,1171,1166,1155,1157,1160,1155,1154,1146,1153,1155,1375,1161, + 1080,1155,1112,1245,1117,1141,1123,1151,1108,1107,1137,1107,1138,1100,1137,1109,1258,1109, + 1061,1134,1093,1224,1099,1121,1105,1120,1092,1087,1117,1088,1116,1083,1116,1093,1239,1091, + 1020,1087,1054,1178,1054,1068,1065,1072,1052,1044,1065,1044,1066,1036,1061,1052,1191,1049, + 991,1054,1028,1145,1033,1039,1036,1038,1020,1016,1032,1018,1033,1015,1037,1027,1160,1021, + 952,1008, 989,1101, 994, 993, 998, 993, 981, 976, 984, 977, 988, 977, 992, 989,1113, 979, + 929, 985, 969,1079, 975, 970, 976, 965, 960, 954, 958, 956, 964, 956, 968, 967,1088, 957, + 893, 942, 933,1039, 938, 927, 942, 926, 920, 916, 912, 918, 922, 920, 928, 935,1049, 918, + 807,1123,1017,1052, 952, 940, 955, 934, 932, 926, 921, 928, 934, 933, 941, 949,1063, 787, + 1791,2040,2027, 937, 922, 927, 918, 913, 917, 967, 978, 988, 981, 987,1092, 920, 901, 745, +#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] = { + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, + 1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700,1700, +#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] = { + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, + 700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700,700, +#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] = { + 116,114,119,109,112,106,104,106,103,108,110,108,110,117,113,115,111,113, + 117,115,118,111,113,111,114,114,109,110,115,114,112,113,112,118,116,119, + 115,113,116,110,112,109,108,108,107,108,113,111,110,111,110,116,111,115, + 116,114,117,112,114,110,109,110,108,109,114,111,111,112,111,117,113,116, + 115,113,116,111,113,110,108,109,107,108,112,111,110,112,111,117,112,116, + 116,115,118,112,114,111,110,110,108,109,114,112,112,113,112,118,114,117, + 114,112,115,110,112,108,107,108,106,107,111,110,110,111,110,116,111,115, + 115,114,117,112,113,110,109,109,108,109,113,111,111,112,111,117,113,116, + 115,113,116,111,113,110,109,109,108,109,113,111,111,112,111,117,112,116, + 117,115,118,113,115,112,111,111,110,112,115,112,112,114,113,118,114,117, + 114,112,115,110,112,109,109,109,107,113,112,110,110,112,110,117,112,115, + 115,112,116,111,113,110,109,109,108,114,112,110,111,112,111,117,112,115, + 117,115,118,113,115,112,111,113,110,118,113,112,113,115,113,119,115,118, + 114,112,116,110,113,110,109,112,108,115,110,110,111,112,111,117,112,115, + 116,113,117,112,114,111,111,113,109,117,112,111,112,114,112,118,114,117, + 116,113,117,112,114,111,110,112,109,116,112,111,111,114,112,118,113,116, + 117,114,119,113,115,112,111,113,110,117,114,112,112,115,113,119,115,117, + 115,112,116,110,112,110,109,110,108,114,111,109,110,112,111,116,112,114, + 116,113,118,112,114,111,111,112,110,116,113,111,112,114,112,118,114,116, + 116,113,117,112,114,111,111,111,110,115,113,111,111,114,112,117,113,115, + 118,115,119,114,115,113,113,113,111,117,114,112,113,115,113,119,115,117, + 116,112,117,111,113,110,110,111,109,114,112,110,111,113,112,117,113,115, + 117,113,118,112,114,111,111,112,109,115,112,111,111,114,112,117,114,116, + 119,115,120,114,116,114,113,115,111,115,113,113,114,117,115,120,116,118, + 117,113,118,112,114,112,112,113,110,112,111,111,111,115,113,118,114,116, + 119,114,119,113,114,113,112,115,111,112,112,112,112,115,114,119,116,119, + 119,114,118,113,114,112,112,114,110,111,111,111,112,114,114,119,115,119, + 121,116,120,114,116,114,114,116,112,113,113,113,114,116,115,121,117,120, + 118,113,117,112,113,111,111,113,109,110,110,110,111,114,113,119,115,118, + 120,115,119,114,115,113,113,115,111,112,112,112,113,116,114,120,117,119, + 119,115,119,113,114,113,114,115,111,111,112,111,113,115,114,120,117,119, + 121,116,121,115,116,114,116,117,113,113,114,113,114,117,115,122,119,121, + 115,112,116,113,114,112,115,114,110,111,111,111,112,115,113,120,116,118, + 115,114,120,114,115,112,110,111,110,107,113,113,110,111,111,120,116,118, +#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] = { + 63,61,64,59,60,57,56,57,55,58,59,58,59,63,61,62,60,61, + 63,62,63,60,61,60,61,61,59,59,62,61,60,61,60,64,62,64, + 62,61,62,59,60,59,58,58,58,58,61,60,59,60,59,62,60,62, + 62,61,63,60,61,59,59,59,58,58,61,60,60,61,60,63,61,63, + 62,61,63,60,61,59,58,59,58,58,60,60,59,60,60,63,60,62, + 63,62,63,60,61,60,59,59,58,59,61,60,60,61,60,64,61,63, + 61,60,62,59,60,58,58,58,57,58,60,59,59,60,59,62,60,62, + 62,61,63,60,61,59,59,59,58,59,61,60,60,60,60,63,61,63, + 62,61,63,60,61,59,59,59,58,58,61,60,60,60,60,63,61,62, + 63,62,63,61,62,60,60,60,59,61,62,60,61,61,61,64,61,63, + 62,60,62,59,60,59,58,59,58,61,60,59,59,60,59,63,60,62, + 62,61,62,60,61,59,59,59,58,61,60,59,60,60,60,63,60,62, + 63,62,64,61,62,60,60,61,59,63,61,60,61,62,61,64,62,63, + 61,60,62,59,61,59,59,60,58,62,59,59,60,60,60,63,60,62, + 62,61,63,60,61,60,60,61,59,63,60,60,60,61,60,63,61,63, + 62,61,63,60,61,60,59,60,59,62,60,60,60,61,60,63,61,62, + 63,62,64,61,62,60,60,61,59,63,61,60,61,62,61,64,62,63, + 62,60,63,59,61,59,59,59,58,61,60,59,59,60,60,63,60,61, + 63,61,63,60,61,60,60,60,59,63,61,60,60,61,60,63,61,62, + 63,61,63,60,61,60,60,60,59,62,61,60,60,61,61,63,61,62, + 64,62,64,61,62,61,61,61,60,63,61,60,61,62,61,64,62,63, + 62,60,63,60,61,59,59,60,58,62,61,59,60,61,60,63,61,62, + 63,61,63,60,61,60,60,61,59,62,60,60,60,61,60,63,61,62, + 64,62,65,61,62,61,61,62,60,62,61,61,61,63,62,65,63,64, + 63,61,63,60,61,60,60,61,59,60,60,60,60,62,61,63,62,63, + 64,61,64,61,61,61,61,62,60,60,60,60,61,62,61,64,62,64, + 64,61,64,61,61,60,61,61,59,60,60,60,60,62,61,64,62,64, + 65,62,65,62,62,61,61,62,60,61,61,61,61,63,62,65,63,65, + 64,61,63,60,61,60,60,61,59,59,59,59,60,61,61,64,62,63, + 64,62,64,61,62,61,61,62,60,60,60,60,61,62,62,65,63,64, + 64,62,64,61,62,61,61,62,60,60,60,60,61,62,61,65,63,64, + 65,62,65,62,63,62,63,63,61,61,61,61,61,63,62,66,64,65, + 62,60,62,61,61,60,62,61,59,60,60,60,60,62,61,64,63,64, + 62,61,64,61,62,60,59,60,59,58,61,61,59,60,60,65,62,63, +#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] = { + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, +#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] = { + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, + -50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50, +#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 */ -- 2.20.1