diff options
author | masonwang <masonwang@google.com> | 2021-07-27 09:54:47 +0800 |
---|---|---|
committer | masonwang <masonwang@google.com> | 2021-07-27 18:09:28 +0800 |
commit | cdc58ea5242971d8a7995f98627db5fe4d0a589b (patch) | |
tree | 06709fd11236509f378c50bd2f61b933f508bdce | |
parent | 23a3369a44f3378bb545aa7fca5fc770e262a519 (diff) | |
download | himax_touch-cdc58ea5242971d8a7995f98627db5fe4d0a589b.tar.gz |
touch/himax: upload initial touch driver.
This version is the initial version from vendor. I committed it
for a record.
Bug: 191845294
Test: It will cause build break, it will be fixed in later commit.
Signed-off-by: masonwang <masonwang@google.com>
Change-Id: Idff93c13bec9a6d60dff24b5d78c532273b24a52
-rw-r--r-- | Kbuild | 146 | ||||
-rw-r--r-- | Kconfig | 140 | ||||
-rw-r--r-- | Makefile | 24 | ||||
-rw-r--r-- | himax_common.c | 3547 | ||||
-rw-r--r-- | himax_common.h | 643 | ||||
-rw-r--r-- | himax_debug.c | 3485 | ||||
-rw-r--r-- | himax_debug.h | 240 | ||||
-rw-r--r-- | himax_debug_info.h | 98 | ||||
-rw-r--r-- | himax_ic_HX83102.c | 1616 | ||||
-rw-r--r-- | himax_ic_HX83102.h | 53 | ||||
-rw-r--r-- | himax_ic_core.h | 1020 | ||||
-rw-r--r-- | himax_ic_incell_core.c | 4585 | ||||
-rw-r--r-- | himax_inspection.c | 2853 | ||||
-rw-r--r-- | himax_inspection.h | 311 | ||||
-rw-r--r-- | himax_modular.h | 137 | ||||
-rw-r--r-- | himax_platform.c | 1321 | ||||
-rw-r--r-- | himax_platform.h | 142 |
17 files changed, 20361 insertions, 0 deletions
@@ -0,0 +1,146 @@ +# Makefile for the Himax touchscreen drivers. + +ccflags-y += -DBEFORE_KERNEL_5_10 + +ifneq ($(filter y, $(CONFIG_KALLSYMS_ALL)),) + ccflags-y += -D__KERNEL_KALLSYMS_ALL_ENABLED__ +endif + +ifneq ($(filter y, $(CONFIG_FB)),) + ccflags-y += -DHX_CONFIG_FB +endif + +ifneq ($(filter y, $(CONFIG_DRM)),) + ccflags-y += -DHX_CONFIG_DRM +endif + +ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + ccflags-y += -D__HIMAX_MOD__ +endif +# obj-y += himax_modular_table.o + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)),) + ccflags-y += -DCONFIG_TOUCHSCREEN_HIMAX_DEBUG + himax_mmi-objs += himax_debug.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_INSPECT)),) + ccflags-y += -DCONFIG_TOUCHSCREEN_HIMAX_INSPECT + himax_mmi-objs += himax_inspection.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_INCELL)),) + ccflags-y += -DCONFIG_TOUCHSCREEN_HIMAX_INCELL + himax_mmi-objs += himax_ic_incell_core.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_ONCELL)),) + himax_mmi-objs += himax_ic_oncell_core.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xG)),) + ccflags-y += -D__HIMAX_HX852xG_MOD__ + himax_mmi-objs += himax_ic_HX852xG.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xH)),) + ccflags-y += -D__HIMAX_HX852xH_MOD__ + himax_mmi-objs += himax_ic_HX852xH.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xJ)),) + ccflags-y += -D__HIMAX_HX852xJ_MOD__ + himax_mmi-objs += himax_ic_HX852xJ.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83102)),) + ccflags-y += -DCONFIG_TOUCHSCREEN_HIMAX_IC_HX83102 + ccflags-y += -D__HIMAX_HX83102_MOD__ + himax_mmi-objs += himax_ic_HX83102.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83121)),) + ccflags-y += -D__HIMAX_HX83121_MOD__ + himax_mmi-objs += himax_ic_HX83121.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83103)),) + ccflags-y += -D__HIMAX_HX83103_MOD__ + himax_mmi-objs += himax_ic_HX83103.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83106)),) + ccflags-y += -D__HIMAX_HX83106_MOD__ + himax_mmi-objs += himax_ic_HX83106.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83108)),) + ccflags-y += -D__HIMAX_HX83108_MOD__ + himax_mmi-objs += himax_ic_HX83108.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83111)),) + ccflags-y += -D__HIMAX_HX83111_MOD__ + himax_mmi-objs += himax_ic_HX83111.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112)),) + ccflags-y += -D__HIMAX_HX83112_MOD__ + himax_mmi-objs += himax_ic_HX83112.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83113)),) + ccflags-y += -D__HIMAX_HX83113_MOD__ + himax_mmi-objs += himax_ic_HX83113.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83191)),) + ccflags-y += -D__HIMAX_HX83191_MOD__ + himax_mmi-objs += himax_ic_HX83191.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83192)),) + ccflags-y += -D__HIMAX_HX83192_MOD__ + himax_mmi-objs += himax_ic_HX83192.o +endif + +ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + ccflags-y += -D__HIMAX_MOD__ + himax_mmi-objs += himax_common.o + himax_mmi-objs += himax_platform.o + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE)),) + himax_mmi-objs += Himax_firmware.o + endif + obj-m += himax_mmi.o +endif +ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + himax_mmi-objs += himax_common.o + himax_mmi-objs += himax_platform.o + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE)),) + himax_mmi-objs += Himax_firmware.o + endif + obj-y += himax_mmi.o +endif + +ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE)),) +ccflags-y += -D__EMBEDDED_FW__ + +ld_array_start_str = _binary_$(srctree)/$(src)_Himax_firmware_bin_start +ld_array_start_sym = $(subst -,_,$(subst .,_,$(subst /,_,$(ld_array_start_str)))) +obj_array_start_sym = _binary___Himax_firmware_bin_start + +ld_array_size_str = _binary_$(srctree)/$(src)_Himax_firmware_bin_size +ld_array_size_sym = $(subst -,_,$(subst .,_,$(subst /,_,$(ld_array_size_str)))) +obj_array_size_sym = _binary___Himax_firmware_bin_size + +ld_array_end_str = _binary_$(srctree)/$(src)_Himax_firmware_bin_end +ld_array_end_sym = $(subst -,_,$(subst .,_,$(subst /,_,$(ld_array_end_str)))) +obj_array_end_sym = _binary___Himax_firmware_bin_end + +$(src)/Himax_firmware.o: $(src)/Himax_firmware.bin FORCE + $(LD) $(LDFLAGS) -r -b binary $(srctree)/$(src)/Himax_firmware.bin -o $(objtree)/$(obj)/Himax_firmware.o + $(OBJCOPY) --redefine-sym $(ld_array_start_sym)=$(obj_array_start_sym) $(objtree)/$(obj)/Himax_firmware.o + $(OBJCOPY) --redefine-sym $(ld_array_size_sym)=$(obj_array_size_sym) $(objtree)/$(obj)/Himax_firmware.o + $(OBJCOPY) --redefine-sym $(ld_array_end_sym)=$(obj_array_end_sym) $(objtree)/$(obj)/Himax_firmware.o + +endif @@ -0,0 +1,140 @@ +# +# Himax Touchscreen driver configuration +# + ++config TOUCHSCREEN_HIMAX_COMMON + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + This enables support for HIMAX CHIPSET touchscreens. + ++choice + prompt "HIMAX touch IC types" + depends on TOUCHSCREEN_HIMAX_COMMON + default TOUCHSCREEN_HIMAX_INCELL + ++config TOUCHSCREEN_HIMAX_ONCELL + bool "HIMAX chipset on-cell function" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for HIMAX CHIPSET of on-cell function. + ++config TOUCHSCREEN_HIMAX_INCELL + bool "HIMAX chipset in-cell function" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for HIMAX CHIPSET of in-cell function. + +endchoice + +# ***************** On-cell Start ***************** ++config TOUCHSCREEN_HIMAX_IC_HX852xH + tristate "HIMAX chipset HX852xH function" + depends on TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX CHIPSET of HX852xH. + ++config TOUCHSCREEN_HIMAX_IC_HX852xG + tristate "HIMAX chipset HX852xG function" + depends on TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX CHIPSET of HX852xG. + ++config TOUCHSCREEN_HIMAX_IC_HX852xJ + tristate "HIMAX chipset HX852xJ function" + depends on TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX CHIPSET of HX852xJ. + +# ***************** On-cell End ******************* +# ***************** In-cell Start ***************** ++config TOUCHSCREEN_HIMAX_IC_HX83192 + tristate "HIMAX chipset HX83192 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83192. + ++config TOUCHSCREEN_HIMAX_IC_HX83191 + tristate "HIMAX chipset HX83191 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83191. + ++config TOUCHSCREEN_HIMAX_IC_HX83113 + tristate "HIMAX chipset HX83113 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83113. + ++config TOUCHSCREEN_HIMAX_IC_HX83112 + tristate "HIMAX chipset HX83112 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83112. + ++config TOUCHSCREEN_HIMAX_IC_HX83111 + tristate "HIMAX chipset HX83111 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83111. + ++config TOUCHSCREEN_HIMAX_IC_HX83106 + tristate "HIMAX chipset HX83106 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83106. + ++config TOUCHSCREEN_HIMAX_IC_HX83108 + tristate "HIMAX chipset HX83108 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83108. + ++config TOUCHSCREEN_HIMAX_IC_HX83103 + tristate "HIMAX chipset HX83103 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83103. + ++config TOUCHSCREEN_HIMAX_IC_HX83102 + tristate "HIMAX chipset HX83102 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83102. + ++config TOUCHSCREEN_HIMAX_IC_HX83121 + tristate "HIMAX chipset HX83121 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83121. + +# ***************** In-cell End ******************* + ++config TOUCHSCREEN_HIMAX_DEBUG + bool "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_INCELL || TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX debug function. ++config TOUCHSCREEN_HIMAX_INSPECT + bool "HIMAX inspect function" + depends on TOUCHSCREEN_HIMAX_INCELL || TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX inspect function. + ++config TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE + bool "HIMAX embedded firmware function" + depends on TOUCHSCREEN_HIMAX_INCELL || TOUCHSCREEN_HIMAX_ONCELL + help + This enables built-in FW inside kernel as binary array + ++config HMX_DB + bool "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for HIMAX driver test over Dragon Board. + ++config HIMAX_SUPPORT_KERNEL_419 + bool "HIMAX support kernel 4.19" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for support kernel 4.19. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7726687 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build +M ?= $(shell pwd) + +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_HIMAX_COMMON=m +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_HIMAX_INSPECT=y +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_HIMAX_IC_HX83102=y + +EXTRA_CFLAGS += -DDYNAMIC_DEBUG_MODULE +EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_TBN +EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_HEATMAP +EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_OFFLOAD +EXTRA_CFLAGS += -I$(KERNEL_SRC)/../google-modules/display +EXTRA_CFLAGS += -I$(KERNEL_SRC)/../google-modules/touch/common +EXTRA_CFLAGS += -I$(KERNEL_SRC)/../google-modules/touch/common/include +EXTRA_SYMBOLS += $(OUT_DIR)/../google-modules/touch/common/Module.symvers + +modules modules_install clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) \ + $(KBUILD_OPTIONS) \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" \ + $(@) diff --git a/himax_common.c b/himax_common.c new file mode 100644 index 0000000..7b4584c --- /dev/null +++ b/himax_common.c @@ -0,0 +1,3547 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*#include "himax_common.h"*/ +/*#include "himax_ic_core.h"*/ +#include "himax_inspection.h" +#include "himax_modular.h" + +#if defined(__HIMAX_MOD__) +int (*hx_msm_drm_register_client)(struct notifier_block *nb); +int (*hx_msm_drm_unregister_client)(struct notifier_block *nb); +#endif + +#if defined(HX_SMART_WAKEUP) +#define GEST_SUP_NUM 26 +/* Setting cust key define (DF = double finger) */ +/* {Double Tap, Up, Down, Left, Right, C, Z, M, + * O, S, V, W, e, m, @, (reserve), + * Finger gesture, ^, >, <, f(R), f(L), Up(DF), Down(DF), + * Left(DF), Right(DF)} + */ +uint8_t gest_event[GEST_SUP_NUM] = { + 0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x81, 0x1D, 0x2D, 0x3D, 0x1F, 0x2F, 0x51, 0x52, + 0x53, 0x54}; + +/*gest_event mapping to gest_key_def*/ +uint16_t gest_key_def[GEST_SUP_NUM] = { + HX_KEY_DOUBLE_CLICK, HX_KEY_UP, HX_KEY_DOWN, HX_KEY_LEFT, + HX_KEY_RIGHT, HX_KEY_C, HX_KEY_Z, HX_KEY_M, + HX_KEY_O, HX_KEY_S, HX_KEY_V, HX_KEY_W, + HX_KEY_E, HX_KEY_LC_M, HX_KEY_AT, HX_KEY_RESERVE, + HX_KEY_FINGER_GEST, HX_KEY_V_DOWN, HX_KEY_V_LEFT, HX_KEY_V_RIGHT, + HX_KEY_F_RIGHT, HX_KEY_F_LEFT, HX_KEY_DF_UP, HX_KEY_DF_DOWN, + HX_KEY_DF_LEFT, HX_KEY_DF_RIGHT}; + +uint8_t *wake_event_buffer; +#endif + + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (5000) +#define FRAME_COUNT 5 + +#if defined(HX_TP_PROC_GUEST_INFO) +struct hx_guest_info *g_guest_info_data; +EXPORT_SYMBOL(g_guest_info_data); + +char *g_guest_info_item[] = { + "projectID", + "CGColor", + "BarCode", + "Reserve1", + "Reserve2", + "Reserve3", + "Reserve4", + "Reserve5", + "VCOM", + "Vcom-3Gar", + NULL +}; +#endif + +uint32_t g_hx_chip_inited; + +#if defined(__EMBEDDED_FW__) +struct firmware g_embedded_fw = { + .data = _binary___Himax_firmware_bin_start, +}; +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +bool g_boot_upgrade_flag; +const struct firmware *hxfw; +int g_i_FW_VER; +int g_i_CFG_VER; +int g_i_CID_MAJ; /*GUEST ID*/ +int g_i_CID_MIN; /*VER for GUEST*/ +#if defined(HX_ZERO_FLASH) +int g_f_0f_updat; +#endif +#ifdef HX_PARSE_FROM_DT +char *g_fw_boot_upgrade_name; +EXPORT_SYMBOL(g_fw_boot_upgrade_name); +#if defined(HX_ZERO_FLASH) +char *g_fw_mp_upgrade_name; +EXPORT_SYMBOL(g_fw_mp_upgrade_name); +#endif +#else +char *g_fw_boot_upgrade_name = BOOT_UPGRADE_FWNAME; +EXPORT_SYMBOL(g_fw_boot_upgrade_name); +#if defined(HX_ZERO_FLASH) +char *g_fw_mp_upgrade_name = MPAP_FWNAME; +EXPORT_SYMBOL(g_fw_mp_upgrade_name); +#endif +#endif +#endif + +#ifdef HX_PARSE_FROM_DT +uint32_t g_proj_id = 0xffff; +EXPORT_SYMBOL(g_proj_id); +#endif + +struct himax_ts_data *private_ts; +EXPORT_SYMBOL(private_ts); + +struct himax_ic_data *ic_data; +EXPORT_SYMBOL(ic_data); + +struct himax_report_data *hx_touch_data; +EXPORT_SYMBOL(hx_touch_data); + +struct himax_core_fp g_core_fp; +EXPORT_SYMBOL(g_core_fp); + +struct himax_debug *debug_data; +EXPORT_SYMBOL(debug_data); + +struct proc_dir_entry *himax_touch_proc_dir; +EXPORT_SYMBOL(himax_touch_proc_dir); + +int g_mmi_refcnt; +EXPORT_SYMBOL(g_mmi_refcnt); + +#define HIMAX_PROC_TOUCH_FOLDER "android_touch" +/*ts_work about start*/ +struct himax_target_report_data *g_target_report_data; +EXPORT_SYMBOL(g_target_report_data); + +static void himax_report_all_leave_event(struct himax_ts_data *ts); +/*ts_work about end*/ + +struct filename* (*kp_getname_kernel)(const char *filename); +void (*kp_putname_kernel)(struct filename *name); +struct file* (*kp_file_open_name)(struct filename *name, + int flags, umode_t mode); + +unsigned long FW_VER_MAJ_FLASH_ADDR; +EXPORT_SYMBOL(FW_VER_MAJ_FLASH_ADDR); + +unsigned long FW_VER_MIN_FLASH_ADDR; +EXPORT_SYMBOL(FW_VER_MIN_FLASH_ADDR); + +unsigned long CFG_VER_MAJ_FLASH_ADDR; +EXPORT_SYMBOL(CFG_VER_MAJ_FLASH_ADDR); + +unsigned long CFG_VER_MIN_FLASH_ADDR; +EXPORT_SYMBOL(CFG_VER_MIN_FLASH_ADDR); + +unsigned long CID_VER_MAJ_FLASH_ADDR; +EXPORT_SYMBOL(CID_VER_MAJ_FLASH_ADDR); + +unsigned long CID_VER_MIN_FLASH_ADDR; +EXPORT_SYMBOL(CID_VER_MIN_FLASH_ADDR); +/*unsigned long PANEL_VERSION_ADDR;*/ +uint32_t CFG_TABLE_FLASH_ADDR; +EXPORT_SYMBOL(CFG_TABLE_FLASH_ADDR); + +uint32_t CFG_TABLE_FLASH_ADDR_T; +EXPORT_SYMBOL(CFG_TABLE_FLASH_ADDR_T); + +unsigned char IC_CHECKSUM; +EXPORT_SYMBOL(IC_CHECKSUM); + +#if defined(HX_EXCP_RECOVERY) +u8 HX_EXCP_RESET_ACTIVATE; +EXPORT_SYMBOL(HX_EXCP_RESET_ACTIVATE); + +int hx_EB_event_flag; +EXPORT_SYMBOL(hx_EB_event_flag); + +int hx_EC_event_flag; +EXPORT_SYMBOL(hx_EC_event_flag); + +#if defined(HW_ED_EXCP_EVENT) +int hx_EE_event_flag; +EXPORT_SYMBOL(hx_EE_event_flag); +#else +int hx_ED_event_flag; +EXPORT_SYMBOL(hx_ED_event_flag); +#endif + +int g_zero_event_count; + +#endif + +static bool chip_test_r_flag; +u8 HX_HW_RESET_ACTIVATE; + +static uint8_t AA_press; +static uint8_t EN_NoiseFilter; +static uint8_t Last_EN_NoiseFilter; + +static int p_point_num = 0xFFFF; +static uint8_t p_stylus_num = 0xFF; +static int probe_fail_flag; +#if defined(HX_USB_DETECT_GLOBAL) +bool USB_detect_flag; +#endif + +#if defined(HX_GESTURE_TRACK) +static int gest_pt_cnt; +static int gest_pt_x[GEST_PT_MAX_NUM]; +static int gest_pt_y[GEST_PT_MAX_NUM]; +static int gest_start_x, gest_start_y, gest_end_x, gest_end_y; +static int gest_width, gest_height, gest_mid_x, gest_mid_y; +static int hx_gesture_coor[16]; +#endif + +int g_ts_dbg; +EXPORT_SYMBOL(g_ts_dbg); + +/* File node for Selftest, SMWP and HSEN - Start*/ +#define HIMAX_PROC_SELF_TEST_FILE "self_test" +struct proc_dir_entry *himax_proc_self_test_file; + +uint8_t HX_PROC_SEND_FLAG; +EXPORT_SYMBOL(HX_PROC_SEND_FLAG); + +#if defined(HX_SMART_WAKEUP) +#define HIMAX_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *himax_proc_SMWP_file; +#define HIMAX_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *himax_proc_GESTURE_file; +uint8_t HX_SMWP_EN; +#if defined(HX_ULTRA_LOW_POWER) +#define HIMAX_PROC_PSENSOR_FILE "Psensor" +struct proc_dir_entry *himax_proc_psensor_file; +#endif +#endif + +#if defined(HX_HIGH_SENSE) +#define HIMAX_PROC_HSEN_FILE "HSEN" +struct proc_dir_entry *himax_proc_HSEN_file; +#endif + +#define HIMAX_PROC_VENDOR_FILE "vendor" +struct proc_dir_entry *himax_proc_vendor_file; + +#if defined(HX_PALM_REPORT) +static int himax_palm_detect(uint8_t *buf) +{ + struct himax_ts_data *ts = private_ts; + int32_t i; + int base = 0; + int x = 0, y = 0, w = 0; + + i = 0; + base = i * 4; + x = buf[base] << 8 | buf[base + 1]; + y = (buf[base + 2] << 8 | buf[base + 3]); + w = buf[(ts->nFinger_support * 4) + i]; + I(" %s HX_PALM_REPORT_loopi=%d,base=%x,X=%x,Y=%x,W=%x\n", + __func__, i, base, x, y, w); + if ((!atomic_read(&ts->suspend_mode)) + && (x == 0xFA5A) + && (y == 0xFA5A) + && (w == 0x00)) + return PALM_REPORT; + else + return NOT_REPORT; +} +#endif + +static ssize_t himax_self_test(struct seq_file *s, void *v) +{ + int val = 0x00; + size_t ret = 0; + + I("%s: enter, %d\n", __func__, __LINE__); + + if (private_ts->suspended == 1) { + E("%s: please do self test in normal active mode\n", __func__); + return HX_INIT_FAIL; + } + + if (private_ts->in_self_test == 1) { + W("%s: Self test is running now!\n", __func__); + return ret; + } + private_ts->in_self_test = 1; + + himax_int_enable(0);/* disable irq */ + + val = g_core_fp.fp_chip_self_test(s, v); +/* + *#if defined(HX_EXCP_RECOVERY) + * HX_EXCP_RESET_ACTIVATE = 1; + *#endif + * himax_int_enable(1); //enable irq + */ + +#if defined(HX_EXCP_RECOVERY) + HX_EXCP_RESET_ACTIVATE = 1; +#endif + himax_int_enable(1); + + private_ts->in_self_test = 0; + + return ret; +} + +static void *himax_self_test_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) + return NULL; + + + return (void *)((unsigned long) *pos + 1); +} + +static void *himax_self_test_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} + +static void himax_self_test_seq_stop(struct seq_file *s, void *v) +{ +} + +static int himax_self_test_seq_read(struct seq_file *s, void *v) +{ + size_t ret = 0; + + if (chip_test_r_flag) { +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + if (g_rslt_data) + seq_printf(s, "%s", g_rslt_data); + else +#endif + seq_puts(s, "No chip test data.\n"); + } else { + himax_self_test(s, v); + } + + return ret; +} + +static const struct seq_operations himax_self_test_seq_ops = { + .start = himax_self_test_seq_start, + .next = himax_self_test_seq_next, + .stop = himax_self_test_seq_stop, + .show = himax_self_test_seq_read, +}; + +static int himax_self_test_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_self_test_seq_ops); +}; + +static ssize_t himax_self_test_write(struct file *filp, const char __user *buff, + size_t len, loff_t *data) +{ + char buf[80]; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == 'r') { + chip_test_r_flag = true; + I("%s: Start to read chip test data.\n", __func__); + } else { + chip_test_r_flag = false; + I("%s: Back to do self test.\n", __func__); + } + + return len; +} + +#if defined(KERNEL_VER_ABOVE_5_10) +static const struct proc_ops himax_proc_self_test_ops = { + .proc_open = himax_self_test_proc_open, + .proc_read = seq_read, + .proc_write = himax_self_test_write, + .proc_release = seq_release, +}; +#else +static const struct file_operations himax_proc_self_test_ops = { + .owner = THIS_MODULE, + .open = himax_self_test_proc_open, + .read = seq_read, + .write = himax_self_test_write, + .release = seq_release, +}; +#endif + +#if defined(HX_HIGH_SENSE) +static ssize_t himax_HSEN_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t count = 0; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + count = snprintf(temp_buf, PAGE_SIZE, "%d\n", + ts->HSEN_enable); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + } + + return count; +} + +static ssize_t himax_HSEN_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->HSEN_enable = 0; + else if (buf[0] == '1') + ts->HSEN_enable = 1; + else + return -EINVAL; + + g_core_fp.fp_set_HSEN_enable(ts->HSEN_enable, ts->suspended); + I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); + return len; +} + +#if defined(KERNEL_VER_ABOVE_5_10) +static const struct proc_ops himax_proc_HSEN_ops = { + .proc_read = himax_HSEN_read, + .proc_write = himax_HSEN_write, +}; +#else +static const struct file_operations himax_proc_HSEN_ops = { + .owner = THIS_MODULE, + .read = himax_HSEN_read, + .write = himax_HSEN_write, +}; +#endif +#endif + +#if defined(HX_SMART_WAKEUP) +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + count = snprintf(temp_buf, PAGE_SIZE, "%d\n", + ts->SMWP_enable); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + } + + return count; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->SMWP_enable = 0; + else if (buf[0] == '1') + ts->SMWP_enable = 1; + else + return -EINVAL; + + g_core_fp.fp_set_SMWP_enable(ts->SMWP_enable, ts->suspended); + HX_SMWP_EN = ts->SMWP_enable; + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); + return len; +} + +#if defined(KERNEL_VER_ABOVE_5_10) +static const struct proc_ops himax_proc_SMWP_ops = { + .proc_read = himax_SMWP_read, + .proc_write = himax_SMWP_write, +}; +#else +static const struct file_operations himax_proc_SMWP_ops = { + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; +#endif + +static ssize_t himax_GESTURE_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + size_t ret = 0; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + for (i = 0; i < GEST_SUP_NUM; i++) + ret += snprintf(temp_buf + ret, len - ret, + "ges_en[%d]=%d\n", + i, ts->gesture_cust_en[i]); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + int j = 0; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + I("himax_GESTURE_store= %s, len = %d\n", buf, (int)len); + + for (i = 0; i < len; i++) { + if (buf[i] == '0' && j < GEST_SUP_NUM) { + ts->gesture_cust_en[j] = 0; + I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]); + j++; + } else if (buf[i] == '1' && j < GEST_SUP_NUM) { + ts->gesture_cust_en[j] = 1; + I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]); + j++; + } else + I("Not 0/1 or >=GEST_SUP_NUM : buf[%d] = %c\n", + i, buf[i]); + } + + return len; +} + +#if defined(KERNEL_VER_ABOVE_5_10) +static const struct proc_ops himax_proc_Gesture_ops = { + .proc_read = himax_GESTURE_read, + .proc_write = himax_GESTURE_write, +}; +#else +static const struct file_operations himax_proc_Gesture_ops = { + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; +#endif + +#if defined(HX_ULTRA_LOW_POWER) +static ssize_t himax_psensor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + count = snprintf(temp_buf, PAGE_SIZE, + "p-sensor flag = %d\n", + ts->psensor_flag); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + } + + return count; +} + +static ssize_t himax_psensor_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0' && ts->SMWP_enable == 1) { + ts->psensor_flag = false; + g_core_fp.fp_black_gest_ctrl(false); + } else if (buf[0] == '1' && ts->SMWP_enable == 1) { + ts->psensor_flag = true; + g_core_fp.fp_black_gest_ctrl(true); + } else if (ts->SMWP_enable == 0) { + I("%s: SMWP is disable, not supprot to ctrl p-sensor.\n", + __func__); + } else + return -EINVAL; + + I("%s: psensor_flag = %d.\n", __func__, ts->psensor_flag); + return len; +} + +#if defined(KERNEL_VER_ABOVE_5_10) +static const struct proc_ops himax_proc_psensor_ops = { + .proc_read = himax_psensor_read, + .proc_write = himax_psensor_write, +}; +#else +static const struct file_operations himax_proc_psensor_ops = { + .owner = THIS_MODULE, + .read = himax_psensor_read, + .write = himax_psensor_write, +}; +#endif + +#endif +#endif + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + ret += snprintf(temp_buf + ret, len - ret, + "IC = %s\n", private_ts->chip_name); + + ret += snprintf(temp_buf + ret, len - ret, + "FW_VER = 0x%2.2X\n", ic_data->vendor_fw_ver); + + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) { + ret += snprintf(temp_buf + ret, len - ret, + "CONFIG_VER = 0x%2.2X\n", + ic_data->vendor_config_ver); + } else { + ret += snprintf(temp_buf + ret, len - ret, + "TOUCH_VER = 0x%2.2X\n", + ic_data->vendor_touch_cfg_ver); + ret += snprintf(temp_buf + ret, len - ret, + "DISPLAY_VER = 0x%2.2X\n", + ic_data->vendor_display_cfg_ver); + } + + if (ic_data->vendor_cid_maj_ver < 0 + && ic_data->vendor_cid_min_ver < 0) { + ret += snprintf(temp_buf + ret, len - ret, + "CID_VER = NULL\n"); + } else { + ret += snprintf(temp_buf + ret, len - ret, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + } + + if (ic_data->vendor_panel_ver < 0) { + ret += snprintf(temp_buf + ret, len - ret, + "PANEL_VER = NULL\n"); + } else { + ret += snprintf(temp_buf + ret, len - ret, + "PANEL_VER = 0x%2.2X\n", + ic_data->vendor_panel_ver); + } + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + ret += snprintf(temp_buf + ret, len - ret, + "Cusomer = %s\n", + ic_data->vendor_cus_info); + ret += snprintf(temp_buf + ret, len - ret, + "Project = %s\n", + ic_data->vendor_proj_info); + } + ret += snprintf(temp_buf + ret, len - ret, "\n"); + ret += snprintf(temp_buf + ret, len - ret, + "Himax Touch Driver Version:\n"); + ret += snprintf(temp_buf + ret, len - ret, "%s\n", + HIMAX_DRIVER_VER); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + } + + return ret; +} +#if defined(KERNEL_VER_ABOVE_5_10) +static const struct proc_ops himax_proc_vendor_ops = { + .proc_read = himax_vendor_read, +}; +#else +static const struct file_operations himax_proc_vendor_ops = { + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; +#endif + +int himax_common_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL); + + if (himax_touch_proc_dir == NULL) { + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + if (fp_himax_self_test_init != NULL) + fp_himax_self_test_init(); +#endif + + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, 0444, + himax_touch_proc_dir, &himax_proc_self_test_ops); + if (himax_proc_self_test_file == NULL) { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_1; + } + +#if defined(HX_HIGH_SENSE) + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, 0666, + himax_touch_proc_dir, &himax_proc_HSEN_ops); + + if (himax_proc_HSEN_file == NULL) { + E(" %s: proc HSEN file create failed!\n", __func__); + goto fail_2; + } + +#endif +#if defined(HX_SMART_WAKEUP) + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, 0666, + himax_touch_proc_dir, &himax_proc_SMWP_ops); + + if (himax_proc_SMWP_file == NULL) { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, 0666, + himax_touch_proc_dir, &himax_proc_Gesture_ops); + + if (himax_proc_GESTURE_file == NULL) { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_4; + } +#if defined(HX_ULTRA_LOW_POWER) + himax_proc_psensor_file = proc_create(HIMAX_PROC_PSENSOR_FILE, 0666, + himax_touch_proc_dir, &himax_proc_psensor_ops); + + if (himax_proc_psensor_file == NULL) { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_5; + } +#endif +#endif + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, 0444, + himax_touch_proc_dir, &himax_proc_vendor_ops); + if (himax_proc_vendor_file == NULL) { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_6; + } + + return 0; + + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +fail_6: +#if defined(HX_SMART_WAKEUP) +#if defined(HX_ULTRA_LOW_POWER) + remove_proc_entry(HIMAX_PROC_PSENSOR_FILE, himax_touch_proc_dir); +fail_5: +#endif + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); +fail_4: + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +fail_3: +#endif +#if defined(HX_HIGH_SENSE) + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +fail_2: +#endif + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +fail_1: + return -ENOMEM; +} + +void himax_common_proc_deinit(void) +{ + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +#if defined(HX_SMART_WAKEUP) +#if defined(HX_ULTRA_LOW_POWER) + remove_proc_entry(HIMAX_PROC_PSENSOR_FILE, himax_touch_proc_dir); +#endif + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +#endif +#if defined(HX_HIGH_SENSE) + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +#endif + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); + + remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); +} + +/* File node for SMWP and HSEN - End*/ + +void himax_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len) +{ + /*I("%s: Entering!\n", __func__);*/ + + switch (len) { + case 1: + cmd[0] = addr; + /*I("%s: cmd[0] = 0x%02X\n", __func__, cmd[0]);*/ + break; + + case 2: + cmd[0] = addr & 0xFF; + cmd[1] = (addr >> 8) & 0xFF; + /*I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X\n",*/ + /* __func__, cmd[0], cmd[1]);*/ + break; + + case 4: + cmd[0] = addr & 0xFF; + cmd[1] = (addr >> 8) & 0xFF; + cmd[2] = (addr >> 16) & 0xFF; + cmd[3] = (addr >> 24) & 0xFF; + /* I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X,*/ + /*cmd[2] = 0x%02X,cmd[3] = 0x%02X\n", */ + /* __func__, cmd[0], cmd[1], cmd[2], cmd[3]);*/ + break; + + default: + E("%s: input length fault,len = %d!\n", __func__, len); + } +} +EXPORT_SYMBOL(himax_parse_assign_cmd); + +int himax_input_register(struct himax_ts_data *ts) +{ + int ret = 0; +#if defined(HX_SMART_WAKEUP) + int i = 0; +#endif + ret = himax_dev_set(ts); + if (ret < 0) { + I("%s, input device register fail!\n", __func__); + return INPUT_REGISTER_FAIL; + } + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); + +#if defined(HX_SMART_WAKEUP) + for (i = 0; i < GEST_SUP_NUM; i++) + set_bit(gest_key_def[i], ts->input_dev->keybit); +#elif defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) || defined(HX_PALM_REPORT) + set_bit(KEY_POWER, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + set_bit(KEY_APPSELECT, ts->input_dev->keybit); + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); +#if defined(HX_PROTOCOL_A) + /*ts->input_dev->mtsize = ts->nFinger_support;*/ + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 1, 10, 0, 0); +#else + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); +#if defined(HX_PROTOCOL_B_3PA) + input_mt_init_slots(ts->input_dev, ts->nFinger_support, + INPUT_MT_DIRECT); +#else + input_mt_init_slots(ts->input_dev, ts->nFinger_support); +#endif +#endif + I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, + ts->pdata->abs_x_max, + ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + ts->pdata->abs_y_min, ts->pdata->abs_y_max, + ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + ts->pdata->abs_pressure_min, + ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); +#if !defined(HX_PROTOCOL_A) + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, + ts->pdata->abs_pressure_min, + ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + ts->pdata->abs_width_min, + ts->pdata->abs_width_max, + ts->pdata->abs_pressure_fuzz, 0); +#endif +/* input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0,*/ +/* ((ts->pdata->abs_pressure_max << 16)*/ +/* | ts->pdata->abs_width_max),*/ +/* 0, 0);*/ +/* input_set_abs_params(ts->input_dev, ABS_MT_POSITION,*/ +/* 0, (BIT(31)*/ +/* | (ts->pdata->abs_x_max << 16)*/ +/* | ts->pdata->abs_y_max),*/ +/* 0, 0);*/ + + if (himax_input_register_device(ts->input_dev) == 0) { + ret = NO_ERR; + } else { + E("%s: input register fail\n", __func__); + input_free_device(ts->input_dev); + return INPUT_REGISTER_FAIL; + } + + if (!ic_data->HX_STYLUS_FUNC) + goto skip_stylus_operation; + + set_bit(EV_SYN, ts->stylus_dev->evbit); + set_bit(EV_ABS, ts->stylus_dev->evbit); + set_bit(EV_KEY, ts->stylus_dev->evbit); + set_bit(BTN_TOUCH, ts->stylus_dev->keybit); + set_bit(INPUT_PROP_DIRECT, ts->stylus_dev->propbit); + + set_bit(BTN_TOOL_PEN, ts->stylus_dev->keybit); + set_bit(BTN_TOOL_RUBBER, ts->stylus_dev->keybit); + + input_set_abs_params(ts->stylus_dev, ABS_PRESSURE, 0, 4095, 0, 0); + input_set_abs_params(ts->stylus_dev, ABS_DISTANCE, 0, 1, 0, 0); + input_set_abs_params(ts->stylus_dev, ABS_TILT_X, -60, 60, 0, 0); + input_set_abs_params(ts->stylus_dev, ABS_TILT_Y, -60, 60, 0, 0); + /*input_set_capability(ts->hx_pen_dev, EV_SW, SW_PEN_INSERT);*/ + input_set_capability(ts->stylus_dev, EV_KEY, BTN_TOUCH); + input_set_capability(ts->stylus_dev, EV_KEY, BTN_STYLUS); + input_set_capability(ts->stylus_dev, EV_KEY, BTN_STYLUS2); + + input_set_abs_params(ts->stylus_dev, ABS_X, ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->stylus_dev, ABS_Y, ts->pdata->abs_y_min, + ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + + if (himax_input_register_device(ts->stylus_dev) == 0) { + ret = NO_ERR; + } else { + E("%s: input register stylus fail\n", __func__); + input_unregister_device(ts->input_dev); + input_free_device(ts->stylus_dev); + return INPUT_REGISTER_FAIL; + } + +skip_stylus_operation: + + I("%s, input device registered.\n", __func__); + + return ret; +} +EXPORT_SYMBOL(himax_input_register); + +#if defined(HX_BOOT_UPGRADE) +static int himax_get_fw_ver_bin(void) +{ + I("%s: use default incell address.\n", __func__); + if (hxfw != NULL) { + I("Catch fw version in bin file!\n"); + g_i_FW_VER = (hxfw->data[FW_VER_MAJ_FLASH_ADDR] << 8) + | hxfw->data[FW_VER_MIN_FLASH_ADDR]; +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) + g_i_CFG_VER = (hxfw->data[CFG_VER_MAJ_FLASH_ADDR] << 8) + | hxfw->data[CFG_VER_MIN_FLASH_ADDR]; +#else + g_i_CFG_VER = hxfw->data[CFG_VER_MAJ_FLASH_ADDR]; +#endif + g_i_CID_MAJ = hxfw->data[CID_VER_MAJ_FLASH_ADDR]; + g_i_CID_MIN = hxfw->data[CID_VER_MIN_FLASH_ADDR]; + } else { + I("FW data is null!\n"); + return 1; + } + return NO_ERR; +} + +static int himax_auto_update_check(void) +{ + int32_t ret; + + I("%s: Entering!\n", __func__); + if (himax_get_fw_ver_bin() == 0) { + if (((ic_data->vendor_fw_ver < g_i_FW_VER) + || (ic_data->vendor_config_ver < g_i_CFG_VER))) { + I("%s: Need update\n", __func__); + ret = 0; + } else { + I("%s: Need not update!\n", __func__); + ret = 1; + } + } else { + E("%s: FW bin fail!\n", __func__); + ret = 1; + } + + return ret; +} +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +static int i_get_FW(void) +{ + int ret = -1; + int result = NO_ERR; + + ret = request_firmware(&hxfw, g_fw_boot_upgrade_name, private_ts->dev); + I("%s: request file %s finished\n", __func__, g_fw_boot_upgrade_name); + if (ret < 0) { +#if defined(__EMBEDDED_FW__) + hxfw = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)", + __func__, g_embedded_fw.size); + result = HX_EMBEDDED_FW; +#else + E("%s,%d: error code = %d\n", __func__, __LINE__, ret); + return OPEN_FILE_FAIL; +#endif + } + + return result; +} + +static int i_update_FW(void) +{ + int upgrade_times = 0; + int8_t ret = 0; + int8_t result = 0; + +update_retry: +#if defined(HX_ZERO_FLASH) + + ret = g_core_fp.fp_firmware_update_0f(hxfw, 0); + if (ret != 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + + if (upgrade_times < 3) + goto update_retry; + else + result = -1; + + } else { + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); + } + +#else + + if (hxfw->size == FW_SIZE_32k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_60k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_64k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_124k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_128k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_255k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_255k( + (unsigned char *)hxfw->data, hxfw->size, false); + + if (ret == 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + + if (upgrade_times < 3) + goto update_retry; + else + result = -1; + + } else { + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); + } +#endif + + return result; +} +#endif +/* + *static int himax_loadSensorConfig(struct himax_platform_data *pdata) + *{ + * I("%s: initialization complete\n", __func__); + * return NO_ERR; + *} + */ +#if defined(HX_EXCP_RECOVERY) +static void himax_excp_hw_reset(void) +{ +#if defined(HX_ZERO_FLASH) + int result = 0; +#endif + I("%s: START EXCEPTION Reset\n", __func__); +#if defined(HX_ZERO_FLASH) + result = g_core_fp.fp_0f_op_file_dirly(g_fw_boot_upgrade_name); + if (result) + E("%s: update FW fail, code[%d]!!\n", __func__, result); +#else + g_core_fp.fp_excp_ic_reset(); +#endif + himax_report_all_leave_event(private_ts); + I("%s: END EXCEPTION Reset\n", __func__); +} +#endif + +#if defined(HX_SMART_WAKEUP) +#if defined(HX_GESTURE_TRACK) +static void gest_pt_log_coordinate(int rx, int tx) +{ + /*driver report x y with range 0 - 255 , we scale it up to x/y pixel*/ + gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255; + gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255; +} +#endif +static int himax_wake_event_parse(struct himax_ts_data *ts, int ts_status) +{ + uint8_t *buf = wake_event_buffer; +#if defined(HX_GESTURE_TRACK) + int tmp_max_x = 0x00; + int tmp_min_x = 0xFFFF; + int tmp_max_y = 0x00; + int tmp_min_y = 0xFFFF; + int gest_len; +#endif + int i = 0, check_FC = 0, ret; + int j = 0, gesture_pos = 0, gesture_flag = 0; + + if (g_ts_dbg != 0) + I("%s: Entering!, ts_status=%d\n", __func__, ts_status); + + if (buf == NULL) { + ret = -ENOMEM; + goto END; + } + + memcpy(buf, hx_touch_data->hx_event_buf, hx_touch_data->event_size); + + for (i = 0; i < GEST_PTLG_ID_LEN; i++) { + for (j = 0; j < GEST_SUP_NUM; j++) { + if (buf[i] == gest_event[j]) { + gesture_flag = buf[i]; + gesture_pos = j; + break; + } + } + I("0x%2.2X ", buf[i]); + if (buf[i] == gesture_flag) { + check_FC++; + } else { + I("ID START at %x , value = 0x%2X skip the event\n", + i, buf[i]); + break; + } + } + + I("Himax gesture_flag= %x\n", gesture_flag); + I("Himax check_FC is %d\n", check_FC); + + if (check_FC != GEST_PTLG_ID_LEN) { + ret = 0; + goto END; + } + + if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 + || buf[GEST_PTLG_ID_LEN + 1] != GEST_PTLG_HDR_ID2) { + ret = 0; + goto END; + } + +#if defined(HX_GESTURE_TRACK) + + if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 + && buf[GEST_PTLG_ID_LEN + 1] == GEST_PTLG_HDR_ID2) { + gest_len = buf[GEST_PTLG_ID_LEN + 2]; + I("gest_len = %d\n", gest_len); + i = 0; + gest_pt_cnt = 0; + I("gest doornidate start\n %s", __func__); + + while (i < (gest_len + 1) / 2) { + gest_pt_log_coordinate( + buf[GEST_PTLG_ID_LEN + 4 + i * 2], + buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]); + i++; + I("gest_pt_x[%d]=%d,gest_pt_y[%d]=%d\n", + gest_pt_cnt, + gest_pt_x[gest_pt_cnt], + gest_pt_cnt, + gest_pt_y[gest_pt_cnt]); + gest_pt_cnt += 1; + } + + if (gest_pt_cnt) { + for (i = 0; i < gest_pt_cnt; i++) { + if (tmp_max_x < gest_pt_x[i]) + tmp_max_x = gest_pt_x[i]; + if (tmp_min_x > gest_pt_x[i]) + tmp_min_x = gest_pt_x[i]; + if (tmp_max_y < gest_pt_y[i]) + tmp_max_y = gest_pt_y[i]; + if (tmp_min_y > gest_pt_y[i]) + tmp_min_y = gest_pt_y[i]; + } + + I("gest_point x_min=%d,x_max=%d,y_min=%d,y_max=%d\n", + tmp_min_x, tmp_max_x, tmp_min_y, tmp_max_y); + + gest_start_x = gest_pt_x[0]; + hx_gesture_coor[0] = gest_start_x; + gest_start_y = gest_pt_y[0]; + hx_gesture_coor[1] = gest_start_y; + gest_end_x = gest_pt_x[gest_pt_cnt - 1]; + hx_gesture_coor[2] = gest_end_x; + gest_end_y = gest_pt_y[gest_pt_cnt - 1]; + hx_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + hx_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + hx_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x) / 2; + hx_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y) / 2; + hx_gesture_coor[7] = gest_mid_y; + /*gest_up_x*/ + hx_gesture_coor[8] = gest_mid_x; + /*gest_up_y*/ + hx_gesture_coor[9] = gest_mid_y - gest_height / 2; + /*gest_down_x*/ + hx_gesture_coor[10] = gest_mid_x; + /*gest_down_y*/ + hx_gesture_coor[11] = gest_mid_y + gest_height / 2; + /*gest_left_x*/ + hx_gesture_coor[12] = gest_mid_x - gest_width / 2; + /*gest_left_y*/ + hx_gesture_coor[13] = gest_mid_y; + /*gest_right_x*/ + hx_gesture_coor[14] = gest_mid_x + gest_width / 2; + /*gest_right_y*/ + hx_gesture_coor[15] = gest_mid_y; + } + } + +#endif + + if (!ts->gesture_cust_en[gesture_pos]) { + I("%s NOT report key [%d] = %d\n", __func__, + gesture_pos, gest_key_def[gesture_pos]); + g_target_report_data->SMWP_event_chk = 0; + ret = 0; + } else { + g_target_report_data->SMWP_event_chk = + gest_key_def[gesture_pos]; + ret = gesture_pos; + } +END: + return ret; +} + +static void himax_wake_event_report(void) +{ + int KEY_EVENT = g_target_report_data->SMWP_event_chk; + + if (g_ts_dbg != 0) + I("%s: Entering!\n", __func__); + + if (KEY_EVENT) { + I("%s SMART WAKEUP KEY event %d press\n", __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + I("%s SMART WAKEUP KEY event %d release\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); +#if defined(HX_GESTURE_TRACK) + I("gest_start_x=%d,start_y=%d,end_x=%d,end_y=%d\n", + gest_start_x, + gest_start_y, + gest_end_x, + gest_end_y); + I("gest_width=%d,height=%d,mid_x=%d,mid_y=%d\n", + gest_width, + gest_height, + gest_mid_x, + gest_mid_y); + I("gest_up_x=%d,up_y=%d,down_x=%d,down_y=%d\n", + hx_gesture_coor[8], + hx_gesture_coor[9], + hx_gesture_coor[10], + hx_gesture_coor[11]); + I("gest_left_x=%d,left_y=%d,right_x=%d,right_y=%d\n", + hx_gesture_coor[12], + hx_gesture_coor[13], + hx_gesture_coor[14], + hx_gesture_coor[15]); +#endif + g_target_report_data->SMWP_event_chk = 0; + } +} + +#endif + +int himax_report_data_init(void) +{ + if (hx_touch_data->hx_coord_buf != NULL) { + kfree(hx_touch_data->hx_coord_buf); + hx_touch_data->hx_coord_buf = NULL; + } + + if (hx_touch_data->hx_rawdata_buf != NULL) { + kfree(hx_touch_data->hx_rawdata_buf); + hx_touch_data->hx_rawdata_buf = NULL; + } + +#if defined(HX_SMART_WAKEUP) + hx_touch_data->event_size = g_core_fp.fp_get_touch_data_size(); + + if (hx_touch_data->hx_event_buf != NULL) { + kfree(hx_touch_data->hx_event_buf); + hx_touch_data->hx_event_buf = NULL; + } + + if (wake_event_buffer != NULL) { + kfree(wake_event_buffer); + wake_event_buffer = NULL; + } + +#endif + + if (g_target_report_data != NULL) { + if (ic_data->HX_STYLUS_FUNC) { + kfree(g_target_report_data->s); + g_target_report_data->s = NULL; + } + + kfree(g_target_report_data->p); + g_target_report_data->p = NULL; + kfree(g_target_report_data); + g_target_report_data = NULL; + } + + hx_touch_data->touch_all_size = g_core_fp.fp_get_touch_data_size(); + hx_touch_data->raw_cnt_max = ic_data->HX_MAX_PT / 4; + hx_touch_data->raw_cnt_rmd = ic_data->HX_MAX_PT % 4; + /* more than 4 fingers */ + if (hx_touch_data->raw_cnt_rmd != 0x00) { + hx_touch_data->rawdata_size = + g_core_fp.fp_cal_data_len( + hx_touch_data->raw_cnt_rmd, + ic_data->HX_MAX_PT, + hx_touch_data->raw_cnt_max); + + hx_touch_data->touch_info_size = (ic_data->HX_MAX_PT + + hx_touch_data->raw_cnt_max + 2) * 4; + } else { /* less than 4 fingers */ + hx_touch_data->rawdata_size = + g_core_fp.fp_cal_data_len( + hx_touch_data->raw_cnt_rmd, + ic_data->HX_MAX_PT, + hx_touch_data->raw_cnt_max); + + hx_touch_data->touch_info_size = (ic_data->HX_MAX_PT + + hx_touch_data->raw_cnt_max + 1) * 4; + } + + if (ic_data->HX_STYLUS_FUNC) { + hx_touch_data->touch_info_size += STYLUS_INFO_SZ; + hx_touch_data->rawdata_size -= STYLUS_INFO_SZ; + } + + if ((ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + + ic_data->HX_RX_NUM) + % hx_touch_data->rawdata_size == 0) + hx_touch_data->rawdata_frame_size = + (ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + + ic_data->HX_RX_NUM) + / hx_touch_data->rawdata_size; + else + hx_touch_data->rawdata_frame_size = + (ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + + ic_data->HX_RX_NUM) + / hx_touch_data->rawdata_size + + 1; + + I("%s:rawdata_fsz = %d,HX_MAX_PT:%d,hx_raw_cnt_max:%d\n", + __func__, + hx_touch_data->rawdata_frame_size, + ic_data->HX_MAX_PT, + hx_touch_data->raw_cnt_max); + I("%s:hx_raw_cnt_rmd:%d,g_hx_rawdata_size:%d,touch_info_size:%d\n", + __func__, + hx_touch_data->raw_cnt_rmd, + hx_touch_data->rawdata_size, + hx_touch_data->touch_info_size); + + hx_touch_data->hx_coord_buf = kzalloc(sizeof(uint8_t) + * (hx_touch_data->touch_info_size), + GFP_KERNEL); + + if (hx_touch_data->hx_coord_buf == NULL) + goto mem_alloc_fail_coord_buf; + +#if defined(HX_SMART_WAKEUP) + wake_event_buffer = kcalloc(hx_touch_data->event_size, + sizeof(uint8_t), GFP_KERNEL); + if (wake_event_buffer == NULL) + goto mem_alloc_fail_smwp; + + hx_touch_data->hx_event_buf = kzalloc(sizeof(uint8_t) + * (hx_touch_data->event_size), GFP_KERNEL); + if (hx_touch_data->hx_event_buf == NULL) + goto mem_alloc_fail_event_buf; +#endif + + hx_touch_data->hx_rawdata_buf = kzalloc(sizeof(uint8_t) + * (hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size), + GFP_KERNEL); + if (hx_touch_data->hx_rawdata_buf == NULL) + goto mem_alloc_fail_rawdata_buf; + + if (g_target_report_data == NULL) { + g_target_report_data = + kzalloc(sizeof(struct himax_target_report_data), + GFP_KERNEL); + if (g_target_report_data == NULL) + goto mem_alloc_fail_report_data; +/* + *#if defined(HX_SMART_WAKEUP) + * g_target_report_data->SMWP_event_chk = 0; + *#endif + * I("%s: SMWP_event_chk = %d\n", __func__, + * g_target_report_data->SMWP_event_chk); + */ + + g_target_report_data->p = kzalloc( + sizeof(struct himax_target_point_data) + *(ic_data->HX_MAX_PT), GFP_KERNEL); + if (g_target_report_data->p == NULL) + goto mem_alloc_fail_report_data_p; + + if (!ic_data->HX_STYLUS_FUNC) + goto skip_stylus_operation; + + g_target_report_data->s = kzalloc( + sizeof(struct himax_target_stylus_data)*2, GFP_KERNEL); + if (g_target_report_data->s == NULL) + goto mem_alloc_fail_report_data_s; + } + +skip_stylus_operation: + + return NO_ERR; + +mem_alloc_fail_report_data_s: + kfree(g_target_report_data->p); + g_target_report_data->p = NULL; +mem_alloc_fail_report_data_p: + kfree(g_target_report_data); + g_target_report_data = NULL; +mem_alloc_fail_report_data: + kfree(hx_touch_data->hx_rawdata_buf); + hx_touch_data->hx_rawdata_buf = NULL; +mem_alloc_fail_rawdata_buf: +#if defined(HX_SMART_WAKEUP) + kfree(hx_touch_data->hx_event_buf); + hx_touch_data->hx_event_buf = NULL; +mem_alloc_fail_event_buf: + kfree(wake_event_buffer); + wake_event_buffer = NULL; +mem_alloc_fail_smwp: +#endif + kfree(hx_touch_data->hx_coord_buf); + hx_touch_data->hx_coord_buf = NULL; +mem_alloc_fail_coord_buf: + + E("%s: Failed to allocate memory\n", __func__); + return MEM_ALLOC_FAIL; +} +EXPORT_SYMBOL(himax_report_data_init); + +void himax_report_data_deinit(void) +{ + if (ic_data->HX_STYLUS_FUNC) { + kfree(g_target_report_data->s); + g_target_report_data->s = NULL; + } + + kfree(g_target_report_data->p); + g_target_report_data->p = NULL; + kfree(g_target_report_data); + g_target_report_data = NULL; + +#if defined(HX_SMART_WAKEUP) + kfree(wake_event_buffer); + wake_event_buffer = NULL; + kfree(hx_touch_data->hx_event_buf); + hx_touch_data->hx_event_buf = NULL; +#endif + kfree(hx_touch_data->hx_rawdata_buf); + hx_touch_data->hx_rawdata_buf = NULL; + kfree(hx_touch_data->hx_coord_buf); + hx_touch_data->hx_coord_buf = NULL; +} + +/*start ts_work*/ +#if defined(HX_USB_DETECT_GLOBAL) +void himax_cable_detect_func(bool force_renew) +{ + struct himax_ts_data *ts; + + /*u32 connect_status = 0;*/ + uint8_t connect_status = 0; + + connect_status = USB_detect_flag;/* upmu_is_chr_det(); */ + ts = private_ts; + + /* I("Touch: cable status=%d, cable_config=%p, usb_connected=%d\n",*/ + /* connect_status, ts->cable_config, ts->usb_connected); */ + if (ts->cable_config) { + if ((connect_status != ts->usb_connected) || force_renew) { + if (connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + g_core_fp.fp_usb_detect_set(ts->cable_config); + I("%s: Cable status change: 0x%2.2X\n", __func__, + ts->usb_connected); + } + + /*else*/ + /* I("%s: Cable status is the same as*/ + /* previous one, ignore.\n", __func__);*/ + } +} +#endif + +static int himax_ts_work_status(struct himax_ts_data *ts) +{ + /* 1: normal, 2:SMWP */ + int result = HX_REPORT_COORD; + + hx_touch_data->diag_cmd = ts->diag_cmd; + if (hx_touch_data->diag_cmd) + result = HX_REPORT_COORD_RAWDATA; + +#if defined(HX_SMART_WAKEUP) + if (atomic_read(&ts->suspend_mode) + && (ts->SMWP_enable) + && (!hx_touch_data->diag_cmd)) + result = HX_REPORT_SMWP_EVENT; +#endif + /* I("Now Status is %d\n", result); */ + return result; +} + +static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, + int ts_path, int ts_status) +{ + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + switch (ts_path) { + /*normal*/ + case HX_REPORT_COORD: + if ((HX_HW_RESET_ACTIVATE) +#if defined(HX_EXCP_RECOVERY) + || (HX_EXCP_RESET_ACTIVATE) +#endif + ) { + if (!g_core_fp.fp_read_event_stack(buf, 128)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + } else { + if (!g_core_fp.fp_read_event_stack(buf, + hx_touch_data->touch_info_size)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + } + break; +#if defined(HX_SMART_WAKEUP) + + /*SMWP*/ + case HX_REPORT_SMWP_EVENT: + __pm_wakeup_event(ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(20); + g_core_fp.fp_burst_enable(0); + + if (!g_core_fp.fp_read_event_stack(buf, + hx_touch_data->event_size)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + break; +#endif + case HX_REPORT_COORD_RAWDATA: + if (!g_core_fp.fp_read_event_stack(buf, 128)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + break; + default: + break; + } + + return ts_status; +} + +/* start error_control*/ +static int himax_checksum_cal(struct himax_ts_data *ts, uint8_t *buf, + int ts_path, int ts_status) +{ + uint16_t check_sum_cal = 0; + int32_t i = 0; + int length = 0; + int zero_cnt = 0; + int raw_data_sel = 0; + int ret_val = ts_status; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + /* Normal */ + switch (ts_path) { + case HX_REPORT_COORD: + length = hx_touch_data->touch_info_size; + break; +#if defined(HX_SMART_WAKEUP) +/* SMWP */ + case HX_REPORT_SMWP_EVENT: + length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN); + break; +#endif + case HX_REPORT_COORD_RAWDATA: + length = hx_touch_data->touch_info_size; + break; + default: + I("%s, Neither Normal Nor SMWP error!\n", __func__); + ret_val = HX_PATH_FAIL; + goto END_FUNCTION; + } + + for (i = 0; i < length; i++) { + check_sum_cal += buf[i]; + if (buf[i] == 0x00) + zero_cnt++; + } + + if (check_sum_cal % 0x100 != 0) { + I("point data_checksum not match check_sum_cal: 0x%02X", + check_sum_cal); + ret_val = HX_CHKSUM_FAIL; + } else if (zero_cnt == length) { + if (ts->use_irq) + I("[HIMAX TP MSG] All Zero event\n"); + + ret_val = HX_CHKSUM_FAIL; + } else { + raw_data_sel = buf[HX_TOUCH_INFO_POINT_CNT]>>4 & 0x0F; + /*I("%s:raw_out_sel=%x , hx_touch_data->diag_cmd=%x.\n",*/ + /* __func__, raw_data_sel,*/ + /* hx_touch_data->diag_cmd);*/ + /*raw data out not match skip it*/ + if ((raw_data_sel != 0x0F) + && (raw_data_sel != hx_touch_data->diag_cmd)) { + /*I("%s:raw data out not match.\n", __func__);*/ + if (!hx_touch_data->diag_cmd) { + /*Need to clear event stack here*/ + g_core_fp.fp_read_event_stack(buf, + (128-hx_touch_data->touch_info_size)); + /*I("%s: size =%d, buf[0]=%x ,buf[1]=%x,*/ + /* buf[2]=%x, buf[3]=%x.\n",*/ + /* __func__,*/ + /* (128-hx_touch_data->touch_info_size),*/ + /* buf[0], buf[1], buf[2], buf[3]);*/ + /*I("%s:also clear event stack.\n", __func__);*/ + } + ret_val = HX_READY_SERVE; + } + } + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ret_val=%d!\n", __func__, ret_val); + return ret_val; +} + +#if defined(HX_EXCP_RECOVERY) +#if defined(HW_ED_EXCP_EVENT) +static int himax_ts_event_check(struct himax_ts_data *ts, + uint8_t *buf, int ts_path, int ts_status) +{ + uint32_t hx_EB_event = 0; + uint32_t hx_EC_event = 0; + uint32_t hx_EE_event = 0; + uint32_t hx_ED_event = 0; + uint32_t hx_excp_event = 0; + int shaking_ret = 0; + + uint32_t i = 0; + uint32_t length = 0; + int ret_val = ts_status; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + /* Normal */ + switch (ts_path) { + case HX_REPORT_COORD: + length = hx_touch_data->touch_info_size; + break; +#if defined(HX_SMART_WAKEUP) + /* SMWP */ + case HX_REPORT_SMWP_EVENT: + length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN); + break; +#endif + case HX_REPORT_COORD_RAWDATA: + length = hx_touch_data->touch_info_size; + break; + default: + I("%s, Neither Normal Nor SMWP error!\n", __func__); + ret_val = HX_PATH_FAIL; + goto END_FUNCTION; + } + + if (g_ts_dbg != 0) + I("Now Path=%d, Now status=%d, length=%d\n", + ts_path, ts_status, length); + + if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) { + if (ic_data->HX_STYLUS_FUNC) + length -= STYLUS_INFO_SZ; + for (i = 0; i < length; i++) { + /* case 1 EXCEEPTION recovery flow */ + if (buf[i] == 0xEB) { + hx_EB_event++; + } else if (buf[i] == 0xEC) { + hx_EC_event++; + } else if (buf[i] == 0xEE) { + hx_EE_event++; + /* case 2 EXCEPTION recovery flow-Disable */ + } else if (buf[i] == 0xED) { + hx_ED_event++; + } else { + g_zero_event_count = 0; + break; + } + } + } + + if (hx_EB_event == length) { + hx_excp_event = length; + hx_EB_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEB.\n"); + } else if (hx_EC_event == length) { + hx_excp_event = length; + hx_EC_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEC.\n"); + } else if (hx_EE_event == length) { + hx_excp_event = length; + hx_EE_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEE.\n"); + } else if (hx_ED_event == length) { + g_core_fp.fp_0f_reload_to_active(); + } + + if ((hx_excp_event == length || hx_ED_event == length) + && (HX_HW_RESET_ACTIVATE == 0) + && (HX_EXCP_RESET_ACTIVATE == 0) + && (hx_touch_data->diag_cmd == 0)) { + shaking_ret = g_core_fp.fp_ic_excp_recovery( + hx_excp_event, hx_ED_event, length); + + if (shaking_ret == HX_EXCP_EVENT) { + g_core_fp.fp_read_FW_status(); + himax_excp_hw_reset(); + ret_val = HX_EXCP_EVENT; + } else if (shaking_ret == HX_ZERO_EVENT_COUNT) { + g_core_fp.fp_read_FW_status(); + ret_val = HX_ZERO_EVENT_COUNT; + } else { + I("IC is running. Nothing to be done!\n"); + ret_val = HX_IC_RUNNING; + } + + /* drop 1st interrupts after chip reset */ + } else if (HX_EXCP_RESET_ACTIVATE) { + HX_EXCP_RESET_ACTIVATE = 0; + I("%s: Skip by HX_EXCP_RESET_ACTIVATE.\n", __func__); + ret_val = HX_EXCP_REC_OK; + } + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ret_val=%d!\n", __func__, ret_val); + + return ret_val; +} + +#else +static int himax_ts_event_check(struct himax_ts_data *ts, + uint8_t *buf, int ts_path, int ts_status) +{ + uint32_t hx_EB_event = 0; + uint32_t hx_EC_event = 0; + uint32_t hx_ED_event = 0; + uint32_t hx_excp_event = 0; + uint32_t hx_zero_event = 0; + int shaking_ret = 0; + + uint32_t i = 0; + uint32_t length = 0; + int ret_val = ts_status; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + /* Normal */ + switch (ts_path) { + case HX_REPORT_COORD: + length = hx_touch_data->touch_info_size; + break; +#if defined(HX_SMART_WAKEUP) +/* SMWP */ + case HX_REPORT_SMWP_EVENT: + length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN); + break; +#endif + case HX_REPORT_COORD_RAWDATA: + length = hx_touch_data->touch_info_size; + break; + default: + I("%s, Neither Normal Nor SMWP error!\n", __func__); + ret_val = HX_PATH_FAIL; + goto END_FUNCTION; + } + + if (g_ts_dbg != 0) + I("Now Path=%d, Now status=%d, length=%d\n", + ts_path, ts_status, length); + + if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) { + if (ic_data->HX_STYLUS_FUNC) + length -= STYLUS_INFO_SZ; + for (i = 0; i < length; i++) { + /* case 1 EXCEEPTION recovery flow */ + if (buf[i] == 0xEB) { + hx_EB_event++; + } else if (buf[i] == 0xEC) { + hx_EC_event++; + } else if (buf[i] == 0xED) { + hx_ED_event++; + + /* case 2 EXCEPTION recovery flow-Disable */ + } else if (buf[i] == 0x00) { + hx_zero_event++; + } else { + g_zero_event_count = 0; + break; + } + } + } + + if (hx_EB_event == length) { + hx_excp_event = length; + hx_EB_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEB.\n"); + } else if (hx_EC_event == length) { + hx_excp_event = length; + hx_EC_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEC.\n"); + } else if (hx_ED_event == length) { + hx_excp_event = length; + hx_ED_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xED.\n"); + } +/*#if defined(HX_ZERO_FLASH) + * //This is for previous version(a, b) because HW pull TSIX + * low continuely after watchdog timeout reset + * else if (hx_zero_event == length) { + * //check zero flash status + * if (g_core_fp.fp_0f_esd_check() < 0) { + * g_zero_event_count = 6; + * I("[HIMAX TP MSG]: ESD event checked + - ALL Zero in ZF.\n"); + * } else { + * I("[HIMAX TP MSG]: Status check pass in ZF.\n"); + * } + * } + *#endif + */ + + if ((hx_excp_event == length || hx_zero_event == length) + && (HX_HW_RESET_ACTIVATE == 0) + && (HX_EXCP_RESET_ACTIVATE == 0) + && (hx_touch_data->diag_cmd == 0)) { + shaking_ret = g_core_fp.fp_ic_excp_recovery( + hx_excp_event, hx_zero_event, length); + + if (shaking_ret == HX_EXCP_EVENT) { + g_core_fp.fp_read_FW_status(); + himax_excp_hw_reset(); + ret_val = HX_EXCP_EVENT; + } else if (shaking_ret == HX_ZERO_EVENT_COUNT) { + g_core_fp.fp_read_FW_status(); + ret_val = HX_ZERO_EVENT_COUNT; + } else { + I("IC is running. Nothing to be done!\n"); + ret_val = HX_IC_RUNNING; + } + + /* drop 1st interrupts after chip reset */ + } else if (HX_EXCP_RESET_ACTIVATE) { + HX_EXCP_RESET_ACTIVATE = 0; + I("%s: Skip by HX_EXCP_RESET_ACTIVATE.\n", __func__); + ret_val = HX_EXCP_REC_OK; + } + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ret_val=%d!\n", __func__, ret_val); + + return ret_val; +} +#endif +#endif + +static int himax_err_ctrl(struct himax_ts_data *ts, + uint8_t *buf, int ts_path, int ts_status) +{ +#if defined(HX_RST_PIN_FUNC) + if (HX_HW_RESET_ACTIVATE) { + /* drop 1st interrupts after chip reset */ + HX_HW_RESET_ACTIVATE = 0; + I("[HX_HW_RESET_ACTIVATE]%s:Back from reset,ready to serve.\n", + __func__); + ts_status = HX_RST_OK; + goto END_FUNCTION; + } +#endif + + ts_status = himax_checksum_cal(ts, buf, ts_path, ts_status); + if (ts_status == HX_CHKSUM_FAIL) { + goto CHK_FAIL; + } else { +#if defined(HX_EXCP_RECOVERY) + /* continuous N times record, not total N times. */ + g_zero_event_count = 0; +#endif + goto END_FUNCTION; + } + +CHK_FAIL: +#if defined(HX_EXCP_RECOVERY) + ts_status = himax_ts_event_check(ts, buf, ts_path, ts_status); +#endif + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ts_status=%d!\n", __func__, ts_status); + return ts_status; +} +/* end error_control*/ + +/* start distribute_data*/ +static int himax_distribute_touch_data(uint8_t *buf, + int ts_path, int ts_status) +{ + uint8_t hx_state_info_pos = hx_touch_data->touch_info_size - 3; + + if (ic_data->HX_STYLUS_FUNC) + hx_state_info_pos -= STYLUS_INFO_SZ; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + if (ts_path == HX_REPORT_COORD) { + memcpy(hx_touch_data->hx_coord_buf, &buf[0], + hx_touch_data->touch_info_size); + + if (buf[hx_state_info_pos] != 0xFF + && buf[hx_state_info_pos + 1] != 0xFF) + memcpy(hx_touch_data->hx_state_info, + &buf[hx_state_info_pos], 2); + else + memset(hx_touch_data->hx_state_info, 0x00, + sizeof(hx_touch_data->hx_state_info)); + + if ((HX_HW_RESET_ACTIVATE) +#if defined(HX_EXCP_RECOVERY) + || (HX_EXCP_RESET_ACTIVATE) +#endif + ) { + memcpy(hx_touch_data->hx_rawdata_buf, + &buf[hx_touch_data->touch_info_size], + hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size); + } + } else if (ts_path == HX_REPORT_COORD_RAWDATA) { + memcpy(hx_touch_data->hx_coord_buf, &buf[0], + hx_touch_data->touch_info_size); + + if (buf[hx_state_info_pos] != 0xFF + && buf[hx_state_info_pos + 1] != 0xFF) + memcpy(hx_touch_data->hx_state_info, + &buf[hx_state_info_pos], 2); + else + memset(hx_touch_data->hx_state_info, 0x00, + sizeof(hx_touch_data->hx_state_info)); + + memcpy(hx_touch_data->hx_rawdata_buf, + &buf[hx_touch_data->touch_info_size], + hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size); +#if defined(HX_SMART_WAKEUP) + } else if (ts_path == HX_REPORT_SMWP_EVENT) { + memcpy(hx_touch_data->hx_event_buf, buf, + hx_touch_data->event_size); +#endif + } else { + E("%s, Fail Path!\n", __func__); + ts_status = HX_PATH_FAIL; + } + + if (g_ts_dbg != 0) + I("%s: End, ts_status=%d!\n", __func__, ts_status); + return ts_status; +} +/* end assign_data*/ + +/* start parse_report_data*/ +int himax_parse_report_points(struct himax_ts_data *ts, + int ts_path, int ts_status) +{ + int x = 0, y = 0, w = 0; + + uint8_t p_hover = 0, p_btn = 0, p_btn2 = 0; + int8_t p_tilt_x = 0, p_tilt_y = 0; + int p_x = 0, p_y = 0, p_w = 0; + static uint8_t p_p_on; + + int base = 0; + int32_t i = 0; + + if (g_ts_dbg != 0) + I("%s: start!\n", __func__); + + base = hx_touch_data->touch_info_size; + + if (!ic_data->HX_STYLUS_FUNC) + goto skip_stylus_operation; + + p_p_on = 0; + base -= STYLUS_INFO_SZ; + + p_x = hx_touch_data->hx_coord_buf[base] << 8 + | hx_touch_data->hx_coord_buf[base + 1]; + p_y = (hx_touch_data->hx_coord_buf[base + 2] << 8 + | hx_touch_data->hx_coord_buf[base + 3]); + p_w = (hx_touch_data->hx_coord_buf[base + 4] << 8 + | hx_touch_data->hx_coord_buf[base + 5]); + p_tilt_x = (int8_t)hx_touch_data->hx_coord_buf[base + 6]; + p_hover = hx_touch_data->hx_coord_buf[base + 7]; + p_btn = hx_touch_data->hx_coord_buf[base + 8]; + p_btn2 = hx_touch_data->hx_coord_buf[base + 9]; + p_tilt_y = (int8_t)hx_touch_data->hx_coord_buf[base + 10]; + + if (g_ts_dbg != 0) { + D("%s: p_x=%d, p_y=%d, p_w=%d,p_tilt_x=%d, p_hover=%d\n", + __func__, p_x, p_y, p_w, p_tilt_x, p_hover); + D("%s: p_btn=%d, p_btn2=%d, p_tilt_y=%d\n", + __func__, p_btn, p_btn2, p_tilt_y); + } + + if (p_x >= 0 + && p_x <= ts->pdata->abs_x_max + && p_y >= 0 + && p_y <= ts->pdata->abs_y_max) { + g_target_report_data->s[0].x = p_x; + g_target_report_data->s[0].y = p_y; + g_target_report_data->s[0].w = p_w; + g_target_report_data->s[0].hover = p_hover; + g_target_report_data->s[0].id = 1; + g_target_report_data->s[0].btn = p_btn; + g_target_report_data->s[0].btn2 = p_btn2; + g_target_report_data->s[0].tilt_x = p_tilt_x; + g_target_report_data->s[0].tilt_y = p_tilt_y; + g_target_report_data->s[0].on = 1; + ts->hx_stylus_num++; + } else {/* report coordinates */ + g_target_report_data->s[0].x = 0; + g_target_report_data->s[0].y = 0; + g_target_report_data->s[0].w = 0; + g_target_report_data->s[0].hover = 0; + g_target_report_data->s[0].id = 0; + g_target_report_data->s[0].btn = 0; + g_target_report_data->s[0].btn2 = 0; + g_target_report_data->s[0].tilt_x = 0; + g_target_report_data->s[0].tilt_y = 0; + g_target_report_data->s[0].on = 0; + } + + if (g_ts_dbg != 0) { + if (p_p_on != g_target_report_data->s[0].on) { + I("s[0].on = %d, hx_stylus_num=%d\n", + g_target_report_data->s[0].on, + ts->hx_stylus_num); + p_p_on = g_target_report_data->s[0].on; + } + } +skip_stylus_operation: + + ts->old_finger = ts->pre_finger_mask; + if (ts->hx_point_num == 0) { + if (g_ts_dbg != 0) + I("%s: hx_point_num = 0!\n", __func__); + return ts_status; + } + ts->pre_finger_mask = 0; + hx_touch_data->finger_num = + hx_touch_data->hx_coord_buf[base - 4] & 0x0F; + hx_touch_data->finger_on = 1; + AA_press = 1; + + g_target_report_data->finger_num = hx_touch_data->finger_num; + g_target_report_data->finger_on = hx_touch_data->finger_on; + g_target_report_data->ig_count = + hx_touch_data->hx_coord_buf[base - 5]; + + if (g_ts_dbg != 0) + I("%s:finger_num = 0x%2X, finger_on = %d\n", __func__, + g_target_report_data->finger_num, + g_target_report_data->finger_on); + + for (i = 0; i < ts->nFinger_support; i++) { + base = i * 4; + x = hx_touch_data->hx_coord_buf[base] << 8 + | hx_touch_data->hx_coord_buf[base + 1]; + y = (hx_touch_data->hx_coord_buf[base + 2] << 8 + | hx_touch_data->hx_coord_buf[base + 3]); + w = hx_touch_data->hx_coord_buf[(ts->nFinger_support * 4) + i]; + + if (g_ts_dbg != 0) + D("%s: now parsing[%d]:x=%d, y=%d, w=%d\n", __func__, + i, x, y, w); + + if (x >= 0 + && x <= ts->pdata->abs_x_max + && y >= 0 + && y <= ts->pdata->abs_y_max) { + hx_touch_data->finger_num--; + + g_target_report_data->p[i].x = x; + g_target_report_data->p[i].y = y; + g_target_report_data->p[i].w = w; + g_target_report_data->p[i].id = 1; + + /*I("%s: g_target_report_data->x[loop_i]=%d,*/ + /*g_target_report_data->y[loop_i]=%d,*/ + /*g_target_report_data->w[loop_i]=%d",*/ + /*__func__, g_target_report_data->x[loop_i],*/ + /*g_target_report_data->y[loop_i],*/ + /*g_target_report_data->w[loop_i]); */ + + if (!ts->first_pressed) { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[i][0] = x; + ts->pre_finger_data[i][1] = y; + + ts->pre_finger_mask = ts->pre_finger_mask + (1<<i); + } else {/* report coordinates */ + g_target_report_data->p[i].x = x; + g_target_report_data->p[i].y = y; + g_target_report_data->p[i].w = w; + g_target_report_data->p[i].id = 0; + + if (i == 0 && ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + } + } + + if (g_ts_dbg != 0) { + for (i = 0; i < ts->nFinger_support; i++) + D("DBG X=%d Y=%d ID=%d\n", + g_target_report_data->p[i].x, + g_target_report_data->p[i].y, + g_target_report_data->p[i].id); + + D("DBG finger number %d\n", g_target_report_data->finger_num); + } + + if (g_ts_dbg != 0) + I("%s: end!\n", __func__); + return ts_status; +} + +static int himax_parse_report_data(struct himax_ts_data *ts, + int ts_path, int ts_status) +{ + + if (g_ts_dbg != 0) + I("%s: start now_status=%d!\n", __func__, ts_status); + + + EN_NoiseFilter = + (hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); + /* I("EN_NoiseFilter=%d\n", EN_NoiseFilter); */ + EN_NoiseFilter = EN_NoiseFilter & 0x01; + /* I("EN_NoiseFilter2=%d\n", EN_NoiseFilter); */ + p_point_num = ts->hx_point_num; + + if (hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + ts->hx_point_num = 0; + else + ts->hx_point_num = + hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] + & 0x0f; + + if (ic_data->HX_STYLUS_FUNC) { + p_stylus_num = ts->hx_stylus_num; + ts->hx_stylus_num = 0; + } + + switch (ts_path) { + case HX_REPORT_COORD: + ts_status = himax_parse_report_points(ts, ts_path, ts_status); + break; + case HX_REPORT_COORD_RAWDATA: + /* touch monitor rawdata */ + if (debug_data != NULL) { + if (debug_data->fp_set_diag_cmd(ic_data, hx_touch_data)) + I("%s:raw data_checksum not match\n", __func__); + } else { + E("%s,There is no init set_diag_cmd\n", __func__); + } + ts_status = himax_parse_report_points(ts, ts_path, ts_status); + break; +#if defined(HX_SMART_WAKEUP) + case HX_REPORT_SMWP_EVENT: + himax_wake_event_parse(ts, ts_status); + break; +#endif + default: + E("%s:Fail Path!\n", __func__); + ts_status = HX_PATH_FAIL; + break; + } + if (g_ts_dbg != 0) + I("%s: end now_status=%d!\n", __func__, ts_status); + return ts_status; +} + +/* end parse_report_data*/ + +static void himax_report_all_leave_event(struct himax_ts_data *ts) +{ + int i = 0; + + for (i = 0; i < ts->nFinger_support; i++) { +#if !defined(HX_PROTOCOL_A) + 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_WIDTH_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); + input_sync(ts->input_dev); +} + +/* start report_point*/ +static void himax_point_report(struct himax_ts_data *ts) +{ + int i = 0; + bool valid = false; + + + if (g_ts_dbg != 0) { + I("%s:start hx_touch_data->finger_num=%d\n", + __func__, hx_touch_data->finger_num); + } + for (i = 0; i < ts->nFinger_support; i++) { + if (g_target_report_data->p[i].x >= 0 + && g_target_report_data->p[i].x <= ts->pdata->abs_x_max + && g_target_report_data->p[i].y >= 0 + && g_target_report_data->p[i].y <= ts->pdata->abs_y_max) + valid = true; + else + valid = false; + if (g_ts_dbg != 0) + I("valid=%d\n", valid); + if (valid) { + if (g_ts_dbg != 0) { + I("report_data->x[i]=%d,y[i]=%d,w[i]=%d", + g_target_report_data->p[i].x, + g_target_report_data->p[i].y, + g_target_report_data->p[i].w); + } +#if !defined(HX_PROTOCOL_A) + input_mt_slot(ts->input_dev, i); +#else + input_report_key(ts->input_dev, BTN_TOUCH, 1); +#endif + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + g_target_report_data->p[i].w); +#if !defined(HX_PROTOCOL_A) + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + g_target_report_data->p[i].w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + g_target_report_data->p[i].w); +#else + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, + i + 1); +#endif + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + g_target_report_data->p[i].x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + g_target_report_data->p[i].y); +#if !defined(HX_PROTOCOL_A) + ts->last_slot = i; + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 1); +#else + input_mt_sync(ts->input_dev); +#endif + } else { +#if !defined(HX_PROTOCOL_A) + 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_WIDTH_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 + } + } +#if !defined(HX_PROTOCOL_A) + input_report_key(ts->input_dev, BTN_TOUCH, 1); +#endif + input_sync(ts->input_dev); + + if (g_ts_dbg != 0) + I("%s:end\n", __func__); +} + +static void himax_point_leave(struct himax_ts_data *ts) +{ +#if !defined(HX_PROTOCOL_A) + int32_t i = 0; +#endif + + if (g_ts_dbg != 0) + I("%s: start!\n", __func__); +#if defined(HX_PALM_REPORT) + if (himax_palm_detect(hx_touch_data->hx_coord_buf) == PALM_REPORT) { + I(" %s HX_PALM_REPORT KEY power event press\n", __func__); + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + msleep(100); + + I(" %s HX_PALM_REPORT KEY power event release\n", __func__); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + return; + } +#endif + + hx_touch_data->finger_on = 0; + g_target_report_data->finger_on = 0; + g_target_report_data->finger_num = 0; + AA_press = 0; + +#if defined(HX_PROTOCOL_A) + input_mt_sync(ts->input_dev); +#endif +#if !defined(HX_PROTOCOL_A) + for (i = 0; i < ts->nFinger_support; 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_WIDTH_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 + if (ts->pre_finger_mask > 0) + ts->pre_finger_mask = 0; + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + + /*if (ts->debug_log_level & BIT(1))*/ + /* himax_log_touch_event(x, y, w, loop_i, EN_NoiseFilter,*/ + /* HX_FINGER_LEAVE); */ + + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); + + if (g_ts_dbg != 0) + I("%s: end!\n", __func__); +} + +static void himax_stylus_report(struct himax_ts_data *ts) +{ + bool valid = false; + + if (g_ts_dbg != 0) { + I("%s:start hx_touch_data->stylus_num=%d\n", + __func__, ts->hx_stylus_num); + } + + if (g_target_report_data->s[0].x >= 0 + && g_target_report_data->s[0].x <= ts->pdata->abs_x_max + && g_target_report_data->s[0].y >= 0 + && g_target_report_data->s[0].y <= ts->pdata->abs_y_max + && (g_target_report_data->s[0].on == 1)) + valid = true; + else + valid = false; + + if (g_ts_dbg != 0) + I("stylus valid=%d\n", valid); + + if (valid) {/*stylus down*/ + if (g_ts_dbg != 0) + I("s[i].x=%d, s[i].y=%d, s[i].w=%d\n", + g_target_report_data->s[0].x, + g_target_report_data->s[0].y, + g_target_report_data->s[0].w); + + input_report_abs(ts->stylus_dev, ABS_X, + g_target_report_data->s[0].x); + input_report_abs(ts->stylus_dev, ABS_Y, + g_target_report_data->s[0].y); + + if (g_target_report_data->s[0].btn != + g_target_report_data->s[0].pre_btn) { + if (g_ts_dbg != 0) + I("BTN_STYLUS:%d\n", + g_target_report_data->s[0].btn); + + input_report_key(ts->stylus_dev, BTN_STYLUS, + g_target_report_data->s[0].btn); + + g_target_report_data->s[0].pre_btn = + g_target_report_data->s[0].btn; + } else { + if (g_ts_dbg != 0) + I("BTN_STYLUS status is %d!\n", + g_target_report_data->s[0].btn); + } + + if (g_target_report_data->s[0].btn2 + != g_target_report_data->s[0].pre_btn2) { + if (g_ts_dbg != 0) + I("BTN_STYLUS2:%d\n", + g_target_report_data->s[0].btn2); + + input_report_key(ts->stylus_dev, BTN_STYLUS2, + g_target_report_data->s[0].btn2); + + g_target_report_data->s[0].pre_btn2 = + g_target_report_data->s[0].btn2; + } else { + if (g_ts_dbg != 0) + I("BTN_STYLUS2 status is %d!\n", + g_target_report_data->s[0].btn2); + } + input_report_abs(ts->stylus_dev, ABS_TILT_X, + g_target_report_data->s[0].tilt_x); + + input_report_abs(ts->stylus_dev, ABS_TILT_Y, + g_target_report_data->s[0].tilt_y); + + input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 1); + + if (g_target_report_data->s[0].hover == 0) { + input_report_key(ts->stylus_dev, BTN_TOUCH, 1); + input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, + g_target_report_data->s[0].w); + } else { + input_report_key(ts->stylus_dev, BTN_TOUCH, 0); + input_report_abs(ts->stylus_dev, ABS_DISTANCE, 1); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0); + } + } else {/*Pen up*/ + g_target_report_data->s[0].pre_btn = 0; + g_target_report_data->s[0].pre_btn2 = 0; + input_report_key(ts->stylus_dev, BTN_STYLUS, 0); + input_report_key(ts->stylus_dev, BTN_STYLUS2, 0); + input_report_key(ts->stylus_dev, BTN_TOUCH, 0); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0); + input_sync(ts->stylus_dev); + + input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0); + input_report_key(ts->stylus_dev, BTN_TOOL_RUBBER, 0); + input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 0); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0); + } + input_sync(ts->stylus_dev); + + if (g_ts_dbg != 0) + I("%s:end\n", __func__); +} + +static void himax_stylus_leave(struct himax_ts_data *ts) +{ + if (g_ts_dbg != 0) + I("%s: start!\n", __func__); + + g_target_report_data->s[0].pre_btn = 0; + g_target_report_data->s[0].pre_btn2 = 0; + input_report_key(ts->stylus_dev, BTN_STYLUS, 0); + input_report_key(ts->stylus_dev, BTN_STYLUS2, 0); + input_report_key(ts->stylus_dev, BTN_TOUCH, 0); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0); + input_sync(ts->stylus_dev); + + input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0); + input_report_abs(ts->stylus_dev, ABS_TILT_X, 0); + input_report_abs(ts->stylus_dev, ABS_TILT_Y, 0); + input_report_key(ts->stylus_dev, BTN_TOOL_RUBBER, 0); + input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 0); + input_sync(ts->stylus_dev); + + if (g_ts_dbg != 0) + I("%s: end!\n", __func__); +} + +int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status) +{ + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) { + /* Touch Point information */ + + if (ts->hx_point_num != 0) + himax_point_report(ts); + else if (ts->hx_point_num == 0 && p_point_num != 0) + himax_point_leave(ts); + + if (ic_data->HX_STYLUS_FUNC) { + if (ts->hx_stylus_num != 0) + himax_stylus_report(ts); + else if (ts->hx_stylus_num == 0 && p_stylus_num != 0) + himax_stylus_leave(ts); + } + + Last_EN_NoiseFilter = EN_NoiseFilter; + +#if defined(HX_SMART_WAKEUP) + } else if (ts_path == HX_REPORT_SMWP_EVENT) { + himax_wake_event_report(); +#endif + } else { + E("%s:Fail Path!\n", __func__); + ts_status = HX_PATH_FAIL; + } + + if (g_ts_dbg != 0) + I("%s: END, ts_status=%d!\n", __func__, ts_status); + return ts_status; +} +/* end report_data */ + +static int himax_ts_operation(struct himax_ts_data *ts, + int ts_path, int ts_status) +{ + uint8_t hw_reset_check[2]; + + memset(ts->xfer_buff, 0x00, 128 * sizeof(uint8_t)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + + ts_status = himax_touch_get(ts, ts->xfer_buff, ts_path, ts_status); + if (ts_status == HX_TS_GET_DATA_FAIL) + goto END_FUNCTION; + + ts_status = himax_distribute_touch_data(ts->xfer_buff, + ts_path, ts_status); + ts_status = himax_err_ctrl(ts, ts->xfer_buff, ts_path, ts_status); + if (ts_status == HX_REPORT_DATA || ts_status == HX_TS_NORMAL_END) + ts_status = himax_parse_report_data(ts, ts_path, ts_status); + else + goto END_FUNCTION; + + + ts_status = himax_report_data(ts, ts_path, ts_status); + + +END_FUNCTION: + return ts_status; +} + +void himax_ts_work(struct himax_ts_data *ts) +{ + + int ts_status = HX_TS_NORMAL_END; + int ts_path = 0; + + if (debug_data != NULL) { + if (debug_data->is_checking_irq) { + if (g_ts_dbg != 0) + I("Now checking IRQ, skip it!\n"); + return; + } + debug_data->fp_ts_dbg_func(ts, HX_FINGER_ON); + } + if (ts->notouch_frame > 0) { + if (g_ts_dbg != 0) + I("Skipit=%d\n", ts->notouch_frame--); + else + ts->notouch_frame--; + return; + } + +#if defined(HX_USB_DETECT_GLOBAL) + himax_cable_detect_func(false); +#endif + + ts_path = himax_ts_work_status(ts); + switch (ts_path) { + case HX_REPORT_COORD: + ts_status = himax_ts_operation(ts, ts_path, ts_status); + break; + case HX_REPORT_SMWP_EVENT: + ts_status = himax_ts_operation(ts, ts_path, ts_status); + break; + case HX_REPORT_COORD_RAWDATA: + ts_status = himax_ts_operation(ts, ts_path, ts_status); + break; + default: + E("%s:Path Fault! value=%d\n", __func__, ts_path); + goto END_FUNCTION; + } + + if (ts_status == HX_TS_GET_DATA_FAIL) + goto GET_TOUCH_FAIL; + else + goto END_FUNCTION; + +GET_TOUCH_FAIL: + I("%s: Now reset the Touch chip.\n", __func__); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, true); +#else + g_core_fp.fp_system_reset(); +#endif +#if defined(HX_ZERO_FLASH) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif +END_FUNCTION: + if (debug_data != NULL) + debug_data->fp_ts_dbg_func(ts, HX_FINGER_LEAVE); + +} +/*end ts_work*/ +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#if !defined(HX_ZERO_FLASH) +static int hx_chk_flash_sts(uint32_t size) +{ + int rslt = 0; + + I("%s: Entering, %d\n", __func__, size); + + rslt = (!g_core_fp.fp_calculateChecksum(false, size)); + /*avoid the FW is full of zero*/ + rslt |= g_core_fp.fp_flash_lastdata_check(size); + + return rslt; +} +#endif + +static void himax_boot_upgrade(struct work_struct *work) +{ +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + int fw_sts = -1; +#endif + +#if defined(__EMBEDDED_FW__) + g_embedded_fw.size = (size_t)_binary___Himax_firmware_bin_end - + (size_t)_binary___Himax_firmware_bin_start; +#endif + +#if defined(HX_ZERO_FLASH) + g_boot_upgrade_flag = true; +#else + if (hx_chk_flash_sts(ic_data->flash_size) == 1) { + E("%s: check flash fail, please upgrade FW\n", __func__); + #if defined(HX_BOOT_UPGRADE) + g_boot_upgrade_flag = true; + #else + goto END; + #endif + } else { + g_core_fp.fp_reload_disable(0); + g_core_fp.fp_power_on_init(); + g_core_fp.fp_read_FW_ver(); + g_core_fp.fp_tp_info_check(); + } +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + fw_sts = i_get_FW(); + if (fw_sts < NO_ERR) + goto END; + + g_core_fp.fp_bin_desc_get((unsigned char *)hxfw->data, HX1K); + +#if defined(HX_BOOT_UPGRADE) + if (g_boot_upgrade_flag == false) { + if (himax_auto_update_check() == 0) + g_boot_upgrade_flag = true; + } +#endif + + if (g_boot_upgrade_flag == true) { + if (i_update_FW() <= 0) { + E("%s: Update FW fail\n", __func__); + } else { + I("%s: Update FW success\n", __func__); + #if !defined(HX_ALG_OVERLAY) + g_core_fp.fp_reload_disable(0); + g_core_fp.fp_power_on_init(); + #endif + g_core_fp.fp_read_FW_ver(); + g_core_fp.fp_tp_info_check(); + } + } + + if (fw_sts == NO_ERR) + release_firmware(hxfw); + hxfw = NULL; +#endif + +END: + ic_boot_done = 1; + himax_int_enable(1); +} + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) \ + || defined(HX_CONFIG_DRM_PANEL) +static void himax_fb_register(struct work_struct *work) +{ + int ret = 0; + + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + work_att.work); + + I("%s in\n", __func__); +#if defined(HX_CONFIG_FB) + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); +#elif defined(HX_CONFIG_DRM_PANEL) + ts->fb_notif.notifier_call = drm_notifier_callback; + if (active_panel) + ret = drm_panel_notifier_register(active_panel, + &ts->fb_notif); + else + ret = drm_panel_notifier_register(&gNotifier_dummy_panel, + &ts->fb_notif); +#elif defined(HX_CONFIG_DRM) +#if defined(__HIMAX_MOD__) + hx_msm_drm_register_client = + (void *)symbol_get("msm_drm_register_client"); + if (hx_msm_drm_register_client != NULL) { + ts->fb_notif.notifier_call = drm_notifier_callback; + ret = hx_msm_drm_register_client(&ts->fb_notif); + } else + E("hx_msm_drm_register_client is NULL\n"); +#else + ts->fb_notif.notifier_call = drm_notifier_callback; + ret = msm_drm_register_client(&ts->fb_notif); +#endif +#endif + if (ret) + E("Unable to register fb_notifier: %d\n", ret); +} +#endif + +#if defined(HX_CONTAINER_SPEED_UP) +static void himax_resume_work_func(struct work_struct *work) +{ + himax_chip_common_resume(private_ts); +} + +#endif +int hx_ic_register(void) +{ + int ret = !NO_ERR; + + I("%s:Entering!\n", __func__); +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xG) + if (_hx852xG_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xH) + if (_hx852xH_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xJ) + if (_hx852xJ_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83102) + if (_hx83102_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83103) + if (_hx83103_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83106) + if (_hx83106_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83108) + if (_hx83108_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83111) + if (_hx83111_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112) + if (_hx83112_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83113) + if (_hx83113_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83121) + if (_hx83121_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83191) + if (_hx83191_init()) { + ret = NO_ERR; + goto END; + } +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83192) + if (_hx83192_init()) { + ret = NO_ERR; + goto END; + } +#endif +END: + if (ret == NO_ERR) + I("%s: detect IC!\n", __func__); + else + E("%s: There is no IC!\n", __func__); + I("%s:END!\n", __func__); + + return ret; +} + +int himax_chip_common_init(void) +{ + int ret = 0; + int err = PROBE_FAIL; + struct himax_ts_data *ts = private_ts; + struct himax_platform_data *pdata; + + + + I("Prepare kernel fp\n"); + kp_getname_kernel = (void *)symbol_get("getname_kernel"); + if (!kp_getname_kernel) { + E("prepare kp_getname_kernel failed!\n"); + /*goto err_xfer_buff_fail;*/ + } + + kp_putname_kernel = (void *)symbol_get("putname"); + if (!kp_putname_kernel) { + E("prepare kp_putname_kernel failed!\n"); + /*goto err_xfer_buff_fail;*/ + } + + kp_file_open_name = (void *)symbol_get("file_open_name"); + if (!kp_file_open_name) { + E("prepare kp_file_open_name failed!\n"); + /*goto err_xfer_buff_fail;*/ + } + + ts->xfer_buff = devm_kzalloc(ts->dev, 128 * sizeof(uint8_t), + GFP_KERNEL); + if (ts->xfer_buff == NULL) { + err = -ENOMEM; + goto err_xfer_buff_fail; + } + + I("PDATA START\n"); + pdata = kzalloc(sizeof(struct himax_platform_data), GFP_KERNEL); + + if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; + } + + I("ic_data START\n"); + ic_data = kzalloc(sizeof(struct himax_ic_data), GFP_KERNEL); + if (ic_data == NULL) { /*Allocate IC data space*/ + err = -ENOMEM; + goto err_dt_ic_data_fail; + } + memset(ic_data, 0xFF, sizeof(struct himax_ic_data)); + /* default 128k, different size please follow HX83121A style */ + ic_data->flash_size = 131072; + + /* allocate report data */ + hx_touch_data = kzalloc(sizeof(struct himax_report_data), GFP_KERNEL); + if (hx_touch_data == NULL) { + err = -ENOMEM; + goto err_alloc_touch_data_failed; + } + + ts->pdata = pdata; + + if (himax_parse_dt(ts, pdata) < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; + +#if defined(HX_RST_PIN_FUNC) + ts->rst_gpio = pdata->gpio_reset; +#endif + + himax_gpio_power_config(pdata); + +#if !defined(CONFIG_OF) + if (pdata->power) { + ret = pdata->power(1); + if (ret < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + +#if defined(CONFIG_OF) + ts->power = pdata->power; +#endif + + g_hx_chip_inited = 0; + + if (hx_ic_register() != NO_ERR) { + E("%s: can't detect IC!\n", __func__); + goto error_ic_detect_failed; + } + + private_ts->notouch_frame = 0; + private_ts->ic_notouch_frame = 0; + + if (g_core_fp.fp_chip_init != NULL) { + g_core_fp.fp_chip_init(); + } else { + E("%s: function point of chip_init is NULL!\n", __func__); + goto error_ic_detect_failed; + } +#ifdef HX_PARSE_FROM_DT + himax_parse_dt_ic_info(ts, pdata); +#endif + g_core_fp.fp_touch_information(); + + spin_lock_init(&ts->irq_lock); + + if (himax_ts_register_interrupt()) { + E("%s: register interrupt failed\n", __func__); + goto err_register_interrupt_failed; + } + + himax_int_enable(0); + + ts->himax_boot_upgrade_wq = + create_singlethread_workqueue("HX_boot_upgrade"); + if (!ts->himax_boot_upgrade_wq) { + E("allocate himax_boot_upgrade_wq failed\n"); + err = -ENOMEM; + goto err_boot_upgrade_wq_failed; + } + INIT_DELAYED_WORK(&ts->work_boot_upgrade, himax_boot_upgrade); + queue_delayed_work(ts->himax_boot_upgrade_wq, &ts->work_boot_upgrade, + msecs_to_jiffies(200)); + + g_core_fp.fp_calc_touch_data_size(); + + /*Himax Power On and Load Config*/ +/* if (himax_loadSensorConfig(pdata)) { + * E("%s: Load Sesnsor configuration failed, unload driver.\n", + * __func__); + * goto err_detect_failed; + * } + */ + +#if defined(CONFIG_OF) + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0xF0; + pdata->cable_config[1] = 0x00; +#endif + + ts->suspended = false; + +#if defined(HX_USB_DETECT_GLOBAL) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + +#if defined(HX_PROTOCOL_A) + ts->protocol_type = PROTOCOL_TYPE_A; +#else + ts->protocol_type = PROTOCOL_TYPE_B; +#endif + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + +#if defined(HX_SMART_WAKEUP) + ts->SMWP_enable = 0; +#if defined(KERNEL_VER_ABOVE_4_19) + ts->ts_SMWP_wake_lock = + wakeup_source_register(ts->dev, HIMAX_common_NAME); +#else + wakeup_source_init(ts->ts_SMWP_wake_lock, HIMAX_common_NAME); +#endif +#endif + +#if defined(HX_HIGH_SENSE) + ts->HSEN_enable = 0; +#endif + + if (himax_common_proc_init()) { + E(" %s: himax_common proc_init failed!\n", __func__); + goto err_creat_proc_file_failed; + } + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + if (himax_debug_init()) { + E(" %s: debug initial failed!\n", __func__); + goto err_debug_init_failed; + } +#endif + + ret = himax_input_register(ts); + if (ret) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } + +#if defined(HX_CONTAINER_SPEED_UP) + ts->ts_int_workqueue = + create_singlethread_workqueue("himax_ts_resume_wq"); + if (!ts->ts_int_workqueue) { + E("create ts_resume workqueue failed\n"); + goto err_create_ts_resume_wq_failed; + } + INIT_DELAYED_WORK(&ts->ts_int_work, himax_resume_work_func); +#endif + + ts->initialized = true; + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) + ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_request"); + if (!ts->himax_att_wq) { + E(" allocate himax_att_wq failed\n"); + err = -ENOMEM; + goto err_get_intr_bit_failed; + } + + INIT_DELAYED_WORK(&ts->work_att, himax_fb_register); + queue_delayed_work(ts->himax_att_wq, &ts->work_att, + msecs_to_jiffies(0)); +#endif + + g_hx_chip_inited = true; + return 0; + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +err_get_intr_bit_failed: +#endif +#if defined(HX_CONTAINER_SPEED_UP) + cancel_delayed_work_sync(&ts->ts_int_work); + destroy_workqueue(ts->ts_int_workqueue); +err_create_ts_resume_wq_failed: +#endif + input_unregister_device(ts->input_dev); + if (ic_data->HX_STYLUS_FUNC) + input_unregister_device(ts->stylus_dev); +err_input_register_device_failed: +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_debug_remove(); +err_debug_init_failed: +#endif + himax_common_proc_deinit(); +err_creat_proc_file_failed: +#if defined(HX_SMART_WAKEUP) +#if defined(KERNEL_VER_ABOVE_4_19) + wakeup_source_unregister(ts->ts_SMWP_wake_lock); +#else + wakeup_source_trash(ts->ts_SMWP_wake_lock); +#endif +#endif + cancel_delayed_work_sync(&ts->work_boot_upgrade); + destroy_workqueue(ts->himax_boot_upgrade_wq); +err_boot_upgrade_wq_failed: + himax_ts_unregister_interrupt(); +err_register_interrupt_failed: +/*err_detect_failed:*/ +error_ic_detect_failed: +#if !defined(CONFIG_OF) +err_power_failed: +#endif + himax_gpio_power_deconfig(pdata); +err_alloc_dt_pdata_failed: + kfree(hx_touch_data); + hx_touch_data = NULL; +err_alloc_touch_data_failed: + kfree(ic_data); + ic_data = NULL; +err_dt_ic_data_fail: + kfree(pdata); + pdata = NULL; +err_dt_platform_data_fail: + devm_kfree(ts->dev, ts->xfer_buff); + ts->xfer_buff = NULL; +err_xfer_buff_fail: + probe_fail_flag = 1; + return err; +} + +void himax_chip_common_deinit(void) +{ + struct himax_ts_data *ts = private_ts; + + himax_ts_unregister_interrupt(); + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + himax_inspect_data_clear(); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_debug_remove(); +#endif + + himax_common_proc_deinit(); + himax_report_data_deinit(); + +#if defined(HX_SMART_WAKEUP) +#if defined(KERNEL_VER_ABOVE_4_19) + wakeup_source_unregister(ts->ts_SMWP_wake_lock); +#else + wakeup_source_trash(ts->ts_SMWP_wake_lock); +#endif +#endif +#if defined(HX_CONFIG_FB) + if (fb_unregister_client(&ts->fb_notif)) + E("Error occurred while unregistering fb_notifier.\n"); + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +#elif defined(HX_CONFIG_DRM_PANEL) +if (active_panel) + if (drm_panel_notifier_unregister(active_panel, + &ts->fb_notif)) + E("Error occurred while unregistering active_panel.\n"); +else + if (drm_panel_notifier_unregister(&gNotifier_dummy_panel, + &ts->fb_notif)) + E("Error occurred while unregistering dummy_panel.\n"); + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +#elif defined(HX_CONFIG_DRM) +#if defined(__HIMAX_MOD__) + hx_msm_drm_unregister_client = + (void *)symbol_get("msm_drm_unregister_client"); + if (hx_msm_drm_unregister_client != NULL) { + if (hx_msm_drm_unregister_client(&ts->fb_notif)) + E("Error occurred while unregistering drm_notifier.\n"); + } else + E("hx_msm_drm_unregister_client is NULL\n"); +#else + if (msm_drm_unregister_client(&ts->fb_notif)) + E("Error occurred while unregistering drm_notifier.\n"); +#endif + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +#endif + input_free_device(ts->input_dev); +#if defined(HX_CONTAINER_SPEED_UP) + cancel_delayed_work_sync(&ts->ts_int_work); + destroy_workqueue(ts->ts_int_workqueue); +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + cancel_delayed_work_sync(&ts->work_boot_upgrade); + destroy_workqueue(ts->himax_boot_upgrade_wq); +#endif + himax_gpio_power_deconfig(ts->pdata); + if (himax_mcu_cmd_struct_free) + himax_mcu_cmd_struct_free(); + + kfree(hx_touch_data); + hx_touch_data = NULL; + kfree(ic_data); + ic_data = NULL; + kfree(ts->pdata->virtual_key); + ts->pdata->virtual_key = NULL; + devm_kfree(ts->dev, ts->xfer_buff); + ts->xfer_buff = NULL; + kfree(ts->pdata); + ts->pdata = NULL; + kfree(ts); + ts = NULL; + probe_fail_flag = 0; +#if defined(HX_USE_KSYM) + hx_release_chip_entry(); +#endif + + I("%s: Common section deinited!\n", __func__); +} + +int himax_chip_common_suspend(struct himax_ts_data *ts) +{ + if (ts->suspended) { + I("%s: Already suspended, skip...\n", __func__); + goto END; + } else { + ts->suspended = true; + } + + if (debug_data != NULL && debug_data->flash_dump_going == true) { + I("%s: It is dumping flash, reject suspend\n", __func__); + goto END; + } + + I("%s: enter\n", __func__); + + if (ts->in_self_test == 1) { + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + if (g_core_fp._ap_notify_fw_sus != NULL) + g_core_fp._ap_notify_fw_sus(1); + ts->suspend_resume_done = 1; + goto END; + } + +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) +#if !defined(HX_RESUME_SEND_CMD) + g_core_fp.fp_resend_cmd_func(ts->suspended); +#endif +#endif +#if defined(HX_SMART_WAKEUP) + + if (ts->SMWP_enable) { +#if defined(HX_CODE_OVERLAY) + g_core_fp.fp_0f_overlay(2, 0); +#endif + if (g_core_fp._ap_notify_fw_sus != NULL) + g_core_fp._ap_notify_fw_sus(1); + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + I("%s: SMART WAKE UP enable, reject suspend\n", __func__); + goto END; + } + +#endif + himax_int_enable(0); + himax_report_all_leave_event(ts); + if (g_core_fp.fp_suspend_ic_action != NULL) + g_core_fp.fp_suspend_ic_action(); + + if (!ts->use_irq) { + int32_t cancel_state; + + cancel_state = cancel_work_sync(&ts->work); + if (cancel_state) + himax_int_enable(1); + } + + /*ts->first_pressed = 0;*/ + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + + if (ts->pdata) + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + +END: + + I("%s: END\n", __func__); + + return 0; +} + +int himax_chip_common_resume(struct himax_ts_data *ts) +{ +#if defined(HX_RESUME_SET_FW) + int result = 0; +#endif + + if (ts->suspended == false) { + I("%s: Already resumed, skip...\n", __func__); + goto END; + } else { + ts->suspended = false; + } + + I("%s: enter\n", __func__); + + if (ts->in_self_test == 1) { + atomic_set(&ts->suspend_mode, 0); + ts->diag_cmd = 0; + if (g_core_fp._ap_notify_fw_sus != NULL) + g_core_fp._ap_notify_fw_sus(0); + ts->suspend_resume_done = 1; + goto END; + } + +#if defined(HX_EXCP_RECOVERY) + /* continuous N times record, not total N times. */ + g_zero_event_count = 0; +#endif + + atomic_set(&ts->suspend_mode, 0); + ts->diag_cmd = 0; + + if (ts->pdata) + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); +#if defined(HX_RST_PIN_FUNC) && defined(HX_RESUME_HW_RESET) + if (g_core_fp.fp_ic_reset != NULL) + g_core_fp.fp_ic_reset(false, false); +#endif + +#if defined(HX_RESUME_SET_FW) +#if defined(HX_SMART_WAKEUP) && !defined(HX_SWU_RESUME_SET_FW) + if (!ts->SMWP_enable) { +#endif + + if (g_core_fp.fp_0f_op_file_dirly != NULL) { + result = g_core_fp.fp_0f_op_file_dirly(g_fw_boot_upgrade_name); + if (result) + E("%s: update FW fail, code[%d]!!\n", __func__, result); + } + +#if defined(HX_SMART_WAKEUP) && !defined(HX_SWU_RESUME_SET_FW) + } +#endif +#endif + +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) + if (g_core_fp.fp_resend_cmd_func != NULL) + g_core_fp.fp_resend_cmd_func(ts->suspended); + +#if defined(HX_CODE_OVERLAY)\ + && defined(HX_SMART_WAKEUP)\ + && !defined(HX_SWU_RESUME_SET_FW) + if (ts->SMWP_enable) + g_core_fp.fp_0f_overlay(3, 0); +#endif + if (g_core_fp._ap_notify_fw_sus != NULL) + g_core_fp._ap_notify_fw_sus(0); +#endif + himax_report_all_leave_event(ts); + + if (g_core_fp.fp_resume_ic_action != NULL) + g_core_fp.fp_resume_ic_action(); + + himax_int_enable(1); +/* + *#if defined(HX_ZERO_FLASH) && defined(HX_RESUME_SET_FW) + *ESCAPE_0F_UPDATE: + *#*endif + */ +END: + + I("%s: END\n", __func__); + return 0; +} diff --git a/himax_common.h b/himax_common.h new file mode 100644 index 0000000..cc4e3ab --- /dev/null +++ b/himax_common.h @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef HIMAX_COMMON_H +#define HIMAX_COMMON_H + +#include <linux/uaccess.h> +#include <linux/atomic.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/async.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/input/mt.h> +#include <linux/firmware.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/pm_wakeup.h> +#include <linux/seq_file.h> +#include <linux/proc_fs.h> +#include "himax_platform.h" +#include <linux/kallsyms.h> +#include <linux/version.h> + +#if defined(CONFIG_OF) + #include <linux/of_gpio.h> +#endif + +#define HIMAX_DRIVER_VER "2.0.0.81_ABCD1234_01" + +#define FLASH_DUMP_FILE "/sdcard/HX_Flash_Dump.bin" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define HX_TP_PROC_2T2R +/*if enable, selftest works in driver*/ +/*#define HX_TP_SELF_TEST_DRIVER*/ +#endif +/*===========Himax Option function=============*/ +#define HX_RST_PIN_FUNC +#define HX_EXCP_RECOVERY + +/*#define HX_NEW_EVENT_STACK_FORMAT*/ +/*#define HX_BOOT_UPGRADE*/ +/*#define HX_SMART_WAKEUP*/ +/*#define HX_GESTURE_TRACK*/ +#define HX_RESUME_SEND_CMD /*Need to enable on TDDI chipset*/ +/*#define HX_HIGH_SENSE*/ +/*#define HX_PALM_REPORT*/ +/*#define HX_USB_DETECT_GLOBAL*/ + +/* for MTK special platform.If turning on, + * it will report to system by using specific format. + */ +/*#define HX_PROTOCOL_A*/ +#define HX_PROTOCOL_B_3PA + +#define HX_ZERO_FLASH + +/*system suspend-chipset power off, + *oncell chipset need to enable the definition + */ +/*#define HX_RESUME_HW_RESET*/ + +/*for Himax auto-motive chipset + */ +/*#define HX_PON_PIN_SUPPORT*/ + +/*#define HX_PARSE_FROM_DT*/ + +/*Enable this if testing suspend/resume + *on nitrogen8m + */ +/*#define HX_CONFIG_DRM_PANEL*/ + +/*=============================================*/ + +/* Enable it if driver go into suspend/resume twice */ +/*#undef HX_CONFIG_FB*/ + +/* Enable it if driver go into suspend/resume twice */ +#undef HX_CONFIG_DRM + +#if defined(HX_CONFIG_DRM_PANEL) +#undef HX_CONFIG_FB +#include <drm/drm_panel.h> +extern struct drm_panel gNotifier_dummy_panel; +#elif defined(HX_CONFIG_FB) +#include <linux/notifier.h> +#include <linux/fb.h> +#elif defined(HX_CONFIG_DRM) +#include <linux/msm_drm_notify.h> +#endif + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +#define KERNEL_VER_ABOVE_4_19 +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +#define KERNEL_VER_ABOVE_5_10 +#include <linux/time64.h> +#endif + +#if defined(HX_ZERO_FLASH) +/*zero flash case, you need to setup the fix_touch_info of module*/ +/*Please set the size according to IC*/ +#define DSRAM_SIZE HX_32K_SZ +#define HX_RESUME_SET_FW +/* used for 102p overlay */ +/*#define HX_ALG_OVERLAY*/ +/* used for 102d overlay */ +/*#define HX_CODE_OVERLAY*/ +/*Independent threads run the notification chain notification function resume*/ +/*#define HX_CONTAINER_SPEED_UP*/ +#else +#define HX_TP_PROC_GUEST_INFO +#endif + +#if defined(HX_EXCP_RECOVERY) && defined(HX_ZERO_FLASH) +/* used for 102e/p zero flash */ +#define HW_ED_EXCP_EVENT +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +/* FW Auto upgrade case, you need to setup the fix_touch_info of module + */ +extern char *g_fw_boot_upgrade_name; +#define BOOT_UPGRADE_FWNAME "Himax_firmware.bin" +#if defined(HX_ZERO_FLASH) +extern char *g_fw_mp_upgrade_name; +#define MPAP_FWNAME "Himax_mpfw.bin" +#endif +#endif + +#if defined(HX_PARSE_FROM_DT) +extern uint32_t g_proj_id; +#endif + +#if defined(HX_SMART_WAKEUP) +/*This feature need P-sensor driver notified, and FW need to support*/ +/*#define HX_ULTRA_LOW_POWER*/ +#endif + +#if defined(HX_SMART_WAKEUP) && defined(HX_RESUME_SET_FW) +/* decide whether reload FW after Smart Wake Up */ +#define HX_SWU_RESUME_SET_FW +#endif + +#if defined(HX_CONTAINER_SPEED_UP) +/*Resume queue delay work time after LCM RST (unit:ms) + */ +#define DELAY_TIME 40 +#endif + +#if defined(HX_RST_PIN_FUNC) +/* origin is 20/50 */ +#define RST_LOW_PERIOD_S 5000 +#define RST_LOW_PERIOD_E 5100 +#if defined(HX_ZERO_FLASH) +#define RST_HIGH_PERIOD_S 5000 +#define RST_HIGH_PERIOD_E 5100 +#else +#define RST_HIGH_PERIOD_S 50000 +#define RST_HIGH_PERIOD_E 50100 +#endif +#endif + +#if defined(HX_CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(HX_CONFIG_DRM) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#endif + +/* notice the size of isram */ +#define HX_MAX_WRITE_SZ (128 * 1024) +#define HX_MAX_READ_SZ (1024) + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_85XX_A_SERIES_PWON "HX85xxA" +#define HX_85XX_B_SERIES_PWON "HX85xxB" +#define HX_85XX_C_SERIES_PWON "HX85xxC" +#define HX_85XX_D_SERIES_PWON "HX85xxD" +#define HX_85XX_E_SERIES_PWON "HX85xxE" +#define HX_85XX_ES_SERIES_PWON "HX85xxES" +#define HX_85XX_F_SERIES_PWON "HX85xxF" +#define HX_85XX_G_SERIES_PWON "HX85xxG" +#define HX_85XX_H_SERIES_PWON "HX85xxH" +#define HX_85XX_J_SERIES_PWON "HX85xxJ" +#define HX_83100A_SERIES_PWON "HX83100A" +#define HX_83102A_SERIES_PWON "HX83102A" +#define HX_83102B_SERIES_PWON "HX83102B" +#define HX_83102D_SERIES_PWON "HX83102D" +#define HX_83102E_SERIES_PWON "HX83102E" +#define HX_83103A_SERIES_PWON "HX83103A" +#define HX_83106A_SERIES_PWON "HX83106A" +#define HX_83108A_SERIES_PWON "HX83108A" +#define HX_83110A_SERIES_PWON "HX83110A" +#define HX_83110B_SERIES_PWON "HX83110B" +#define HX_83111B_SERIES_PWON "HX83111B" +#define HX_83112A_SERIES_PWON "HX83112A" +#define HX_83112B_SERIES_PWON "HX83112B" +#define HX_83113A_SERIES_PWON "HX83113A" +#define HX_83112D_SERIES_PWON "HX83112D" +#define HX_83112E_SERIES_PWON "HX83112E" +#define HX_83112F_SERIES_PWON "HX83112F" +#define HX_83121A_SERIES_PWON "HX83121A" +#define HX_83191A_SERIES_PWON "HX83191A" +#define HX_83192A_SERIES_PWON "HX83192A" + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +#define SHIFTBITS 5 + +#define FW_SIZE_32k 32768 +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 +#define FW_SIZE_255k 261120 + +#define NO_ERR 0 +#define READY_TO_SERVE 1 +#define WORK_OUT 2 +#define HX_EMBEDDED_FW 3 +#define BUS_FAIL -1 +#define HX_INIT_FAIL -1 +#define MEM_ALLOC_FAIL -2 +#define CHECKSUM_FAIL -3 +#define GESTURE_DETECT_FAIL -4 +#define INPUT_REGISTER_FAIL -5 +#define FW_NOT_READY -6 +#define LENGTH_FAIL -7 +#define OPEN_FILE_FAIL -8 +#define PROBE_FAIL -9 +#define ERR_WORK_OUT -10 +#define ERR_STS_WRONG -11 +#define ERR_TEST_FAIL -12 +#define HW_CRC_FAIL 1 + +#define HX_FINGER_ON 1 +#define HX_FINGER_LEAVE 2 + +#if defined(HX_PALM_REPORT) +#define PALM_REPORT 1 +#define NOT_REPORT -1 +#endif + +#define STYLUS_INFO_SZ 12 + +#if defined(__EMBEDDED_FW__) +extern const uint8_t _binary___Himax_firmware_bin_start[]; +extern const uint8_t _binary___Himax_firmware_bin_end[]; +extern struct firmware g_embedded_fw; +#endif + +enum HX_TS_PATH { + HX_REPORT_COORD = 1, + HX_REPORT_SMWP_EVENT, + HX_REPORT_COORD_RAWDATA, +}; + +enum HX_TS_STATUS { + HX_TS_GET_DATA_FAIL = -4, + HX_EXCP_EVENT, + HX_CHKSUM_FAIL, + HX_PATH_FAIL, + HX_TS_NORMAL_END = 0, + HX_EXCP_REC_OK, + HX_READY_SERVE, + HX_REPORT_DATA, + HX_EXCP_WARNING, + HX_IC_RUNNING, + HX_ZERO_EVENT_COUNT, + HX_RST_OK, +}; + +enum cell_type { + CHIP_IS_ON_CELL, + CHIP_IS_IN_CELL +}; + +#if defined(HX_SMART_WAKEUP) +#define HX_KEY_DOUBLE_CLICK KEY_POWER +#define HX_KEY_UP KEY_UP +#define HX_KEY_DOWN KEY_DOWN +#define HX_KEY_LEFT KEY_LEFT +#define HX_KEY_RIGHT KEY_RIGHT +#define HX_KEY_C KEY_C +#define HX_KEY_Z KEY_Z +#define HX_KEY_M KEY_M +#define HX_KEY_O KEY_O +#define HX_KEY_S KEY_S +#define HX_KEY_V KEY_V +#define HX_KEY_W KEY_W +#define HX_KEY_E KEY_E +#define HX_KEY_LC_M 263 +#define HX_KEY_AT 264 +#define HX_KEY_RESERVE 265 +#define HX_KEY_FINGER_GEST 266 +#define HX_KEY_V_DOWN 267 +#define HX_KEY_V_LEFT 268 +#define HX_KEY_V_RIGHT 269 +#define HX_KEY_F_RIGHT 270 +#define HX_KEY_F_LEFT 271 +#define HX_KEY_DF_UP 272 +#define HX_KEY_DF_DOWN 273 +#define HX_KEY_DF_LEFT 274 +#define HX_KEY_DF_RIGHT 275 +#endif + +enum fix_touch_info { + FIX_HX_RX_NUM = 48, + FIX_HX_TX_NUM = 32, + FIX_HX_BT_NUM = 0, + FIX_HX_MAX_PT = 10, + FIX_HX_INT_IS_EDGE = true, + FIX_HX_STYLUS_FUNC = 0, +#if defined(HX_TP_PROC_2T2R) + FIX_HX_RX_NUM_2 = 0, + FIX_HX_TX_NUM_2 = 0, +#endif +}; + +#if defined(HX_ZERO_FLASH) + #define HX_SPI_OPERATION + #define HX_0F_DEBUG +#endif +struct himax_ic_data { + int vendor_fw_ver; + int vendor_config_ver; + int vendor_touch_cfg_ver; + int vendor_display_cfg_ver; + int vendor_cid_maj_ver; + int vendor_cid_min_ver; + int vendor_panel_ver; + int vendor_sensor_id; + int ic_adc_num; + uint8_t vendor_cus_info[12]; + uint8_t vendor_proj_info[12]; + uint32_t flash_size; + uint32_t HX_RX_NUM; + uint32_t HX_TX_NUM; + uint32_t HX_BT_NUM; + uint32_t HX_X_RES; + uint32_t HX_Y_RES; + uint32_t HX_MAX_PT; + uint8_t HX_INT_IS_EDGE; + uint8_t HX_STYLUS_FUNC; +#if defined(HX_TP_PROC_2T2R) + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif +}; + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_target_point_data { + int x; + int y; + int w; + int id; +}; + +struct himax_target_stylus_data { + int32_t x; + int32_t y; + int32_t w; + int32_t id; + uint32_t hover; + int32_t tilt_x; + uint32_t btn; + uint32_t btn2; + int32_t tilt_y; + uint32_t on; + int pre_btn; + int pre_btn2; +}; + +struct himax_target_report_data { + + struct himax_target_point_data *p; + + int finger_on; + int finger_num; + +#if defined(HX_SMART_WAKEUP) + int SMWP_event_chk; +#endif + + struct himax_target_stylus_data *s; + + int ig_count; +}; + +struct himax_report_data { + int touch_all_size; + int raw_cnt_max; + int raw_cnt_rmd; + int touch_info_size; + uint8_t finger_num; + uint8_t finger_on; + uint8_t *hx_coord_buf; + uint8_t hx_state_info[2]; +#if defined(HX_SMART_WAKEUP) + int event_size; + uint8_t *hx_event_buf; +#endif + + int rawdata_size; + uint8_t diag_cmd; + uint8_t *hx_rawdata_buf; + uint8_t rawdata_frame_size; +}; + +struct himax_ts_data { + bool initialized; + bool suspended; + int notouch_frame; + int ic_notouch_frame; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_cmd; + char chip_name[30]; + uint8_t chip_cell_type; + + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t coordInfoSize; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + uint16_t old_finger; + int hx_point_num; + uint8_t hx_stylus_num; + + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int rst_gpio; + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + + struct input_dev *stylus_dev; + + struct hrtimer timer; + struct i2c_client *client; + struct himax_platform_data *pdata; + struct himax_virtual_key *button; + struct mutex rw_lock; + atomic_t irq_state; + spinlock_t irq_lock; + +/******* SPI-start *******/ + struct spi_device *spi; + int hx_irq; + uint8_t *xfer_buff; +/******* SPI-end *******/ + + int in_self_test; + int suspend_resume_done; + int bus_speed; + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) + struct notifier_block fb_notif; + struct workqueue_struct *himax_att_wq; + struct delayed_work work_att; +#endif + + struct workqueue_struct *dump_wq; + struct work_struct dump_work; + struct workqueue_struct *himax_boot_upgrade_wq; + struct delayed_work work_boot_upgrade; + +#if defined(HX_CONTAINER_SPEED_UP) + struct workqueue_struct *ts_int_workqueue; + struct delayed_work ts_int_work; +#endif + + struct workqueue_struct *himax_diag_wq; + struct delayed_work himax_diag_delay_work; + +#if defined(HX_SMART_WAKEUP) + uint8_t SMWP_enable; + uint8_t gesture_cust_en[26]; + struct wakeup_source *ts_SMWP_wake_lock; +#if defined(HX_ULTRA_LOW_POWER) + bool psensor_flag; +#endif +#endif + +#if defined(HX_HIGH_SENSE) + uint8_t HSEN_enable; +#endif + +#if defined(HX_USB_DETECT_GLOBAL) + uint8_t usb_connected; + uint8_t *cable_config; +#endif + +#if defined(HX_TP_PROC_GUEST_INFO) + struct workqueue_struct *guest_info_wq; + struct work_struct guest_info_work; +#endif + + +}; + +struct himax_debug { + bool flash_dump_going; + bool is_checking_irq; + bool is_call_help; + void (*fp_ts_dbg_func)(struct himax_ts_data *ts, int start); + int (*fp_set_diag_cmd)(struct himax_ic_data *ic_data, + struct himax_report_data *hx_touch_data); +}; + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +#if defined(HX_HIGH_SENSE) + void himax_set_HSEN_func(uint8_t HSEN_enable); +#endif + +#if defined(HX_SMART_WAKEUP) +void himax_set_SMWP_func(uint8_t SMWP_enable); + +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +extern uint8_t *wake_event_buffer; +#endif + +extern int g_mmi_refcnt; +extern int *g_inspt_crtra_flag; +extern uint32_t g_hx_chip_inited; +/*void himax_HW_reset(uint8_t loadconfig,uint8_t int_off);*/ + +int himax_chip_common_suspend(struct himax_ts_data *ts); +int himax_chip_common_resume(struct himax_ts_data *ts); + +extern struct filename* (*kp_getname_kernel)(const char *filename); +extern void (*kp_putname_kernel)(struct filename *name); +extern struct file * (*kp_file_open_name)(struct filename *name, + int flags, umode_t mode); + +struct himax_core_fp; +extern struct himax_core_fp g_core_fp; +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; +extern struct device *g_device; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + int himax_debug_init(void); + int himax_debug_remove(void); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + extern char *g_rslt_data; + extern void (*fp_himax_self_test_init)(void); +#endif + +#if defined(HX_CONFIG_DRM) +#if defined(HX_CONFIG_DRM_PANEL) + extern struct drm_panel *active_panel; +#endif +#endif +extern int HX_TOUCH_INFO_POINT_CNT; + +extern bool ic_boot_done; + +int himax_parse_dt(struct himax_ts_data *ts, struct himax_platform_data *pdata); + +extern void himax_parse_dt_ic_info(struct himax_ts_data *ts, + struct himax_platform_data *pdata); + +int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status); + +int himax_report_data_init(void); + +int himax_dev_set(struct himax_ts_data *ts); +int himax_input_register_device(struct input_dev *input_dev); + +#endif diff --git a/himax_debug.c b/himax_debug.c new file mode 100644 index 0000000..a442225 --- /dev/null +++ b/himax_debug.c @@ -0,0 +1,3485 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for debug nodes + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_debug.h" +#include "himax_ic_core.h" + +#if defined(HX_TP_PROC_2T2R) + bool Is_2T2R; +EXPORT_SYMBOL(Is_2T2R); + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif + +uint8_t g_diag_arr_num; + +int g_max_mutual; +int g_min_mutual = 0xFFFF; +int g_max_self; +int g_min_self = 0xFFFF; + +/* moved from debug.h */ + +static char g_file_path[256]; + +uint8_t proc_reg_addr[4]; +uint8_t proc_reg_addr_type; +uint8_t *proc_reg_buf; +uint8_t proc_reg_85xx_flag; + +struct proc_dir_entry *himax_proc_stack_file; +struct proc_dir_entry *himax_proc_delta_file; +struct proc_dir_entry *himax_proc_dc_file; +struct proc_dir_entry *himax_proc_baseline_file; +bool dsram_flag; + +#if defined(HX_TP_PROC_2T2R) +uint32_t *diag_mutual_2; +#endif +int32_t *diag_mutual; +int32_t *diag_mutual_new; +int32_t *diag_mutual_old; +uint8_t hx_state_info[2]; +uint8_t diag_coor[128]; +int32_t *diag_self; +int32_t *diag_self_new; +int32_t *diag_self_old; + +struct proc_dir_entry *himax_proc_debug_file; +bool fw_update_complete; +bool fw_update_going; +int handshaking_result; +unsigned char debug_level_cmd; +uint8_t cmd_set[8]; +uint8_t mutual_set_flag; + +struct proc_dir_entry *himax_proc_flash_dump_file; +uint8_t *g_dump_buffer; +uint8_t g_dump_cmd; +uint8_t g_dump_show; +uint32_t g_dump_addr; +uint32_t g_dump_size; +uint8_t g_flash_progress; +bool g_flash_dump_rst; /*Fail = 0, Pass = 1*/ + +uint32_t **raw_data_array; +uint8_t X_NUM; +uint8_t Y_NUM; +uint8_t sel_type = 0x0D; + +/* Moved from debug.h End */ +char buf_tmp[BUF_SIZE] = {0}; + +struct proc_dir_entry *himax_proc_pen_pos_file; + +#if defined(KERNEL_VER_ABOVE_5_10) +struct timespec64 timeStart, timeEnd, timeDelta; +#else +struct timespec timeStart, timeEnd, timeDelta; +#endif +int g_switch_mode; +/* + * Segment : Himax PROC Debug Function + */ + +/****** useful functions ******/ +int count_char(char *input) +{ + int count = 0; + int i = 0; + + for (i = 0; input[i] != '\0'; i++) + count++; + return count; +} + +#define SIOS_DBG_STR "i = %d, j =%d, idx_find_str=%d, sts_find[%d]=%d\n" +static int str_idx_of_str(char *base, char *find) +{ + int i = 0, j = 0; + int idx_find_str = 0; + int len_find_str = strlen(find); + int len_base_str = strlen(base); + int ret = -1; + int sts_find[256]; + if (len_find_str > 256) + len_find_str = 256; + + for (i = 0; i < len_base_str; i++) { + if (i + len_find_str > len_base_str) { + I("Command Check End!\n"); + sts_find[0] = -1; + goto END; + } + for (j = 0; j < len_find_str; j++) { + if (*(base + i + j) == *(find + idx_find_str)) { + sts_find[idx_find_str] = i + j; + I(SIOS_DBG_STR, + i, j, idx_find_str, + idx_find_str, sts_find[idx_find_str]); + if (idx_find_str++ == (len_find_str - 1)) { + I("all check finish!\n"); + goto END; + } + } else { + idx_find_str = 0; + sts_find[0] = -1; + break; + } + } + } +END: + ret = sts_find[0]; + return ret; +} +static void _str_to_arr_in_char(char **arr, int arr_size, char *str, char c) +{ + int i = 0; + int _arr_str_idx = 0; + int _arr_idx = 0; + int _arr_max_idx = arr_size; + + for (i = 0; str[i] != '\0'; i++) { + if (_arr_max_idx <= _arr_idx) { + I("%s: Oversize!\n", __func__); + goto END; + } + if (str[i] == c || str[i] == '\0') { + I("%s: String parse compelete!\n", __func__); + _arr_idx++; + _arr_str_idx = 0; + } else { + arr[_arr_idx][_arr_str_idx] = str[i]; + _arr_str_idx++; + continue; + } + } +END: + return; +} + +bool chk_normal_str(char *str) +{ + int i = 0; + bool result = false; + int str_len = strlen(str); + + I("%s, str_len=%d\n", __func__, str_len); + for (i = 0; i < str_len; i++) { + if (str[i] >= '0' && str[i] <= '9') { + result = true; + continue; + } else if (str[i] >= 'A' && str[i] <= 'Z') { + result = true; + continue; + } else if (str[i] >= 'a' && str[i] <= 'z') { + result = true; + continue; + } else { + result = false; + break; + } + } + return result; +} +bool chk_normal_char(char c) +{ + bool result = false; + + if (c >= '0' && c <= '9') + result = true; + else if (c >= 'A' && c <= 'Z') + result = true; + else if (c >= 'a' && c <= 'z') + result = true; + else + result = false; + + return result; +} +/* claculate 10's power function */ +static int himax_power_cal(int pow, int number, int base) +{ + int i = 0; + int result = 1; + + for (i = 0; i < pow; i++) + result *= base; + result = result * number; + + return result; + +} + +/* String to int */ +static int hiamx_parse_str2int(char *str) +{ + int i = 0; + int temp_cal = 0; + int result = -948794; + unsigned int str_len = strlen(str); + int negtive_flag = 0; + + for (i = 0; i < str_len; i++) { + if (i == 0) + result = 0; + if (str[i] != '-' && str[i] > '9' && str[i] < '0') { + E("%s: Parsing fail!\n", __func__); + result = -9487; + negtive_flag = 0; + break; + } + if (str[i] == '-') { + negtive_flag = 1; + continue; + } + temp_cal = str[i] - '0'; + result += himax_power_cal(str_len-i-1, temp_cal, 10); + /* str's the lowest char is the number's the highest number + * So we should reverse this number before using the power + * function + * -1: starting number is from 0 ex:10^0 = 1,10^1=10 + */ + } + + if (negtive_flag == 1) + result = 0 - result; + + return result; +} + +/* String in Hex to int */ +static int hx_parse_hexstr2int(char *str) +{ + int i = 0; + int temp_cal = 0; + int result = -948794; + unsigned int str_len = strlen(str); + int negtive_flag = 0; + + for (i = 0; i < str_len; i++) { + if (i == 0) + result = 0; + if (str[i] == '-' && i == 0) { + negtive_flag = 1; + continue; + } else if (str[i] <= '9' && str[i] >= '0') { + temp_cal = str[i] - '0'; + result += himax_power_cal(str_len-i-1, temp_cal, 16); + } else if (str[i] <= 'f' && str[i] >= 'a') { + temp_cal = str[i] - 'a' + 10; + result += himax_power_cal(str_len-i-1, temp_cal, 16); + } else if (str[i] <= 'F' && str[i] >= 'A') { + temp_cal = str[i] - 'A' + 10; + result += himax_power_cal(str_len-i-1, temp_cal, 16); + } else { + E("%s: Parsing fail!\n", __func__); + result = -9487; + negtive_flag = 0; + break; + } + } + + if (negtive_flag == 1) + result = 0 - result; + + return result; +} + +/****** end ******/ +static int himax_crc_test_read(struct seq_file *m) +{ + int ret = 0; + uint8_t result = 0; + uint32_t size = 0; + + g_core_fp.fp_sense_off(true); + msleep(20); + if (g_core_fp._diff_overlay_flash() == 1) + size = FW_SIZE_128k; + else + size = FW_SIZE_64k; + result = g_core_fp.fp_calculateChecksum(false, size); + g_core_fp.fp_sense_on(0x01); + + if (result) + seq_printf(m, + "CRC test is Pass!\n"); + else + seq_printf(m, + "CRC test is Fail!\n"); + + + return ret; +} + +static int himax_proc_FW_debug_read(struct seq_file *m) +{ + int ret = 0; + uint8_t i = 0; + uint8_t addr[4] = {0}; + uint8_t data[4] = {0}; + int len = 0; + + len = (size_t)(sizeof(dbg_reg_ary)/sizeof(uint32_t)); + + for (i = 0; i < len; i++) { + himax_parse_assign_cmd(dbg_reg_ary[i], addr, 4); + g_core_fp.fp_register_read(addr, data, DATA_LEN_4); + + seq_printf(m, + "reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + dbg_reg_ary[i], data[0], data[1], data[2], data[3]); + I("reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + dbg_reg_ary[i], data[0], data[1], data[2], data[3]); + } + + return ret; +} + +static int himax_attn_read(struct seq_file *m) +{ + int ret = 0; + struct himax_ts_data *ts_data; + + ts_data = private_ts; + + seq_printf(m, "attn = %x\n", + himax_int_gpio_read(ts_data->pdata->gpio_irq)); + + return ret; +} + +static int himax_layout_read(struct seq_file *m) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + if (debug_data->is_call_help) { + seq_printf(m, HELP_LAYOUT); + debug_data->is_call_help = false; + } else { + seq_printf(m, "%d ", + ts->pdata->abs_x_min); + seq_printf(m, "%d ", + ts->pdata->abs_x_max); + seq_printf(m, "%d ", + ts->pdata->abs_y_min); + seq_printf(m, "%d ", + ts->pdata->abs_y_max); + seq_puts(m, "\n"); + } + + return ret; +} + +static ssize_t himax_layout_write(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5] = {0}; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + goto END; + } else { + + for (i = 0; i < 20; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + if (i - j <= 5) { + memcpy(buf_tmp, buf + j, i - j); + } else { + I("buffer size is over 5 char\n"); + return len; + } + + j = i + 1; + + if (k < 4) { + ret = kstrtoul(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + + if (k == 4) { + ts->pdata->abs_x_min = layout[0]; + ts->pdata->abs_x_max = (layout[1] - 1); + ts->pdata->abs_y_min = layout[2]; + ts->pdata->abs_y_max = (layout[3] - 1); + I("%d, %d, %d, %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else { + I("ERR@%d, %d, %d, %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + } + } +END: + return len; +} + +#if defined(HX_EXCP_RECOVERY) +#if defined(HW_ED_EXCP_EVENT) +static int himax_excp_cnt_read(struct seq_file *m) +{ + int ret = 0; + + I("%s: enter, %d\n", __func__, __LINE__); + + if (debug_data->is_call_help) { + seq_printf(m, HELP_EXCPT); + debug_data->is_call_help = false; + } else { + seq_printf(m, + "EB_cnt = %d, EC_cnt = %d, EE_cnt = %d\n", + hx_EB_event_flag, + hx_EC_event_flag, + hx_EE_event_flag); + } + return ret; +} + +static ssize_t himax_excp_cnt_write(char *buf, size_t len) +{ + int i = 0; + + if (len >= 12) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + } else { + if (buf[i] == '0') { + I("Clear EXCEPTION Flag\n"); + hx_EB_event_flag = 0; + hx_EC_event_flag = 0; + hx_EE_event_flag = 0; + } + } + + return len; +} +#else +static int himax_excp_cnt_read(struct seq_file *m) +{ + int ret = 0; + + I("%s: enter, %d\n", __func__, __LINE__); + if (debug_data->is_call_help) { + seq_printf(m, HELP_EXCPT); + debug_data->is_call_help = false; + } else { + seq_printf(m, + "EB_cnt = %d, EC_cnt = %d, ED_cnt = %d\n", + hx_EB_event_flag, + hx_EC_event_flag, + hx_ED_event_flag); + } + return ret; +} + +static ssize_t himax_excp_cnt_write(char *buf, size_t len) +{ + int i = 0; + + if (len >= 12) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + } else { + I("Clear EXCEPTION Flag\n"); + + if (buf[i] == '0') { + hx_EB_event_flag = 0; + hx_EC_event_flag = 0; + hx_ED_event_flag = 0; + } + } + return len; +} +#endif +#endif + +static ssize_t himax_sense_on_off_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (buf[0] == '0') { + g_core_fp.fp_sense_off(true); + I("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == 's') { + g_core_fp.fp_sense_on(0x00); + I("Sense on re-map on, run sram\n"); + } else { + g_core_fp.fp_sense_on(0x01); + I("Sense on re-map off, run flash\n"); + } + } else { + I("Do nothing\n"); + } + + return len; +} + +static int test_irq_pin(void) +{ + struct himax_ts_data *ts = private_ts; + int result = NO_ERR; + int irq_sts = -1; + uint8_t tmp_addr[DATA_LEN_4] = {0}; + uint8_t tmp_data[DATA_LEN_4] = {0}; + uint8_t tmp_read[DATA_LEN_4] = {0}; + + g_core_fp.fp_sense_off(true); + + I("check IRQ LOW\n"); + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028060, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000002, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028064, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028068, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000000, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + irq_sts = himax_int_gpio_read(ts->pdata->gpio_irq); + if (irq_sts == 0) { + I("[LOW]Now IRQ is LOW!\n"); + result += NO_ERR; + } else { + I("[LOW]Now IRQ is High!\n"); + result += 1; + } + + I("check IRQ High\n"); + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028060, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000002, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028064, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028068, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + irq_sts = himax_int_gpio_read(ts->pdata->gpio_irq); + if (irq_sts == 0) { + I("[High]Now IRQ is LOW!\n"); + result += 1; + } else { + I("[High]Now IRQ is High!\n"); + result += NO_ERR; + } + debug_data->is_checking_irq = false; + + g_core_fp.fp_sense_on(0x00); + + return result; +} +static int himax_int_en_read(struct seq_file *m) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + int check_rslt = -1; + + + if (debug_data->is_checking_irq) { + check_rslt = test_irq_pin(); + if (check_rslt == NO_ERR) { + seq_printf(m, + "IRQ check OK!\n"); + } else { + seq_printf(m, + "IRQ check Fail!\n"); + } + } else { + seq_printf(m, "irq_status:%d\n", + ts->irq_enabled); + } + return ret; +} + +static ssize_t himax_int_en_write(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + + if (buf[0] == '0') { + himax_int_enable(0); + } else if (buf[0] == '1') { + himax_int_enable(1); + } else if (buf[0] == '2') { + himax_int_enable(0); + free_irq(ts->hx_irq, ts); + ts->irq_enabled = 0; + } else if (buf[0] == '3') { + ret = himax_int_en_set(); + + if (ret == 0) { + ts->irq_enabled = 1; + atomic_set(&ts->irq_state, 1); + } + } else if (str_idx_of_str(buf, "test") >= 0) { + debug_data->is_checking_irq = true; + I("Checking IRQ start!\n"); + } else + return -EINVAL; + + return len; +} + +static int himax_irq_info_read(struct seq_file *m) +{ + // struct himax_ts_data *ts = private_ts; + int ret = 0; + + if (g_core_fp.fp_read_ic_trigger_type() == 1) + seq_printf(m, + "IC Interrupt type is edge trigger.\n"); + else if (g_core_fp.fp_read_ic_trigger_type() == 0) + seq_printf(m, + "IC Interrupt type is level trigger.\n"); + else + seq_printf(m, + "Unkown IC trigger type.\n"); + + if (ic_data->HX_INT_IS_EDGE) + seq_printf(m, + "Driver register Interrupt : EDGE TIRGGER\n"); + else + seq_printf(m, + "Driver register Interrupt : LEVEL TRIGGER\n"); + + return ret; +} + +static ssize_t himax_irq_info_write(char *buf, size_t len) +{ + // struct himax_ts_data *ts = private_ts; + // int ret = 0; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + + + return len; +} + +static int himax_debug_level_read(struct seq_file *m) +{ + struct himax_ts_data *ts_data; + int ret = 0; + + ts_data = private_ts; + seq_printf(m, "tsdbg: %d\n", + g_ts_dbg); + seq_printf(m, "level: %X\n", + ts_data->debug_log_level); + + + return ret; +} + +static ssize_t himax_debug_level_write(char *buf, size_t len) +{ + struct himax_ts_data *ts; + int i; + + int cmp_rslt = -1; + + ts = private_ts; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + + cmp_rslt = str_idx_of_str(buf, "tsdbg"); + if (cmp_rslt >= 0) { + if (buf[5] == '1') { + I("Open Ts Debug!\n"); + g_ts_dbg = 1; + } else if (buf[5] == '0') { + I("Close Ts Debug!\n"); + g_ts_dbg = 0; + } else { + E("Parameter fault for ts debug\n"); + } + } else { + + ts->debug_log_level = 0; + + for (i = 0; i < len; i++) { + if (buf[i] >= '0' && buf[i] <= '9') + ts->debug_log_level |= (buf[i] - '0'); + else if (buf[i] >= 'A' && buf[i] <= 'F') + ts->debug_log_level |= (buf[i] - 'A' + 10); + else if (buf[i] >= 'a' && buf[i] <= 'f') + ts->debug_log_level |= (buf[i] - 'a' + 10); + + if (i != len - 1) + ts->debug_log_level <<= 4; + } + I("Now debug level value=%d\n", ts->debug_log_level); + + if (ts->debug_log_level & BIT(4)) { + I("Turn on/Enable Debug Mode for Inspection!\n"); + goto END_FUNC; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 + && ts->pdata->screenHeight > 0 + && (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 + && (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = + (ts->pdata->screenWidth << SHIFTBITS) + / (ts->pdata->abs_x_max + - ts->pdata->abs_x_min); + ts->heightFactor = + (ts->pdata->screenHeight << SHIFTBITS) + / (ts->pdata->abs_y_max + - ts->pdata->abs_y_min); + + if (ts->widthFactor > 0 && + ts->heightFactor > 0) { + ts->useScreenRes = 1; + } else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else + I("En-finger-dbg with raw position mode!\n"); + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } + } +END_FUNC: + return len; +} + +static int himax_proc_register_read(struct seq_file *m) +{ + int ret = 0; + uint16_t i; + + if (debug_data->is_call_help) { + seq_printf(m, HELP_REGISTER); + debug_data->is_call_help = false; + } else { + + memset(proc_reg_buf, 0x00, 128 * sizeof(uint8_t)); + + I("himax_register_show: %02X,%02X,%02X,%02X\n", + proc_reg_addr[3], proc_reg_addr[2], proc_reg_addr[1], + proc_reg_addr[0]); + + if (proc_reg_addr_type == 1) { + ret = himax_bus_read(proc_reg_addr[0], proc_reg_buf, + 128); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + } else { + if (proc_reg_85xx_flag) + g_core_fp.fp_idle_mode(1); + + g_core_fp.fp_register_read(proc_reg_addr, proc_reg_buf, + 128); + + /* don't enable idle mode ?? + *if (proc_reg_85xx_flag) + * g_core_fp.fp_idle_mode(0); + */ + } + + seq_printf(m, "command: %02X,%02X,%02X,%02X\n", + proc_reg_addr[3], proc_reg_addr[2], proc_reg_addr[1], + proc_reg_addr[0]); + + for (i = 0; i < 128; i++) { + seq_printf(m, "0x%2.2X ", proc_reg_buf[i]); + if ((i % 16) == 15) + seq_puts(m, "\n"); + + } + + seq_puts(m, "\n"); + } + + return ret; +} + +static ssize_t himax_proc_register_write(char *buf, size_t len) +{ + char buff_tmp[16] = {0}; + uint8_t length = 0; + uint8_t byte_length = 0; + unsigned long result = 0; + uint8_t i = 0; + char *data_str = NULL; + uint8_t w_data[20] = {0}; + uint8_t x_pos[20] = {0}; + uint8_t count = 0; + int ret = 0; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + I("himax %s\n", buf); + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + goto END; + } + + memset(proc_reg_addr, 0x0, sizeof(proc_reg_addr)); + proc_reg_85xx_flag = 0; + + if ((buf[0] == 'r' || buf[0] == 'w') + && buf[1] == ':' && buf[2] == 'x') { + length = strlen(buf); + + /* I("%s: length = %d.\n", __func__,length); */ + for (i = 0; i < length; i++) { + /* find postion of 'x' */ + if (buf[i] == 'x') { + x_pos[count] = i; + count++; + } + } + + data_str = strrchr(buf, 'x'); + I("%s: %s.\n", __func__, data_str); + length = strlen(data_str + 1); + + switch (buf[0]) { + case 'r': + if (buf[3] == 'F' && buf[4] == 'E' && length == 4) { + length = length - 2; + proc_reg_addr_type = 1; + memcpy(buff_tmp, data_str + 3, length); + } else { + proc_reg_addr_type = 0; + memcpy(buff_tmp, data_str + 1, length); + } + byte_length = length / 2; + if (!kstrtoul(buff_tmp, 16, &result)) { + for (i = 0; i < byte_length; i++) + proc_reg_addr[i] = (uint8_t)(result >> (i * 8)); + } + + if (strcmp(HX_85XX_H_SERIES_PWON, private_ts->chip_name) == 0) + proc_reg_85xx_flag = 1; + + break; + + case 'w': + if (buf[3] == 'F' && buf[4] == 'E') { + proc_reg_addr_type = 1; + memcpy(buff_tmp, buf + 5, length); + } else { + proc_reg_addr_type = 0; + memcpy(buff_tmp, buf + 3, length); + } + + if (count < 3) { + byte_length = length / 2; + + if (!kstrtoul(buff_tmp, 16, &result)) { + /* command */ + for (i = 0; i < byte_length; i++) + proc_reg_addr[i] = + (uint8_t)(result >> (i * 8)); + } + + if (!kstrtoul(data_str + 1, 16, &result)) { + /* data */ + for (i = 0; i < byte_length; i++) + w_data[i] = (uint8_t)(result >> i * 8); + } + } else { + for (i = 0; i < count; i++) { + /* parsing addr after 'x' */ + memset(buff_tmp, 0x0, sizeof(buff_tmp)); + if (proc_reg_addr_type != 0 && i != 0) + byte_length = 2; + else + byte_length = x_pos[1] - x_pos[0] - 2; + /* original */ + + memcpy(buff_tmp, buf+x_pos[i]+1, byte_length); + + if (!kstrtoul(buff_tmp, 16, &result)) { + if (i == 0) + proc_reg_addr[i] = + (uint8_t)(result); + else + w_data[i - 1] = + (uint8_t)(result); + } + } + + byte_length = count - 1; + + if (strcmp(HX_85XX_H_SERIES_PWON, private_ts->chip_name) + == 0) + proc_reg_85xx_flag = 1; + } + + if (proc_reg_addr_type == 1) { + ret = himax_bus_write(proc_reg_addr[0], w_data, + byte_length); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + } else { + if (proc_reg_85xx_flag) + g_core_fp.fp_idle_mode(1); + + g_core_fp.fp_register_write(proc_reg_addr, w_data, + byte_length); + + if (proc_reg_85xx_flag) + g_core_fp.fp_idle_mode(0); + } + + break; + }; + } +END: + return len; +} + +int32_t *getMutualBuffer(void) +{ + return diag_mutual; +} +int32_t *getMutualNewBuffer(void) +{ + return diag_mutual_new; +} +int32_t *getMutualOldBuffer(void) +{ + return diag_mutual_old; +} +int32_t *getSelfBuffer(void) +{ + return diag_self; +} +int32_t *getSelfNewBuffer(void) +{ + return diag_self_new; +} +int32_t *getSelfOldBuffer(void) +{ + return diag_self_old; +} +void setMutualBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_mutual = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); +} +void setMutualNewBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_mutual_new = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); +} +void setMutualOldBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_mutual_old = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); +} +void setSelfBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_self = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); +} +void setSelfNewBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_self_new = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); +} +void setSelfOldBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_self_old = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); +} + +#if defined(HX_TP_PROC_2T2R) +int32_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +void setMutualBuffer_2(uint8_t x_num_2, uint8_t y_num_2) +{ + diag_mutual_2 = + kzalloc(x_num_2 * y_num_2 * sizeof(int32_t), GFP_KERNEL); +} +#endif + +int himax_set_diag_cmd(struct himax_ic_data *ic_data, + struct himax_report_data *hx_touch_data) +{ + struct himax_ts_data *ts = private_ts; + int32_t *mutual_data; + int32_t *self_data; + int mul_num; + int self_num; + /* int RawDataLen = 0; */ + hx_touch_data->diag_cmd = ts->diag_cmd; + + if (hx_touch_data->diag_cmd >= 1 && hx_touch_data->diag_cmd <= 7) { + /* Check event stack CRC */ + if (!g_core_fp.fp_diag_check_sum(hx_touch_data)) + goto bypass_checksum_failed_packet; + +#if defined(HX_TP_PROC_2T2R) + if (Is_2T2R && (hx_touch_data->diag_cmd >= 4 && + hx_touch_data->diag_cmd <= 6)) { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + /* initiallize the block number of mutual and self */ + mul_num = ic_data->HX_RX_NUM_2 * ic_data->HX_TX_NUM_2; + self_num = ic_data->HX_RX_NUM_2 + ic_data->HX_TX_NUM_2; + } else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + /* initiallize the block number of mutual and self */ + mul_num = ic_data->HX_RX_NUM * ic_data->HX_TX_NUM; + self_num = ic_data->HX_RX_NUM + ic_data->HX_TX_NUM; + } + g_core_fp.fp_diag_parse_raw_data(hx_touch_data, mul_num, + self_num, hx_touch_data->diag_cmd, mutual_data, + self_data); + } else if (hx_touch_data->diag_cmd == 8) { + memset(diag_coor, 0x00, sizeof(diag_coor)); + memcpy(&(diag_coor[0]), &hx_touch_data->hx_coord_buf[0], + hx_touch_data->touch_info_size); + } + + /* assign state info data */ + memcpy(&(hx_state_info[0]), &hx_touch_data->hx_state_info[0], 2); + return NO_ERR; +bypass_checksum_failed_packet: + return 1; +} + +/* #if defined(HX_DEBUG_LEVEL) */ +void himax_log_touch_data(int start) +{ + int i = 0; + int print_size = 0; + uint8_t *buf = NULL; + + if (start == 1) + return; /* report data when end of ts_work*/ + + if (hx_touch_data->diag_cmd > 0) { + print_size = hx_touch_data->touch_all_size; + buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + + memcpy(buf, hx_touch_data->hx_coord_buf, + hx_touch_data->touch_info_size); + memcpy(&buf[hx_touch_data->touch_info_size], + hx_touch_data->hx_rawdata_buf, + print_size - hx_touch_data->touch_info_size); + } +#if defined(HX_SMART_WAKEUP) + else if (private_ts->SMWP_enable > 0 && private_ts->suspended) { + print_size = hx_touch_data->event_size; + buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + + memcpy(buf, hx_touch_data->hx_event_buf, print_size); + } +#endif + else if (hx_touch_data->diag_cmd == 0) { + print_size = hx_touch_data->touch_info_size; + buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + + memcpy(buf, hx_touch_data->hx_coord_buf, print_size); + } else { + E("%s:cmd fault\n", __func__); + return; + } + + for (i = 0; i < print_size; i += 8) { + if ((i + 7) >= print_size) { + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + i, + buf[i], + i + 1, + buf[i + 1]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X\n", + i + 2, + buf[i + 2], + i + 3, + buf[i + 3]); + break; + } + + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + i, buf[i], i + 1, buf[i + 1]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + i + 2, buf[i + 2], i + 3, buf[i + 3]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + i + 4, buf[i + 4], i + 5, buf[i + 5]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + i + 6, buf[i + 6], i + 7, buf[i + 7]); + I("\n"); + } + kfree(buf); +} + +void himax_log_touch_event(struct himax_ts_data *ts, int start) +{ + int i = 0; + + if (start == 1) + return; /*report data when end of ts_work*/ + + if (g_target_report_data->finger_on > 0 && + g_target_report_data->finger_num > 0) { + for (i = 0; i < ts->nFinger_support; i++) { + if (g_target_report_data->p[i].x >= 0 + && g_target_report_data->p[i].x + <= ts->pdata->abs_x_max + && g_target_report_data->p[i].y >= 0 + && g_target_report_data->p[i].y + <= ts->pdata->abs_y_max) { + I(PRT_LOG, + i + 1, + g_target_report_data->p[i].x, + g_target_report_data->p[i].y, + g_target_report_data->p[i].w, + g_target_report_data->p[i].w, + i + 1, + g_target_report_data->ig_count); + } + } + } else if (g_target_report_data->finger_on == 0 + && g_target_report_data->finger_num == 0) { + I("All Finger leave\n"); + } else { + I("%s : wrong input!\n", __func__); + } +} +void himax_log_touch_int_devation(int touched) +{ + if (touched == HX_FINGER_ON) { +#if defined(KERNEL_VER_ABOVE_5_10) + ktime_get_ts64(&timeStart); +#else + getnstimeofday(&timeStart); +#endif + /* I(" Irq start time = %ld.%06ld s\n", + * timeStart.tv_sec, timeStart.tv_nsec/1000); + */ + } else if (touched == HX_FINGER_LEAVE) { +#if defined(KERNEL_VER_ABOVE_5_10) + ktime_get_ts64(&timeEnd); +#else + getnstimeofday(&timeEnd); +#endif + timeDelta.tv_nsec = + (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) - + (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + /* I("Irq finish time = %ld.%06ld s\n", + * timeEnd.tv_sec, timeEnd.tv_nsec/1000); + */ + I("Touch latency = %ld us\n", timeDelta.tv_nsec / 1000); + I("bus_speed = %d kHz\n", private_ts->bus_speed); + if (g_target_report_data->finger_on == 0 + && g_target_report_data->finger_num == 0) + I("All Finger leave\n"); + } else { + I("%s : wrong input!\n", __func__); + } +} + +void himax_log_touch_event_detail(struct himax_ts_data *ts, int start) +{ + int i = 0; + + if (start == HX_FINGER_LEAVE) { + for (i = 0; i < ts->nFinger_support; i++) { + if (((ts->old_finger >> i & 1) == 0) + && ((ts->pre_finger_mask >> i & 1) == 1)) { + if (g_target_report_data->p[i].x >= 0 + && g_target_report_data->p[i].x + <= ts->pdata->abs_x_max + && g_target_report_data->p[i].y >= 0 + && g_target_report_data->p[i].y + <= ts->pdata->abs_y_max) { + I(RAW_DOWN_STATUS, i + 1, + g_target_report_data->p[i].x, + g_target_report_data->p[i].y, + g_target_report_data->p[i].w); + } + } else if ((((ts->old_finger >> i & 1) == 1) + && ((ts->pre_finger_mask >> i & 1) == 0))) { + I(RAW_UP_STATUS, i + 1, + ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } else { + /* I("dbg hx_point_num=%d, old_finger=0x%02X," + * " pre_finger_mask=0x%02X\n", + * ts->hx_point_num, ts->old_finger, + * ts->pre_finger_mask); + */ + } + } + } +} + +void himax_ts_dbg_func(struct himax_ts_data *ts, int start) +{ + if (ts->debug_log_level & BIT(0)) { + /* I("debug level 1\n"); */ + himax_log_touch_data(start); + } + if (ts->debug_log_level & BIT(1)) { + /* I("debug level 2\n"); */ + himax_log_touch_event(ts, start); + } + if (ts->debug_log_level & BIT(2)) { + /* I("debug level 4\n"); */ + himax_log_touch_int_devation(start); + } + if (ts->debug_log_level & BIT(3)) { + /* I("debug level 8\n"); */ + himax_log_touch_event_detail(ts, start); + } +} + +static int himax_change_mode(uint8_t str_pw, uint8_t end_pw) +{ + uint8_t data[4] = {0}; + int count = 0; + + /*sense off*/ + g_core_fp.fp_sense_off(true); + /*mode change*/ + data[1] = str_pw; data[0] = str_pw; + if (g_core_fp.fp_assign_sorting_mode != NULL) + g_core_fp.fp_assign_sorting_mode(data); + + /*sense on*/ + g_core_fp.fp_sense_on(1); + /*wait mode change*/ + do { + if (g_core_fp.fp_check_sorting_mode != NULL) + g_core_fp.fp_check_sorting_mode(data); + if ((data[0] == end_pw) && (data[1] == end_pw)) + return 0; + + I("Now retry %d times!\n", count); + count++; + msleep(50); + } while (count < 50); + + return ERR_WORK_OUT; +} + +static ssize_t himax_irq_dbg_cmd_write(char *buf, size_t len) +{ + // struct himax_ts_data *ts = private_ts; + int cmd = 0; + + if (!kstrtoint(buf, 16, &cmd)) { + I("%s, now irq_dbg status=%d!\n", __func__, cmd); + g_ts_dbg = cmd; + } else { + E("%s: command not int!\n", __func__); + } + return len; +} + +static ssize_t himax_diag_cmd_write(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + char *dbg_map_str = "mode:"; + char *str_ptr = NULL; + int str_len = 0; + int rst = 0; + uint8_t str_pw = 0; + uint8_t end_pw = 0; + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + goto END; + } + + switch (len) { + case 1:/*raw out select - diag,X*/ + if (!kstrtoint(buf, 16, &rst)) { + ts->diag_cmd = rst; + I("%s: dsram_flag = %d\n", __func__, dsram_flag); + if (dsram_flag) { + /*Cancal work queue and return to stack*/ + process_type = 0; + while (dsram_flag == true) + usleep_range(10000, 11000); + cancel_delayed_work(&ts->himax_diag_delay_work); + himax_int_enable(1); + g_core_fp.fp_return_event_stack(); + } + g_core_fp.fp_diag_register_set(ts->diag_cmd, 0, false); + I("%s: Set raw out select 0x%X.\n", + __func__, ts->diag_cmd); + } + if (!ts->diag_cmd) { + if (mode_flag) /*back to normal mode*/ + himax_change_mode(0x00, 0x99); + } + break; + case 2:/*data processing + rawout select - diag,XY*/ + if (!kstrtoint(buf, 16, &rst)) { + process_type = (rst >> 4) & 0xF; + ts->diag_cmd = rst & 0xF; + } + if (ts->diag_cmd == 0) + break; + else if (process_type > 0 && process_type <= 3) { + if (!dsram_flag) { + /*Start wrok queue*/ + himax_int_enable(0); + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, false); + + queue_delayed_work(ts->himax_diag_wq, + &ts->himax_diag_delay_work, 2 * HZ / 100); + dsram_flag = true; + + I("%s: Start get raw data in DSRAM\n", + __func__); + } else { + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, false); + } + } + break; + case 4:/*data processing + rawout select - diag,XXYY*/ + /*ex:XXYY=010A=dsram rawdata*/ + I("%s, now case 4\n", __func__); + if (!kstrtoint(buf, 16, &rst)) { + process_type = (rst >> 8) & 0xFF; + ts->diag_cmd = rst & 0xFF; + I("%s:process_type=0x%02X, diag_cmd=0x%02X\n", + __func__, process_type, ts->diag_cmd); + } + if (process_type <= 0 || ts->diag_cmd <= 0) + break; + else if (process_type > 0 && process_type <= 3) { + if (!dsram_flag) { + /*Start wrok queue*/ + himax_int_enable(0); + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, true); + + queue_delayed_work(ts->himax_diag_wq, + &ts->himax_diag_delay_work, 2 * HZ / 100); + dsram_flag = true; + + I("%s: Start get raw data in DSRAM\n", + __func__); + } else { + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, true); + } + } + break; + case 9:/*change mode - mode:XXYY(start PW,end PW)*/ + str_ptr = strnstr(buf, dbg_map_str, len); + if (str_ptr) { + str_len = strlen(dbg_map_str); + if (!kstrtoint(buf + str_len, 16, &rst)) { + str_pw = (rst >> 8) & 0xFF; + end_pw = rst & 0xFF; + if (!himax_change_mode(str_pw, end_pw)) { + mode_flag = 1; + I(PRT_OK_LOG, __func__, + rst, str_pw, end_pw); + } else + I(PRT_FAIL_LOG, __func__, + str_pw, end_pw); + } + } else { + I("%s: Can't find string [%s].\n", + __func__, dbg_map_str); + } + break; + default: + I("%s: Length is not correct.\n", __func__); + } +END: + return len; +} + +static int himax_diag_arrange_read(struct seq_file *m) +{ + int ret = NO_ERR; + + if (debug_data->is_call_help) { + seq_printf(m, HELP_DIAG_ARR); + debug_data->is_call_help = false; + } else { + seq_printf(m, "diag value=%d\n", g_diag_arr_num); + } + return ret; +} + +static ssize_t himax_diag_arrange_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + } else { + g_diag_arr_num = buf[0] - '0'; + I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num); + } + return len; +} + +void himax_get_mutual_edge(void) +{ + int i = 0; + + for (i = 0; i < (ic_data->HX_RX_NUM * ic_data->HX_TX_NUM); i++) { + if (diag_mutual[i] > g_max_mutual) + g_max_mutual = diag_mutual[i]; + + if (diag_mutual[i] < g_min_mutual) + g_min_mutual = diag_mutual[i]; + } +} + +void himax_get_self_edge(void) +{ + int i = 0; + + for (i = 0; i < (ic_data->HX_RX_NUM + ic_data->HX_TX_NUM); i++) { + if (diag_self[i] > g_max_self) + g_max_self = diag_self[i]; + + if (diag_self[i] < g_min_self) + g_min_self = diag_self[i]; + } +} + +static void print_state_info(struct seq_file *s) +{ + /* seq_printf(s, "State_info_2bytes:%3d, %3d\n", + * _state_info[0],hx_state_info[1]); + */ + +#if defined(HX_NEW_EVENT_STACK_FORMAT) + seq_printf(s, "ReCal = %d\t", hx_state_info[0] & 0x03); + seq_printf(s, "Base Line = %d\t", hx_state_info[0] >> 2 & 0x01); + seq_printf(s, "Palm = %d\t", hx_state_info[0] >> 3 & 0x01); + seq_printf(s, "Idle mode = %d\t", hx_state_info[0] >> 4 & 0x01); + seq_printf(s, "Water = %d\n", hx_state_info[0] >> 5 & 0x01); + seq_printf(s, "TX Hop = %d\t", hx_state_info[0] >> 6 & 0x01); + seq_printf(s, "AC mode = %d\t", hx_state_info[0] >> 7 & 0x01); + seq_printf(s, "Glove = %d\t", hx_state_info[1] & 0x01); + seq_printf(s, "Stylus = %d\t", hx_state_info[1] >> 1 & 0x01); + seq_printf(s, "Hovering = %d\t", hx_state_info[1] >> 2 & 0x01); + seq_printf(s, "Proximity = %d\t", hx_state_info[1] >> 3 & 0x01); + seq_printf(s, "KEY = %d\n", hx_state_info[1] >> 4 & 0x0F); +#else + seq_printf(s, "ReCal = %d\t", hx_state_info[0] & 0x01); + seq_printf(s, "Palm = %d\t", hx_state_info[0] >> 1 & 0x01); + seq_printf(s, "AC mode = %d\t", hx_state_info[0] >> 2 & 0x01); + seq_printf(s, "Water = %d\n", hx_state_info[0] >> 3 & 0x01); + seq_printf(s, "Glove = %d\t", hx_state_info[0] >> 4 & 0x01); + seq_printf(s, "TX Hop = %d\t", hx_state_info[0] >> 5 & 0x01); + seq_printf(s, "Base Line = %d\t", hx_state_info[0] >> 6 & 0x01); + seq_printf(s, "OSR Hop = %d\t", hx_state_info[1] >> 3 & 0x01); + seq_printf(s, "KEY = %d\n", hx_state_info[1] >> 4 & 0x0F); +#endif +} + +static void himax_diag_arrange_print(struct seq_file *s, int i, int j, + int transpose) +{ + if (transpose) + seq_printf(s, "%6d", diag_mutual[j + i * ic_data->HX_RX_NUM]); + else + seq_printf(s, "%6d", diag_mutual[i + j * ic_data->HX_RX_NUM]); +} + +/* ready to print second step which is column*/ +static void himax_diag_arrange_inloop(struct seq_file *s, int in_init, + int out_init, bool transpose, int j) +{ + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int i; + int in_max = 0; + + if (transpose) + in_max = y_channel; + else + in_max = x_channel; + + if (in_init > 0) { /* bit0 = 1 */ + for (i = in_init - 1; i >= 0; i--) + himax_diag_arrange_print(s, i, j, transpose); + + if (transpose) { + if (out_init > 0) + seq_printf(s, " %5d\n", diag_self[j]); + else + seq_printf(s, " %5d\n", + diag_self[x_channel - j - 1]); + } + } else { /* bit0 = 0 */ + for (i = 0; i < in_max; i++) + himax_diag_arrange_print(s, i, j, transpose); + + if (transpose) { + if (out_init > 0) + seq_printf(s, " %5d\n", + diag_self[x_channel - j - 1]); + else + seq_printf(s, " %5d\n", diag_self[j]); + } + } +} + +/* print first step which is row */ +static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, + int out_init, int in_init) +{ + int j; + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int out_max = 0; + int self_cnt = 0; + + if (transpose) + out_max = x_channel; + else + out_max = y_channel; + + if (out_init > 0) { /* bit1 = 1 */ + self_cnt = 1; + + for (j = out_init - 1; j >= 0; j--) { + seq_printf(s, "%3c%02d%c", '[', j + 1, ']'); + himax_diag_arrange_inloop(s, in_init, out_init, + transpose, j); + + if (!transpose) { + seq_printf(s, " %5d\n", + diag_self[y_channel + x_channel - self_cnt]); + self_cnt++; + } + } + } else { /* bit1 = 0 */ + /* self_cnt = x_channel; */ + for (j = 0; j < out_max; j++) { + seq_printf(s, "%3c%02d%c", '[', j + 1, ']'); + himax_diag_arrange_inloop(s, in_init, out_init, + transpose, j); + + if (!transpose) { + seq_printf(s, " %5d\n", + diag_self[j + x_channel]); + } + } + } +} + +/* determin the output format of diag */ +static void himax_diag_arrange(struct seq_file *s) +{ + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int bit2, bit1, bit0; + int i; + /* rotate bit */ + bit2 = g_diag_arr_num >> 2; + /* reverse Y */ + bit1 = g_diag_arr_num >> 1 & 0x1; + /* reverse X */ + bit0 = g_diag_arr_num & 0x1; + + if (g_diag_arr_num < 4) { + for (i = 0 ; i <= x_channel; i++) + seq_printf(s, "%3c%02d%c", '[', i, ']'); + + seq_puts(s, "\n"); + himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, + bit0 * x_channel); + seq_printf(s, "%6c", ' '); + + if (bit0 == 1) { + for (i = x_channel - 1; i >= 0; i--) + seq_printf(s, "%6d", diag_self[i]); + } else { + for (i = 0; i < x_channel; i++) + seq_printf(s, "%6d", diag_self[i]); + } + } else { + for (i = 0 ; i <= y_channel; i++) + seq_printf(s, "%3c%02d%c", '[', i, ']'); + + seq_puts(s, "\n"); + himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, + bit0 * y_channel); + seq_printf(s, "%6c", ' '); + + if (bit1 == 1) { + for (i = x_channel + y_channel - 1; i >= x_channel; + i--) + seq_printf(s, "%6d", diag_self[i]); + } else { + for (i = x_channel; i < x_channel + y_channel; i++) + seq_printf(s, "%6d", diag_self[i]); + } + } +} + +/* DSRAM thread */ +bool himax_ts_diag_func(int dsram_type) +{ + int i = 0, j = 0; + unsigned int index = 0; + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int total_size = (y_channel * x_channel + y_channel + x_channel) * 2; + uint8_t *info_data = NULL; + int32_t *mutual_data = NULL; + int32_t *mutual_data_new = NULL; + int32_t *mutual_data_old = NULL; + int32_t *self_data = NULL; + int32_t *self_data_new = NULL; + int32_t *self_data_old = NULL; + int32_t new_data; + /* 1:common dsram,2:100 frame Max,3:N-(N-1)frame */ + if (dsram_type < 1 || dsram_type > 3) { + E("%s: type %d is out of range\n", __func__, dsram_type); + return false; + } + + info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (info_data == NULL) { + E("%s: Failed to allocate memory\n", __func__); + return false; + } + + memset(info_data, 0, total_size * sizeof(uint8_t)); + + g_core_fp.fp_burst_enable(1); + + if (dsram_type == 1 || dsram_type == 2) { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + } else if (dsram_type == 3) { + mutual_data = getMutualBuffer(); + mutual_data_new = getMutualNewBuffer(); + mutual_data_old = getMutualOldBuffer(); + self_data = getSelfBuffer(); + self_data_new = getSelfNewBuffer(); + self_data_old = getSelfOldBuffer(); + } + + if (!g_core_fp.fp_get_DSRAM_data(info_data, dsram_flag)) { + E("%s: Get DSRAM data failed\n", __func__); + kfree(info_data); + return false; + } + + index = 0; + + for (i = 0; i < y_channel; i++) { /*mutual data*/ + for (j = 0; j < x_channel; j++) { + new_data = (((int8_t)info_data[index + 1] << 8) | + info_data[index]); + + if (dsram_type <= 1) { + mutual_data[i * x_channel + j] = new_data; + } else if (dsram_type == 2) { /* Keep max data */ + if (mutual_data[i * x_channel + j] < new_data) + mutual_data[i * x_channel + j] = + new_data; + } else if (dsram_type == 3) { + /* Cal data for [N]-[N-1] frame */ + mutual_data_new[i * x_channel + j] = new_data; + mutual_data[i * x_channel + j] = + mutual_data_new[i * x_channel + j] + - mutual_data_old[i * x_channel + j]; + } + index += 2; + } + } + + for (i = 0; i < x_channel + y_channel; i++) { /*self data*/ + new_data = (((int8_t)info_data[index + 1] << 8) | + info_data[index]); + if (dsram_type <= 1) { + self_data[i] = new_data; + } else if (dsram_type == 2) { /* Keep max data */ + if (self_data[i] < new_data) + self_data[i] = new_data; + } else if (dsram_type == 3) { /* Cal data for [N]-[N-1] frame */ + self_data_new[i] = new_data; + self_data[i] = self_data_new[i] - self_data_old[i]; + } + index += 2; + } + + kfree(info_data); + + if (dsram_type == 3) { + memcpy(mutual_data_old, mutual_data_new, + x_channel * y_channel * sizeof(int32_t)); + /* copy N data to N-1 array */ + memcpy(self_data_old, self_data_new, + (x_channel + y_channel) * sizeof(int32_t)); + /* copy N data to N-1 array */ + } + + + return true; +} + +static int himax_diag_print(struct seq_file *s, void *v) +{ + int x_num = ic_data->HX_RX_NUM; + int y_num = ic_data->HX_TX_NUM; + size_t ret = 0; + uint16_t mutual_num, self_num, width; + + mutual_num = x_num * y_num; + self_num = x_num + y_num; + /* don't add KEY_COUNT */ + width = x_num; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_num, y_num); + + /* start to show out the raw data in adb shell */ + himax_diag_arrange(s); + seq_puts(s, "\n"); + seq_puts(s, "ChannelEnd"); + seq_puts(s, "\n"); + + /* print Mutual/Slef Maximum and Minimum */ + himax_get_mutual_edge(); + himax_get_self_edge(); + seq_printf(s, "Mutual Max:%3d, Min:%3d\n", g_max_mutual, + g_min_mutual); + seq_printf(s, "Self Max:%3d, Min:%3d\n", g_max_self, + g_min_self); + /* recovery status after print*/ + g_max_mutual = 0; + g_min_mutual = 0xFFFF; + g_max_self = 0; + g_min_self = 0xFFFF; + + /*pring state info*/ + print_state_info(s); + + if (s->count >= s->size) + overflow++; + + return ret; +} + +static int himax_stack_show(struct seq_file *s, void *v) +{ + struct himax_ts_data *ts = private_ts; + + if (debug_data->is_call_help) { + seq_puts(s, HELP_DIAG); + debug_data->is_call_help = false; + } else { + if (ts->diag_cmd) + himax_diag_print(s, v); + else + seq_puts(s, "Please set raw out select 'echo diag,X > debug'\n\n"); + } + return 0; +} +__CREATE_OREAD_NODE_HX(stack); + +static int himax_sram_read(struct seq_file *s, void *v, uint8_t rs) +{ + struct himax_ts_data *ts = private_ts; + int d_type = 0; + int current_size = + ((ic_data->HX_TX_NUM + 1) * (ic_data->HX_RX_NUM + 1) + + ic_data->HX_TX_NUM + ic_data->HX_RX_NUM) * 6 + 256; + if (debug_data->is_call_help) { + seq_puts(s, HELP_DIAG); + debug_data->is_call_help = false; + } else { + d_type = (!ts->diag_cmd)?rs:ts->diag_cmd; + + I("%s, s->size = %d\n", __func__, (int)s->size); + I("%s, sizeof(s->buf) = %d\n", __func__, (int)sizeof(s->buf)); + + s->size = current_size; + s->buf = kcalloc(s->size, sizeof(char), GFP_KERNEL); + if (s->buf == NULL) { + E("%s,%d: Memory allocation falied!\n", + __func__, __LINE__); + return -ENOMEM; + } + + memset(s->buf, 0, s->size * sizeof(char)); + + if (!overflow) { + if (!process_type) { + himax_int_enable(0); + g_core_fp.fp_diag_register_set(d_type, + 0, false); + + /* use process type 1 for default */ + if (!himax_ts_diag_func(1)) + seq_puts(s, "Get sram data failed."); + else + himax_diag_print(s, v); + + ts->diag_cmd = 0; + g_core_fp.fp_diag_register_set(0, 0, false); + himax_int_enable(1); + } + } + + if ((process_type <= 3 + && ts->diag_cmd + && dsram_flag) + || overflow) { + himax_diag_print(s, v); + overflow = 0; + } + } + return 0; +} + +static int himax_delta_show(struct seq_file *s, void *v) +{ + return himax_sram_read(s, v, 0x09); +} +__CREATE_OREAD_NODE_HX(delta); + +static int himax_dc_show(struct seq_file *s, void *v) +{ + return himax_sram_read(s, v, 0x0A); +} +__CREATE_OREAD_NODE_HX(dc); + +static int himax_baseline_show(struct seq_file *s, void *v) +{ + return himax_sram_read(s, v, 0x0B); +} +__CREATE_OREAD_NODE_HX(baseline); + +#if defined(HX_RST_PIN_FUNC) +static void test_rst_pin(void) +{ + int rst_sts1 = -1; + int rst_sts2 = -1; + int cnt = 0; + uint8_t tmp_addr[DATA_LEN_4] = {0}; + uint8_t tmp_data[DATA_LEN_4] = {0}; + uint8_t tmp_read[DATA_LEN_4] = {0}; + + himax_int_enable(0); + g_core_fp.fp_sense_off(true); + + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x900000F0, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + I("trigger Reset Pin\n"); + g_core_fp.fp_ic_reset(false, false); + + usleep_range(20000, 20001); + do { + himax_parse_assign_cmd(0x900000A8, tmp_addr, DATA_LEN_4); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + rst_sts1 = tmp_read[0]; + cnt++; + if (rst_sts1 == 0x05) + break; + if (rst_sts1 == 0x00) + cnt += 5; + if (cnt > 20) + goto END_FUNC; + } while (rst_sts1 == 0x04); + + himax_parse_assign_cmd(0x900000F0, tmp_addr, DATA_LEN_4); + g_core_fp.fp_register_read(tmp_addr, tmp_read, DATA_LEN_4); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + rst_sts2 = tmp_read[0]; + +END_FUNC: + if (rst_sts1 == 0x05 && rst_sts2 == 0x00) + I("%s: TP Reset test OK!\n", __func__); + else if (rst_sts1 == 0xFF || rst_sts2 == 0x01) + I("%s: TP Reset test Fail!\n", __func__); + else + I("%s, Unknown Fail state1=0x%02X, state2=0x%02X!\n", + __func__, rst_sts1, rst_sts2); + + g_core_fp.fp_sense_on(0x00); + himax_int_enable(1); +} +#endif + +static int himax_reset_read(struct seq_file *m) +{ + int ret = NO_ERR; + + if (debug_data->is_call_help) { + seq_printf(m, HELP_RST); + debug_data->is_call_help = false; + } else { + seq_printf(m, "diag value=%d\n", g_diag_arr_num); + } + return ret; +} +static ssize_t himax_reset_write(char *buf, size_t len) +{ + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + } else { +#if defined(HX_RST_PIN_FUNC) + if (buf[0] == '1') + g_core_fp.fp_ic_reset(false, false); + else if (buf[0] == '2') + g_core_fp.fp_ic_reset(false, true); + /* else if (buf[0] == '5') */ + /* ESD_HW_REST(); */ + else if (str_idx_of_str(buf, "test") >= 0) + test_rst_pin(); +#endif +#if defined(HX_ZERO_FLASH) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif + } + return len; +} + + + +void hx_dump_prog_set(uint8_t prog) +{ + g_flash_progress = prog; + if (prog == ONGOING) + debug_data->flash_dump_going = ONGOING; + else + debug_data->flash_dump_going = START; +} + +static int himax_flash_dump_show(struct seq_file *s, void *v) +{ + ssize_t ret = 0; + int i; + uint8_t flash_progress = g_flash_progress; + // uint8_t flash_cmd = g_dump_show; + bool flash_rst = g_flash_dump_rst; +#if !defined(KERNEL_VER_ABOVE_5_10) + mm_segment_t fs; +#endif + struct file *fn = NULL; + struct filename *vts_name = NULL; + loff_t pos = 0; + + I("dump_progress = %d\n", flash_progress); + + if (!flash_rst) { + seq_puts(s, "DumpStart:Fail\n"); + seq_puts(s, "DumpEnd\n"); + goto END; + } + + if (flash_progress == START) + seq_puts(s, "Dump - Start\n"); + else if (flash_progress == ONGOING) + seq_puts(s, "Dump - On-going\n"); + else if (flash_progress == FINISHED) + seq_puts(s, "Dump - Finished\n"); + + /*print flash dump data*/ + if (g_dump_show == 2 && flash_progress == FINISHED) { + seq_puts(s, "Start to print dump data\n"); + for (i = 0; i < ic_data->flash_size; i++) { + seq_printf(s, "0x%02X,", g_dump_buffer[i]); + if (i % 16 == 15) + seq_puts(s, "\n"); + } + } else if (g_dump_show == 1) { + I("Now Save to file!\n"); + if (!kp_getname_kernel && !kp_file_open_name) { + E("kp_getname_kernel or kp_file_open_name is NULL, not open file!\n"); + } else { + + vts_name = kp_getname_kernel(g_file_path); + I("Now vts_name=%s\n", vts_name->name); + fn = kp_file_open_name(vts_name, + O_TRUNC|O_CREAT|O_RDWR, 0660); + + if (IS_ERR(fn)) { + E("%s Open file failed!\n", __func__); + g_flash_dump_rst = false; + } else { + I("%s create file and ready to write\n", + __func__); +#if defined(KERNEL_VER_ABOVE_5_10) + kernel_write(fn, g_dump_buffer, + ic_data->flash_size * sizeof(uint8_t), &pos); + filp_close(fn, NULL); +#else + fs = get_fs(); + set_fs(KERNEL_DS); + vfs_write(fn, g_dump_buffer, + ic_data->flash_size * sizeof(uint8_t), &pos); + filp_close(fn, NULL); + set_fs(fs); +#endif + } + } + + } + + seq_puts(s, "DumpEnd\n"); +END: + return ret; +} +#define FDS_DBG1 "%s, input cmd:is_flash=%d, is_file=%d, dump_size=%d, addr=0x%08X\n" +#define FDS_DBG2 "%s, assigned:is_flash=%d, is_file=%d, dump_size=%d, addr=0x%08X\n" +static ssize_t himax_flash_dump_store(struct file *filp, + const char __user *buff, size_t len, loff_t *data) +{ + char buf[80] = {0}; + char *input_str[4]; + int i = 0; + int is_flash = -1; + int is_file = -1; + int dump_size = -1; + uint32_t addr = 0x000000; + + g_dump_cmd = 0; + g_dump_size = 0; + g_dump_show = 0; + g_dump_addr = 0; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + I("%s: buf = %s\n", __func__, buf); + + if (g_flash_progress == ONGOING) { + E("%s: process is busy , return!\n", __func__); + return len; + } + + buf[len - 1] = '\0'; + + for (i = 0; i < 4; i++) + input_str[i] = kzalloc(sizeof(char) * 128, GFP_KERNEL); + + _str_to_arr_in_char(input_str, 4, buf, ','); + + for (i = 0; i < 4; i++) { + if (input_str[i] == NULL) { + continue; + } else { + I("%d:%s\n", i, input_str[i]); + switch (i) { + case 0: + if (str_idx_of_str(input_str[i], + "help") >= 0) { + is_flash = 0; + goto CON_WORK; + } else if (str_idx_of_str(input_str[i], + "flash") >= 0) { + is_flash = 1; + } else if (str_idx_of_str(input_str[i], + "ram") >= 0) { + is_flash = 2; + } else { + is_flash = -1; + goto CON_WORK; + } + break; + case 1: + if (str_idx_of_str(input_str[i], + "print") >= 0) { + is_file = 2; + } else if (str_idx_of_str(input_str[i], + "file") >= 0) { + is_file = 1; + } else { + is_file = -1; + goto CON_WORK; + } + break; + case 2: + dump_size = hiamx_parse_str2int( + input_str[i]); + break; + case 3: + if (input_str[i] == NULL) + addr = 0x00; + else + addr = hx_parse_hexstr2int( + input_str[i]); + I("addr=%d\n", addr); + break; + default: + break; + } + } + } +CON_WORK: + I(FDS_DBG1, + __func__, is_flash, is_file, dump_size, addr); +/* + * + * if ((buf[1] == '_') && (buf[2] == '3') && (buf[3] == '2')) + * g_dump_size = FW_SIZE_32k; + * else if ((buf[1] == '_') && (buf[2] == '6')) { + * if (buf[3] == '0') + * g_dump_size = FW_SIZE_60k; + * else if (buf[3] == '4') + * g_dump_size = FW_SIZE_64k; + + *} else if ((buf[1] == '_') && (buf[2] == '2')) { + * if (buf[3] == '4') + * g_dump_size = FW_SIZE_124k; + * else if (buf[3] == '8') + * g_dump_size = FW_SIZE_128k; + *} + * + * //1 : print flash to window, 2 : dump to sdcard + *if (buf[0] == '1') { + * //1_32,1_60,1_64,1_24,1_28 for flash size: + * // 32k,60k,64k,124k,128k + * + * g_dump_cmd = 1; + * hx_dump_prog_set(START); + * g_flash_dump_rst = true; + * queue_work(private_ts->dump_wq, &private_ts->dump_work); + *} else if (buf[0] == '2') { + * // 2_32,2_60,2_64,2_24,2_28 for dump size: + * // 32k,60k,64k,124k,128k + * + * g_dump_cmd = 2; + * hx_dump_prog_set(START); + * g_flash_dump_rst = true; + * queue_work(private_ts->dump_wq, &private_ts->dump_work); + *} + **/ + + g_dump_cmd = is_flash; + g_dump_size = dump_size; + g_dump_show = is_file; + g_dump_addr = addr; + I(FDS_DBG2, + __func__, g_dump_cmd, g_dump_show, g_dump_size, g_dump_addr); + hx_dump_prog_set(START); + g_flash_dump_rst = true; + queue_work(private_ts->dump_wq, &private_ts->dump_work); + + for (i = 0; i < 4; i++) + kfree(input_str[i]); + return len; +} +__CREATE_RW_NODE_HX(flash_dump); + +void himax_ts_dump_func(void) +{ + uint8_t tmp_addr[DATA_LEN_4] = {0}; + int ret = NO_ERR; + + hx_dump_prog_set(ONGOING); + + /*msleep(100);*/ + // I("%s: flash_command = %d enter.\n", __func__, flash_command); + I("%s: entering, is_flash=%d, is_file=%d, size=%d, add=0x%08X\n", + __func__, g_dump_cmd, g_dump_show, g_dump_size, g_dump_addr); + + if (g_dump_cmd == 1) { + himax_int_enable(0); + g_core_fp.fp_flash_dump_func(g_dump_cmd, g_dump_size, + g_dump_buffer); + g_flash_dump_rst = true; + himax_int_enable(1); + } else if (g_dump_cmd == 2) { + I("dump ram start\n"); + if (g_dump_addr != -948794) { + tmp_addr[0] = g_dump_addr % 0x100; + tmp_addr[1] = (g_dump_addr >> 8) % 0x100; + tmp_addr[2] = (g_dump_addr >> 16) % 0x100; + tmp_addr[3] = g_dump_addr / 0x1000000; + ret = g_core_fp.fp_register_read(tmp_addr, + g_dump_buffer, g_dump_size); + g_flash_dump_rst = true; + } else { + E("addr is wrong!\n"); + g_flash_dump_rst = false; + goto END; + } + if (ret) { + E("read ram fail, please check cmd !\n"); + g_flash_dump_rst = false; + goto END; + } + } + + I("Dump Complete\n"); + + +END: + hx_dump_prog_set(FINISHED); +} + +#if defined(HX_TP_PROC_GUEST_INFO) +static int printMat(struct seq_file *m, int max_size, + uint8_t *guest_str, int loc) +{ + int ret = loc; + int i; + + for (i = 0; i < max_size; i++) { + if ((i % 16) == 0 && i > 0) + seq_puts(m, "\n"); + + seq_printf(m, "0x%02X\t", + guest_str[i]); + } + return ret; +} + +static int printUnit(struct seq_file *m, int max_size, + char *info_item, uint8_t *guest_str, int loc) +{ + int ret = loc; + + seq_printf(m, "%s:\n", info_item); + ret = printMat(m, max_size, guest_str, ret); + seq_puts(m, "\n"); + return ret; +} + +static int himax_proc_guest_info_read(struct seq_file *m) +{ + int ret = 0; + int j = 0; + int max_size = 128; + struct hx_guest_info *info = g_guest_info_data; + + + if (debug_data->is_call_help) { + seq_printf(m, HELP_GUEST_INFO); + debug_data->is_call_help = false; + } else { + I("guest info progress\n"); + + if (g_core_fp.guest_info_get_status()) { + seq_printf(m, + "Not Ready\n"); + goto END_FUNCTION; + } else { + if (info->g_guest_info_type == 1) { + for (j = 0; j < 3; j++) { + ret = printUnit(m, max_size, + g_guest_info_item[j], + info->g_guest_str[j], ret); + I("str[%d] %s\n", j, + info->g_guest_str[j]); + } + ret = printUnit(m, max_size, + g_guest_info_item[8], + info->g_guest_str[8], + ret); + + I("str[8] %s\n", + info->g_guest_str[8]); + + ret = printUnit(m, max_size, + g_guest_info_item[9], + info->g_guest_str[9], + ret); + + I("str[9] %s\n", info->g_guest_str[9]); + } else if (info->g_guest_info_type == 0) { + for (j = 0; j < 10; j++) { + if (j == 3) + j = 8; + + seq_printf(m, "%s:\n", + g_guest_info_item[j]); + + if (info->g_guest_data_type[j] == 0) { + seq_printf(m, "%s", + info->g_guest_str_in_format[j]); + } else { + ret = printMat(m, + info->g_guest_data_len[j], + info->g_guest_str_in_format[j], + ret); + } + seq_puts(m, "\n"); + } + } + } + } +END_FUNCTION: + return ret; +} + +static ssize_t himax_proc_guest_info_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + I("%s: buf = %s\n", __func__, buf); + + if (str_idx_of_str(buf, "help") >= 0) { + debug_data->is_call_help = true; + } else { + if (buf[0] == 'r') { + I("%s,Test to get", __func__); + queue_work(private_ts->guest_info_wq, + &private_ts->guest_info_work); + } + } + return len; +} + +#endif + +static int himax_test_bus_read(struct seq_file *m) +{ + int ret = NO_ERR; + + if (g_core_fp.fp_read_i2c_status()) + seq_printf(m, + "Bus communication is bad.\n"); + else + seq_printf(m, + "Bus communication is good.\n"); + return ret; +} + +static int himax_info_read(struct seq_file *m) +{ + int ret = NO_ERR; + + seq_printf(m, + "Himax Touch IC Information :\n"); + seq_printf(m, + "%s\n", private_ts->chip_name); + + switch (IC_CHECKSUM) { + case HX_TP_BIN_CHECKSUM_SW: + seq_printf(m, + "IC Checksum : SW\n"); + break; + + case HX_TP_BIN_CHECKSUM_HW: + seq_printf(m, + "IC Checksum : HW\n"); + break; + + case HX_TP_BIN_CHECKSUM_CRC: + seq_printf(m, + "IC Checksum : CRC\n"); + break; + + default: + seq_printf(m, + "IC Checksum error.\n"); + } + + if (ic_data->HX_INT_IS_EDGE) + seq_printf(m, + "Driver register Interrupt : EDGE TIRGGER\n"); + else + seq_printf(m, + "Driver register Interrupt : LEVEL TRIGGER\n"); + + if (private_ts->protocol_type == PROTOCOL_TYPE_A) + seq_printf(m, + "Protocol : TYPE_A\n"); + else + seq_printf(m, + "Protocol : TYPE_B\n"); + + seq_printf(m, + "RX Num : %d\n", ic_data->HX_RX_NUM); + seq_printf(m, + "TX Num : %d\n", ic_data->HX_TX_NUM); + seq_printf(m, + "BT Num : %d\n", ic_data->HX_BT_NUM); + seq_printf(m, + "X Resolution : %d\n", ic_data->HX_X_RES); + seq_printf(m, + "Y Resolution : %d\n", ic_data->HX_Y_RES); + seq_printf(m, + "Max Point : %d\n", ic_data->HX_MAX_PT); +#if defined(HX_TP_PROC_2T2R) + if (Is_2T2R) { + seq_printf(m, + "2T2R panel\n"); + seq_printf(m, + "RX Num_2 : %d\n", HX_RX_NUM_2); + seq_printf(m, + "TX Num_2 : %d\n", HX_TX_NUM_2); + } +#endif + + return ret; +} + +static int hx_node_update(char *buf, size_t is_len) +{ + int result; + char fileName[128]; + int fw_type = 0; + + const struct firmware *fw = NULL; + + fw_update_complete = false; + fw_update_going = true; + memset(fileName, 0, 128); + /* parse the file name */ + if (!is_len) + memcpy(fileName, buf, strlen(buf) * sizeof(char)); + else + snprintf(fileName, is_len - 2, "%s", &buf[2]); + + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + /* manual upgrade will not use embedded firmware */ + result = request_firmware(&fw, fileName, private_ts->dev); + if (result < 0) { + E("request FW %s failed(%d)\n", fileName, result); + return result; + } + + I("%s: FW image: %02X, %02X, %02X, %02X\n", __func__, + fw->data[0], fw->data[1], + fw->data[2], fw->data[3]); + + himax_int_enable(0); + +#if defined(HX_ZERO_FLASH) + I("NOW Running Zero flash update!\n"); + + /* FW type: 0, normal; 1, MPFW */ + if (strcmp(fileName, MPAP_FWNAME) == 0) + fw_type = 1; + + CFG_TABLE_FLASH_ADDR = CFG_TABLE_FLASH_ADDR_T; + g_core_fp.fp_bin_desc_get((unsigned char *)fw->data, HX1K); + + result = g_core_fp.fp_firmware_update_0f(fw, fw_type); + if (result) { + fw_update_complete = false; + I("Zero flash update fail!\n"); + } else { + fw_update_complete = true; + I("Zero flash update complete!\n"); + } +#else + I("NOW Running common flow update!\n"); + + fw_type = (fw->size) / 1024; + I("Now FW size is : %dk\n", fw_type); + + switch (fw_type) { + case 32: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 60: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 64: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 124: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 128: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 255: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_255k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + default: + E("%s: Flash command fail: %d\n", __func__, __LINE__); + fw_update_complete = false; + break; + } +#endif + release_firmware(fw); + goto firmware_upgrade_done; +firmware_upgrade_done: + fw_update_going = false; + g_core_fp.fp_reload_disable(0); + g_core_fp.fp_power_on_init(); + g_core_fp.fp_read_FW_ver(); + + g_core_fp.fp_tp_info_check(); + + himax_int_enable(1); + return result; +} + +static int himax_update_read(struct seq_file *m) +{ + int ret = NO_ERR; + + if (debug_data->is_call_help) { + seq_printf(m, HELP_UPDATE); + debug_data->is_call_help = false; + } else { + if (!fw_update_going) { + if (fw_update_complete) + seq_printf(m, + "FW Update Complete\n"); + else + seq_printf(m, + "FW Update Fail\n"); + } else { + seq_printf(m, + "FW Update Ongoing\n"); + } + } + + return ret; +} +static ssize_t himax_update_write(char *buf, size_t len) +{ + + I("Now cmd=%s", buf); + if (str_idx_of_str(buf, "help") >= 0) + debug_data->is_call_help = true; + else + hx_node_update(buf, 0); + return len; +} + +static int himax_version_read(struct seq_file *m) +{ + int ret = NO_ERR; + + if (debug_data->is_call_help) { + seq_printf(m, HELP_VER); + debug_data->is_call_help = false; + } else { + seq_printf(m, + "FW_VER = 0x%2.2X\n", + ic_data->vendor_fw_ver); + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) + seq_printf(m, + "CONFIG_VER = 0x%2.2X\n", + ic_data->vendor_config_ver); + else { + seq_printf(m, + "TOUCH_VER = 0x%2.2X\n", + ic_data->vendor_touch_cfg_ver); + seq_printf(m, + "DISPLAY_VER = 0x%2.2X\n", + ic_data->vendor_display_cfg_ver); + } + if (ic_data->vendor_cid_maj_ver < 0 + && ic_data->vendor_cid_min_ver < 0) + seq_printf(m, + "CID_VER = NULL\n"); + else + seq_printf(m, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + + if (ic_data->vendor_panel_ver < 0) + seq_printf(m, + "PANEL_VER = NULL\n"); + else + seq_printf(m, + "PANEL_VER = 0x%2.2X\n", + ic_data->vendor_panel_ver); + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + seq_printf(m, + "Cusomer = %s\n", + ic_data->vendor_cus_info); + + seq_printf(m, + "Project = %s\n", + ic_data->vendor_proj_info); + } + seq_puts(m, "\n"); + seq_printf(m, + "Himax Touch Driver Version:\n"); + seq_printf(m, + "%s\n", HIMAX_DRIVER_VER); + } + return ret; +} +static ssize_t himax_version_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + I("Now cmd=%s", buf); + if (str_idx_of_str(buf, "help") >= 0) + debug_data->is_call_help = true; + else + g_core_fp.fp_read_FW_ver(); + + return len; +} + +static int himax_list_cmd_read(struct seq_file *m) +{ + int ret = NO_ERR; + int i = 0, j = 0; + + for (i = CMD_START_IDX; dbg_cmd_str[i] != NULL; i++) { + for (j = 0; dbg_cmd_str[i][j] != NULL ; j++) { + if (j != 0) + seq_puts(m, ", "); + seq_printf(m, dbg_cmd_str[i][j]); + } + seq_puts(m, "\n"); + } + return ret; +} + +static int himax_help_read(struct seq_file *m) +{ + int ret = NO_ERR; + + seq_printf(m, HELP_ALL_DEBUG); + return ret; +} +static ssize_t himax_help_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + I("Now cmd=%s", buf); + + return len; +} + +static int himax_debug_show(struct seq_file *m, void *v) +{ + int ret = 0; + + if (dbg_cmd_flag) { + if (dbg_func_ptr_r[dbg_cmd_flag]) { + dbg_func_ptr_r[dbg_cmd_flag](m); + goto END_FUNC_R; + } + } + + if (debug_level_cmd == 't') { + if (!fw_update_going) { + if (fw_update_complete) + seq_printf(m, + "FW Update Complete "); + else + seq_printf(m, + "FW Update Fail "); + } else { + seq_printf(m, + "FW Update Ongoing "); + } + } else if (debug_level_cmd == 'h') { + if (handshaking_result == 0) + seq_printf(m, + "Handshaking Result = %d (MCU Running)\n", + handshaking_result); + else if (handshaking_result == 1) + seq_printf(m, + "Handshaking Result = %d (MCU Stop)\n", + handshaking_result); + else if (handshaking_result == 2) + seq_printf(m, + "Handshaking Result = %d (I2C Error)\n", + handshaking_result); + else + seq_printf(m, + "Handshaking Result = error\n"); + + } else { + himax_list_cmd_read(m); + } + +END_FUNC_R: + + return ret; +} + +static ssize_t himax_debug_store(struct file *file, const char __user *ubuf, + size_t len, loff_t *data) +{ + + char buf[80] = "\0"; + char *str_ptr = NULL; + int str_len = 0; + int input_cmd_len = 0; + int i = 0, j = 0; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, ubuf, len)) + return -EFAULT; + + str_len = len; + buf[str_len - 1] = '\0';/*remove \n*/ + input_cmd_len = (int)strcspn(buf, ","); + if (input_cmd_len == -1) + input_cmd_len = str_len; + + i = CMD_START_IDX; /* start from 1*/ + while (dbg_cmd_str[i] != NULL) { + while (dbg_cmd_str[i][j] != NULL) { + str_ptr = strnstr(buf, dbg_cmd_str[i][j], len); + str_len = strlen(dbg_cmd_str[i][j]); + if (str_len != input_cmd_len) { + str_ptr = NULL; + j++; + continue; + } + if (str_ptr) { + dbg_cmd_flag = i; + debug_level_cmd = 0; + I("Cmd is correct :%s, dbg_cmd = %d\n", + str_ptr, dbg_cmd_flag); + goto CHECK; + } + j++; + } + j = 0; + i++; + } +CHECK: + if (!str_ptr) { + I("Cmd is in old fromat or incorrect\n"); + dbg_cmd_flag = 0; + goto CONTI; + } + + if (buf[str_len] == ',') { + dbg_cmd_par = buf + str_len + 1; + if (dbg_func_ptr_w[dbg_cmd_flag]) + /* 2 => '/n' + ','*/ + dbg_func_ptr_w[dbg_cmd_flag](dbg_cmd_par, + len - str_len - 2); + + I("string of paremeter is %s; dbg_cmd_par = %s, size = %d\n", + buf + str_len + 1, + dbg_cmd_par, (int)(len - str_len - 2)); + } else { + I("Write cmd=%s, without parameter\n", + dbg_cmd_str[dbg_cmd_flag][0]); + } +CONTI: + if (dbg_cmd_flag) + return len; + + if (buf[0] == 't') { + debug_level_cmd = buf[0]; + hx_node_update(buf, len); + } else if (buf[0] == 'c' && buf[1] == 't' && buf[2] == 'i') { + /* Compare Touch Information */ + g_core_fp.fp_tp_info_check(); + goto ENDFUCTION; + } else { + /* others,do nothing */ + debug_level_cmd = 0; + } + +ENDFUCTION: + return len; +} +__CREATE_RW_NODE_HX(debug); + +static int himax_vendor_show(struct seq_file *m, void *v) +{ + int ret = 0; + + seq_printf(m, + "IC = %s\n", private_ts->chip_name); + + seq_printf(m, + "FW_VER = 0x%2.2X\n", ic_data->vendor_fw_ver); + + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) { + seq_printf(m, + "CONFIG_VER = 0x%2.2X\n", + ic_data->vendor_config_ver); + } else { + seq_printf(m, + "TOUCH_VER = 0x%2.2X\n", + ic_data->vendor_touch_cfg_ver); + seq_printf(m, + "DISPLAY_VER = 0x%2.2X\n", + ic_data->vendor_display_cfg_ver); + } + + if (ic_data->vendor_cid_maj_ver < 0 + && ic_data->vendor_cid_min_ver < 0) { + seq_printf(m, + "CID_VER = NULL\n"); + } else { + seq_printf(m, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + } + + if (ic_data->vendor_panel_ver < 0) { + seq_printf(m, + "PANEL_VER = NULL\n"); + } else { + seq_printf(m, + "PANEL_VER = 0x%2.2X\n", + ic_data->vendor_panel_ver); + } + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + seq_printf(m, + "Cusomer = %s\n", + ic_data->vendor_cus_info); + seq_printf(m, + "Project = %s\n", + ic_data->vendor_proj_info); + } + seq_puts(m, "\n"); + seq_printf(m, + "Himax Touch Driver Version:\n"); + seq_printf(m, "%s\n", + HIMAX_DRIVER_VER); + + return ret; +} +__CREATE_OREAD_NODE_HX(vendor); + +static void himax_himax_data_init(void) +{ + debug_data->fp_ts_dbg_func = himax_ts_dbg_func; + debug_data->fp_set_diag_cmd = himax_set_diag_cmd; + debug_data->flash_dump_going = false; + debug_data->is_checking_irq = false; + debug_data->is_call_help = false; +} + +static void himax_ts_dump_work_func(struct work_struct *work) +{ + himax_ts_dump_func(); +} +#if defined(HX_TP_PROC_GUEST_INFO) +static void himax_ts_guest_info_work_func(struct work_struct *work) +{ + g_core_fp.read_guest_info(); +} +#endif + +static void himax_ts_diag_work_func(struct work_struct *work) +{ + himax_ts_diag_func(process_type); + + if (process_type != 0) { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_work, 1 / 10 * HZ); + } else { + dsram_flag = false; + } +} + +void dbg_func_ptr_init(void) +{ + /*debug function ptr init*/ + int idx = 1; + + dbg_func_ptr_r[idx] = himax_crc_test_read; + idx++; + + dbg_func_ptr_r[idx] = himax_proc_FW_debug_read; + idx++; + + dbg_func_ptr_r[idx] = himax_attn_read; + idx++; + + dbg_func_ptr_w[idx] = himax_layout_write; + dbg_func_ptr_r[idx] = himax_layout_read; + idx++; + +#if defined(HX_EXCP_RECOVERY) + dbg_func_ptr_w[idx] = himax_excp_cnt_write; + dbg_func_ptr_r[idx] = himax_excp_cnt_read; +#endif + idx++; + + dbg_func_ptr_w[idx] = himax_sense_on_off_write; + idx++; + + dbg_func_ptr_w[idx] = himax_debug_level_write; + dbg_func_ptr_r[idx] = himax_debug_level_read; + idx++; + +#if defined(HX_TP_PROC_GUEST_INFO) + dbg_func_ptr_w[idx] = himax_proc_guest_info_write; + dbg_func_ptr_r[idx] = himax_proc_guest_info_read; +#endif + idx++; + + dbg_func_ptr_w[idx] = himax_int_en_write; + dbg_func_ptr_r[idx] = himax_int_en_read; + idx++; + + dbg_func_ptr_w[idx] = himax_irq_info_write; + dbg_func_ptr_r[idx] = himax_irq_info_read; + idx++; + + dbg_func_ptr_r[idx] = himax_proc_register_read; + dbg_func_ptr_w[idx] = himax_proc_register_write; + idx++; + + dbg_func_ptr_r[idx] = himax_reset_read; + dbg_func_ptr_w[idx] = himax_reset_write; + idx++; + + dbg_func_ptr_r[idx] = himax_diag_arrange_read; + dbg_func_ptr_w[idx] = himax_diag_arrange_write; + idx++; + + dbg_func_ptr_w[idx] = himax_diag_cmd_write; + idx++; + + dbg_func_ptr_w[idx] = himax_irq_dbg_cmd_write; + idx++; + + dbg_func_ptr_r[idx] = himax_test_bus_read; + idx++; + + dbg_func_ptr_w[idx] = himax_update_write; + dbg_func_ptr_r[idx] = himax_update_read; + idx++; + + dbg_func_ptr_w[idx] = himax_version_write; + dbg_func_ptr_r[idx] = himax_version_read; + idx++; + + dbg_func_ptr_r[idx] = himax_info_read; + idx++; + + dbg_func_ptr_r[idx] = himax_list_cmd_read; + idx++; + + dbg_func_ptr_w[idx] = himax_help_write; + dbg_func_ptr_r[idx] = himax_help_read; + idx++; + +} + +int himax_touch_proc_init(void) +{ + himax_proc_diag_dir = proc_mkdir(HIMAX_PROC_DIAG_FOLDER, + himax_touch_proc_dir); + + if (himax_proc_diag_dir == NULL) { + E(" %s: himax_proc_diag_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_stack_file = proc_create(HIMAX_PROC_STACK_FILE, 0444, + himax_proc_diag_dir, &himax_stack_ops); + if (himax_proc_stack_file == NULL) { + E(" %s: proc stack file create failed!\n", __func__); + goto fail_2_1; + } + + himax_proc_delta_file = proc_create(HIMAX_PROC_DELTA_FILE, 0444, + himax_proc_diag_dir, &himax_delta_ops); + if (himax_proc_delta_file == NULL) { + E(" %s: proc delta file create failed!\n", __func__); + goto fail_2_2; + } + + himax_proc_dc_file = proc_create(HIMAX_PROC_DC_FILE, 0444, + himax_proc_diag_dir, &himax_dc_ops); + if (himax_proc_dc_file == NULL) { + E(" %s: proc dc file create failed!\n", __func__); + goto fail_2_3; + } + + himax_proc_baseline_file = proc_create(HIMAX_PROC_BASELINE_FILE, 0444, + himax_proc_diag_dir, &himax_baseline_ops); + if (himax_proc_baseline_file == NULL) { + E(" %s: proc baseline file create failed!\n", __func__); + goto fail_2_4; + } + + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, + 0644, himax_touch_proc_dir, + &himax_debug_ops); + if (himax_proc_debug_file == NULL) { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_3; + } + dbg_func_ptr_init(); + + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, + 0644, himax_touch_proc_dir, + &himax_flash_dump_ops); + if (himax_proc_flash_dump_file == NULL) { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_4; + } + + return 0; + +fail_4: remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +fail_3: remove_proc_entry(HIMAX_PROC_BASELINE_FILE, himax_proc_diag_dir); +fail_2_4: remove_proc_entry(HIMAX_PROC_DC_FILE, himax_proc_diag_dir); +fail_2_3: remove_proc_entry(HIMAX_PROC_DELTA_FILE, himax_proc_diag_dir); +fail_2_2: remove_proc_entry(HIMAX_PROC_STACK_FILE, himax_proc_diag_dir); +fail_2_1: + return -ENOMEM; +} + +void himax_touch_proc_deinit(void) +{ + + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_BASELINE_FILE, himax_proc_diag_dir); + remove_proc_entry(HIMAX_PROC_DC_FILE, himax_proc_diag_dir); + remove_proc_entry(HIMAX_PROC_DELTA_FILE, himax_proc_diag_dir); + remove_proc_entry(HIMAX_PROC_STACK_FILE, himax_proc_diag_dir); +} + +int himax_debug_init(void) +{ + struct himax_ts_data *ts = private_ts; + + I("%s:Enter\n", __func__); + + if (ts == NULL) { + E("%s: ts struct is NULL\n", __func__); + return -EPROBE_DEFER; + } + + proc_reg_buf = kzalloc(128 * sizeof(uint8_t), GFP_KERNEL); + if (proc_reg_buf == NULL) { + E("%s: reg_read_data allocate failed\n", __func__); + goto err_alloc_reg_read_data_fail; + } + + debug_data = kzalloc(sizeof(struct himax_debug), GFP_KERNEL); + if (debug_data == NULL) { /*Allocate debug data space*/ + E("%s: debug_data allocate failed\n", __func__); + goto err_alloc_debug_data_fail; + } + + himax_himax_data_init(); + + g_dump_buffer = kcalloc(ic_data->flash_size, + sizeof(uint8_t), + GFP_KERNEL); + if (g_dump_buffer == NULL) { + E("%s: dump buffer allocate fail failed\n", __func__); + goto err_dump_buf_alloc_failed; + } + + ts->dump_wq = create_singlethread_workqueue("himax_dump_wq"); + if (!ts->dump_wq) { + E("%s: create flash workqueue failed\n", __func__); + goto err_create_flash_dump_wq_failed; + } + INIT_WORK(&ts->dump_work, himax_ts_dump_work_func); + g_flash_progress = START; + +#if defined(HX_TP_PROC_GUEST_INFO) + if (g_guest_info_data == NULL) { + g_guest_info_data = kzalloc(sizeof(struct hx_guest_info), + GFP_KERNEL); + if (g_guest_info_data == NULL) { + E("%s: flash buffer allocate fail failed\n", __func__); + goto err_guest_info_alloc_failed; + } + g_guest_info_data->g_guest_info_ongoing = 0; + g_guest_info_data->g_guest_info_type = 0; + } + + ts->guest_info_wq = + create_singlethread_workqueue("himax_guest_info_wq"); + if (!ts->guest_info_wq) { + E("%s: create guest info workqueue failed\n", __func__); + goto err_create_guest_info_wq_failed; + } + INIT_WORK(&ts->guest_info_work, himax_ts_guest_info_work_func); +#endif + + setSelfBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getSelfBuffer() == NULL) { + E("%s: self buffer allocate failed\n", __func__); + goto err_self_buf_alloc_failed; + } + + setSelfNewBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getSelfNewBuffer() == NULL) { + E("%s: self new buffer allocate failed\n", __func__); + goto err_self_new_alloc_failed; + } + + setSelfOldBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getSelfOldBuffer() == NULL) { + E("%s: self old buffer allocate failed\n", __func__); + goto err_self_old_alloc_failed; + } + + setMutualBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate failed\n", __func__); + goto err_mut_buf_alloc_failed; + } + + setMutualNewBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getMutualNewBuffer() == NULL) { + E("%s: mutual new buffer allocate failed\n", __func__); + goto err_mut_new_alloc_failed; + } + + setMutualOldBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getMutualOldBuffer() == NULL) { + E("%s: mutual old buffer allocate failed\n", __func__); + goto err_mut_old_alloc_failed; + } + +#if defined(HX_TP_PROC_2T2R) + if (Is_2T2R) { + setMutualBuffer_2(ic_data->HX_RX_NUM_2, ic_data->HX_TX_NUM_2); + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate failed\n", __func__); + goto err_mut_buf2_alloc_failed; + } + } +#endif + + ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); + if (!ts->himax_diag_wq) { + E("%s: create diag workqueue failed\n", __func__); + goto err_create_diag_wq_failed; + } + INIT_DELAYED_WORK(&ts->himax_diag_delay_work, himax_ts_diag_work_func); + + if (himax_touch_proc_init()) + goto err_proc_init_failed; + + + snprintf(g_file_path, (int)(strlen(HX_RSLT_OUT_PATH) + + strlen(HX_RSLT_OUT_FILE)+1), + "%s%s", HX_RSLT_OUT_PATH, HX_RSLT_OUT_FILE); + + return 0; + +err_proc_init_failed: + cancel_delayed_work_sync(&ts->himax_diag_delay_work); + destroy_workqueue(ts->himax_diag_wq); +err_create_diag_wq_failed: +#if defined(HX_TP_PROC_2T2R) + kfree(diag_mutual_2); + diag_mutual_2 = NULL; +err_mut_buf2_alloc_failed: +#endif + kfree(diag_mutual_old); + diag_mutual_old = NULL; +err_mut_old_alloc_failed: + kfree(diag_mutual_new); + diag_mutual_new = NULL; +err_mut_new_alloc_failed: + kfree(diag_mutual); + diag_mutual = NULL; +err_mut_buf_alloc_failed: + kfree(diag_self_old); + diag_self_old = NULL; +err_self_old_alloc_failed: + kfree(diag_self_new); + diag_self_new = NULL; +err_self_new_alloc_failed: + kfree(diag_self); + diag_self = NULL; +err_self_buf_alloc_failed: +#if defined(HX_TP_PROC_GUEST_INFO) + cancel_work_sync(&ts->guest_info_work); + destroy_workqueue(ts->guest_info_wq); +err_create_guest_info_wq_failed: + if (g_guest_info_data != NULL) { + kfree(g_guest_info_data); + g_guest_info_data = NULL; + } +err_guest_info_alloc_failed: +#endif + cancel_work_sync(&ts->dump_work); + destroy_workqueue(ts->dump_wq); +err_create_flash_dump_wq_failed: + kfree(g_dump_buffer); + g_dump_buffer = NULL; +err_dump_buf_alloc_failed: + kfree(debug_data); + debug_data = NULL; +err_alloc_debug_data_fail: + kfree(proc_reg_buf); + proc_reg_buf = NULL; +err_alloc_reg_read_data_fail: + + return -ENOMEM; +} +EXPORT_SYMBOL(himax_debug_init); + +int himax_debug_remove(void) +{ + struct himax_ts_data *ts = private_ts; + + himax_touch_proc_deinit(); + + cancel_delayed_work_sync(&ts->himax_diag_delay_work); + destroy_workqueue(ts->himax_diag_wq); + + kfree(diag_mutual_2); + diag_mutual_2 = NULL; + + kfree(diag_mutual_old); + diag_mutual_old = NULL; + + kfree(diag_mutual_new); + diag_mutual_new = NULL; + + kfree(diag_mutual); + diag_mutual = NULL; + + kfree(diag_self_old); + diag_self_old = NULL; + + kfree(diag_self_new); + diag_self_new = NULL; + + kfree(diag_self); + diag_self = NULL; + +#if defined(HX_TP_PROC_GUEST_INFO) + cancel_work_sync(&ts->guest_info_work); + destroy_workqueue(ts->guest_info_wq); + if (g_guest_info_data != NULL) { + kfree(g_guest_info_data); + g_guest_info_data = NULL; + } +#endif + + cancel_work_sync(&ts->dump_work); + destroy_workqueue(ts->dump_wq); + + kfree(g_dump_buffer); + g_dump_buffer = NULL; + + kfree(debug_data); + debug_data = NULL; + + kfree(proc_reg_buf); + proc_reg_buf = NULL; + + return 0; +} +EXPORT_SYMBOL(himax_debug_remove); + diff --git a/himax_debug.h b/himax_debug.h new file mode 100644 index 0000000..cbb8938 --- /dev/null +++ b/himax_debug.h @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for debug nodes + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef H_HIMAX_DEBUG +#define H_HIMAX_DEBUG + +#include "himax_platform.h" +#include "himax_common.h" +#include "himax_debug_info.h" + + +#define HX_RSLT_OUT_PATH "/data/" +#define HX_RSLT_OUT_FILE "hx_dump_result.txt" + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +extern int hx_EB_event_flag; +extern int hx_EC_event_flag; +#if defined(HW_ED_EXCP_EVENT) +extern int hx_EE_event_flag; +#else +extern int hx_ED_event_flag; +#endif +#endif + +#define HIMAX_PROC_PEN_POS_FILE "pen_pos" + +int himax_touch_proc_init(void); +void himax_touch_proc_deinit(void); +extern int himax_int_en_set(void); + +#define HIMAX_PROC_DIAG_FOLDER "diag" +struct proc_dir_entry *himax_proc_diag_dir; +#define HIMAX_PROC_STACK_FILE "stack" +extern struct proc_dir_entry *himax_proc_stack_file; +#define HIMAX_PROC_DELTA_FILE "delta_s" +extern struct proc_dir_entry *himax_proc_delta_file; +#define HIMAX_PROC_DC_FILE "dc_s" +extern struct proc_dir_entry *himax_proc_dc_file; +#define HIMAX_PROC_BASELINE_FILE "baseline_s" +extern struct proc_dir_entry *himax_proc_baseline_file; + +#if defined(HX_TP_PROC_2T2R) +extern uint32_t *diag_mutual_2; + +int32_t *getMutualBuffer_2(void); +void setMutualBuffer_2(uint8_t x_num, uint8_t y_num); +#endif +extern int32_t *diag_mutual; +extern int32_t *diag_mutual_new; +extern int32_t *diag_mutual_old; +extern uint8_t hx_state_info[2]; +extern uint8_t diag_coor[128]; +extern int32_t *diag_self; +extern int32_t *diag_self_new; +extern int32_t *diag_self_old; +int32_t *getMutualBuffer(void); +int32_t *getMutualNewBuffer(void); +int32_t *getMutualOldBuffer(void); +int32_t *getSelfBuffer(void); +int32_t *getSelfNewBuffer(void); +int32_t *getSelfOldBuffer(void); +void setMutualBuffer(uint8_t x_num, uint8_t y_num); +void setMutualNewBuffer(uint8_t x_num, uint8_t y_num); +void setMutualOldBuffer(uint8_t x_num, uint8_t y_num); +uint8_t process_type; +uint8_t mode_flag; +uint8_t overflow; + +#define HIMAX_PROC_DEBUG_FILE "debug" +extern struct proc_dir_entry *himax_proc_debug_file; +extern bool fw_update_complete; +extern int handshaking_result; +extern unsigned char debug_level_cmd; +extern uint8_t cmd_set[8]; +extern uint8_t mutual_set_flag; + +#define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" +extern struct proc_dir_entry *himax_proc_flash_dump_file; +extern uint8_t *flash_buffer; +extern uint8_t g_flash_cmd; +extern uint8_t g_flash_progress; +extern bool g_flash_dump_rst; /*Fail = 0, Pass = 1*/ +void setFlashBuffer(void); + +enum flash_dump_prog { + START, + ONGOING, + FINISHED, +}; + +extern uint32_t **raw_data_array; +extern uint8_t X_NUM4; +extern uint8_t Y_NUM; +extern uint8_t sel_type; + +/* Moved from debug.c */ +extern struct himax_debug *debug_data; +extern unsigned char IC_CHECKSUM; +extern int i2c_error_count; +extern struct proc_dir_entry *himax_touch_proc_dir; + +#if defined(HX_TP_PROC_GUEST_INFO) +extern struct hx_guest_info *g_guest_info_data; +extern char *g_guest_info_item[]; +#endif + +extern int himax_input_register(struct himax_ts_data *ts); +#if defined(HX_TP_PROC_2T2R) +extern bool Is_2T2R; +#endif + +#if defined(HX_RST_PIN_FUNC) +extern void himax_ic_reset(uint8_t loadconfig, uint8_t int_off); +#endif + +extern uint8_t HX_PROC_SEND_FLAG; +extern struct himax_target_report_data *g_target_report_data; +extern struct himax_report_data *hx_touch_data; +extern int g_ts_dbg; + +/* Moved from debug.c end */ +#define BUF_SIZE 1024 +#define CMD_NUM 24 +#define CMD_START_IDX 1 +char *cmd_crc_test_str[] = {"crc_test", NULL}; +char *cmd_fw_debug_str[] = {"fw_debug", NULL}; +char *cmd_attn_str[] = {"attn", NULL}; +char *cmd_layout_str[] = {"layout", NULL}; +char *cmd_excp_cnt_str[] = {"excp_cnt", NULL}; +char *cmd_senseonoff_str[] = {"senseonoff", "SenseOnOff", NULL}; +char *cmd_dbg_lvl_str[] = {"debug_level", "dbg_lvl", NULL}; +char *cmd_guest_info_str[] = {"guest_info", NULL}; +char *cmd_int_en_str[] = {"int_en", NULL}; +char *cmd_irq_info_str[] = {"int", "irq_info", NULL}; +char *cmd_register_str[] = {"register", NULL}; +char *cmd_reset_str[] = {"reset", "rst", NULL}; +char *cmd_diag_arr_str[] = {"diag_arr", NULL}; +char *cmd_diag_str[] = {"diag", NULL}; +char *cmd_irq_dbg_str[] = {"irq_dbg", NULL}; +char *cmd_bus_str[] = {"bus", "i2c", "spi", NULL}; +char *cmd_update_str[] = {"update", "t", NULL}; +char *cmd_version_str[] = {"version", "v", "V", NULL}; +char *cmd_dbg_info_str[] = {"d", "info", NULL}; +char *cmd_list_str[] = {"list", "l", NULL}; +char *cmd_help_str[] = {"help", "h", "?", "-?", NULL}; +char **dbg_cmd_str[] = { + NULL, + cmd_crc_test_str, + cmd_fw_debug_str, + cmd_attn_str, + cmd_layout_str, + cmd_excp_cnt_str, + cmd_senseonoff_str, + cmd_dbg_lvl_str, + cmd_guest_info_str, + cmd_int_en_str, + cmd_irq_info_str, + cmd_register_str, + cmd_reset_str, + cmd_diag_arr_str, + cmd_diag_str, + cmd_irq_dbg_str, + cmd_bus_str, + cmd_update_str, + cmd_version_str, + cmd_dbg_info_str, + cmd_list_str, + cmd_help_str, + NULL, +}; + +int dbg_cmd_flag; +char *dbg_cmd_par; +int (*dbg_func_ptr_r[CMD_NUM])(struct seq_file *m); +ssize_t (*dbg_func_ptr_w[CMD_NUM])(char *buf, size_t len); + +#define STR_TO_UL_ERR "String to ul is fail in cnt = %d, buf_tmp2 = %s\n" +#define PRT_LOG "Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, Int_Delay_Cnt:%d\n" +#define RAW_DOWN_STATUS "status: Raw:F:%02d Down, X:%d, Y:%d, W:%d\n" +#define RAW_UP_STATUS "status: Raw:F:%02d Up, X:%d, Y:%d\n" +#define PRT_OK_LOG "%s: change mode 0x%4X. str_pw = %2X, end_pw = %2X\n" +#define PRT_FAIL_LOG "%s: change mode failed. str_pw = %2X, end_pw = %2X\n" + +#if defined(KERNEL_VER_ABOVE_5_10) +#define __CREATE_OREAD_NODE_HX(name)\ +static int himax_##name##_open(struct inode *inode, struct file *file)\ +{return single_open(file, himax_##name##_show, NULL); } \ +static const struct proc_ops himax_##name##_ops = {\ + .proc_open = himax_##name##_open,\ + .proc_read = seq_read,\ +} +#else +#define __CREATE_OREAD_NODE_HX(name)\ +static int himax_##name##_open(struct inode *inode, struct file *file)\ +{return single_open(file, himax_##name##_show, NULL); } \ +static const struct file_operations himax_##name##_ops = {\ + .owner = THIS_MODULE,\ + .open = himax_##name##_open,\ + .read = seq_read,\ +} +#endif + +#if defined(KERNEL_VER_ABOVE_5_10) +#define __CREATE_RW_NODE_HX(name)\ +static int himax_##name##_open(struct inode *inode, struct file *file)\ +{return single_open(file, himax_##name##_show, NULL); } \ +static const struct proc_ops himax_##name##_ops = {\ + .proc_open = himax_##name##_open,\ + .proc_write = himax_##name##_store,\ + .proc_read = seq_read,\ + .proc_release = single_release,\ +} +#else +#define __CREATE_RW_NODE_HX(name)\ +static int himax_##name##_open(struct inode *inode, struct file *file)\ +{return single_open(file, himax_##name##_show, NULL); } \ +static const struct file_operations himax_##name##_ops = {\ + .owner = THIS_MODULE,\ + .open = himax_##name##_open,\ + .write = himax_##name##_store,\ + .read = seq_read,\ + .llseek = seq_lseek,\ + .release = single_release,\ +} +#endif + +#endif diff --git a/himax_debug_info.h b/himax_debug_info.h new file mode 100644 index 0000000..ecf25e0 --- /dev/null +++ b/himax_debug_info.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define HX_TAB "\t" +#define DBG_REG_NAME "register" +#define DBG_INT_NAME "int_en" +#define DBG_SNS_NAME "SenseOnOff" +#define DBG_RST_NAME "reset" +#define DBG_LVL_NAME "debug_level" +#define DBG_VER_NAME "version" +#define DBG_DIAG_NAME "diag" +#define DBG_DIAG_ARR_NAME "diag_arr" +#define DBG_LAYOUT_NAME "layout" +#define DBG_EXCPT_NAME "excp_cnt" +#define DBG_GUEST_INFO_NAME "guest_info" +#define DBG_UPDATE_NAME "update" + +#define HELP_INT_EN DBG_INT_NAME ":\n"\ +HX_TAB "0 : disable irq\n"\ +HX_TAB "1 : enable irq\n" +#define HELP_REGISTER DBG_REG_NAME ":\n"\ +HX_TAB "echo " DBG_REG_NAME ",r:x > debug\n"\ +HX_TAB "echo " DBG_REG_NAME ",w:x:x > debug\n" +#define HELP_SNS DBG_SNS_NAME ":\n"\ +HX_TAB "0 : Sense off\n"\ +HX_TAB "1 : Sesne on by leave safe mode\n"\ +HX_TAB "1s : Sesne on with reset\n" +#define HELP_RST DBG_RST_NAME ":\n"\ +HX_TAB "1 : trigger reset without reload\n"\ +HX_TAB "2 : trigger reset with reload config\n"\ +HX_TAB "test : test reset pin, show in kernel log\n" +#define HELP_LVL DBG_LVL_NAME ":\n"\ +HX_TAB "0 : turn off all\n"\ +HX_TAB "1 : all of event stack data,56~128 bytes\n"\ +HX_TAB "2 : point data, all of actions of finger point\n"\ +HX_TAB "4 : process time of irq\n"\ +HX_TAB "8 : info of finger point down/up\n"\ +HX_TAB "10 : detail info of processing self_test\n"\ +HX_TAB "tsdbg0 : turn off irq process state\n"\ +HX_TAB "tsdbg1 : turn on irq process state\n" +#define HELP_VER DBG_VER_NAME ":\n"\ +HX_TAB "echo version > debug, it will RE-LOAD the FW version, Becare to use..\n" +#define HELP_DIAG DBG_DIAG_NAME ":\n"\ +HX_TAB " - enter one number to use event stack or dsram rawdata\n"\ +HX_TAB " - enter 4 number to choose type(stack/dsram)"\ +"and rawout select(fw) to get rawdata" +#define HELP_DIAG_ARR DBG_DIAG_ARR_NAME ":\n"\ +HX_TAB "0 : turn off all\n"\ +HX_TAB "1 : rx reverse\n"\ +HX_TAB "2 : tx reverse\n"\ +HX_TAB "3 : rx & tx reverse\n"\ +HX_TAB "4 : rotate 90 degree without reverse\n"\ +HX_TAB "5 : rotate 90 degree with rx reverse\n"\ +HX_TAB "6 : rotate 90 degree with tx reverse\n"\ +HX_TAB "7 : rotate 90 degree with rx & tx reverse\n" +#define HELP_LAYOUT DBG_LAYOUT_NAME ":\n"\ +HX_TAB "To change the touch resolution in driver\n"\ +HX_TAB "min_x,max_x,min_y,max_y\n" +#define HELP_DD_DBG DBG_DDDBG_NAME ":\n"\ +HX_TAB "To read DD register\n"\ +HX_TAB "r:x[DD reg]:x[Bank]:x[Size]\n" +#define HELP_EXCPT DBG_EXCPT_NAME ":\n"\ +HX_TAB "Show Exception Event\n"\ +HX_TAB "0 : clear now all of state of exception event\n" +#define HELP_GUEST_INFO DBG_GUEST_INFO_NAME ":\n"\ +HX_TAB "Only for project with FLASH\n"\ +HX_TAB "It should turn on in define (Macro of source code)\n"\ +HX_TAB "r : read customer info from flash\n" +#define HELP_LOT DBG_LOT_NAME ":\n"\ +HX_TAB "Read lot id(ic id) from dd reg\n" +#define HELP_UPDATE DBG_UPDATE_NAME ":\n"\ +HX_TAB "Using file name to update FW\n"\ +HX_TAB "echo update,[file name bin file] > debug\n" +#define HELP_ALL_DEBUG "All:\n"\ +HELP_REGISTER \ +HELP_INT_EN \ +HELP_SNS \ +HELP_RST \ +HELP_LVL \ +HELP_VER \ +HELP_DIAG \ +HELP_DIAG_ARR \ +HELP_EXCPT \ +HELP_GUEST_INFO \ +HELP_UPDATE + diff --git a/himax_ic_HX83102.c b/himax_ic_HX83102.c new file mode 100644 index 0000000..b57ceba --- /dev/null +++ b/himax_ic_HX83102.c @@ -0,0 +1,1616 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for HX83102 chipset + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_ic_HX83102.h" +#include "himax_modular.h" + +static void hx83102_chip_init(void) +{ + private_ts->chip_cell_type = CHIP_IS_IN_CELL; + I("%s:IC cell type = %d\n", __func__, private_ts->chip_cell_type); + (IC_CHECKSUM) = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + (FW_VER_MAJ_FLASH_ADDR) = 49157; /*0x00C005*/ + (FW_VER_MIN_FLASH_ADDR) = 49158; /*0x00C006*/ + (CFG_VER_MAJ_FLASH_ADDR) = 49408; /*0x00C100*/ + (CFG_VER_MIN_FLASH_ADDR) = 49409; /*0x00C101*/ + (CID_VER_MAJ_FLASH_ADDR) = 49154; /*0x00C002*/ + (CID_VER_MIN_FLASH_ADDR) = 49155; /*0x00C003*/ + (CFG_TABLE_FLASH_ADDR) = 0x10000; + /*PANEL_VERSION_ADDR = 49156;*/ /*0x00C004*/ + (CFG_TABLE_FLASH_ADDR_T) = (CFG_TABLE_FLASH_ADDR); +} + +static void hx83102e_chip_init(void) +{ + private_ts->chip_cell_type = CHIP_IS_IN_CELL; + I("%s:IC cell type = %d\n", __func__, private_ts->chip_cell_type); + (IC_CHECKSUM) = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + (FW_VER_MAJ_FLASH_ADDR) = 59397; /*0x00E805*/ + (FW_VER_MIN_FLASH_ADDR) = 59398; /*0x00E806*/ + (CFG_VER_MAJ_FLASH_ADDR) = 59648; /*0x00E900*/ + (CFG_VER_MIN_FLASH_ADDR) = 59649; /*0x00E901*/ + (CID_VER_MAJ_FLASH_ADDR) = 59394; /*0x00E802*/ + (CID_VER_MIN_FLASH_ADDR) = 59395; /*0x00E803*/ + (CFG_TABLE_FLASH_ADDR) = 0x10000; + /*PANEL_VERSION_ADDR = 59396;*/ /*0x00E804*/ + (CFG_TABLE_FLASH_ADDR_T) = (CFG_TABLE_FLASH_ADDR); +} + +void hx83102_burst_enable(uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + int ret = 0; + + tmp_data[0] = 0x31; + + ret = himax_bus_write(0x13, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + + ret = himax_bus_write(0x0D, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } +} + +int hx83102_flash_write_burst(uint8_t *reg_byte, uint8_t *write_data) +{ + uint8_t data_byte[8]; + int i = 0, j = 0, ret = 0; + + for (i = 0; i < 4; i++) + data_byte[i] = reg_byte[i]; + for (j = 4; j < 8; j++) + data_byte[j] = write_data[j-4]; + + ret = himax_bus_write(0x00, data_byte, 8); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + return 0; +} + +static int hx83102_register_read(uint8_t *addr, uint8_t *buf, int len) +{ + uint8_t tmp_data[4]; + int i = 0; + int address = 0; + int ret = 0; + + if (len > 256) { + E("%s: read len over 256!\n", __func__); + return LENGTH_FAIL; + } + if (len > 4) + hx83102_burst_enable(1); + else + hx83102_burst_enable(0); + + address = (addr[3] << 24) + (addr[2] << 16) + (addr[1] << 8) + addr[0]; + + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + + ret = himax_bus_write(0x00, tmp_data, 4); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + tmp_data[0] = 0x00; + + ret = himax_bus_write(0x0C, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + + ret = himax_bus_read(0x08, buf, len); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + if (len > 4) + hx83102_burst_enable(0); + + return 0; +} + +#if defined(HX_RST_PIN_FUNC) +static void hx83102_pin_reset(void) +{ + I("%s: Now reset the Touch chip.\n", __func__); + himax_rst_gpio_set(private_ts->rst_gpio, 0); + usleep_range(RST_LOW_PERIOD_S, RST_LOW_PERIOD_E); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + usleep_range(RST_HIGH_PERIOD_S, RST_HIGH_PERIOD_E); +} +#endif + +static bool hx83102_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_addr[DATA_LEN_4]; + uint8_t tmp_writ[DATA_LEN_4]; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + if (cnt == 0 + || (tmp_data[0] != 0xA5 + && tmp_data[0] != 0x00 + && tmp_data[0] != 0x87)) { + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x5C; + + tmp_writ[3] = 0x00; + tmp_writ[2] = 0x00; + tmp_writ[1] = 0x00; + tmp_writ[0] = 0xA5; + hx83102_flash_write_burst(tmp_addr, tmp_writ); + } + msleep(20); + + /* check fw status */ + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + hx83102_register_read(tmp_addr, tmp_data, DATA_LEN_4); + + if (tmp_data[0] != 0x05) { + I("%s: Do not need wait FW, Status = 0x%02X!\n", + __func__, tmp_data[0]); + break; + } + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x5C; + hx83102_register_read(tmp_addr, tmp_data, DATA_LEN_4); + I("%s: cnt = %d, data[0] = 0x%02X!\n", __func__, + cnt, tmp_data[0]); + } while (tmp_data[0] != 0x87 && (++cnt < 50) && check_en == true); + + cnt = 0; + + do { + /** + *I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = 0x27; + ret = himax_bus_write(0x31, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /** + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = 0x95; + ret = himax_bus_write(0x32, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /** + *Check enter_save_mode + */ + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + hx83102_register_read(tmp_addr, tmp_data, ADDR_LEN_4); + I("%s: Check enter_save_mode data[0]=%X\n", + __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /** + *Reset TCON + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + hx83102_flash_write_burst(tmp_addr, tmp_data); + /** + *Reset ADC + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x94; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + hx83102_flash_write_burst(tmp_addr, tmp_data); + + return true; + } + usleep_range(10000, 10001); +#if defined(HX_RST_PIN_FUNC) + hx83102_pin_reset(); +#endif + + } while (cnt++ < 15); + + return false; +} + +static bool hx83102ab_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_addr[DATA_LEN_4]; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + /** + *I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = 0x27; + ret = himax_bus_write(0x31, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /** + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = 0x95; + ret = himax_bus_write(0x32, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /** + *Check enter_save_mode + */ + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + hx83102_register_read(tmp_addr, tmp_data, ADDR_LEN_4); + I("%s: Check enter_save_mode data[0]=%X\n", + __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /** + *Reset TCON + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + hx83102_flash_write_burst(tmp_addr, tmp_data); + /** + *Reset ADC + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x94; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + hx83102_flash_write_burst(tmp_addr, tmp_data); + + return true; + } + /*msleep(10);*/ + usleep_range(5000, 5001); +#if defined(HX_RST_PIN_FUNC) + himax_rst_gpio_set(private_ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + msleep(50); +#endif + + } while (cnt++ < 5); + + return false; +} + +static void hx83102ab_set_SMWP_enable(uint8_t SMWP_enable, bool suspended) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + g_core_fp.fp_sense_off(true); + + do { + if (SMWP_enable) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_smwp_enable, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_smwp_enable, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + } + + g_core_fp.fp_register_read(pfw_op->addr_smwp_enable, tmp_data, + DATA_LEN_4); + /*I("%s: tmp_data[0]=%d, SMWP_enable=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],SMWP_enable,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); + + g_core_fp.fp_sense_on(0x00); +} + +static void hx83102ab_set_HSEN_enable(uint8_t HSEN_enable, bool suspended) +{ + uint8_t tmp_data[DATA_LEN_4]; + + if (HSEN_enable) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_hsen_enable, + tmp_data, DATA_LEN_4); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_hsen_enable, + tmp_data, DATA_LEN_4); + } + + /*I("%s: tmp_data[0]=%d, HSEN_enable=%d, retry_cnt=%d\n", __func__, + * tmp_data[0],HSEN_enable,retry_cnt); + */ +} + +static void hx83102ab_usb_detect_set(uint8_t *cable_config) +{ + uint8_t tmp_data[DATA_LEN_4]; + + if (cable_config[1] == 0x01) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_usb_detect, + tmp_data, DATA_LEN_4); + I("%s: USB detect status IN!\n", __func__); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_usb_detect, + tmp_data, DATA_LEN_4); + I("%s: USB detect status OUT!\n", __func__); + } +} + +static uint8_t hx83102ab_read_DD_status(uint8_t *cmd_set, uint8_t *tmp_data) +{ + int cnt = 0; + uint8_t req_size = cmd_set[0]; + + cmd_set[3] = pfw_op->data_dd_request[0]; + + g_core_fp.fp_register_write(pfw_op->addr_dd_handshak_addr, + cmd_set, DATA_LEN_4); + I("%s:cmd_set[0]=0x%02X,set[1]=0x%02X,set[2]=0x%02X,set[3]=0x%02X\n", + __func__, cmd_set[0], cmd_set[1], cmd_set[2], cmd_set[3]); + + /* Doing hand shaking 0xAA -> 0xBB */ + for (cnt = 0; cnt < 100; cnt++) { + g_core_fp.fp_register_read(pfw_op->addr_dd_handshak_addr, + tmp_data, DATA_LEN_4); + usleep_range(10000, 10001); + + if (tmp_data[3] == pfw_op->data_dd_ack[0]) { + I("%s Data ready goto moving data\n", __func__); + break; + } + if (cnt >= 99) { + I("%s Data not ready in FW\n", __func__); + return FW_NOT_READY; + } + } + + g_core_fp.fp_sense_off(true); + g_core_fp.fp_register_read(pfw_op->addr_dd_data_addr, tmp_data, + req_size); + g_core_fp.fp_sense_on(0x01); + return NO_ERR; +} + +static void hx83102ab_power_on_init(void) +{ + uint8_t data[4] = {0}; + uint8_t retry = 0; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + data, DATA_LEN_4); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(data); + /*FW reload done initial*/ + g_core_fp.fp_register_write(pdriver_op->addr_fw_define_2nd_flash_reload, + data, DATA_LEN_4); + + g_core_fp.fp_sense_on(0x00); + + I("%s: waiting for FW reload done\n", __func__); + + while (retry++ <= 30) { + g_core_fp.fp_register_read( + pdriver_op->addr_fw_define_2nd_flash_reload, data, + DATA_LEN_4); + + /* use all 4 bytes to compare */ + if ((data[3] == 0x00 && data[2] == 0x00 && + data[1] == 0x72 && data[0] == 0xC0)) { + I("%s: FW finish reload done\n", __func__); + break; + } + I("%s: wait reload done %d times\n", __func__, retry); + g_core_fp.fp_read_FW_status(); + usleep_range(10000, 11000); + } +} + +static int hx83102ab_fts_ctpm_fw_upgrade_with_sys_fs_64k(unsigned char *fw, + int len, bool change_iref) +{ + int burnFW_success = 0; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + if (len != FW_SIZE_64k) { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + g_core_fp.fp_sense_off(true); + g_core_fp.fp_chip_erase(); + g_core_fp.fp_flash_programming(fw, FW_SIZE_64k); + + ret = g_core_fp.fp_check_CRC( + pfw_op->addr_program_reload_from, + FW_SIZE_64k); + if (ret == 0) + burnFW_success = 1; + + himax_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(pfw_op->addr_sorting_mode_en, + tmp_data, DATA_LEN_4); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + /*System reset*/ + g_core_fp.fp_system_reset(); +#endif + return burnFW_success; +} + +#if defined(HX_EXCP_RECOVERY) +static void hx83102ab_excp_ic_reset(void) +{ + (HX_EXCP_RESET_ACTIVATE) = 1; +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_pin_reset(); +#else + g_core_fp.fp_system_reset(); +#endif + I("%s:\n", __func__); +} +#if defined(HX_ZERO_FLASH) +static int hx83102d_0f_excp_check(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + int ret = NO_ERR; + + I("Enter %s\n", __func__); + + g_core_fp.fp_register_read(pzf_op->addr_sts_chk, tmp_data, + DATA_LEN_4); + + if (tmp_data[0] != (pzf_op)->data_activ_sts[0]) { + ret = ERR_STS_WRONG; + I("%s:status : %8X = %2X\n", __func__, + zf_addr_sts_chk, tmp_data[0]); + } + + g_core_fp.fp_register_read(pzf_op->addr_activ_relod, tmp_data, + DATA_LEN_4); + + if (tmp_data[0] != (pzf_op)->data_activ_in[0]) { + ret = ERR_STS_WRONG; + I("%s:status : %8X = %2X\n", __func__, + zf_addr_activ_relod, tmp_data[0]); + } + + return ret; +} +#endif +#endif + +static bool hx83102d_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_addr[DATA_LEN_4]; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + if (cnt == 0 + || (tmp_data[0] != 0xA5 + && tmp_data[0] != 0x00 + && tmp_data[0] != 0x87)) + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + pfw_op->data_fw_stop, DATA_LEN_4); + /*msleep(20);*/ + usleep_range(10000, 10001); + + /* check fw status */ + g_core_fp.fp_register_read(pic_op->addr_cs_central_state, + tmp_data, DATA_LEN_4); + + if (tmp_data[0] != 0x05) { + I("%s: Do not need wait FW, Status = 0x%02X!\n", + __func__, tmp_data[0]); + break; + } + + g_core_fp.fp_register_read(pfw_op->addr_ctrl_fw_isr, tmp_data, + 4); + I("%s: cnt = %d, data[0] = 0x%02X!\n", __func__, + cnt, tmp_data[0]); + } while (tmp_data[0] != 0x87 && (++cnt < 10) && check_en == true); + + cnt = 0; + + do { + /* + *I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = 0x27; + ret = himax_bus_write(0x31, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /* + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = 0x95; + ret = himax_bus_write(0x32, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /* + *Check enter_save_mode + */ + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + hx83102_register_read(tmp_addr, tmp_data, ADDR_LEN_4); + I("%s: Check enter_save_mode data[0]=%X\n", + __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /* + *Reset TCON + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + + /* + *Reset ADC + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x94; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + hx83102_flash_write_burst(tmp_addr, tmp_data); + + return true; + } + /*msleep(10);*/ + usleep_range(5000, 5001); + +#if defined(HX_RST_PIN_FUNC) + himax_rst_gpio_set(private_ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + msleep(50); +#endif + + } while (cnt++ < 5); + + return false; +} + +#if defined(HX_ZERO_FLASH) +static void hx83102e_reload_to_active(void) +{ + uint8_t addr[DATA_LEN_4] = {0}; + uint8_t data[DATA_LEN_4] = {0}; + uint8_t retry_cnt = 0; + + addr[3] = 0x90; + addr[2] = 0x00; + addr[1] = 0x00; + addr[0] = 0x48; + + do { + data[3] = 0x00; + data[2] = 0x00; + data[1] = 0x00; + data[0] = 0xEC; + g_core_fp.fp_register_write(addr, data, DATA_LEN_4); + usleep_range(1000, 1100); + g_core_fp.fp_register_read(addr, data, DATA_LEN_4); + I("%s: data[1]=%d, data[0]=%d, retry_cnt=%d\n", __func__, + data[1], data[0], retry_cnt); + retry_cnt++; + } while ((data[1] != 0x01 + || data[0] != 0xEC) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void hx83102e_resume_ic_action(void) +{ +#if !defined(HX_RESUME_HW_RESET) + hx83102e_reload_to_active(); +#endif +} +#endif + +static void hx83102e_sense_on(uint8_t FlashMode) +{ + uint8_t tmp_data[DATA_LEN_4] = {0}; + int ret = 0; + + I("Enter %s\n", __func__); + private_ts->notouch_frame = private_ts->ic_notouch_frame; + g_core_fp.fp_interface_on(); + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*msleep(20);*/ + usleep_range(10000, 11000); + if (!FlashMode) { +#ifdef HX_RST_PIN_FUNC + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1); + if (ret < 0) { + E("%s: cmd=%x bus access fail!\n", + __func__, + pic_op->adr_i2c_psw_lb[0]); + } + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], tmp_data, 1); + if (ret < 0) { + E("%s: cmd=%x bus access fail!\n", + __func__, + pic_op->adr_i2c_psw_ub[0]); + } + } +#if defined(HX_ZERO_FLASH) + hx83102e_reload_to_active(); +#endif +} + +static bool hx83102e_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_addr[DATA_LEN_4]; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + if (cnt == 0 + || (tmp_data[0] != 0xA5 + && tmp_data[0] != 0x00 + && tmp_data[0] != 0x87)) + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + pfw_op->data_fw_stop, DATA_LEN_4); + /*msleep(20);*/ + usleep_range(10000, 10001); + + /* check fw status */ + g_core_fp.fp_register_read(pic_op->addr_cs_central_state, + tmp_data, ADDR_LEN_4); + + if (tmp_data[0] != 0x05) { + I("%s: Do not need wait FW, Status = 0x%02X!\n", + __func__, tmp_data[0]); + break; + } + + g_core_fp.fp_register_read(pfw_op->addr_ctrl_fw_isr, tmp_data, + 4); + I("%s: cnt = %d, data[0] = 0x%02X!\n", __func__, + cnt, tmp_data[0]); + } while (tmp_data[0] != 0x87 && (++cnt < 35) && check_en == true); + + cnt = 0; + + do { + /** + *I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = 0x27; + ret = himax_bus_write(0x31, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /** + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = 0x95; + ret = himax_bus_write(0x32, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + /** + *Check enter_save_mode + */ + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + hx83102_register_read(tmp_addr, tmp_data, ADDR_LEN_4); + I("%s: Check enter_save_mode data[0]=%X\n", + __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /** + *Reset TCON + */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + hx83102_flash_write_burst(tmp_addr, tmp_data); + usleep_range(1000, 1001); + return true; + } + /*msleep(10);*/ + usleep_range(5000, 5001); +#if defined(HX_RST_PIN_FUNC) + himax_rst_gpio_set(private_ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + msleep(50); +#endif + + } while (cnt++ < 5); + + return false; +} + +#if defined(HX_ZERO_FLASH) +static void himax_hx83102d_reload_to_active(void) +{ + uint8_t addr[DATA_LEN_4] = {0}; + uint8_t data[DATA_LEN_4] = {0}; + uint8_t retry_cnt = 0; + + addr[3] = 0x90; + addr[2] = 0x00; + addr[1] = 0x00; + addr[0] = 0x48; + + do { + data[3] = 0x00; + data[2] = 0x00; + data[1] = 0x00; + data[0] = 0xEC; + g_core_fp.fp_register_write(addr, data, DATA_LEN_4); + usleep_range(1000, 1100); + g_core_fp.fp_register_read(addr, data, DATA_LEN_4); + I("%s: data[1]=%d, data[0]=%d, retry_cnt=%d\n", __func__, + data[1], data[0], retry_cnt); + retry_cnt++; + } while ((data[1] != 0x01 + || data[0] != 0xEC) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void himax_hx83102d_resume_ic_action(void) +{ +#if !defined(HX_RESUME_HW_RESET) + himax_hx83102d_reload_to_active(); +#endif +} + +static void himax_hx83102d_sense_on(uint8_t FlashMode) +{ + uint8_t tmp_data[DATA_LEN_4]; + int retry = 0; + int ret = 0; + + I("Enter %s\n", __func__); + private_ts->notouch_frame = private_ts->ic_notouch_frame; + g_core_fp.fp_interface_on(); + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*msleep(20);*/ + usleep_range(10000, 10001); + if (!FlashMode) { +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + do { + g_core_fp.fp_register_read( + pfw_op->addr_flag_reset_event, + tmp_data, DATA_LEN_4); + I("%s:Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x01 + || tmp_data[0] != 0x00) + && retry++ < 5); + + if (retry >= 5) { + E("%s: Fail:\n", __func__); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + I("%s:OK and Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + /* reset code*/ + tmp_data[0] = 0x00; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], + tmp_data, 1); + if (ret < 0) { + E("%s: cmd=%x bus access fail!\n", + __func__, + pic_op->adr_i2c_psw_lb[0]); + } + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], + tmp_data, 1); + if (ret < 0) { + E("%s: cmd=%x bus access fail!\n", + __func__, + pic_op->adr_i2c_psw_ub[0]); + } + } + } + himax_hx83102d_reload_to_active(); +} + +static int hx83102ab_firmware_update_0f(const struct firmware *fw_entry, + int type) +{ + uint8_t tmp_addr[4]; + int ret = 0; + + I("%s, Entering\n", __func__); + + g_core_fp.fp_register_write(pzf_op->addr_system_reset, + pzf_op->data_system_reset, 4); + + g_core_fp.fp_sense_off(false); + + /* first 32K */ + /*bin file start*/ + /*isram*/ + g_core_fp.fp_write_sram_0f((pzf_op)->data_sram_start_addr, + &fw_entry->data[0], HX_32K_SZ); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x73; + tmp_addr[0] = 0x00; + g_core_fp.fp_write_sram_0f(tmp_addr, &fw_entry->data[0x8000], + (0x200*4)); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x68; + tmp_addr[0] = 0x00; + g_core_fp.fp_write_sram_0f(tmp_addr, &fw_entry->data[0x8800], + (0x200*4)); + + /*last 16k*/ + /*config info*/ + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0x04; /*0x10007206 <= size 60,from 0x0000C180*/ + g_core_fp.fp_write_sram_0f(tmp_addr, &fw_entry->data[0xC178], (84)); + + /*FW config*/ + if ((G_POWERONOF) == 1) + g_core_fp.fp_write_sram_0f((pzf_op)->data_fw_cfg_1, + &fw_entry->data[0xBFFE], 388); + else + g_core_fp.fp_clean_sram_0f((pzf_op)->data_fw_cfg_1, + 388, 1); + /*ADC config*/ + if ((G_POWERONOF) == 1) + g_core_fp.fp_write_sram_0f((pzf_op)->data_adc_cfg_1, + &fw_entry->data[0xe000], (128 * 4)); + else + g_core_fp.fp_clean_sram_0f((pzf_op)->data_adc_cfg_1, + (128 * 4), 2); + + I("%s, END\n", __func__); + return ret; +} +#if defined(HX_0F_DEBUG) +static void hx83102ab_firmware_read_0f(const struct firmware *fw_entry, + int type) +{ + uint8_t tmp_addr[4]; + + I("%s, Entering\n", __func__); + if (type == 0) { /* first 32K */ + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_sram_start_addr, 0, HX_32K_SZ); + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x68; + tmp_addr[0] = 0x00; + g_core_fp.fp_read_sram_0f(fw_entry, tmp_addr, + 0x8000, (0x200*4)); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x73; + tmp_addr[0] = 0x00; + g_core_fp.fp_read_sram_0f(fw_entry, tmp_addr, + 0x8800, (0x200*4)); + + } else { /*last 16k*/ + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0x04; /*0x10007206 <= size 80,from 0x0000C180*/ + g_core_fp.fp_read_sram_0f(fw_entry, tmp_addr, + 0xC178, (84)); + + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_fw_cfg_1, 0xBFFE, 388); + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_adc_cfg_1, 0xE000, (128*4)); + + } + I("%s, END\n", __func__); +} +static void hx83102d_firmware_read_0f(const struct firmware *fw_entry, + int type) +{ + uint8_t tmp_data[4]; + + I("%s, Entering\n", __func__); + + switch (type) { + case 0: + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_sram_start_addr, 0, HX_40K_SZ); + break; + case 1: + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_cfg_info, 0xC000, 132); + break; + case 2: + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_fw_cfg_1, 0xC0FE, 484); + break; + case 3: + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_adc_cfg_1, 0xD000, 768); + break; + case 4: + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_adc_cfg_2, 0xD300, 1536); + break; + case 5: + g_core_fp.fp_read_sram_0f(fw_entry, + (pzf_op)->data_adc_cfg_3, 0xE000, 1536); + break; + case 6: + himax_parse_assign_cmd(hx83102d_zf_data_bor_prevent_info, + tmp_data, 4); + g_core_fp.fp_read_sram_0f(fw_entry, tmp_data, 0xC9E0, 32); + break; + case 7: + himax_parse_assign_cmd(hx83102d_zf_data_notch_info, + tmp_data, 4); + g_core_fp.fp_read_sram_0f(fw_entry, tmp_data, + 0xCA00, 128); + break; + case 8: + himax_parse_assign_cmd(hx83102d_zf_func_info_en, + tmp_data, 4); + g_core_fp.fp_read_sram_0f(fw_entry, tmp_data, 0xCB00, 12); + break; + case 9: + himax_parse_assign_cmd(hx83102d_zf_po_sub_func, + tmp_data, 4); + g_core_fp.fp_read_sram_0f(fw_entry, tmp_data, + 0xA000, HX4K); + break; + default: + break; + } + I("%s, END\n", __func__); +} +#endif + +#if defined(HX_CODE_OVERLAY) +static int hx83102d_0f_overlay(int ovl_type, int mode) +{ + int ret = 0; + uint8_t count = 0; + uint8_t count2 = 0; + const struct firmware *fwp = NULL; + uint8_t part_num = 0; + uint8_t buf[16]; + uint8_t handshaking_addr[4] = {0xFC, 0x7F, 0x00, 0x10}; + /*uint8_t mpap_addr[4] = {0xEC, 0x73, 0x00, 0x10};*/ + uint8_t ovl_idx_t; + uint8_t request; + uint8_t reply; + uint8_t sram_addr[4] = {0}; + uint32_t offset = 0; + uint32_t size = 0; + uint8_t send_data[4] = {0}; + uint8_t recv_data[4] = {0}; + + ret = request_firmware(&fwp, BOOT_UPGRADE_FWNAME, + private_ts->dev); + if (ret < 0) { + E("%s: request firmware FAIL!!!\n", __func__); + return ret; + } + + /*1. get number of partition*/ + part_num = fwp->data[HX64K + 12]; + if (part_num <= 1) { + E("%s, size of cfg part failed! part_num = %d\n", + __func__, part_num); + return LENGTH_FAIL; + } + + I("%s: overlay section %d\n", __func__, ovl_type-1); + if (ovl_type == 2) { + request = ovl_gesture_request; + reply = ovl_gesture_reply; + } else if (ovl_type == 3) { + request = ovl_border_request; + reply = ovl_border_reply; + } else { + E("%s: error overlay type %d\n", __func__, ovl_type); + return HX_INIT_FAIL; + } + ovl_idx_t = *((ovl_idx) + ovl_type - 1); + memcpy(buf, &fwp->data[ovl_idx_t * 0x10 + HX64K], 16); + memcpy(sram_addr, buf, 4); + offset = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]; + size = buf[7]<<24 | buf[6]<<16 | buf[5]<<8 | buf[4]; + +/* + * if (ovl_type == 1) { + * if (mode == 0) { + * //border overlay when finish self_test + * send_data[3] = 0x00; + * send_data[2] = 0x00; + * send_data[1] = 0x00; + * send_data[0] = 0x00; + * offset = zf_info_arr[2].fw_addr; + * size = zf_info_arr[2].write_size; + * I("%s: self test overlay section 2\n", __func__); + * } else if (mode == 1) { + * //sorting overlay when call self_test + * send_data[3] = 0x00; + * send_data[2] = 0x10; + * send_data[1] = 0x73; + * send_data[0] = 0x80; + * offset = zf_info_arr[0].fw_addr; + * size = zf_info_arr[0].write_size; + * I("%s: self test overlay section 0\n", __func__); + * } + * } + */ + +/* + * if (ovl_type == 1) { + * + * g_core_fp.fp_sense_off(false); + * + * //g_core_fp.fp_register_write(mpap_addr, DATA_LEN_4, + send_data, 0); + * count = 0; + * do { + * g_core_fp.fp_register_write(mpap_addr, DATA_LEN_4, + send_data, 0); + * g_core_fp.fp_register_read(mpap_addr, DATA_LEN_4, + recv_data, 0); + * } while ((recv_data[0] != send_data[0] + * || recv_data[1] != send_data[1] + * || recv_data[2] != send_data[2] + * || recv_data[3] != send_data[3]) + * && count++ < 10); + * + * I("%s: set mpap pw %d times\n", __func__, count); + * + * //g_core_fp.fp_write_sram_0f(fwp, sram_addr, offset, size); + * if (g_core_fp.fp_write_sram_0f_crc(fwp, sram_addr, + offset, size) != 0) + * E("%s, Overlay HW CRC FAIL\n", __func__); + * + * g_core_fp.fp_reload_disable(0); + * + * g_core_fp.fp_sense_on(0x00); + * + * } else { + */ + + count = 0; + do { + g_core_fp.fp_register_read(handshaking_addr, recv_data, + DATA_LEN_4); + } while (recv_data[0] != request && count++ < 10); + + if (count < 10) { + /*g_core_fp.fp_write_sram_0f(fwp, sram_addr, offset, size);*/ + if (g_core_fp.fp_write_sram_0f_crc(sram_addr, + &fwp->data[offset], size) != 0) + E("%s, Overlay HW CRC FAIL\n", __func__); + + send_data[3] = 0x00; + send_data[2] = 0x00; + send_data[1] = 0x00; + send_data[0] = reply; + + count2 = 0; + do { + g_core_fp.fp_register_write(handshaking_addr, + send_data, DATA_LEN_4); + usleep_range(1000, 1100); + g_core_fp.fp_register_read(handshaking_addr, recv_data, + DATA_LEN_4); + } while (recv_data[0] != reply && count2++ < 10); + + if (ovl_type == 3) { +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } + } + + I("%s: overlay request %d times; reply %d times\n", __func__, + count, count2); + + release_firmware(fwp); + + /* rescue mechanism */ + if (count >= 10) + g_core_fp.fp_0f_op_file_dirly(BOOT_UPGRADE_FWNAME); + + return 0; +} +#endif +#endif + +static bool hx83102e_read_event_stack(uint8_t *buf, uint8_t length) +{ +#if defined(KERNEL_VER_ABOVE_5_10) + struct timespec64 t_start, t_end, t_delta; +#else + struct timespec t_start, t_end, t_delta; +#endif + int len = length; + int i2c_speed = 0; + + if (private_ts->debug_log_level & BIT(2)) +#if defined(KERNEL_VER_ABOVE_5_10) + ktime_get_ts64(&t_start); +#else + getnstimeofday(&t_start); +#endif + + himax_bus_read(pfw_op->addr_event_addr[0], buf, length); + + if (private_ts->debug_log_level & BIT(2)) { +#if defined(KERNEL_VER_ABOVE_5_10) + ktime_get_ts64(&t_end); +#else + getnstimeofday(&t_end); +#endif + t_delta.tv_nsec = (t_end.tv_sec * 1000000000 + t_end.tv_nsec) + - (t_start.tv_sec + * 1000000000 + + t_start.tv_nsec); /*ns*/ + + i2c_speed = (len * 9 * 1000000 + / (int)t_delta.tv_nsec) * 13 / 10; + private_ts->bus_speed = (int)i2c_speed; + } + return 1; +} + +static void himax_hx83102ab_reg_re_init(uint8_t ic_name) +{ + I("%s:Entering!\n", __func__); + private_ts->ic_notouch_frame = hx83102ab_notouch_frame; + himax_parse_assign_cmd(hx83102ab_fw_addr_sorting_mode_en, + pfw_op->addr_sorting_mode_en, + sizeof(pfw_op->addr_sorting_mode_en)); + himax_parse_assign_cmd(hx83102ab_fw_addr_selftest_addr_en, + pfw_op->addr_selftest_addr_en, + sizeof(pfw_op->addr_selftest_addr_en)); +#if defined(HX_ZERO_FLASH) + himax_parse_assign_cmd(hx83102ab_data_adc_cfg_1, + (pzf_op)->data_adc_cfg_1, + sizeof((pzf_op)->data_adc_cfg_1)); +#endif + + if (ic_name == 0x2a) { + himax_parse_assign_cmd(hx83102a_data_df_rx, + (pdriver_op)->data_df_rx, + sizeof((pdriver_op)->data_df_rx)); + himax_parse_assign_cmd(hx83102a_data_df_tx, + (pdriver_op)->data_df_tx, + sizeof((pdriver_op)->data_df_tx)); + } +} + +static void himax_hx83102ab_func_re_init(void) +{ + I("%s:Entering!\n", __func__); + g_core_fp.fp_chip_init = hx83102_chip_init; + g_core_fp.fp_sense_off = hx83102ab_sense_off; + g_core_fp.fp_set_SMWP_enable = hx83102ab_set_SMWP_enable; + g_core_fp.fp_set_HSEN_enable = hx83102ab_set_HSEN_enable; + g_core_fp.fp_usb_detect_set = hx83102ab_usb_detect_set; + g_core_fp.fp_read_DD_status = hx83102ab_read_DD_status; + g_core_fp.fp_power_on_init = hx83102ab_power_on_init; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k = + hx83102ab_fts_ctpm_fw_upgrade_with_sys_fs_64k; +#if defined(HX_EXCP_RECOVERY) + g_core_fp.fp_excp_ic_reset = hx83102ab_excp_ic_reset; +#endif +#if defined(HX_ZERO_FLASH) + g_core_fp.fp_firmware_update_0f = hx83102ab_firmware_update_0f; +#if defined(HX_0F_DEBUG) + g_core_fp.fp_firmware_read_0f = hx83102ab_firmware_read_0f; +#endif +#endif + +} + +static void himax_hx83102d_reg_re_init(void) +{ + I("%s:Entering!\n", __func__); + private_ts->ic_notouch_frame = hx83102d_notouch_frame; + himax_parse_assign_cmd(hx83102d_fw_addr_raw_out_sel, + pfw_op->addr_raw_out_sel, + sizeof(pfw_op->addr_raw_out_sel)); +#if defined(HX_ZERO_FLASH) + himax_parse_assign_cmd(hx83102d_zf_data_sram_start_addr, + (pzf_op)->data_sram_start_addr, + sizeof((pzf_op)->data_sram_start_addr)); + himax_parse_assign_cmd(hx83102d_zf_data_adc_cfg_1, + (pzf_op)->data_adc_cfg_1, + sizeof((pzf_op)->data_adc_cfg_1)); + himax_parse_assign_cmd(hx83102d_zf_data_adc_cfg_2, + (pzf_op)->data_adc_cfg_2, + sizeof((pzf_op)->data_adc_cfg_2)); + himax_parse_assign_cmd(hx83102d_zf_data_adc_cfg_3, + (pzf_op)->data_adc_cfg_3, + sizeof((pzf_op)->data_adc_cfg_3)); +#endif + himax_parse_assign_cmd(hx83102d_adr_osc_en, + pic_op->adr_osc_en, + sizeof(pic_op->adr_osc_en)); + himax_parse_assign_cmd(hx83102d_adr_osc_pw, + pic_op->adr_osc_pw, + sizeof(pic_op->adr_osc_pw)); +} + +static void himax_hx83102d_func_re_init(void) +{ + I("%s:Entering!\n", __func__); + g_core_fp.fp_chip_init = hx83102_chip_init; + g_core_fp.fp_sense_off = hx83102d_sense_off; +#if defined(HX_ZERO_FLASH) + /*g_core_fp.fp_firmware_update_0f = hx83102d_firmware_update_0f;*/ + g_core_fp.fp_resume_ic_action = himax_hx83102d_resume_ic_action; + g_core_fp.fp_sense_on = himax_hx83102d_sense_on; + g_core_fp.fp_0f_reload_to_active = himax_hx83102d_reload_to_active; +#if defined(HX_0F_DEBUG) + g_core_fp.fp_firmware_read_0f = hx83102d_firmware_read_0f; +#endif +#if defined(HX_CODE_OVERLAY) + g_core_fp.fp_0f_overlay = hx83102d_0f_overlay; +#endif +#if defined(HX_EXCP_RECOVERY) + g_core_fp.fp_0f_excp_check = hx83102d_0f_excp_check; +#endif +#endif +} + +static void himax_hx83102e_reg_re_init(void) +{ + I("%s:Entering!\n", __func__); + private_ts->ic_notouch_frame = hx83102e_notouch_frame; + himax_parse_assign_cmd(hx83102e_fw_addr_raw_out_sel, + pfw_op->addr_raw_out_sel, + sizeof(pfw_op->addr_raw_out_sel)); + himax_parse_assign_cmd(hx83102e_data_df_rx, + (pdriver_op)->data_df_rx, + sizeof((pdriver_op)->data_df_rx)); + himax_parse_assign_cmd(hx83102e_data_df_tx, + (pdriver_op)->data_df_tx, + sizeof((pdriver_op)->data_df_tx)); + himax_parse_assign_cmd(hx83102e_ic_adr_tcon_rst, + pic_op->addr_tcon_on_rst, + sizeof(pic_op->addr_tcon_on_rst)); +} + +static void himax_hx83102e_func_re_init(void) +{ + I("%s:Entering!\n", __func__); + + g_core_fp.fp_chip_init = hx83102e_chip_init; + g_core_fp.fp_sense_on = hx83102e_sense_on; + g_core_fp.fp_sense_off = hx83102e_sense_off; + g_core_fp.fp_read_event_stack = hx83102e_read_event_stack; + +#if defined(HX_ZERO_FLASH) + g_core_fp.fp_resume_ic_action = hx83102e_resume_ic_action; + g_core_fp.fp_0f_reload_to_active = hx83102e_reload_to_active; +#endif +} + + +static bool hx83102_chip_detect(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_addr[DATA_LEN_4]; + bool ret_data = false; + int ret = 0; + int i = 0; + + +#if defined(HX_RST_PIN_FUNC) + hx83102_pin_reset(); +#endif + + ret = himax_bus_read(0x13, tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } +#if defined(HX_ZERO_FLASH) + if (hx83102_sense_off(false) == false) { +#else + if (hx83102_sense_off(true) == false) { +#endif + ret_data = false; + E("%s:hx83102_sense_off Fail:\n", __func__); + return ret_data; + } + + for (i = 0; i < 5; i++) { + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xD0; + ret = hx83102_register_read(tmp_addr, tmp_data, DATA_LEN_4); + if (ret != 0) { + ret_data = false; + E("%s:hx83102_register_read Fail:\n", __func__); + return ret_data; + } + I("%s:Read driver IC ID = %X,%X,%X\n", __func__, tmp_data[3], + tmp_data[2], tmp_data[1]); /*83,10,2X*/ + + if ((tmp_data[3] == 0x83) + && (tmp_data[2] == 0x10) + && ((tmp_data[1] == 0x2a) + || (tmp_data[1] == 0x2b) + || (tmp_data[1] == 0x2d) + || (tmp_data[1] == 0x2e))) { + if (tmp_data[1] == 0x2a) { + strlcpy(private_ts->chip_name, + HX_83102A_SERIES_PWON, 30); + (ic_data)->ic_adc_num = + hx83102a_data_adc_num; + I("%s:detect IC HX83102A successfully\n", + __func__); + } else if (tmp_data[1] == 0x2b) { + strlcpy(private_ts->chip_name, + HX_83102B_SERIES_PWON, 30); + (ic_data)->ic_adc_num = + hx83102b_data_adc_num; + I("%s:detect IC HX83102B successfully\n", + __func__); + } else if (tmp_data[1] == 0x2d) { + strlcpy(private_ts->chip_name, + HX_83102D_SERIES_PWON, 30); + (ic_data)->ic_adc_num = + hx83102d_data_adc_num; + I("%s:detect IC HX83102D successfully\n", + __func__); + } else { + strlcpy(private_ts->chip_name, + HX_83102E_SERIES_PWON, 30); + (ic_data)->ic_adc_num = + hx83102e_data_adc_num; + I("%s:detect IC HX83102E successfully\n", + __func__); + } + + ret = himax_mcu_in_cmd_struct_init(); + if (ret < 0) { + ret_data = false; + E("%s:cmd_struct_init Fail:\n", __func__); + return ret_data; + } + + himax_mcu_in_cmd_init(); + if ((tmp_data[1] == 0x2a) || (tmp_data[1] == 0x2b)) { + himax_hx83102ab_reg_re_init(tmp_data[1]); + himax_hx83102ab_func_re_init(); + } else if (tmp_data[1] == 0x2d) { + himax_hx83102d_reg_re_init(); + himax_hx83102d_func_re_init(); + } else {/* 0x2e */ + himax_hx83102e_reg_re_init(); + himax_hx83102e_func_re_init(); + } + ret_data = true; + break; + } + + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + E("Could NOT find Himax Chipset\n"); + E("Please check 1.VCCD,VCCA,VSP,VSN\n"); + E("2. LCM_RST,TP_RST\n"); + E("3. Power On Sequence\n"); + + } + + return ret_data; +} + +bool _hx83102_init(void) +{ + bool ret = false; + + I("%s\n", __func__); + ret = hx83102_chip_detect(); + return ret; +} diff --git a/himax_ic_HX83102.h b/himax_ic_HX83102.h new file mode 100644 index 0000000..fca0426 --- /dev/null +++ b/himax_ic_HX83102.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for HX83102 chipset + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_platform.h" +#include "himax_common.h" +#include "himax_ic_core.h" +#include <linux/slab.h> + +#define hx83102ab_fw_addr_sorting_mode_en 0x100007FC +#define hx83102ab_fw_addr_selftest_addr_en 0x100007F8 +#define hx83102ab_data_adc_cfg_1 0x10007B00 +#define hx83102a_data_df_rx 48 +#define hx83102a_data_df_tx 24 +#define hx83102a_data_adc_num 100 +#define hx83102b_data_adc_num 64 +#define hx83102ab_notouch_frame 0 + +#define hx83102d_fw_addr_raw_out_sel 0x800204f4 +#define hx83102d_zf_data_adc_cfg_1 0x10007B00 +#define hx83102d_zf_data_adc_cfg_2 0x10006A00 +#define hx83102d_zf_data_adc_cfg_3 0x10007500 +#define hx83102d_zf_data_bor_prevent_info 0x10007268 +#define hx83102d_zf_data_notch_info 0x10007300 +#define hx83102d_zf_func_info_en 0x10007FD0 +#define hx83102d_zf_po_sub_func 0x10005A00 +#define hx83102d_zf_data_sram_start_addr 0x20000000 +#define hx83102d_adr_osc_en 0x9000009C +#define hx83102d_adr_osc_pw 0x90000280 +#define hx83102d_data_adc_num 48 +#define hx83102d_notouch_frame 0 + +#define hx83102e_fw_addr_raw_out_sel 0x100072EC +#define hx83102e_ic_adr_tcon_rst 0x80020004 +#define hx83102e_data_df_rx 48 +#define hx83102e_data_df_tx 30 +#define hx83102e_data_adc_num 400 /* 200x2 */ +#define hx83102e_notouch_frame 0 + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif diff --git a/himax_ic_core.h b/himax_ic_core.h new file mode 100644 index 0000000..8e84aff --- /dev/null +++ b/himax_ic_core.h @@ -0,0 +1,1020 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for ic core functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HIMAX_IC_CORE_H__ +#define __HIMAX_IC_CORE_H__ + +#include "himax_platform.h" +#include "himax_common.h" +#include <linux/slab.h> + +#define DATA_LEN_8 8 +#define DATA_LEN_4 4 +#define ADDR_LEN_4 4 +#define FLASH_RW_MAX_LEN 256 +#define FLASH_WRITE_BURST_SZ 8 +#define PROGRAM_SZ 48 +#define MAX_I2C_TRANS_SZ 128 +#define HIMAX_REG_RETRY_TIMES 5 +#define FW_BIN_16K_SZ 0x4000 +#define HIMAX_TOUCH_DATA_SIZE 128 +#define MASK_BIT_0 0x01 +#define MASK_BIT_1 0x02 +#define MASK_BIT_2 0x04 + +#define FW_SECTOR_PER_BLOCK 8 +#define FW_PAGE_PER_SECTOR 64 +#define FW_PAGE_SZ 128 +#define HX256B 0x100 +#define HX1K 0x400 +#define HX4K 0x1000 +#define HX_32K_SZ 0x8000 +#define HX_40K_SZ 0xA000 +#define HX_48K_SZ 0xC000 +#define HX64K 0x10000 +#define HX124K 0x1f000 +#define HX4000K 0x1000000 + +#define HX_NORMAL_MODE 1 +#define HX_SORTING_MODE 2 +#define HX_CHANGE_MODE_FAIL (-1) +#define HX_RW_REG_FAIL (-1) +#define HX_DRIVER_MAX_IC_NUM 12 + +#if defined(__HIMAX_HX852xG_MOD__) +#define HX_MOD_KSYM_HX852xG HX_MOD_KSYM_HX852xG +#endif + +#if defined(__HIMAX_HX852xH_MOD__) +#define HX_MOD_KSYM_HX852xH HX_MOD_KSYM_HX852xH +#endif + +#if defined(__HIMAX_HX852xJ_MOD__) +#define HX_MOD_KSYM_HX852xJ HX_MOD_KSYM_HX852xJ +#endif + +#if defined(__HIMAX_HX83102_MOD__) +#define HX_MOD_KSYM_HX83102 HX_MOD_KSYM_HX83102 +#endif + +#if defined(__HIMAX_HX83121_MOD__) +#define HX_MOD_KSYM_HX83121 HX_MOD_KSYM_HX83121 +#endif + +#if defined(__HIMAX_HX83103_MOD__) +#define HX_MOD_KSYM_HX83103 HX_MOD_KSYM_HX83103 +#endif + +#if defined(__HIMAX_HX83106_MOD__) +#define HX_MOD_KSYM_HX83106 HX_MOD_KSYM_HX83106 +#endif + +#if defined(__HIMAX_HX83108_MOD__) +#define HX_MOD_KSYM_HX83108 HX_MOD_KSYM_HX83108 +#endif +#if defined(__HIMAX_HX83111_MOD__) +#define HX_MOD_KSYM_HX83111 HX_MOD_KSYM_HX83111 +#endif + +#if defined(__HIMAX_HX83112_MOD__) +#define HX_MOD_KSYM_HX83112 HX_MOD_KSYM_HX83112 +#endif + +#if defined(__HIMAX_HX83113_MOD__) +#define HX_MOD_KSYM_HX83113 HX_MOD_KSYM_HX83113 +#endif + +#if defined(__HIMAX_HX83191_MOD__) +#define HX_MOD_KSYM_HX83191 HX_MOD_KSYM_HX83191 +#endif + +#if defined(__HIMAX_HX83192_MOD__) +#define HX_MOD_KSYM_HX83192 HX_MOD_KSYM_HX83192 +#endif + +#if defined(__HIMAX_HX83121_MOD__) +#define HX_MOD_KSYM_HX83121 HX_MOD_KSYM_HX83121 +#endif + +/* CORE_INIT */ +/* CORE_IC */ +/* CORE_FW */ +/* CORE_FLASH */ +/* CORE_SRAM */ +/* CORE_DRIVER */ + +#define HX_0F_DEBUG + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) + +#if defined(HX_TP_PROC_GUEST_INFO) +extern struct hx_guest_info *g_guest_info_data; +#endif + +void himax_mcu_in_cmd_struct_free(void); + +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_ONCELL) +void himax_mcu_on_cmd_struct_free(void); +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +extern int g_i_FW_VER; +extern int g_i_CFG_VER; +extern int g_i_CID_MAJ; +extern int g_i_CID_MIN; +extern const struct firmware *hxfw; +#if defined(HX_ZERO_FLASH) +extern int g_f_0f_updat; +#endif +#endif + +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +extern unsigned long CID_VER_MAJ_FLASH_ADDR; +extern unsigned long CID_VER_MIN_FLASH_ADDR; +extern uint32_t CFG_TABLE_FLASH_ADDR; +extern uint32_t CFG_TABLE_FLASH_ADDR_T; + +extern unsigned char IC_CHECKSUM; +#if defined(HX_EXCP_RECOVERY) +extern int g_zero_event_count; +#endif + +#if defined(HX_RST_PIN_FUNC) +extern u8 HX_HW_RESET_ACTIVATE; +void himax_rst_gpio_set(int pinnum, uint8_t value); +#endif + +#if defined(HX_USB_DETECT_GLOBAL) +void himax_cable_detect_func(bool force_renew); +#endif + +int himax_report_data_init(void); +extern int i2c_error_count; + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif + +/* CORE_INIT */ +int himax_mcu_in_cmd_struct_init(void); +void himax_mcu_in_cmd_init(void); + +int himax_mcu_on_cmd_struct_init(void); +void himax_mcu_on_cmd_init(void); +void himax_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len); + +extern void (*himax_mcu_cmd_struct_free)(void); +/* CORE_INIT */ + +enum HX_FLASH_SPEED_ENUM { + HX_FLASH_SPEED_25M = 0, + HX_FLASH_SPEED_12p5M = 0x01, + HX_FLASH_SPEED_8p3M = 0x02, + HX_FLASH_SPEED_6p25M = 0x03, +}; + +#if defined(HX_TP_PROC_GUEST_INFO) +#define HX_GUEST_INFO_FLASH_SADDR 0x20000 +#define HX_GUEST_INFO_SIZE 10 +#define HX_GUEST_INFO_LEN_SIZE 4 +#define HX_GUEST_INFO_ID_SIZE 4 + +struct hx_guest_info { + int g_guest_info_ongoing; /* 0 stop, 1 ongoing */ + uint8_t g_guest_str[10][128]; + uint8_t g_guest_str_in_format[10][128]; + uint8_t g_guest_data_type[10]; + int g_guest_data_len[10]; + int g_guest_info_type; +}; +#endif + +/* CORE_IC */ + #define ic_adr_ahb_addr_byte_0 0x00 + #define ic_adr_ahb_rdata_byte_0 0x08 + #define ic_adr_ahb_access_direction 0x0c + #define ic_adr_conti 0x13 + #define ic_adr_incr4 0x0D + #define ic_adr_i2c_psw_lb 0x31 + #define ic_adr_i2c_psw_ub 0x32 + #define ic_cmd_ahb_access_direction_read 0x00 + #define ic_cmd_conti 0x31 + #define ic_cmd_incr4 0x10 + #define ic_cmd_i2c_psw_lb 0x27 + #define ic_cmd_i2c_psw_ub 0x95 + #define ic_adr_tcon_on_rst 0x80020020 + #define ic_addr_adc_on_rst 0x80020094 + #define ic_adr_psl 0x900000A0 + #define ic_adr_cs_central_state 0x900000A8 + #define ic_cmd_rst 0x00000000 + #define ic_adr_osc_en 0x900880A8 + #define ic_adr_osc_pw 0x900880E0 + + #define on_ic_adr_ahb_addr_byte_0 0x00 + #define on_ic_adr_ahb_rdata_byte_0 0x08 + #define on_ic_adr_ahb_access_direction 0x0c + #define on_ic_adr_conti 0x13 + #define on_ic_adr_incr4 0x0D + #define on_ic_cmd_ahb_access_direction_read 0x00 + #define on_ic_cmd_conti 0x31 + #define on_ic_cmd_incr4 0x10 + #define on_ic_adr_mcu_ctrl 0x82 + #define on_ic_cmd_mcu_on 0x25 + #define on_ic_cmd_mcu_off 0xDA + #define on_ic_adr_sleep_ctrl 0x99 + #define on_ic_cmd_sleep_in 0x80 + #define on_ic_adr_tcon_ctrl 0x80020000 + #define on_ic_cmd_tcon_on 0x00000000 + #define on_ic_adr_wdg_ctrl 0x9000800C + #define on_ic_cmd_wdg_psw 0x0000AC53 + #define on_ic_adr_wdg_cnt_ctrl 0x90008010 + #define on_ic_cmd_wdg_cnt_clr 0x000035CA +/* CORE_IC */ + +/* CORE_FW */ + #define fw_addr_system_reset 0x90000018 + #define fw_addr_ctrl_fw 0x9000005c + #define fw_addr_flag_reset_event 0x900000e4 + #define fw_addr_hsen_enable 0x10007F14 + #define fw_addr_smwp_enable 0x10007F10 + #define fw_usb_detect_addr 0x10007F38 + #define fw_addr_program_reload_from 0x00000000 + #define fw_addr_program_reload_to 0x08000000 + #define fw_addr_program_reload_page_write 0x0000fb00 + #define fw_addr_raw_out_sel 0x800204b4 + #define fw_addr_reload_status 0x80050000 + #define fw_addr_reload_crc32_result 0x80050018 + #define fw_addr_reload_addr_from 0x80050020 + #define fw_addr_reload_addr_cmd_beat 0x80050028 + #define fw_data_system_reset 0x00000055 + #define fw_data_safe_mode_release_pw_active 0x00000053 + #define fw_data_safe_mode_release_pw_reset 0x00000000 + #define fw_data_clear 0x00000000 + #define fw_data_fw_stop 0x000000A5 + #define fw_data_program_reload_start 0x0A3C3000 + #define fw_data_program_reload_compare 0x04663000 + #define fw_data_program_reload_break 0x15E75678 + #define fw_addr_selftest_addr_en 0x10007F18 + #define fw_addr_selftest_result_addr 0x10007f24 + #define fw_data_selftest_request 0x00006AA6 + #define fw_addr_criteria_addr 0x10007f1c + #define fw_data_criteria_aa_top 0x64 + #define fw_data_criteria_aa_bot 0x00 + #define fw_data_criteria_key_top 0x64 + #define fw_data_criteria_key_bot 0x00 + #define fw_data_criteria_avg_top 0x64 + #define fw_data_criteria_avg_bot 0x00 + #define fw_addr_set_frame_addr 0x10007294 + #define fw_data_set_frame 0x0000000A + #define fw_data_selftest_ack_hb 0xa6 + #define fw_data_selftest_ack_lb 0x6a + #define fw_data_selftest_pass 0xaa + #define fw_data_normal_cmd 0x00 + #define fw_data_normal_status 0x99 + #define fw_data_sorting_cmd 0xaa + #define fw_data_sorting_status 0xcc + #define fw_data_idle_dis_pwd 0x17 + #define fw_data_idle_en_pwd 0x1f + #define fw_addr_sorting_mode_en 0x10007f04 + #define fw_addr_fw_mode_status 0x10007088 + #define fw_addr_icid_addr 0x900000d0 + #define fw_addr_fw_ver_addr 0x10007004 + #define fw_addr_fw_cfg_addr 0x10007084 + #define fw_addr_fw_vendor_addr 0x10007000 + #define fw_addr_cus_info 0x10007008 + #define fw_addr_proj_info 0x10007014 + #define fw_addr_fw_state_addr 0x900000f8 + #define fw_addr_fw_dbg_msg_addr 0x10007f40 + #define fw_addr_chk_fw_status 0x900000a8 + #define fw_addr_chk_dd_status 0x900000E8 + #define fw_addr_dd_handshak_addr 0x900000fc + #define fw_addr_dd_data_addr 0x10007f80 + #define fw_addr_clr_fw_record_dd_sts 0x10007FCC + #define fw_addr_ap_notify_fw_sus 0x10007FD0 + #define fw_data_ap_notify_fw_sus_en 0xA55AA55A + #define fw_data_ap_notify_fw_sus_dis 0x00000000 + #define fw_data_dd_request 0xaa + #define fw_data_dd_ack 0xbb + #define fw_data_rawdata_ready_hb 0xa3 + #define fw_data_rawdata_ready_lb 0x3a + #define fw_addr_ahb_addr 0x11 + #define fw_data_ahb_dis 0x00 + #define fw_data_ahb_en 0x01 + #define fw_addr_event_addr 0x30 + #define fw_func_handshaking_pwd 0xA55AA55A + #define fw_func_handshaking_end 0x77887788 + #define fw_addr_ulpm_33 0x33 + #define fw_addr_ulpm_34 0x34 + #define fw_data_ulpm_11 0x11 + #define fw_data_ulpm_22 0x22 + #define fw_data_ulpm_33 0x33 + #define fw_data_ulpm_aa 0xAA + #define fw_addr_ctrl_mpap_ovl 0x100073EC + #define fw_data_ctrl_mpap_ovl_on 0x107380 + + #define on_fw_addr_smwp_enable 0xA2 + #define on_fw_usb_detect_addr 0xA4 + #define on_fw_addr_program_reload_from 0x00000000 + #define on_fw_addr_raw_out_sel 0x98 + #define on_fw_addr_flash_checksum 0x80000044 + #define on_fw_data_flash_checksum 0x00000491 + #define on_fw_addr_crc_value 0x80000050 + #define on_fw_data_safe_mode_release_pw_active 0x00000053 + #define on_fw_data_safe_mode_release_pw_reset 0x00000000 + #define on_fw_addr_criteria_addr 0x9A + #define on_fw_data_selftest_pass 0xaa + #define on_fw_addr_reK_crtl 0x8000000C + #define on_fw_data_reK_en 0x02 + #define on_fw_data_reK_dis 0xFD + #define on_fw_data_rst_init 0xF0 + #define on_fw_data_dc_set 0x02 + #define on_fw_data_bank_set 0x03 + #define on_fw_addr_selftest_addr_en 0x98 + #define on_fw_addr_selftest_result_addr 0x9B + #define on_fw_data_selftest_request 0x06 + #define on_fw_data_thx_avg_mul_dc_lsb 0x22 + #define on_fw_data_thx_avg_mul_dc_msb 0x0B + #define on_fw_data_thx_mul_dc_up_low_bud 0x64 + #define on_fw_data_thx_avg_slf_dc_lsb 0x14 + #define on_fw_data_thx_avg_slf_dc_msb 0x05 + #define on_fw_data_thx_slf_dc_up_low_bud 0x64 + #define on_fw_data_thx_slf_bank_up 0x40 + #define on_fw_data_thx_slf_bank_low 0x00 + #define on_fw_data_idle_dis_pwd 0x40 + #define on_fw_data_idle_en_pwd 0x00 + #define on_fw_addr_fw_mode_status 0x99 + #define on_fw_addr_icid_addr 0x900000d0 + #define on_fw_addr_fw_ver_start 0x90 + #define on_fw_data_rawdata_ready_hb 0xa3 + #define on_fw_data_rawdata_ready_lb 0x3a + #define on_fw_addr_ahb_addr 0x11 + #define on_fw_data_ahb_dis 0x00 + #define on_fw_data_ahb_en 0x01 + #define on_fw_addr_event_addr 0x30 +/* CORE_FW */ + +/* CORE_FLASH */ + #define flash_addr_ctrl_base 0x80000000 + #define flash_addr_spi200_trans_fmt (flash_addr_ctrl_base + 0x10) + #define flash_addr_spi200_trans_ctrl (flash_addr_ctrl_base + 0x20) + #define flash_addr_spi200_cmd (flash_addr_ctrl_base + 0x24) + #define flash_addr_spi200_addr (flash_addr_ctrl_base + 0x28) + #define flash_addr_spi200_data (flash_addr_ctrl_base + 0x2c) + #define flash_addr_spi200_fifo_rst (flash_addr_ctrl_base + 0x30) + #define flash_addr_spi200_rst_status (flash_addr_ctrl_base + 0x34) + #define flash_addr_spi200_flash_speed (flash_addr_ctrl_base + 0x40) + #define flash_addr_spi200_bt_num (flash_addr_ctrl_base + 0xe8) + #define flash_data_spi200_txfifo_rst 0x00000004 + #define flash_data_spi200_rxfifo_rst 0x00000002 + #define flash_data_spi200_trans_fmt 0x00020780 + #define flash_data_spi200_trans_ctrl_1 0x42000003 + #define flash_data_spi200_trans_ctrl_2 0x47000000 + #define flash_data_spi200_trans_ctrl_3 0x67000000 + #define flash_data_spi200_trans_ctrl_4 0x610ff000 + #define flash_data_spi200_trans_ctrl_5 0x694002ff + #define flash_data_spi200_trans_ctrl_6 0x42000000 + #define flash_data_spi200_trans_ctrl_7 0x6940020f + #define flash_data_spi200_cmd_1 0x00000005 + #define flash_data_spi200_cmd_2 0x00000006 + #define flash_data_spi200_cmd_3 0x000000C7 + #define flash_data_spi200_cmd_4 0x000000D8 + #define flash_data_spi200_cmd_5 0x00000020 + #define flash_data_spi200_cmd_6 0x00000002 + #define flash_data_spi200_cmd_7 0x0000003b + #define flash_data_spi200_cmd_8 0x00000003 + #define flash_data_spi200_addr 0x00000000 + #define flash_clk_setup_addr 0x80000040 + + #define on_flash_addr_ctrl_base 0x80000000 + #define on_flash_addr_ctrl_auto 0x80000004 + #define on_flash_data_main_erase 0x0000A50D + #define on_flash_data_auto 0xA5 + #define on_flash_data_main_read 0x03 + #define on_flash_data_page_write 0x05 + #define on_flash_data_spp_read 0x10 + #define on_flash_data_sfr_read 0x14 + #define on_flash_addr_ahb_ctrl 0x80000020 + #define on_flash_data_ahb_squit 0x00000001 + #define on_flash_addr_unlock_0 0x00000000 + #define on_flash_addr_unlock_4 0x00000004 + #define on_flash_addr_unlock_8 0x00000008 + #define on_flash_addr_unlock_c 0x0000000C + #define on_flash_data_cmd0 0x28178EA0 + #define on_flash_data_cmd1 0x0A0E03FF + #define on_flash_data_cmd2 0x8C203D0C + #define on_flash_data_cmd3 0x00300263 + #define on_flash_data_lock 0x03400000 +/* CORE_FLASH */ + +/* CORE_SRAM */ + #define sram_adr_mkey 0x100070E8 + #define sram_adr_rawdata_addr 0x10000000 + #define sram_adr_rawdata_end 0x00000000 + #define sram_passwrd_start 0x5AA5 + #define sram_passwrd_end 0xA55A + + #define on_sram_adr_rawdata_addr 0x10000400 + #define on_sram_adr_rawdata_end 0x00000000 + #define on_sram_cmd_conti 0x44332211 + #define on_sram_cmd_fin 0x00000000 + #define on_sram_passwrd_start 0x5AA5 + #define on_sram_passwrd_end 0xA55A +/* CORE_SRAM */ + +/* CORE_DRIVER */ + #define driver_addr_fw_define_flash_reload 0x10007f00 + #define driver_addr_fw_define_2nd_flash_reload 0x100072c0 + #define driver_data_fw_define_flash_reload_dis 0x0000a55a + #define driver_data_fw_define_flash_reload_en 0x00000000 + #define driver_addr_fw_define_int_is_edge 0x10007088 + #define driver_addr_fw_define_rxnum_txnum 0x100070f4 + #define driver_data_fw_define_rxnum_txnum_maxpt_sorting 0x00000008 + #define driver_data_fw_define_rxnum_txnum_maxpt_normal 0x00000014 + #define driver_addr_fw_define_maxpt_xyrvs 0x100070f8 + #define driver_addr_fw_define_x_y_res 0x100070fc + #define driver_data_df_rx 36 + #define driver_data_df_tx 18 + #define driver_data_df_pt 10 + #define on_driver_addr_fw_define_int_is_edge 0x10007088 + #define on_driver_data_df_rx 28 + #define on_driver_data_df_tx 14 + #define on_driver_data_df_pt 10 +#if !defined(HX_NEW_EVENT_STACK_FORMAT) + #define on_driver_addr_fw_rx_tx_maxpt_num 0x0800001C + #define on_driver_addr_fw_xy_rev_int_edge 0x0800000C + #define on_driver_addr_fw_define_x_y_res 0x08000030 +#else + #define on_driver_addr_fw_rx_tx_maxpt_num 0x08000004 + #define on_driver_addr_fw_maxpt_bt_num 0x0800000C + #define on_driver_addr_fw_xy_rev_int_edge 0x08000110 + #define on_driver_addr_fw_define_x_y_res 0x08000010 +#endif + +/* CORE_DRIVER */ + +#if defined(HX_ZERO_FLASH) + #define zf_data_dis_flash_reload 0x00009AA9 + #define zf_addr_system_reset 0x90000018 + #define zf_data_system_reset 0x00000055 + #define zf_data_sram_start_addr 0x08000000 + #define zf_data_cfg_info 0x10007000 + #define zf_data_fw_cfg_1 0x10007084 + #define zf_data_fw_cfg_2 0x10007264 + #define zf_data_fw_cfg_3 0x10007300 + #define zf_data_adc_cfg_1 0x10006A00 + #define zf_data_adc_cfg_2 0x10007B28 + #define zf_data_adc_cfg_3 0x10007AF0 + #define zf_data_map_table 0x10007500 +/* #define zf_data_mode_switch 0x10007294*/ + #define zf_addr_sts_chk 0x900000A8 + #define zf_data_activ_sts 0x05 + #define zf_addr_activ_relod 0x90000048 + #define zf_data_activ_in 0xEC + +#if defined(HX_CODE_OVERLAY) + #define ovl_section_num 3 + #define ovl_gesture_request 0x11 + #define ovl_gesture_reply 0x22 + #define ovl_border_request 0x55 + #define ovl_border_reply 0x66 + #define ovl_sorting_request 0x99 + #define ovl_sorting_reply 0xAA + #define ovl_fault 0xFF +#endif + +#if defined(HX_ALG_OVERLAY) + #define ovl_alg_request 0x11 + #define ovl_alg_reply 0x22 + #define ovl_alg_fault 0xFF +#endif + +struct zf_info { + uint8_t sram_addr[4]; + int write_size; + uint32_t fw_addr; + uint32_t cfg_addr; +}; +#endif +/* New Version 1K*/ +enum bin_desc_map_table { + TP_CONFIG_TABLE = 0x00000A00, + FW_CID = 0x10000000, + FW_VER = 0x10000100, + CFG_VER = 0x10000600, +}; + +/*Old Version 1K + *enum bin_desc_map_table { + *TP_CONFIG_TABLE = 0x0000000A, + *FW_CID = 0x10000000, + *FW_VER = 0x10000001, + *CFG_VER = 0x10000005, + *}; + **/ + +extern uint32_t dbg_reg_ary[4]; + +struct ic_operation { + uint8_t addr_ahb_addr_byte_0[1]; + uint8_t addr_ahb_rdata_byte_0[1]; + uint8_t addr_ahb_access_direction[1]; + uint8_t addr_conti[1]; + uint8_t addr_incr4[1]; + uint8_t adr_i2c_psw_lb[1]; + uint8_t adr_i2c_psw_ub[1]; + uint8_t data_ahb_access_direction_read[1]; + uint8_t data_conti[1]; + uint8_t data_incr4[1]; + uint8_t data_i2c_psw_lb[1]; + uint8_t data_i2c_psw_ub[1]; + uint8_t addr_tcon_on_rst[4]; + uint8_t addr_adc_on_rst[4]; + uint8_t addr_psl[4]; + uint8_t addr_cs_central_state[4]; + uint8_t data_rst[4]; + uint8_t adr_osc_en[4]; + uint8_t adr_osc_pw[4]; +}; + +struct fw_operation { + uint8_t addr_system_reset[4]; + uint8_t addr_ctrl_fw_isr[4]; + uint8_t addr_flag_reset_event[4]; + uint8_t addr_hsen_enable[4]; + uint8_t addr_smwp_enable[4]; + uint8_t addr_program_reload_from[4]; + uint8_t addr_program_reload_to[4]; + uint8_t addr_program_reload_page_write[4]; + uint8_t addr_raw_out_sel[4]; + uint8_t addr_reload_status[4]; + uint8_t addr_reload_crc32_result[4]; + uint8_t addr_reload_addr_from[4]; + uint8_t addr_reload_addr_cmd_beat[4]; + uint8_t addr_selftest_addr_en[4]; + uint8_t addr_criteria_addr[4]; + uint8_t addr_set_frame_addr[4]; + uint8_t addr_selftest_result_addr[4]; + uint8_t addr_sorting_mode_en[4]; + uint8_t addr_fw_mode_status[4]; + uint8_t addr_icid_addr[4]; + uint8_t addr_fw_ver_addr[4]; + uint8_t addr_fw_cfg_addr[4]; + uint8_t addr_fw_vendor_addr[4]; + uint8_t addr_cus_info[4]; + uint8_t addr_proj_info[4]; + uint8_t addr_fw_state_addr[4]; + uint8_t addr_fw_dbg_msg_addr[4]; + uint8_t addr_chk_fw_status[4]; + uint8_t addr_dd_handshak_addr[4]; + uint8_t addr_dd_data_addr[4]; + uint8_t addr_clr_fw_record_dd_sts[4]; + uint8_t addr_ap_notify_fw_sus[4]; + uint8_t data_ap_notify_fw_sus_en[4]; + uint8_t data_ap_notify_fw_sus_dis[4]; + uint8_t data_system_reset[4]; + uint8_t data_safe_mode_release_pw_active[4]; + uint8_t data_safe_mode_release_pw_reset[4]; + uint8_t data_clear[4]; + uint8_t data_fw_stop[4]; + uint8_t data_program_reload_start[4]; + uint8_t data_program_reload_compare[4]; + uint8_t data_program_reload_break[4]; + uint8_t data_selftest_request[4]; + uint8_t data_criteria_aa_top[1]; + uint8_t data_criteria_aa_bot[1]; + uint8_t data_criteria_key_top[1]; + uint8_t data_criteria_key_bot[1]; + uint8_t data_criteria_avg_top[1]; + uint8_t data_criteria_avg_bot[1]; + uint8_t data_set_frame[4]; + uint8_t data_selftest_ack_hb[1]; + uint8_t data_selftest_ack_lb[1]; + uint8_t data_selftest_pass[1]; + uint8_t data_normal_cmd[1]; + uint8_t data_normal_status[1]; + uint8_t data_sorting_cmd[1]; + uint8_t data_sorting_status[1]; + uint8_t data_dd_request[1]; + uint8_t data_dd_ack[1]; + uint8_t data_idle_dis_pwd[1]; + uint8_t data_idle_en_pwd[1]; + uint8_t data_rawdata_ready_hb[1]; + uint8_t data_rawdata_ready_lb[1]; + uint8_t addr_ahb_addr[1]; + uint8_t data_ahb_dis[1]; + uint8_t data_ahb_en[1]; + uint8_t addr_event_addr[1]; + uint8_t addr_usb_detect[4]; + uint8_t addr_ulpm_33[1]; + uint8_t addr_ulpm_34[1]; + uint8_t data_ulpm_11[1]; + uint8_t data_ulpm_22[1]; + uint8_t data_ulpm_33[1]; + uint8_t data_ulpm_aa[1]; +}; + +struct flash_operation { + uint8_t addr_spi200_trans_fmt[4]; + uint8_t addr_spi200_trans_ctrl[4]; + uint8_t addr_spi200_fifo_rst[4]; + uint8_t addr_spi200_rst_status[4]; + uint8_t addr_spi200_flash_speed[4]; + uint8_t addr_spi200_cmd[4]; + uint8_t addr_spi200_addr[4]; + uint8_t addr_spi200_data[4]; + uint8_t addr_spi200_bt_num[4]; + + uint8_t data_spi200_txfifo_rst[4]; + uint8_t data_spi200_rxfifo_rst[4]; + uint8_t data_spi200_trans_fmt[4]; + uint8_t data_spi200_trans_ctrl_1[4]; + uint8_t data_spi200_trans_ctrl_2[4]; + uint8_t data_spi200_trans_ctrl_3[4]; + uint8_t data_spi200_trans_ctrl_4[4]; + uint8_t data_spi200_trans_ctrl_5[4]; + uint8_t data_spi200_trans_ctrl_6[4]; + uint8_t data_spi200_trans_ctrl_7[4]; + uint8_t data_spi200_cmd_1[4]; + uint8_t data_spi200_cmd_2[4]; + uint8_t data_spi200_cmd_3[4]; + uint8_t data_spi200_cmd_4[4]; + uint8_t data_spi200_cmd_5[4]; + uint8_t data_spi200_cmd_6[4]; + uint8_t data_spi200_cmd_7[4]; + uint8_t data_spi200_cmd_8[4]; + uint8_t data_spi200_addr[4]; +}; + +struct sram_operation { + uint8_t addr_mkey[4]; + uint8_t addr_rawdata_addr[4]; + uint8_t addr_rawdata_end[4]; + uint8_t passwrd_start[2]; + uint8_t passwrd_end[2]; +}; + +struct driver_operation { + uint8_t addr_fw_define_flash_reload[4]; + uint8_t addr_fw_define_2nd_flash_reload[4]; + uint8_t addr_fw_define_int_is_edge[4]; + uint8_t addr_fw_define_rxnum_txnum[4]; + uint8_t addr_fw_define_maxpt_xyrvs[4]; + uint8_t addr_fw_define_x_y_res[4]; + uint8_t data_df_rx[1]; + uint8_t data_df_tx[1]; + uint8_t data_df_pt[1]; + uint8_t data_fw_define_flash_reload_dis[4]; + uint8_t data_fw_define_flash_reload_en[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_sorting[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_normal[4]; +}; + +struct zf_operation { + uint8_t data_dis_flash_reload[4]; + uint8_t addr_system_reset[4]; + uint8_t data_system_reset[4]; + uint8_t data_sram_start_addr[4]; + uint8_t data_sram_clean[4]; + uint8_t data_cfg_info[4]; + uint8_t data_fw_cfg_1[4]; + uint8_t data_fw_cfg_2[4]; + uint8_t data_fw_cfg_3[4]; + uint8_t data_adc_cfg_1[4]; + uint8_t data_adc_cfg_2[4]; + uint8_t data_adc_cfg_3[4]; + uint8_t data_map_table[4]; +/* uint8_t data_mode_switch[4];*/ + uint8_t addr_sts_chk[4]; + uint8_t data_activ_sts[1]; + uint8_t addr_activ_relod[4]; + uint8_t data_activ_in[1]; +}; + +struct himax_core_command_operation { + struct ic_operation *ic_op; + struct fw_operation *fw_op; + struct flash_operation *flash_op; + struct sram_operation *sram_op; + struct driver_operation *driver_op; + struct zf_operation *zf_op; +}; + +struct on_ic_operation { + uint8_t addr_ahb_addr_byte_0[1]; + uint8_t addr_ahb_rdata_byte_0[1]; + uint8_t addr_ahb_access_direction[1]; + uint8_t addr_conti[1]; + uint8_t addr_incr4[1]; + uint8_t adr_mcu_ctrl[1]; + uint8_t data_ahb_access_direction_read[1]; + uint8_t data_conti[1]; + uint8_t data_incr4[1]; + uint8_t cmd_mcu_on[1]; + uint8_t cmd_mcu_off[1]; + uint8_t adr_sleep_ctrl[1]; + uint8_t cmd_sleep_in[1]; + uint8_t adr_tcon_ctrl[4]; + uint8_t cmd_tcon_on[4]; + uint8_t adr_wdg_ctrl[4]; + uint8_t cmd_wdg_psw[4]; + uint8_t adr_wdg_cnt_ctrl[4]; + uint8_t cmd_wdg_cnt_clr[4]; +}; + +struct on_fw_operation { + uint8_t addr_smwp_enable[1]; + uint8_t addr_program_reload_from[4]; + uint8_t addr_raw_out_sel[1]; + uint8_t addr_flash_checksum[4]; + uint8_t data_flash_checksum[4]; + uint8_t addr_crc_value[4]; + uint8_t addr_reload_status[4]; + uint8_t addr_reload_crc32_result[4]; + uint8_t addr_reload_addr_from[4]; + uint8_t addr_reload_addr_cmd_beat[4]; + uint8_t addr_set_frame_addr[4]; + uint8_t addr_fw_mode_status[1]; + uint8_t addr_icid_addr[4]; + uint8_t addr_fw_ver_start[1]; + uint8_t data_safe_mode_release_pw_active[4]; + uint8_t data_safe_mode_release_pw_reset[4]; + uint8_t data_clear[4]; + uint8_t addr_criteria_addr[1]; + uint8_t data_selftest_pass[1]; + uint8_t addr_reK_crtl[4]; + uint8_t data_reK_en[1]; + uint8_t data_reK_dis[1]; + uint8_t data_rst_init[1]; + uint8_t data_dc_set[1]; + uint8_t data_bank_set[1]; + uint8_t addr_selftest_addr_en[1]; + uint8_t addr_selftest_result_addr[1]; + uint8_t data_selftest_request[1]; + uint8_t data_thx_avg_mul_dc_lsb[1]; + uint8_t data_thx_avg_mul_dc_msb[1]; + uint8_t data_thx_mul_dc_up_low_bud[1]; + uint8_t data_thx_avg_slf_dc_lsb[1]; + uint8_t data_thx_avg_slf_dc_msb[1]; + uint8_t data_thx_slf_dc_up_low_bud[1]; + uint8_t data_thx_slf_bank_up[1]; + uint8_t data_thx_slf_bank_low[1]; + uint8_t data_idle_dis_pwd[1]; + uint8_t data_idle_en_pwd[1]; + uint8_t data_rawdata_ready_hb[1]; + uint8_t data_rawdata_ready_lb[1]; + uint8_t addr_ahb_addr[1]; + uint8_t data_ahb_dis[1]; + uint8_t data_ahb_en[1]; + uint8_t addr_event_addr[1]; + uint8_t addr_usb_detect[1]; +}; + +struct on_flash_operation { + uint8_t addr_ctrl_base[4]; + uint8_t addr_ctrl_auto[4]; + uint8_t data_main_erase[4]; + uint8_t data_auto[1]; + uint8_t data_main_read[1]; + uint8_t data_page_write[1]; + uint8_t data_sfr_read[1]; + uint8_t data_spp_read[1]; + uint8_t addr_ahb_ctrl[4]; + uint8_t data_ahb_squit[4]; + + uint8_t addr_unlock_0[4]; + uint8_t addr_unlock_4[4]; + uint8_t addr_unlock_8[4]; + uint8_t addr_unlock_c[4]; + uint8_t data_cmd0[4]; + uint8_t data_cmd1[4]; + uint8_t data_cmd2[4]; + uint8_t data_cmd3[4]; + uint8_t data_lock[4]; +}; + +struct on_sram_operation { + uint8_t addr_rawdata_addr[4]; + uint8_t addr_rawdata_end[4]; + uint8_t data_conti[4]; + uint8_t data_fin[4]; + uint8_t passwrd_start[2]; + uint8_t passwrd_end[2]; +}; + +struct on_driver_operation { + uint8_t addr_fw_define_int_is_edge[4]; + uint8_t addr_fw_rx_tx_maxpt_num[4]; +#if defined(HX_NEW_EVENT_STACK_FORMAT) + uint8_t addr_fw_maxpt_bt_num[4]; +#endif + uint8_t addr_fw_xy_rev_int_edge[4]; + uint8_t addr_fw_define_x_y_res[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_sorting[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_normal[4]; + uint8_t data_df_rx[1]; + uint8_t data_df_tx[1]; + uint8_t data_df_pt[1]; +}; + +struct himax_on_core_command_operation { + struct on_ic_operation *ic_op; + struct on_fw_operation *fw_op; + struct on_flash_operation *flash_op; + struct on_sram_operation *sram_op; + struct on_driver_operation *driver_op; +}; + +struct himax_chip_detect { + bool (*fp_chip_detect)(void); +}; + +struct himax_chip_entry { + struct himax_chip_detect *core_chip_dt; + uint32_t hx_ic_dt_num; +}; + +struct himax_core_fp { +/* CORE_IC */ + void (*fp_burst_enable)(uint8_t auto_add_4_byte); + int (*fp_register_read)(uint8_t *addr, uint8_t *buf, uint32_t len); + /*int (*fp_flash_write_burst)(uint8_t *reg_byte, uint8_t *write_data);*/ + /*void (*fp_flash_write_burst_lenth)(uint8_t *reg_byte, + * uint8_t *write_data, uint32_t length); + */ + int (*fp_register_write)(uint8_t *addr, uint8_t *val, uint32_t len); + void (*fp_interface_on)(void); + void (*fp_sense_on)(uint8_t FlashMode); + void (*fp_tcon_on)(void); + bool (*fp_watch_dog_off)(void); + bool (*fp_sense_off)(bool check_en); + void (*fp_sleep_in)(void); + bool (*fp_wait_wip)(int Timing); + void (*fp_init_psl)(void); + void (*fp_resume_ic_action)(void); + void (*fp_suspend_ic_action)(void); + void (*fp_power_on_init)(void); + bool (*fp_slave_tcon_reset)(void); + bool (*fp_slave_adc_reset_slave)(void); + bool (*fp_slave_wdt_off_slave)(void); +/* CORE_IC */ + +/* CORE_FW */ + void (*fp_parse_raw_data)(struct himax_report_data *hx_touch_data, + int mul_num, + int self_num, + uint8_t diag_cmd, + int16_t *mutual_data, + int16_t *self_data); + void (*fp_system_reset)(void); + int (*fp_Calculate_CRC_with_AP)(unsigned char *FW_content, + int CRC_from_FW, + int len); + uint32_t (*fp_check_CRC)(uint8_t *start_addr, int reload_length); + void (*fp_set_reload_cmd)(uint8_t *write_data, + int idx, + uint32_t cmd_from, + uint32_t cmd_to, + uint32_t cmd_beat); + bool (*fp_program_reload)(void); + void (*fp_set_SMWP_enable)(uint8_t SMWP_enable, bool suspended); + void (*fp_set_HSEN_enable)(uint8_t HSEN_enable, bool suspended); + void (*fp_diag_register_set)(uint8_t diag_command, + uint8_t storage_type, bool is_dirly); + void (*_clr_fw_reord_dd_sts)(void); + void (*_ap_notify_fw_sus)(int suspend); +#if defined(HX_TP_SELF_TEST_DRIVER) + void (*fp_control_reK)(bool enable); +#endif + int (*fp_chip_self_test)(struct seq_file *s, void *v); + void (*fp_idle_mode)(int disable); + void (*fp_reload_disable)(int disable); + bool (*fp_check_chip_version)(void); + int (*fp_read_ic_trigger_type)(void); + int (*fp_read_i2c_status)(void); + void (*fp_read_FW_ver)(void); + bool (*fp_read_event_stack)(uint8_t *buf, uint8_t length); + void (*fp_return_event_stack)(void); + bool (*fp_calculateChecksum)(bool change_iref, uint32_t size); + void (*fp_read_FW_status)(void); + void (*fp_irq_switch)(int switch_on); + int (*fp_assign_sorting_mode)(uint8_t *tmp_data); + int (*fp_check_sorting_mode)(uint8_t *tmp_data); + int (*fp_get_max_dc)(void); + uint8_t (*fp_read_DD_status)(uint8_t *cmd_set, uint8_t *tmp_data); + int (*fp_ulpm_in)(void); + int (*fp_black_gest_ctrl)(bool enable); + int (*_diff_overlay_bin)(void); +/* CORE_FW */ + +/* CORE_FLASH */ + void (*fp_chip_erase)(void); + bool (*fp_block_erase)(int start_addr, int length); + bool (*fp_sector_erase)(int start_addr); + void (*fp_flash_programming)(uint8_t *FW_content, int FW_Size); + void (*fp_flash_page_write)(uint8_t *write_addr, int length, + uint8_t *write_data); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_32k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_60k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_64k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_124k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_128k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_255k)(unsigned char *fw, + int len, bool change_iref); + void (*fp_flash_dump_func)(uint8_t local_flash_command, + int Flash_Size, uint8_t *flash_buffer); + bool (*fp_flash_lastdata_check)(uint32_t size); + bool (*fp_bin_desc_get)(unsigned char *fw, uint32_t max_sz); + bool (*fp_ahb_squit)(void); + void (*fp_flash_read)(uint8_t *r_data, int start_addr, int length); + bool (*fp_sfr_rw)(uint8_t *addr, int length, + uint8_t *data, uint8_t rw_ctrl); + bool (*fp_lock_flash)(void); + bool (*fp_unlock_flash)(void); + void (*fp_init_auto_func)(void); + int (*_diff_overlay_flash)(void); +/* CORE_FLASH */ + +/* CORE_SRAM */ + void (*fp_sram_write)(uint8_t *FW_content); + bool (*fp_sram_verify)(uint8_t *FW_File, int FW_Size); + bool (*fp_get_DSRAM_data)(uint8_t *info_data, bool DSRAM_Flag); +/* CORE_SRAM */ + +/* CORE_DRIVER */ + void (*fp_chip_init)(void); + void (*fp_pin_reset)(void); + uint8_t (*fp_tp_info_check)(void); + void (*fp_touch_information)(void); + void (*fp_calc_touch_data_size)(void); + void (*fp_reload_config)(void); + int (*fp_get_touch_data_size)(void); + void (*fp_usb_detect_set)(uint8_t *cable_config); + int (*fp_hand_shaking)(void); + int (*fp_determin_diag_rawdata)(int diag_command); + int (*fp_determin_diag_storage)(int diag_command); + int (*fp_cal_data_len)(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); + bool (*fp_diag_check_sum)(struct himax_report_data *hx_touch_data); + void (*fp_diag_parse_raw_data)(struct himax_report_data *hx_touch_data, + int mul_num, + int self_num, + uint8_t diag_cmd, + int32_t *mutual_data, + int32_t *self_data); + void (*fp_ic_reset)(uint8_t loadconfig, uint8_t int_off); + int (*fp_ic_excp_recovery)(uint32_t hx_excp_event, + uint32_t hx_zero_event, uint32_t length); + void (*fp_excp_ic_reset)(void); + void (*fp_resend_cmd_func)(bool suspended); +#if defined(HX_TP_PROC_GUEST_INFO) + int (*guest_info_get_status)(void); + int (*read_guest_info)(void); +#endif +/* CORE_DRIVER */ + int (*fp_turn_on_mp_func)(int on); +#if defined(HX_ZERO_FLASH) + void (*fp_clean_sram_0f)(uint8_t *addr, int write_len, int type); + void (*fp_write_sram_0f)(uint8_t *addr, const uint8_t *data, + uint32_t len); + int (*fp_write_sram_0f_crc)(uint8_t *addr, const uint8_t *data, + uint32_t len); + int (*fp_firmware_update_0f)(const struct firmware *fw_entry, int type); + int (*fp_0f_op_file_dirly)(char *file_name); + int (*fp_0f_excp_check)(void); + void (*fp_0f_reload_to_active)(void); +#if defined(HX_0F_DEBUG) + void (*fp_read_sram_0f)(const struct firmware *fw_entry, + uint8_t *addr, + int start_index, + int read_len); + void (*fp_read_all_sram)(uint8_t *addr, int read_len); + void (*fp_firmware_read_0f)(const struct firmware *fw_entry, int type); +#endif +#if defined(HX_CODE_OVERLAY) + int (*fp_0f_overlay)(int ovl_type, int mode); +#endif +#endif +}; + +#endif diff --git a/himax_ic_incell_core.c b/himax_ic_incell_core.c new file mode 100644 index 0000000..dc746ed --- /dev/null +++ b/himax_ic_incell_core.c @@ -0,0 +1,4585 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for incell ic core functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_ic_core.h" + +struct himax_core_command_operation *g_core_cmd_op; +struct ic_operation *pic_op; +EXPORT_SYMBOL(pic_op); + +struct fw_operation *pfw_op; +EXPORT_SYMBOL(pfw_op); + +struct flash_operation *pflash_op; +EXPORT_SYMBOL(pflash_op); + +struct sram_operation *psram_op; +struct driver_operation *pdriver_op; +EXPORT_SYMBOL(pdriver_op); + +#if defined(HX_ZERO_FLASH) +struct zf_operation *pzf_op; +EXPORT_SYMBOL(pzf_op); +#if defined(HX_CODE_OVERLAY) +uint8_t *ovl_idx; +EXPORT_SYMBOL(ovl_idx); +#endif +#endif + +#define Arr4_to_Arr4(A, B) {\ + A[3] = B[3];\ + A[2] = B[2];\ + A[1] = B[1];\ + A[0] = B[0];\ + } + +int HX_TOUCH_INFO_POINT_CNT; + +void (*himax_mcu_cmd_struct_free)(void); +static uint8_t *g_internal_buffer; +uint32_t dbg_reg_ary[4] = {fw_addr_fw_dbg_msg_addr, fw_addr_chk_fw_status, + fw_addr_chk_dd_status, fw_addr_flag_reset_event}; + +/* CORE_IC */ +/* IC side start*/ +static void himax_mcu_burst_enable(uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[DATA_LEN_4]; + int ret; + + /*I("%s,Entering\n", __func__);*/ + tmp_data[0] = pic_op->data_conti[0]; + + ret = himax_bus_write(pic_op->addr_conti[0], tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } + + tmp_data[0] = (pic_op->data_incr4[0] | auto_add_4_byte); + + ret = himax_bus_write(pic_op->addr_incr4[0], tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } +} + +static int himax_mcu_register_read(uint8_t *addr, uint8_t *buf, uint32_t len) +{ + uint8_t tmp_data[DATA_LEN_4]; + int i = 0; + int address = 0; + int ret = 0; + int max_bus_size = 0; + +#if defined(HX_ZERO_FLASH) + max_bus_size = (len > HX_MAX_READ_SZ - 4) ? (HX_MAX_READ_SZ - 4) : len; +#else + max_bus_size = FLASH_RW_MAX_LEN; +#endif + + if (len > max_bus_size) { + E("%s: read len over %d!\n", __func__, max_bus_size); + return LENGTH_FAIL; + } + + if (len > DATA_LEN_4) + g_core_fp.fp_burst_enable(1); + else + g_core_fp.fp_burst_enable(0); + + address = (addr[3] << 24) + (addr[2] << 16) + (addr[1] << 8) + addr[0]; + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], tmp_data, + DATA_LEN_4); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + + tmp_data[0] = pic_op->data_ahb_access_direction_read[0]; + + ret = himax_bus_write(pic_op->addr_ahb_access_direction[0], tmp_data, + 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + + ret = himax_bus_read(pic_op->addr_ahb_rdata_byte_0[0], buf, len); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + + if (len > DATA_LEN_4) + g_core_fp.fp_burst_enable(0); + + return NO_ERR; +} + +static int himax_mcu_flash_write_burst_lenth(uint8_t *reg_byte, + uint8_t *write_data, uint32_t length) +{ + uint8_t *data_byte; + int ret = 0; + + if (!g_internal_buffer) { + E("%s: internal buffer not initialized!\n", __func__); + return MEM_ALLOC_FAIL; + } + data_byte = g_internal_buffer; + + /* assign addr 4bytes */ + memcpy(data_byte, reg_byte, ADDR_LEN_4); + /* assign data n bytes */ + memcpy(data_byte + ADDR_LEN_4, write_data, length); + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], data_byte, + length + ADDR_LEN_4); + if (ret < 0) { + E("%s: xfer fail!\n", __func__); + return BUS_FAIL; + } + + return NO_ERR; +} + +static int himax_mcu_register_write(uint8_t *addr, uint8_t *val, uint32_t len) +{ + int address; + uint8_t tmp_addr[4]; + uint8_t *tmp_data; + int total_read_times = 0; + uint32_t max_bus_size = MAX_I2C_TRANS_SZ; + uint32_t total_size_temp = 0; + unsigned int i = 0; + int ret = 0; + + total_size_temp = len; +#if defined(HX_ZERO_FLASH) + max_bus_size = (len > HX_MAX_WRITE_SZ) ? HX_MAX_WRITE_SZ : len; +#endif + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + if (len > DATA_LEN_4) + g_core_fp.fp_burst_enable(1); + else + g_core_fp.fp_burst_enable(0); + + for (i = 0; i < total_read_times; i++) { + if (total_size_temp >= max_bus_size) { + tmp_data = val + (i * max_bus_size); + ret = himax_mcu_flash_write_burst_lenth(tmp_addr, + tmp_data, max_bus_size); + if (ret < 0) { + I("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + total_size_temp = total_size_temp - max_bus_size; + } else { + tmp_data = val + (i * max_bus_size); + ret = himax_mcu_flash_write_burst_lenth(tmp_addr, + tmp_data, total_size_temp); + if (ret < 0) { + I("%s: bus access fail!\n", __func__); + return BUS_FAIL; + } + } + + address = ((i+1) * max_bus_size); + tmp_addr[0] = addr[0] + (uint8_t)((address) & 0x00FF); + + if (tmp_addr[0] < addr[0]) { + tmp_addr[1] = addr[1] + + (uint8_t)((address>>8) & 0x00FF) + 1; + } else { + tmp_addr[1] = addr[1] + + (uint8_t)((address>>8) & 0x00FF); + } + + udelay(100); + } + + return NO_ERR; +} + +static int himax_write_read_reg(uint8_t *tmp_addr, uint8_t *tmp_data, + uint8_t hb, uint8_t lb) +{ + uint16_t retry = 0; + uint8_t r_data[ADDR_LEN_4] = {0}; + + while (retry++ < 40) { /* ceil[16.6*2] */ + g_core_fp.fp_register_read(tmp_addr, r_data, DATA_LEN_4); + if (r_data[1] == lb && r_data[0] == hb) + break; + else if (r_data[1] == hb && r_data[0] == lb) + return NO_ERR; + + g_core_fp.fp_register_write(tmp_addr, tmp_data, DATA_LEN_4); + usleep_range(1000, 1100); + } + + if (retry >= 40) + goto FAIL; + + retry = 0; + while (retry++ < 200) { /* self test item might take long time */ + g_core_fp.fp_register_read(tmp_addr, r_data, DATA_LEN_4); + if (r_data[1] == hb && r_data[0] == lb) + return NO_ERR; + + I("%s: wait data ready %d times\n", __func__, retry); + usleep_range(10000, 10100); + } + +FAIL: + E("%s: failed to handshaking with DSRAM\n", __func__); + E("%s: addr = %02X%02X%02X%02X; data = %02X%02X%02X%02X", + __func__, tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + E("%s: target = %02X%02X; r_data = %02X%02X\n", + __func__, hb, lb, r_data[1], r_data[0]); + + return HX_RW_REG_FAIL; + +} + +static void himax_mcu_interface_on(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_data2[DATA_LEN_4]; + int cnt = 0; + int ret = 0; + + /* Read a temp register to wake up BUS. */ + ret = himax_bus_read(pic_op->addr_ahb_rdata_byte_0[0], tmp_data, + DATA_LEN_4); + if (ret < 0) {/* to knock BUS*/ + E("%s: bus access fail!\n", __func__); + return; + } + + do { + tmp_data[0] = pic_op->data_conti[0]; + + ret = himax_bus_write(pic_op->addr_conti[0], tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } + + tmp_data[0] = pic_op->data_incr4[0]; + + ret = himax_bus_write(pic_op->addr_incr4[0], tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } + + /*Check cmd*/ + himax_bus_read(pic_op->addr_conti[0], tmp_data, 1); + himax_bus_read(pic_op->addr_incr4[0], tmp_data2, 1); + + if (tmp_data[0] == pic_op->data_conti[0] + && tmp_data2[0] == pic_op->data_incr4[0]) + break; + + usleep_range(1000, 1100); + } while (++cnt < 10); + + if (cnt > 0) + I("%s:Polling burst mode: %d times\n", __func__, cnt); +} + +#define WIP_PRT_LOG "%s: retry:%d, bf[0]=%d, bf[1]=%d,bf[2]=%d, bf[3]=%d\n" +static bool himax_mcu_wait_wip(int Timing) +{ + uint8_t tmp_data[DATA_LEN_4]; + int retry_cnt = 0; + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + pflash_op->data_spi200_trans_fmt, DATA_LEN_4); + tmp_data[0] = 0x01; + + do { + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + pflash_op->data_spi200_trans_ctrl_1, DATA_LEN_4); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_1, DATA_LEN_4); + tmp_data[0] = tmp_data[1] = tmp_data[2] = tmp_data[3] = 0xFF; + g_core_fp.fp_register_read(pflash_op->addr_spi200_data, + tmp_data, 4); + + if ((tmp_data[0] & 0x01) == 0x00) + return true; + + retry_cnt++; + + if (tmp_data[0] != 0x00 + || tmp_data[1] != 0x00 + || tmp_data[2] != 0x00 + || tmp_data[3] != 0x00) + I(WIP_PRT_LOG, + __func__, retry_cnt, tmp_data[0], + tmp_data[1], tmp_data[2], tmp_data[3]); + + if (retry_cnt > 100) { + E("%s: Wait wip error!\n", __func__); + return false; + } + + msleep(Timing); + } while ((tmp_data[0] & 0x01) == 0x01); + + return true; +} + +static void himax_mcu_sense_on(uint8_t FlashMode) +{ + uint8_t tmp_data[DATA_LEN_4]; + int retry = 0; + int ret = 0; + + I("Enter %s\n", __func__); + private_ts->notouch_frame = private_ts->ic_notouch_frame; + g_core_fp.fp_interface_on(); + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*msleep(20);*/ + usleep_range(10000, 11000); + if (!FlashMode) { +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + do { + g_core_fp.fp_register_read( + pfw_op->addr_flag_reset_event, + tmp_data, DATA_LEN_4); + I("%s:Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x01 + || tmp_data[0] != 0x00) + && retry++ < 5); + + if (retry >= 5) { + E("%s: Fail:\n", __func__); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + I("%s:OK and Read status from IC = %X,%X\n", + __func__, tmp_data[0], tmp_data[1]); + /* reset code*/ + tmp_data[0] = 0x00; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], + tmp_data, 1); + if (ret < 0) { + E("%s: cmd=%x bus access fail!\n", + __func__, + pic_op->adr_i2c_psw_lb[0]); + } + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], + tmp_data, 1); + if (ret < 0) { + E("%s: cmd=%x bus access fail!\n", + __func__, + pic_op->adr_i2c_psw_ub[0]); + } + } + } +} + +static bool himax_mcu_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + tmp_data[0] = pic_op->data_i2c_psw_lb[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + tmp_data[0] = pic_op->data_i2c_psw_ub[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], tmp_data, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return false; + } + + g_core_fp.fp_register_read(pic_op->addr_cs_central_state, + tmp_data, ADDR_LEN_4); + I("%s: Check enter_save_mode data[0]=%X\n", __func__, + tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + g_core_fp.fp_register_write(pic_op->addr_tcon_on_rst, + pic_op->data_rst, DATA_LEN_4); + usleep_range(1000, 1100); + tmp_data[3] = pic_op->data_rst[3]; + tmp_data[2] = pic_op->data_rst[2]; + tmp_data[1] = pic_op->data_rst[1]; + tmp_data[0] = pic_op->data_rst[0] | 0x01; + g_core_fp.fp_register_write(pic_op->addr_tcon_on_rst, + tmp_data, DATA_LEN_4); + + g_core_fp.fp_register_write(pic_op->addr_adc_on_rst, + pic_op->data_rst, DATA_LEN_4); + usleep_range(1000, 1100); + tmp_data[3] = pic_op->data_rst[3]; + tmp_data[2] = pic_op->data_rst[2]; + tmp_data[1] = pic_op->data_rst[1]; + tmp_data[0] = pic_op->data_rst[0] | 0x01; + g_core_fp.fp_register_write(pic_op->addr_adc_on_rst, + tmp_data, DATA_LEN_4); + goto TRUE_END; + } else { + /*msleep(10);*/ +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } + } while (cnt++ < 15); + + return false; +TRUE_END: + return true; +} + +/*power saving level*/ +static void himax_mcu_init_psl(void) +{ + g_core_fp.fp_register_write(pic_op->addr_psl, pic_op->data_rst, + sizeof(pic_op->data_rst)); + I("%s: power saving level reset OK!\n", __func__); +} + +static void himax_mcu_resume_ic_action(void) +{ + /* Nothing to do */ +} + +static void himax_mcu_suspend_ic_action(void) +{ + /* Nothing to do */ +} + +static void himax_mcu_power_on_init(void) +{ + uint8_t tmp_data[4] = {0x01, 0x00, 0x00, 0x00}; + uint8_t retry = 0; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + /*N frame initial*/ + /* reset N frame back to default value 1 for normal mode */ + g_core_fp.fp_register_write(pfw_op->addr_set_frame_addr, tmp_data, 4); + /*FW reload done initial*/ + g_core_fp.fp_register_write(pdriver_op->addr_fw_define_2nd_flash_reload, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + + g_core_fp.fp_sense_on(0x00); + + I("%s: waiting for FW reload data\n", __func__); + + while (retry++ < 30) { + g_core_fp.fp_register_read( + pdriver_op->addr_fw_define_2nd_flash_reload, tmp_data, + DATA_LEN_4); + + /* use all 4 bytes to compare */ + if ((tmp_data[3] == 0x00 && tmp_data[2] == 0x00 && + tmp_data[1] == 0x72 && tmp_data[0] == 0xC0)) { + I("%s: FW reload done\n", __func__); + break; + } + I("%s: wait FW reload %d times\n", __func__, retry); + g_core_fp.fp_read_FW_status(); + usleep_range(10000, 11000); + } +} +/* IC side end*/ +/* CORE_IC */ + +/* CORE_FW */ +/* FW side start*/ +static void diag_mcu_parse_raw_data(struct himax_report_data *hx_touch_data, + int mul_num, int self_num, uint8_t diag_cmd, + int32_t *mutual_data, int32_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2, i; + + if (hx_touch_data->hx_rawdata_buf[0] + == pfw_op->data_rawdata_ready_lb[0] + && hx_touch_data->hx_rawdata_buf[1] + == pfw_op->data_rawdata_ready_hb[0] + && hx_touch_data->hx_rawdata_buf[2] > 0 + && hx_touch_data->hx_rawdata_buf[3] == diag_cmd) { + RawDataLen_word = hx_touch_data->rawdata_size / 2; + index = (hx_touch_data->hx_rawdata_buf[2] - 1) + * RawDataLen_word; + + /* I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n",index, + * buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + * I("RawDataLen=%d , RawDataLen_word=%d , + * hx_touch_info_size=%d\n", + * RawDataLen, RawDataLen_word, hx_touch_info_size); + */ + for (i = 0; i < RawDataLen_word; i++) { + temp1 = index + i; + + if (temp1 < mul_num) { /*mutual*/ + mutual_data[index + i] = + ((int8_t)hx_touch_data-> + hx_rawdata_buf[i * 2 + 4 + 1]) * 256 + + hx_touch_data-> + hx_rawdata_buf[i * 2 + 4]; + } else { /*self*/ + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + break; + + self_data[i + index - mul_num] = + (((int8_t)hx_touch_data-> + hx_rawdata_buf[i * 2 + 4 + 1]) << 8) + + hx_touch_data-> + hx_rawdata_buf[i * 2 + 4]; + } + } + } +} + +static void himax_mcu_system_reset(void) +{ +#if defined(HX_PON_PIN_SUPPORT) + g_core_fp.fp_register_write(pfw_op->addr_system_reset, + pfw_op->data_system_reset, sizeof(pfw_op->data_system_reset)); +#else + int ret = 0; + uint8_t tmp_data[DATA_LEN_4]; + int retry = 0; + + g_core_fp.fp_interface_on(); + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + do { + /* reset code*/ + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = pic_op->data_i2c_psw_lb[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1); + if (ret < 0) + E("%s: bus access fail!\n", __func__); + + /** + * I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = pic_op->data_i2c_psw_ub[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], tmp_data, 1); + if (ret < 0) + E("%s: bus access fail!\n", __func__); + + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x00 + */ + tmp_data[0] = 0x00; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1); + if (ret < 0) + E("%s: bus access fail!\n", __func__); + + usleep_range(10000, 11000); + + g_core_fp.fp_register_read(pfw_op->addr_flag_reset_event, + tmp_data, DATA_LEN_4); + I("%s:Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x02 || tmp_data[0] != 0x00) && retry++ < 5); +#endif +} + +static int himax_mcu_Calculate_CRC_with_AP(unsigned char *FW_content, + int CRC_from_FW, int len) +{ + int i, j, length = 0; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + + length = len / 4; + + for (i = 0; i < length; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1; j < 4; j++) { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + CRC = fw_data ^ CRC; + for (j = 0; j < 32; j++) { + if ((CRC % 2) != 0) + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + else + CRC = (((CRC >> 1) & 0x7FFFFFFF)); + } + } + + return CRC; +} + +static uint32_t himax_mcu_check_CRC(uint8_t *start_addr, int reload_length) +{ + uint32_t result = 0; + uint8_t tmp_data[DATA_LEN_4]; + int cnt = 0, ret = 0; + int length = reload_length / DATA_LEN_4; + + ret = g_core_fp.fp_register_write(pfw_op->addr_reload_addr_from, + start_addr, DATA_LEN_4); + if (ret < NO_ERR) { + E("%s: bus access fail!\n", __func__); + return HW_CRC_FAIL; + } + + tmp_data[3] = 0x00; + tmp_data[2] = 0x99; + tmp_data[1] = (length >> 8); + tmp_data[0] = length; + ret = g_core_fp.fp_register_write(pfw_op->addr_reload_addr_cmd_beat, + tmp_data, DATA_LEN_4); + if (ret < NO_ERR) { + E("%s: bus access fail!\n", __func__); + return HW_CRC_FAIL; + } + cnt = 0; + + do { + ret = g_core_fp.fp_register_read(pfw_op->addr_reload_status, + tmp_data, DATA_LEN_4); + if (ret < NO_ERR) { + E("%s: bus access fail!\n", __func__); + return HW_CRC_FAIL; + } + + if ((tmp_data[0] & 0x01) != 0x01) { + ret = g_core_fp.fp_register_read( + pfw_op->addr_reload_crc32_result, tmp_data, + DATA_LEN_4); + if (ret < NO_ERR) { + E("%s: bus access fail!\n", __func__); + return HW_CRC_FAIL; + } + I("%s:data[3]=%X,data[2]=%X,data[1]=%X,data[0]=%X\n", + __func__, + tmp_data[3], + tmp_data[2], + tmp_data[1], + tmp_data[0]); + result = ((tmp_data[3] << 24) + + (tmp_data[2] << 16) + + (tmp_data[1] << 8) + + tmp_data[0]); + goto END; + } else { + I("Waiting for HW ready!\n"); + usleep_range(1000, 1100); + if (cnt >= 100) + g_core_fp.fp_read_FW_status(); + } + + } while (cnt++ < 100); +END: + return result; +} + +static void himax_mcu_set_reload_cmd(uint8_t *write_data, int idx, + uint32_t cmd_from, uint32_t cmd_to, uint32_t cmd_beat) +{ + int index = idx * 12; + int i; + + for (i = 3; i >= 0; i--) { + write_data[index + i] = (cmd_from >> (8 * i)); + write_data[index + 4 + i] = (cmd_to >> (8 * i)); + write_data[index + 8 + i] = (cmd_beat >> (8 * i)); + } +} + +static bool himax_mcu_program_reload(void) +{ + return true; +} + +#if defined(HX_ULTRA_LOW_POWER) +static int himax_mcu_ulpm_in(void) +{ + uint8_t tmp_data[4]; + int rtimes = 0; + int ret = 0; + + I("%s:entering\n", __func__); + + /* 34 -> 11 */ + do { + if (rtimes > 10) { + I("%s:1/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_34[0], + pfw_op->data_ulpm_11, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_34[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x34,correct 0x11=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_11[0]); + + rtimes = 0; + /* 34 -> 11 */ + do { + if (rtimes > 10) { + I("%s:2/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_34[0], + pfw_op->data_ulpm_11, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_34[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x34,correct 0x11=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_11[0]); + + /* 33 -> 33 */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:3/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_33, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33,correct 0x33=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_33[0]); + + /* 34 -> 22 */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:4/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_34[0], + pfw_op->data_ulpm_22, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_34[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x34,correct 0x22=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_22[0]); + + /* 33 -> AA */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:5/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_aa, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33, correct 0xAA=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_aa[0]); + + /* 33 -> 33 */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:6/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_33, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33,correct 0x33=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_33[0]); + + /* 33 -> AA */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:7/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_aa, 1); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33,correct 0xAA=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_aa[0]); + + I("%s:END\n", __func__); + return true; +} + +static int himax_mcu_black_gest_ctrl(bool enable) +{ + int ret = 0; + + I("%s:enable=%d, ts->is_suspended=%d\n", __func__, + enable, private_ts->suspended); + + if (private_ts->suspended) { + if (enable) { +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + I("%s: Please enable TP reset define\n", __func__); +#endif + } else { + g_core_fp.fp_ulpm_in(); + } + } else { + g_core_fp.fp_sense_on(0); + } + return ret; +} +#endif + +static void himax_mcu_set_SMWP_enable(uint8_t SMWP_enable, bool suspended) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + do { + if (SMWP_enable) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_smwp_enable, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_smwp_enable, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + } + + g_core_fp.fp_register_read(pfw_op->addr_smwp_enable, tmp_data, + DATA_LEN_4); + /*I("%s: tmp_data[0]=%d, SMWP_enable=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],SMWP_enable,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void himax_mcu_set_HSEN_enable(uint8_t HSEN_enable, bool suspended) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + do { + if (HSEN_enable) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_hsen_enable, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + + g_core_fp.fp_register_write(pfw_op->addr_hsen_enable, + tmp_data, DATA_LEN_4); + + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + } + + g_core_fp.fp_register_read(pfw_op->addr_hsen_enable, tmp_data, + DATA_LEN_4); + /*I("%s: tmp_data[0]=%d, HSEN_enable=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],HSEN_enable,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void himax_mcu_usb_detect_set(uint8_t *cable_config) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + do { + if (cable_config[1] == 0x01) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_usb_detect, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + I("%s: USB detect status IN!\n", __func__); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_usb_detect, + tmp_data, DATA_LEN_4); + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + I("%s: USB detect status OUT!\n", __func__); + } + + g_core_fp.fp_register_read(pfw_op->addr_usb_detect, tmp_data, + DATA_LEN_4); + /*I("%s: tmp_data[0]=%d, USB detect=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],cable_config[1] ,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +#define PRT_DATA "%s:[3]=0x%2X, [2]=0x%2X, [1]=0x%2X, [0]=0x%2X\n" +static void himax_mcu_diag_register_set(uint8_t diag_command, + uint8_t storage_type, bool is_dirly) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t cnt = 50; + + if (diag_command > 0 && storage_type % 8 > 0 && !is_dirly) + tmp_data[0] = diag_command + 0x08; + else + tmp_data[0] = diag_command; + I("diag_command = %d, tmp_data[0] = %X\n", diag_command, tmp_data[0]); + g_core_fp.fp_interface_on(); + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; + do { + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + tmp_data, DATA_LEN_4); + g_core_fp.fp_register_read(pfw_op->addr_raw_out_sel, back_data, + DATA_LEN_4); + I(PRT_DATA, __func__, + back_data[3], + back_data[2], + back_data[1], + back_data[0]); + cnt--; + } while (tmp_data[0] != back_data[0] && cnt > 0); +} + +static int himax_mcu_chip_self_test(struct seq_file *s, void *v) +{ + uint8_t tmp_data[FLASH_WRITE_BURST_SZ]; + uint8_t self_test_info[20]; + int pf_value = 0x00; + uint8_t test_result_id = 0; + int i; + + memset(tmp_data, 0x00, sizeof(tmp_data)); + g_core_fp.fp_interface_on(); + g_core_fp.fp_sense_off(true); + g_core_fp.fp_burst_enable(1); + g_core_fp.fp_register_write(pfw_op->addr_selftest_addr_en, + pfw_op->data_selftest_request, DATA_LEN_4); + /*Set criteria 0x10007F1C [0,1]=aa/up,down=, [2-3]=key/up,down, + * [4-5]=avg/up,down + */ + tmp_data[0] = pfw_op->data_criteria_aa_top[0]; + tmp_data[1] = pfw_op->data_criteria_aa_bot[0]; + tmp_data[2] = pfw_op->data_criteria_key_top[0]; + tmp_data[3] = pfw_op->data_criteria_key_bot[0]; + tmp_data[4] = pfw_op->data_criteria_avg_top[0]; + tmp_data[5] = pfw_op->data_criteria_avg_bot[0]; + tmp_data[6] = 0x00; + tmp_data[7] = 0x00; + g_core_fp.fp_register_write(pfw_op->addr_criteria_addr, + tmp_data, FLASH_WRITE_BURST_SZ); + g_core_fp.fp_register_write(pfw_op->addr_set_frame_addr, + pfw_op->data_set_frame, DATA_LEN_4); + /*Disable IDLE Mode*/ + g_core_fp.fp_idle_mode(1); + /*Diable Flash Reload*/ + g_core_fp.fp_reload_disable(1); + /*start selftest // leave safe mode*/ + g_core_fp.fp_sense_on(0x01); + + /*Hand shaking*/ + for (i = 0; i < 1000; i++) { + g_core_fp.fp_register_read(pfw_op->addr_selftest_addr_en, + tmp_data, 4); + I("%s:data0=0x%2X,data1=0x%2X,data2=0x%2X,data3=0x%2X cnt=%d\n", + __func__, + tmp_data[0], + tmp_data[1], + tmp_data[2], + tmp_data[3], + i); + usleep_range(10000, 11000); + + if (tmp_data[1] == pfw_op->data_selftest_ack_hb[0] + && tmp_data[0] == pfw_op->data_selftest_ack_lb[0]) { + I("%s Data ready goto moving data\n", __func__); + break; + } + } + + g_core_fp.fp_sense_off(true); + msleep(20); + /** + * Read test result ==> bit[2][1][0] = [key][AA][avg] => 0xF = PASS + */ + g_core_fp.fp_register_read(pfw_op->addr_selftest_result_addr, + self_test_info, 20); + test_result_id = self_test_info[0]; + I("%s: check test result, test_result_id=%x, test_result=%x\n", + __func__, test_result_id, self_test_info[0]); + I("raw top 1 = %d\n", self_test_info[3] * 256 + self_test_info[2]); + I("raw top 2 = %d\n", self_test_info[5] * 256 + self_test_info[4]); + I("raw top 3 = %d\n", self_test_info[7] * 256 + self_test_info[6]); + I("raw last 1 = %d\n", self_test_info[9] * 256 + self_test_info[8]); + I("raw last 2 = %d\n", self_test_info[11] * 256 + self_test_info[10]); + I("raw last 3 = %d\n", self_test_info[13] * 256 + self_test_info[12]); + I("raw key 1 = %d\n", self_test_info[15] * 256 + self_test_info[14]); + I("raw key 2 = %d\n", self_test_info[17] * 256 + self_test_info[16]); + I("raw key 3 = %d\n", self_test_info[19] * 256 + self_test_info[18]); + + if (test_result_id == pfw_op->data_selftest_pass[0]) { + I("[Himax]: self-test pass\n"); + seq_puts(s, "Self_Test Pass:\n"); + pf_value = 0x0; + } else { + E("[Himax]: self-test fail\n"); + seq_puts(s, "Self_Test Fail:\n"); + /* E("[Himax]: bank_avg = %d, bank_max = %d,%d,%d, bank_min = + * %d,%d,%d, key = %d,%d,%d\n", + * tmp_data[1], tmp_data[2], + * tmp_data[3], tmp_data[4], + * tmp_data[5], tmp_data[6], + * tmp_data[7], tmp_data[8], + * tmp_data[9], tmp_data[10]); + */ + pf_value = 0x1; + } + + /*Enable IDLE Mode*/ + g_core_fp.fp_idle_mode(0); +#if !defined(HX_ZERO_FLASH) + /* Enable Flash Reload //recovery*/ + g_core_fp.fp_reload_disable(0); +#endif + g_core_fp.fp_sense_on(0x00); + msleep(120); + + return pf_value; +} + +#define PRT_TMP_DATA "%s:[0]=0x%2X,[1]=0x%2X, [2]=0x%2X,[3]=0x%2X\n" +static void himax_mcu_idle_mode(int disable) +{ + int retry = 20; + uint8_t tmp_data[DATA_LEN_4]; + uint8_t switch_cmd = 0x00; + + I("%s:entering\n", __func__); + + do { + I("%s,now %d times!\n", __func__, retry); + g_core_fp.fp_register_read(pfw_op->addr_fw_mode_status, + tmp_data, DATA_LEN_4); + + if (disable) + switch_cmd = pfw_op->data_idle_dis_pwd[0]; + else + switch_cmd = pfw_op->data_idle_en_pwd[0]; + + tmp_data[0] = switch_cmd; + g_core_fp.fp_register_write(pfw_op->addr_fw_mode_status, + tmp_data, DATA_LEN_4); + g_core_fp.fp_register_read(pfw_op->addr_fw_mode_status, + tmp_data, DATA_LEN_4); + + I(PRT_TMP_DATA, + __func__, + tmp_data[0], + tmp_data[1], + tmp_data[2], + tmp_data[3]); + + retry--; + usleep_range(10000, 11000); + } while ((tmp_data[0] != switch_cmd) && retry > 0); + + I("%s: setting OK!\n", __func__); +} + +static void himax_mcu_reload_disable(int disable) +{ + I("%s:entering\n", __func__); + + if (disable) { /*reload disable*/ + g_core_fp.fp_register_write( + pdriver_op->addr_fw_define_flash_reload, + pdriver_op->data_fw_define_flash_reload_dis, + DATA_LEN_4); + } else { /*reload enable*/ + g_core_fp.fp_register_write( + pdriver_op->addr_fw_define_flash_reload, + pdriver_op->data_fw_define_flash_reload_en, + DATA_LEN_4); + } + + I("%s: setting OK!\n", __func__); +} + +static bool himax_mcu_check_chip_version(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t ret_data = false; + int i = 0; + + for (i = 0; i < 5; i++) { + g_core_fp.fp_register_read(pfw_op->addr_icid_addr, tmp_data, + DATA_LEN_4); + I("%s:Read driver IC ID = %X,%X,%X\n", __func__, + tmp_data[3], tmp_data[2], tmp_data[1]); + + if ((tmp_data[3] == 0x83) + && (tmp_data[2] == 0x10) + && (tmp_data[1] == 0x2a)) { + strlcpy(private_ts->chip_name, + HX_83102A_SERIES_PWON, 30); + ret_data = true; + goto END; + } else { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + } + } +END: + return ret_data; +} + +static int himax_mcu_read_ic_trigger_type(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + int trigger_type = false; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_int_is_edge, + tmp_data, DATA_LEN_4); + + if ((tmp_data[1] & 0x01) == 1) + trigger_type = true; + + return trigger_type; +} + +static int himax_mcu_read_i2c_status(void) +{ + return i2c_error_count; +} + +/* Please call this function after FW finish reload done */ +static void himax_mcu_read_FW_ver(void) +{ + uint8_t data[12] = {0}; + + g_core_fp.fp_register_read(pfw_op->addr_fw_ver_addr, data, DATA_LEN_4); + ic_data->vendor_panel_ver = data[0]; + ic_data->vendor_fw_ver = data[1] << 8 | data[2]; + I("PANEL_VER : %X\n", ic_data->vendor_panel_ver); + I("FW_VER : %X\n", ic_data->vendor_fw_ver); + g_core_fp.fp_register_read(pfw_op->addr_fw_cfg_addr, data, DATA_LEN_4); + ic_data->vendor_config_ver = data[2] << 8 | data[3]; + /*I("CFG_VER : %X\n",ic_data->vendor_config_ver);*/ + ic_data->vendor_touch_cfg_ver = data[2]; + I("TOUCH_VER : %X\n", ic_data->vendor_touch_cfg_ver); + ic_data->vendor_display_cfg_ver = data[3]; + I("DISPLAY_VER : %X\n", ic_data->vendor_display_cfg_ver); + g_core_fp.fp_register_read(pfw_op->addr_fw_vendor_addr, data, + DATA_LEN_4); + ic_data->vendor_cid_maj_ver = data[2]; + ic_data->vendor_cid_min_ver = data[3]; + I("CID_VER : %X\n", (ic_data->vendor_cid_maj_ver << 8 + | ic_data->vendor_cid_min_ver)); + g_core_fp.fp_register_read(pfw_op->addr_cus_info, data, 12); + memcpy(ic_data->vendor_cus_info, data, 12); + I("Cusomer ID = %s\n", ic_data->vendor_cus_info); + g_core_fp.fp_register_read(pfw_op->addr_proj_info, data, 12); + memcpy(ic_data->vendor_proj_info, data, 12); + I("Project ID = %s\n", ic_data->vendor_proj_info); +} + +static bool himax_mcu_read_event_stack(uint8_t *buf, uint8_t length) +{ +#if defined(KERNEL_VER_ABOVE_5_10) + struct timespec64 t_start, t_end, t_delta; +#else + struct timespec t_start, t_end, t_delta; +#endif + uint8_t cmd[DATA_LEN_4]; + int len = length; + int i2c_speed = 0; + int ret = 0; + + /* AHB_I2C Burst Read Off */ + cmd[0] = pfw_op->data_ahb_dis[0]; + + ret = himax_bus_write(pfw_op->addr_ahb_addr[0], cmd, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return 0; + } + if (private_ts->debug_log_level & BIT(2)) +#if defined(KERNEL_VER_ABOVE_5_10) + ktime_get_ts64(&t_start); +#else + getnstimeofday(&t_start); +#endif + + himax_bus_read(pfw_op->addr_event_addr[0], buf, length); + + if (private_ts->debug_log_level & BIT(2)) { +#if defined(KERNEL_VER_ABOVE_5_10) + ktime_get_ts64(&t_end); +#else + getnstimeofday(&t_end); +#endif + t_delta.tv_nsec = (t_end.tv_sec * 1000000000 + t_end.tv_nsec) + - (t_start.tv_sec * 1000000000 + t_start.tv_nsec); + + i2c_speed = (len * 9 * 1000000 + / (int)t_delta.tv_nsec) * 13 / 10; + private_ts->bus_speed = (int)i2c_speed; + } + + /* AHB_I2C Burst Read On */ + cmd[0] = pfw_op->data_ahb_en[0]; + + ret = himax_bus_write(pfw_op->addr_ahb_addr[0], cmd, 1); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return 0; + } + + return 1; +} + +static void himax_mcu_return_event_stack(void) +{ + int retry = 20, i; + uint8_t tmp_data[DATA_LEN_4]; + + I("%s:entering\n", __func__); + + do { + I("now %d times!\n", retry); + + for (i = 0; i < DATA_LEN_4; i++) + tmp_data[i] = psram_op->addr_rawdata_end[i]; + + g_core_fp.fp_register_write(psram_op->addr_rawdata_addr, + tmp_data, DATA_LEN_4); + g_core_fp.fp_register_read(psram_op->addr_rawdata_addr, + tmp_data, DATA_LEN_4); + retry--; + usleep_range(10000, 11000); + } while ((tmp_data[1] != psram_op->addr_rawdata_end[1] + && tmp_data[0] != psram_op->addr_rawdata_end[0]) + && retry > 0); + + I("%s: End of setting!\n", __func__); +} + +static bool himax_mcu_calculateChecksum(bool change_iref, uint32_t size) +{ + uint32_t CRC_result = 0xFFFFFFFF; + uint8_t i; + uint8_t tmp_data[DATA_LEN_4]; + + I("%s:Now size=%d\n", __func__, size); + for (i = 0; i < DATA_LEN_4; i++) + tmp_data[i] = psram_op->addr_rawdata_end[i]; + + CRC_result = g_core_fp.fp_check_CRC(tmp_data, size); + msleep(50); + + if (CRC_result != 0) + I("%s: CRC Fail=%d\n", __func__, CRC_result); + + return (CRC_result == 0) ? true : false; +} + +static void himax_mcu_read_FW_status(void) +{ + uint8_t len = 0; + uint8_t i = 0; + uint8_t addr[4] = {0}; + uint8_t data[4] = {0}; + + len = (uint8_t)(sizeof(dbg_reg_ary)/sizeof(uint32_t)); + + for (i = 0; i < len; i++) { + himax_parse_assign_cmd(dbg_reg_ary[i], addr, 4); + g_core_fp.fp_register_read(addr, data, DATA_LEN_4); + + I("reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + dbg_reg_ary[i], data[0], data[1], data[2], data[3]); + } +} + +static void himax_mcu_irq_switch(int switch_on) +{ + if (switch_on) { + if (private_ts->use_irq) + himax_int_enable(switch_on); + else + hrtimer_start(&private_ts->timer, ktime_set(1, 0), + HRTIMER_MODE_REL); + + } else { + if (private_ts->use_irq) + himax_int_enable(switch_on); + else { + hrtimer_cancel(&private_ts->timer); + cancel_work_sync(&private_ts->work); + } + } +} + +static int himax_mcu_assign_sorting_mode(uint8_t *tmp_data) +{ + I("%s:addr: 0x%02X%02X%02X%02X, write to:0x%02X%02X%02X%02X\n", + __func__, + pfw_op->addr_sorting_mode_en[3], + pfw_op->addr_sorting_mode_en[2], + pfw_op->addr_sorting_mode_en[1], + pfw_op->addr_sorting_mode_en[0], + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + + g_core_fp.fp_register_write(pfw_op->addr_sorting_mode_en, + tmp_data, DATA_LEN_4); + + return NO_ERR; +} + +static int himax_mcu_check_sorting_mode(uint8_t *tmp_data) +{ + int ret = NO_ERR; + + ret = g_core_fp.fp_register_read(pfw_op->addr_sorting_mode_en, tmp_data, + DATA_LEN_4); + I("%s:addr: 0x%02X%02X%02X%02X, Now is:0x%02X%02X%02X%02X\n", + __func__, + pfw_op->addr_sorting_mode_en[3], + pfw_op->addr_sorting_mode_en[2], + pfw_op->addr_sorting_mode_en[1], + pfw_op->addr_sorting_mode_en[0], + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + if (tmp_data[3] == 0xFF + && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF + && tmp_data[0] == 0xFF) { + ret = BUS_FAIL; + I("%s, All 0xFF, Fail!\n", __func__); + } + + return ret; +} + +static uint8_t himax_mcu_read_DD_status(uint8_t *cmd_set, uint8_t *tmp_data) +{ + int cnt = 0; + uint8_t req_size = cmd_set[0]; + + cmd_set[3] = pfw_op->data_dd_request[0]; + g_core_fp.fp_register_write(pfw_op->addr_dd_handshak_addr, + cmd_set, DATA_LEN_4); + I("%s:cmd set[0]=0x%2X,set[1]=0x%2X,set[2]=0x%2X,set[3]=0x%2X\n", + __func__, cmd_set[0], cmd_set[1], cmd_set[2], cmd_set[3]); + + /* Doing hand shaking 0xAA -> 0xBB */ + for (cnt = 0; cnt < 100; cnt++) { + g_core_fp.fp_register_read(pfw_op->addr_dd_handshak_addr, + tmp_data, DATA_LEN_4); + usleep_range(10000, 11000); + + if (tmp_data[3] == pfw_op->data_dd_ack[0]) { + I("%s Data ready goto moving data\n", __func__); + goto FINALIZE; + } else { + if (cnt >= 99) { + I("%s Data not ready in FW\n", __func__); + return FW_NOT_READY; + } + } + } +FINALIZE: + g_core_fp.fp_register_read(pfw_op->addr_dd_data_addr, tmp_data, + req_size); + return NO_ERR; +} +static void hx_clr_fw_reord_dd_sts(void) +{ + uint8_t tmp_data[DATA_LEN_4] = {0}; + + g_core_fp.fp_register_read(pic_op->addr_cs_central_state, tmp_data, + ADDR_LEN_4); + I("%s: Check enter_save_mode data[0]=%02X\n", __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + I("%s: Enter safe mode, OK!\n", __func__); + } else { + E("%s: It doen't enter safe mode, please check it again\n", + __func__); + return; + } + g_core_fp.fp_register_read(pfw_op->addr_clr_fw_record_dd_sts, tmp_data, + DATA_LEN_4); + I("%s,Before Write :Now 10007FCC=0x%02X%02X%02X%02X\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + usleep_range(10000, 10001); + + tmp_data[2] = 0x00; + tmp_data[3] = 0x00; + g_core_fp.fp_register_write(pfw_op->addr_clr_fw_record_dd_sts, + tmp_data, DATA_LEN_4); + usleep_range(10000, 10001); + + g_core_fp.fp_register_read(pfw_op->addr_clr_fw_record_dd_sts, tmp_data, + DATA_LEN_4); + I("%s,After Write :Now 10007FCC=0x%02X%02X%02X%02X\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + +} + +static void hx_ap_notify_fw_sus(int suspend) +{ + int retry = 0; + int read_sts = 0; + uint8_t read_tmp[DATA_LEN_4] = {0}; + uint8_t addr_tmp[DATA_LEN_4] = {0}; + uint8_t data_tmp[DATA_LEN_4] = {0}; + + Arr4_to_Arr4(addr_tmp, pfw_op->addr_ap_notify_fw_sus); + + if (suspend) { + I("%s,Suspend mode!\n", __func__); + Arr4_to_Arr4(data_tmp, pfw_op->data_ap_notify_fw_sus_en); + } else { + I("%s,NonSuspend mode!\n", __func__); + Arr4_to_Arr4(data_tmp, pfw_op->data_ap_notify_fw_sus_dis); + } + + I("%s: R%02X%02X%02X%02XH<-0x%02X%02X%02X%02X\n", + __func__, + addr_tmp[3], addr_tmp[2], addr_tmp[1], addr_tmp[0], + data_tmp[3], data_tmp[2], data_tmp[1], data_tmp[0]); + do { + g_core_fp.fp_register_write(addr_tmp, data_tmp, + sizeof(data_tmp)); + usleep_range(1000, 1001); + read_sts = g_core_fp.fp_register_read(addr_tmp, read_tmp, + sizeof(read_tmp)); + I("%s: read bus status=%d\n", __func__, read_sts); + I("%s: Now retry=%d, data=0x%02X%02X%02X%02X\n", + __func__, retry, + read_tmp[3], read_tmp[2], read_tmp[1], read_tmp[0]); + } while ((retry++ < 10) && (read_sts != NO_ERR) && + (read_tmp[3] != data_tmp[3] && read_tmp[2] != data_tmp[2] && + read_tmp[1] != data_tmp[1] && read_tmp[0] != data_tmp[0])); +} +/* FW side end*/ +/* CORE_FW */ + +/* CORE_FLASH */ +/* FLASH side start*/ +static void himax_mcu_chip_erase(void) +{ + g_core_fp.fp_interface_on(); + + /* Reset power saving level */ + if (g_core_fp.fp_init_psl != NULL) + g_core_fp.fp_init_psl(); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + pflash_op->data_spi200_trans_fmt, DATA_LEN_4); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + pflash_op->data_spi200_trans_ctrl_2, DATA_LEN_4); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_2, DATA_LEN_4); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_3, DATA_LEN_4); + msleep(2000); + + if (!g_core_fp.fp_wait_wip(100)) + E("%s: Chip_Erase Fail\n", __func__); + +} + +static bool himax_mcu_block_erase(int start_addr, int length) +{ + uint32_t page_prog_start = 0; + uint32_t block_size = 0x10000; + + uint8_t tmp_data[4] = {0}; + + g_core_fp.fp_interface_on(); + + g_core_fp.fp_init_psl(); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + pflash_op->data_spi200_trans_fmt, DATA_LEN_4); + + for (page_prog_start = start_addr; + page_prog_start < start_addr + length; + page_prog_start = page_prog_start + block_size) { + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + pflash_op->data_spi200_trans_ctrl_2, DATA_LEN_4); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_2, DATA_LEN_4); + + tmp_data[3] = (page_prog_start >> 24)&0xFF; + tmp_data[2] = (page_prog_start >> 16)&0xFF; + tmp_data[1] = (page_prog_start >> 8)&0xFF; + tmp_data[0] = page_prog_start&0xFF; + g_core_fp.fp_register_write(pflash_op->addr_spi200_addr, + tmp_data, DATA_LEN_4); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + pflash_op->data_spi200_trans_ctrl_3, DATA_LEN_4); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_4, DATA_LEN_4); + msleep(1000); + + if (!g_core_fp.fp_wait_wip(100)) { + E("%s:Erase Fail\n", __func__); + return false; + } + } + + I("%s:END\n", __func__); + return true; +} + +static bool himax_mcu_sector_erase(int start_addr) +{ + return true; +} + +static void himax_mcu_flash_programming(uint8_t *FW_content, int FW_Size) +{ + int page_prog_start = 0, i = 0, j = 0, k = 0; + int program_length = PROGRAM_SZ; + uint8_t tmp_data[DATA_LEN_4]; + uint8_t buring_data[FLASH_RW_MAX_LEN]; + int ret = 0; + /* 4 bytes for padding*/ + g_core_fp.fp_interface_on(); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + pflash_op->data_spi200_trans_fmt, DATA_LEN_4); + + for (page_prog_start = 0; page_prog_start < FW_Size; + page_prog_start += FLASH_RW_MAX_LEN) { + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + pflash_op->data_spi200_trans_ctrl_2, DATA_LEN_4); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_2, DATA_LEN_4); + + /*Programmable size = 1 page = 256 bytes,*/ + /*word_number = 256 byte / 4 = 64*/ + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + pflash_op->data_spi200_trans_ctrl_4, DATA_LEN_4); + + /* Flash start address 1st : 0x0000_0000*/ + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + g_core_fp.fp_register_write(pflash_op->addr_spi200_addr, + tmp_data, DATA_LEN_4); + + for (i = 0; i < ADDR_LEN_4; i++) + buring_data[i] = pflash_op->addr_spi200_data[i]; + + for (i = page_prog_start, j = 0; + i < 16 + page_prog_start; + i++, j++) { + buring_data[j + ADDR_LEN_4] = FW_content[i]; + } + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], + buring_data, ADDR_LEN_4 + 16); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } + + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + pflash_op->data_spi200_cmd_6, DATA_LEN_4); + + for (j = 0; j < 5; j++) { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; + i < (page_prog_start + 16 + (j * 48)) + program_length; + i++, k++) + buring_data[k + ADDR_LEN_4] = FW_content[i]; + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], + buring_data, program_length + ADDR_LEN_4); + if (ret < 0) { + E("%s: bus access fail!\n", __func__); + return; + } + } + + if (!g_core_fp.fp_wait_wip(1)) + E("%s:Flash_Programming Fail\n", __func__); + + } +} + +static void himax_mcu_flash_page_write(uint8_t *write_addr, int length, + uint8_t *write_data) +{ +} + +static void himax_flash_speed_set(uint8_t speed) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_parse_assign_cmd(flash_clk_setup_addr, tmp_addr, 4); + himax_parse_assign_cmd((uint32_t)speed, tmp_data, 4); + g_core_fp.fp_register_write(tmp_addr, tmp_data, 4); +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_32k(unsigned char *fw, + int len, bool change_iref) +{ + /* Not use */ + return 0; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_60k(unsigned char *fw, + int len, bool change_iref) +{ + /* Not use */ + return 0; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_64k(unsigned char *fw, + int len, bool change_iref) +{ + int burnFW_success = 0; + + if (len != FW_SIZE_64k) { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + g_core_fp.fp_sense_off(true); + himax_flash_speed_set(HX_FLASH_SPEED_12p5M); + g_core_fp.fp_block_erase(0x00, FW_SIZE_64k); + g_core_fp.fp_flash_programming(fw, FW_SIZE_64k); + + if (g_core_fp.fp_check_CRC(pfw_op->addr_program_reload_from, + FW_SIZE_64k) == 0) + burnFW_success = 1; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + /*System reset*/ + g_core_fp.fp_system_reset(); +#endif + return burnFW_success; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_124k(unsigned char *fw, + int len, bool change_iref) +{ + /* Not use */ + return 0; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k(unsigned char *fw, + int len, bool change_iref) +{ + int burnFW_success = 0; + + if (len != FW_SIZE_128k) { + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + g_core_fp.fp_sense_off(true); + himax_flash_speed_set(HX_FLASH_SPEED_12p5M); + g_core_fp.fp_block_erase(0x00, FW_SIZE_128k); + g_core_fp.fp_flash_programming(fw, FW_SIZE_128k); + + if (g_core_fp.fp_check_CRC(pfw_op->addr_program_reload_from, + FW_SIZE_128k) == 0) + burnFW_success = 1; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + +/*#if defined(HX_RST_PIN_FUNC) + * g_core_fp.fp_ic_reset(false, false); + *#else + * //System reset + * g_core_fp.fp_system_reset(); + *#endif + */ + return burnFW_success; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_255k(unsigned char *fw, + int len, bool change_iref) +{ + int burnFW_success = 0; + + if (len != FW_SIZE_255k) { + E("%s: The file size is not 255K bytes\n", __func__); + return false; + } + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + g_core_fp.fp_sense_off(true); + himax_flash_speed_set(HX_FLASH_SPEED_12p5M); + g_core_fp.fp_block_erase(0x00, FW_SIZE_255k); + g_core_fp.fp_flash_programming(fw, FW_SIZE_255k); + + if (g_core_fp.fp_check_CRC(pfw_op->addr_program_reload_from, + FW_SIZE_255k) == 0) + burnFW_success = 1; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + +/*#if defined(HX_RST_PIN_FUNC) + * g_core_fp.fp_ic_reset(false, false); + *#else + * //System reset + * g_core_fp.fp_system_reset(); + *#endif + */ + return burnFW_success; +} + +static void himax_mcu_flash_dump_func(uint8_t local_flash_command, + int Flash_Size, uint8_t *flash_buffer) +{ + uint8_t tmp_addr[DATA_LEN_4]; + uint8_t buffer[256]; + int page_prog_start = 0; + + g_core_fp.fp_sense_off(true); + g_core_fp.fp_burst_enable(1); + + for (page_prog_start = 0; page_prog_start < Flash_Size; + page_prog_start += 128) { + tmp_addr[0] = page_prog_start % 0x100; + tmp_addr[1] = (page_prog_start >> 8) % 0x100; + tmp_addr[2] = (page_prog_start >> 16) % 0x100; + tmp_addr[3] = page_prog_start / 0x1000000; + himax_mcu_register_read(tmp_addr, buffer, 128); + memcpy(&flash_buffer[page_prog_start], buffer, 128); + } + + g_core_fp.fp_burst_enable(0); + + g_core_fp.fp_sense_on(0x01); +} + +static bool himax_mcu_flash_lastdata_check(uint32_t size) +{ + uint8_t tmp_addr[4]; + /* 64K - 0x80, which is the address of + * the last 128bytes in 64K, default value + */ + uint32_t start_addr = 0xFFFFFFFF; + uint32_t temp_addr = 0; + uint32_t flash_page_len = 0x80; + uint8_t flash_tmp_buffer[128]; + + if (size < flash_page_len) { + E("%s: flash size is wrong, terminated\n", __func__); + E("%s: flash size = %08X; flash page len = %08X\n", __func__, + size, flash_page_len); + goto FAIL; + } + + /* In order to match other size of fw */ + start_addr = size - flash_page_len; + I("%s: Now size is %d, the start_addr is 0x%08X\n", + __func__, size, start_addr); + for (temp_addr = start_addr; temp_addr < (start_addr + flash_page_len); + temp_addr = temp_addr + flash_page_len) { + /*I("temp_addr=%d,tmp_addr[0]=0x%2X, tmp_addr[1]=0x%2X, + * tmp_addr[2]=0x%2X,tmp_addr[3]=0x%2X\n", + * temp_addr,tmp_addr[0], tmp_addr[1], + * tmp_addr[2],tmp_addr[3]); + */ + tmp_addr[0] = temp_addr % 0x100; + tmp_addr[1] = (temp_addr >> 8) % 0x100; + tmp_addr[2] = (temp_addr >> 16) % 0x100; + tmp_addr[3] = temp_addr / 0x1000000; + g_core_fp.fp_register_read(tmp_addr, &flash_tmp_buffer[0], + flash_page_len); + } + + I("FLASH[%08X] ~ FLASH[%08X] = %02X%02X%02X%02X\n", size-4, size-1, + flash_tmp_buffer[flash_page_len-4], + flash_tmp_buffer[flash_page_len-3], + flash_tmp_buffer[flash_page_len-2], + flash_tmp_buffer[flash_page_len-1]); + + if ((!flash_tmp_buffer[flash_page_len-4]) + && (!flash_tmp_buffer[flash_page_len-3]) + && (!flash_tmp_buffer[flash_page_len-2]) + && (!flash_tmp_buffer[flash_page_len-1])) { + I("Fail, Last four Bytes are all 0x00:\n"); + goto FAIL; + } else if ((flash_tmp_buffer[flash_page_len-4] == 0xFF) + && (flash_tmp_buffer[flash_page_len-3] == 0xFF) + && (flash_tmp_buffer[flash_page_len-2] == 0xFF) + && (flash_tmp_buffer[flash_page_len-1] == 0xFF)) { + I("Fail, Last four Bytes are all 0xFF:\n"); + goto FAIL; + } else { + return 0; + } + +FAIL: + return 1; +} + +static bool hx_bin_desc_data_get(uint32_t addr, uint8_t *flash_buf) +{ + uint8_t data_sz = 0x10; + uint32_t i = 0, j = 0; + uint16_t chk_end = 0; + uint16_t chk_sum = 0; + uint32_t map_code = 0; + unsigned long flash_addr = 0; + + for (i = 0; i < FW_PAGE_SZ; i = i + data_sz) { + for (j = i; j < (i + data_sz); j++) { + chk_end |= flash_buf[j]; + chk_sum += flash_buf[j]; + } + if (!chk_end) { /*1. Check all zero*/ + I("%s: End in %X\n", __func__, i + addr); + return false; + } else if (chk_sum % 0x100) { /*2. Check sum*/ + I("%s: chk sum failed in %X\n", __func__, i + addr); + } else { /*3. get data*/ + map_code = flash_buf[i] + (flash_buf[i + 1] << 8) + + (flash_buf[i + 2] << 16) + (flash_buf[i + 3] << 24); + flash_addr = flash_buf[i + 4] + (flash_buf[i + 5] << 8) + + (flash_buf[i + 6] << 16) + (flash_buf[i + 7] << 24); + switch (map_code) { + case FW_CID: + CID_VER_MAJ_FLASH_ADDR = flash_addr; + CID_VER_MIN_FLASH_ADDR = flash_addr + 1; + I("%s: CID_VER in %lX\n", __func__, + CID_VER_MAJ_FLASH_ADDR); + break; + case FW_VER: + FW_VER_MAJ_FLASH_ADDR = flash_addr; + FW_VER_MIN_FLASH_ADDR = flash_addr + 1; + I("%s: FW_VER in %lX\n", __func__, + FW_VER_MAJ_FLASH_ADDR); + break; + case CFG_VER: + CFG_VER_MAJ_FLASH_ADDR = flash_addr; + CFG_VER_MIN_FLASH_ADDR = flash_addr + 1; + I("%s: CFG_VER in = %08lX\n", __func__, + CFG_VER_MAJ_FLASH_ADDR); + break; + case TP_CONFIG_TABLE: + CFG_TABLE_FLASH_ADDR = flash_addr; + I("%s: CONFIG_TABLE in %X\n", + __func__, CFG_TABLE_FLASH_ADDR); + break; + } + } + chk_end = 0; + chk_sum = 0; + } + + return true; +} + +static bool hx_mcu_bin_desc_get(unsigned char *fw, uint32_t max_sz) +{ + uint32_t addr_t = 0; + unsigned char *fw_buf = NULL; + bool keep_on_flag = false; + bool g_bin_desc_flag = false; + + do { + fw_buf = &fw[addr_t]; + + /*Check bin is with description table or not*/ + if (!g_bin_desc_flag) { + if (fw_buf[0x00] == 0x00 && fw_buf[0x01] == 0x00 + && fw_buf[0x02] == 0x00 && fw_buf[0x03] == 0x00 + && fw_buf[0x04] == 0x00 && fw_buf[0x05] == 0x00 + && fw_buf[0x06] == 0x00 && fw_buf[0x07] == 0x00 + && fw_buf[0x0E] == 0x87) + g_bin_desc_flag = true; + } + if (!g_bin_desc_flag) { + I("%s: fw_buf[0x00] = %2X, fw_buf[0x0E] = %2X\n", + __func__, fw_buf[0x00], fw_buf[0x0E]); + I("%s: No description table\n", __func__); + break; + } + + /*Get related data*/ + keep_on_flag = hx_bin_desc_data_get(addr_t, fw_buf); + + addr_t = addr_t + FW_PAGE_SZ; + } while (max_sz > addr_t && keep_on_flag); + + return g_bin_desc_flag; +} + +static int hx_mcu_diff_overlay_flash(void) +{ + int rslt = 0; + int diff_val = 0; + + diff_val = (ic_data->vendor_fw_ver); + I("%s:Now fw ID is 0x%04X\n", __func__, diff_val); + diff_val = (diff_val >> 12); + I("%s:Now diff value=0x%04X\n", __func__, diff_val); + + if (diff_val == 1) + I("%s:Now size should be 128K!\n", __func__); + else + I("%s:Now size should be 64K!\n", __func__); + rslt = diff_val; + return rslt; +} + +/* FLASH side end*/ +/* CORE_FLASH */ + +/* CORE_SRAM */ +/* SRAM side start*/ +static void himax_mcu_sram_write(uint8_t *FW_content) +{ +} + +static bool himax_mcu_sram_verify(uint8_t *FW_File, int FW_Size) +{ + return true; +} + +static bool himax_mcu_get_DSRAM_data(uint8_t *info_data, bool DSRAM_Flag) +{ + unsigned int i = 0; + unsigned char tmp_addr[ADDR_LEN_4]; + unsigned char tmp_data[DATA_LEN_4]; + unsigned int max_bus_size = MAX_I2C_TRANS_SZ; + uint8_t x_num = ic_data->HX_RX_NUM; + uint8_t y_num = ic_data->HX_TX_NUM; + /*int m_key_num = 0;*/ + unsigned int total_size = (x_num * y_num + x_num + y_num) * 2 + 4; + unsigned int data_size = (x_num * y_num + x_num + y_num) * 2; + unsigned int remain_size; + uint8_t retry = 0; + /*int mutual_data_size = x_num * y_num * 2;*/ + unsigned int addr = 0; + uint8_t *temp_info_data = NULL; /*max mkey size = 8*/ + uint32_t checksum = 0; + int fw_run_flag = -1; + +#if defined(HX_ZERO_FLASH) + max_bus_size = HX_MAX_READ_SZ - ADDR_LEN_4; +#endif + + temp_info_data = kcalloc((total_size + 8), sizeof(uint8_t), GFP_KERNEL); + if (temp_info_data == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return false; + } + /* 1. Read number of MKey R100070E8H to determin data size */ + /* m_key_num = ic_data->HX_BT_NUM; */ + /* I("%s,m_key_num=%d\n",__func__ ,m_key_num); */ + /* total_size += m_key_num * 2; */ + + /* 2. Start DSRAM Rawdata and Wait Data Ready */ + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = psram_op->passwrd_start[1]; + tmp_data[0] = psram_op->passwrd_start[0]; + fw_run_flag = himax_write_read_reg(psram_op->addr_rawdata_addr, + tmp_data, + psram_op->passwrd_end[1], + psram_op->passwrd_end[0]); + + if (fw_run_flag < 0) { + E("%s: Data NOT ready => bypass\n", __func__); + kfree(temp_info_data); + return false; + } + + /* 3. Read RawData */ + while (retry++ < 5) { + remain_size = total_size; + while (remain_size > 0) { + + i = total_size - remain_size; + addr = sram_adr_rawdata_addr + i; + + tmp_addr[3] = (uint8_t)((addr >> 24) & 0x00FF); + tmp_addr[2] = (uint8_t)((addr >> 16) & 0x00FF); + tmp_addr[1] = (uint8_t)((addr >> 8) & 0x00FF); + tmp_addr[0] = (uint8_t)((addr) & 0x00FF); + + if (remain_size >= max_bus_size) { + g_core_fp.fp_register_read(tmp_addr, + &temp_info_data[i], max_bus_size); + remain_size -= max_bus_size; + } else { + g_core_fp.fp_register_read(tmp_addr, + &temp_info_data[i], remain_size); + remain_size = 0; + } + } + + /* 5. Data Checksum Check */ + /* 2 is meaning PASSWORD NOT included */ + checksum = 0; + for (i = 2; i < total_size; i += 2) + checksum += temp_info_data[i+1]<<8 | temp_info_data[i]; + + if (checksum % 0x10000 != 0) { + + E("%s: check_sum_cal fail=%08X\n", __func__, checksum); + + } else { + memcpy(info_data, &temp_info_data[4], + data_size * sizeof(uint8_t)); + break; + } + } + + /* 4. FW stop outputing */ + tmp_data[3] = temp_info_data[3]; + tmp_data[2] = temp_info_data[2]; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + g_core_fp.fp_register_write(psram_op->addr_rawdata_addr, tmp_data, + DATA_LEN_4); + + kfree(temp_info_data); + if (retry >= 5) + return false; + else + return true; + +} +/* SRAM side end*/ +/* CORE_SRAM */ + +/* CORE_DRIVER */ + +static void himax_mcu_init_ic(void) +{ + I("%s: use default incell init.\n", __func__); +} + +#if defined(HX_RST_PIN_FUNC) +static void himax_mcu_pin_reset(void) +{ + I("%s: Now reset the Touch chip.\n", __func__); + himax_rst_gpio_set(private_ts->rst_gpio, 0); + usleep_range(RST_LOW_PERIOD_S, RST_LOW_PERIOD_E); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + usleep_range(RST_HIGH_PERIOD_S, RST_HIGH_PERIOD_E); +} + +static void himax_mcu_ic_reset(uint8_t loadconfig, uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + + HX_HW_RESET_ACTIVATE = 0; + I("%s,status: loadconfig=%d,int_off=%d\n", __func__, + loadconfig, int_off); + + if (ts->rst_gpio >= 0) { + if (int_off) + g_core_fp.fp_irq_switch(0); + + g_core_fp.fp_pin_reset(); + + /* if (loadconfig) */ + /* g_core_fp.fp_reload_config(); */ + + if (int_off) + g_core_fp.fp_irq_switch(1); + + } +} +#endif + +static uint8_t himax_mcu_tp_info_check(void) +{ + char addr[DATA_LEN_4] = {0}; + char data[DATA_LEN_4] = {0}; + uint32_t rx_num; + uint32_t tx_num; + uint32_t bt_num; + uint32_t max_pt; + uint8_t int_is_edge; + uint8_t stylus_func; + uint8_t err_cnt = 0; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_rxnum_txnum, data, + DATA_LEN_4); + rx_num = data[2]; + tx_num = data[3]; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_maxpt_xyrvs, data, + DATA_LEN_4); + max_pt = data[0]; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_int_is_edge, data, + DATA_LEN_4); + if ((data[1] & 0x01) == 1) + int_is_edge = true; + else + int_is_edge = false; + + /*1. Read number of MKey R100070E8H to determin data size*/ + g_core_fp.fp_register_read(psram_op->addr_mkey, data, DATA_LEN_4); + bt_num = data[0] & 0x03; + + addr[3] = 0x10; + addr[2] = 0x00; + addr[1] = 0x71; + addr[0] = 0x9C; + g_core_fp.fp_register_read(addr, data, DATA_LEN_4); + stylus_func = data[3]; + + if (ic_data->HX_RX_NUM != rx_num) { + err_cnt++; + W("%s: RX_NUM, Set = %d ; FW = %d", __func__, + ic_data->HX_RX_NUM, rx_num); + } + + if (ic_data->HX_TX_NUM != tx_num) { + err_cnt++; + W("%s: TX_NUM, Set = %d ; FW = %d", __func__, + ic_data->HX_TX_NUM, tx_num); + } + + if (ic_data->HX_BT_NUM != bt_num) { + err_cnt++; + W("%s: BT_NUM, Set = %d ; FW = %d", __func__, + ic_data->HX_BT_NUM, bt_num); + } + + if (ic_data->HX_MAX_PT != max_pt) { + err_cnt++; + W("%s: MAX_PT, Set = %d ; FW = %d", __func__, + ic_data->HX_MAX_PT, max_pt); + } + + if (ic_data->HX_INT_IS_EDGE != int_is_edge) { + err_cnt++; + W("%s: INT_IS_EDGE, Set = %d ; FW = %d", __func__, + ic_data->HX_INT_IS_EDGE, int_is_edge); + } + + if (ic_data->HX_STYLUS_FUNC != stylus_func) { + err_cnt++; + W("%s: STYLUS_FUNC, Set = %d ; FW = %d", __func__, + ic_data->HX_STYLUS_FUNC, stylus_func); + } + + if (err_cnt > 0) + W("FIX_TOUCH_INFO does NOT match to FW information\n"); + else + I("FIX_TOUCH_INFO is OK\n"); + + return err_cnt; +} + +static void himax_mcu_touch_information(void) +{ + if (ic_data->HX_RX_NUM == 0xFFFFFFFF) + ic_data->HX_RX_NUM = FIX_HX_RX_NUM; + + if (ic_data->HX_TX_NUM == 0xFFFFFFFF) + ic_data->HX_TX_NUM = FIX_HX_TX_NUM; + + if (ic_data->HX_BT_NUM == 0xFFFFFFFF) + ic_data->HX_BT_NUM = FIX_HX_BT_NUM; + + if (ic_data->HX_MAX_PT == 0xFFFFFFFF) + ic_data->HX_MAX_PT = FIX_HX_MAX_PT; + + if (ic_data->HX_INT_IS_EDGE == 0xFF) + ic_data->HX_INT_IS_EDGE = FIX_HX_INT_IS_EDGE; + + if (ic_data->HX_STYLUS_FUNC == 0xFF) + ic_data->HX_STYLUS_FUNC = FIX_HX_STYLUS_FUNC; + + ic_data->HX_Y_RES = private_ts->pdata->screenHeight; + ic_data->HX_X_RES = private_ts->pdata->screenWidth; + + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d\n", __func__, + ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + I("%s:HX_MAX_PT=%d\n", __func__, ic_data->HX_MAX_PT); + I("%s:HX_Y_RES=%d,HX_X_RES =%d\n", __func__, + ic_data->HX_Y_RES, ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d,HX_STYLUS_FUNC = %d\n", __func__, + ic_data->HX_INT_IS_EDGE, ic_data->HX_STYLUS_FUNC); +} + +static void himax_mcu_calcTouchDataSize(void) +{ + struct himax_ts_data *ts_data = private_ts; + + ts_data->x_channel = ic_data->HX_RX_NUM; + ts_data->y_channel = ic_data->HX_TX_NUM; + ts_data->nFinger_support = ic_data->HX_MAX_PT; + + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4; + if ((ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += + (ic_data->HX_MAX_PT / 4) * 4; + else + HX_TOUCH_INFO_POINT_CNT += + ((ic_data->HX_MAX_PT / 4) + 1) * 4; + + if (himax_report_data_init()) + E("%s: allocate data fail\n", __func__); +} + +static int himax_mcu_get_touch_data_size(void) +{ + return HIMAX_TOUCH_DATA_SIZE; +} + +static int himax_mcu_hand_shaking(void) +{ + /* 0:Running, 1:Stop, 2:I2C Fail */ + int result = 0; + return result; +} + +static int himax_mcu_determin_diag_rawdata(int diag_command) +{ + return diag_command % 10; +} + +static int himax_mcu_determin_diag_storage(int diag_command) +{ + return diag_command / 10; +} + +static int himax_mcu_cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, + int raw_cnt_max) +{ + int RawDataLen; + /* rawdata checksum is 2 bytes */ + if (raw_cnt_rmd != 0x00) + RawDataLen = MAX_I2C_TRANS_SZ + - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 2; + else + RawDataLen = MAX_I2C_TRANS_SZ + - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 2; + + return RawDataLen; +} + +static bool himax_mcu_diag_check_sum(struct himax_report_data *hx_touch_data) +{ + uint16_t check_sum_cal = 0; + int i; + + /* Check 128th byte CRC */ + for (i = 0, check_sum_cal = 0; + i < (hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size); + i += 2) { + check_sum_cal += (hx_touch_data->hx_rawdata_buf[i + 1] + * FLASH_RW_MAX_LEN + + hx_touch_data->hx_rawdata_buf[i]); + } + + if (check_sum_cal % HX64K != 0) { + I("%s fail=%2X\n", __func__, check_sum_cal); + return 0; + } + + return 1; +} + +static void himax_mcu_diag_parse_raw_data( + struct himax_report_data *hx_touch_data, + int mul_num, int self_num, uint8_t diag_cmd, + int32_t *mutual_data, int32_t *self_data) +{ + diag_mcu_parse_raw_data(hx_touch_data, mul_num, self_num, + diag_cmd, mutual_data, self_data); +} + +#if defined(HX_EXCP_RECOVERY) +static int himax_mcu_ic_excp_recovery(uint32_t hx_excp_event, + uint32_t hx_zero_event, uint32_t length) +{ + int ret_val = NO_ERR; + + if (hx_excp_event == length) { + g_zero_event_count = 0; + ret_val = HX_EXCP_EVENT; + } else if (hx_zero_event == length) { + if (g_zero_event_count > 5) { + g_zero_event_count = 0; + I("EXCEPTION event checked - ALL Zero.\n"); + ret_val = HX_EXCP_EVENT; + } else { + g_zero_event_count++; + I("ALL Zero event is %d times.\n", + g_zero_event_count); + ret_val = HX_ZERO_EVENT_COUNT; + } + } + + return ret_val; +} + +static void himax_mcu_excp_ic_reset(void) +{ + HX_EXCP_RESET_ACTIVATE = 0; +#if defined(HX_RST_PIN_FUNC) + himax_mcu_pin_reset(); +#else + himax_mcu_system_reset(); +#endif + I("%s:\n", __func__); +} +#endif +#if defined(HX_TP_PROC_GUEST_INFO) +char *g_checksum_str = "check sum fail"; +/* char *g_guest_info_item[] = { + * "projectID", + * "CGColor", + * "BarCode", + * "Reserve1", + * "Reserve2", + * "Reserve3", + * "Reserve4", + * "Reserve5", + * "VCOM", + * "Vcom-3Gar", + * NULL + * }; + */ + +static int himax_guest_info_get_status(void) +{ + return g_guest_info_data->g_guest_info_ongoing; +} +static void himax_guest_info_set_status(int setting) +{ + g_guest_info_data->g_guest_info_ongoing = setting; +} + +static int himax_guest_info_read(uint32_t start_addr, + uint8_t *flash_tmp_buffer) +{ + uint32_t temp_addr = 0; + uint8_t tmp_addr[4]; + uint32_t flash_page_len = 0x1000; + /* uint32_t checksum = 0x00; */ + int result = -1; + + + I("%s:Reading guest info in start_addr = 0x%08X !\n", __func__, + start_addr); + + tmp_addr[0] = start_addr % 0x100; + tmp_addr[1] = (start_addr >> 8) % 0x100; + tmp_addr[2] = (start_addr >> 16) % 0x100; + tmp_addr[3] = start_addr / 0x1000000; + I("addr[0]=0x%2X,addr[1]=0x%2X,addr[2]=0x%2X,addr[3]=0x%2X\n", + tmp_addr[0], tmp_addr[1], + tmp_addr[2], tmp_addr[3]); + + result = g_core_fp.fp_check_CRC(tmp_addr, flash_page_len); + I("Checksum = 0x%8X\n", result); + if (result != 0) + goto END_FUNC; + + for (temp_addr = start_addr; + temp_addr < (start_addr + flash_page_len); + temp_addr = temp_addr + 128) { + + /* I("temp_addr=%d,tmp_addr[0]=0x%2X,tmp_addr[1]=0x%2X, + * tmp_addr[2]=0x%2X,tmp_addr[3]=0x%2X\n", + * temp_addr,tmp_addr[0],tmp_addr[1], + * tmp_addr[2],tmp_addr[3]); + */ + tmp_addr[0] = temp_addr % 0x100; + tmp_addr[1] = (temp_addr >> 8) % 0x100; + tmp_addr[2] = (temp_addr >> 16) % 0x100; + tmp_addr[3] = temp_addr / 0x1000000; + g_core_fp.fp_register_read(tmp_addr, + &flash_tmp_buffer[temp_addr - start_addr], 128); + /* memcpy(&flash_tmp_buffer[temp_addr - start_addr], + * buffer,128); + */ + } + +END_FUNC: + return result; +} + +static int hx_read_guest_info(void) +{ + /* uint8_t tmp_addr[4]; */ + uint32_t panel_info_addr = HX_GUEST_INFO_FLASH_SADDR; + + uint32_t info_len; + uint32_t flash_page_len = 0x1000;/*4k*/ + uint8_t *flash_tmp_buffer = NULL; + /* uint32_t temp_addr = 0; */ + uint8_t temp_str[128]; + int i = 0; + unsigned int custom_info_temp = 0; + int checksum = 0; + + himax_guest_info_set_status(1); + + flash_tmp_buffer = kcalloc(HX_GUEST_INFO_SIZE * flash_page_len, + sizeof(uint8_t), GFP_KERNEL); + if (flash_tmp_buffer == NULL) { + I("%s: Memory allocate fail!\n", __func__); + return MEM_ALLOC_FAIL; + } + + g_core_fp.fp_sense_off(true); + /* g_core_fp.fp_burst_enable(1); */ + + for (custom_info_temp = 0; + custom_info_temp < HX_GUEST_INFO_SIZE; + custom_info_temp++) { + checksum = himax_guest_info_read(panel_info_addr + + custom_info_temp + * flash_page_len, + &flash_tmp_buffer[custom_info_temp * flash_page_len]); + if (checksum != 0) { + E("%s:Checksum Fail! g_checksum_str len=%d\n", __func__, + (int)strlen(g_checksum_str)); + memcpy(&g_guest_info_data-> + g_guest_str_in_format[custom_info_temp][0], + g_checksum_str, (int)strlen(g_checksum_str)); + memcpy(&g_guest_info_data-> + g_guest_str[custom_info_temp][0], + g_checksum_str, (int)strlen(g_checksum_str)); + continue; + } + + info_len = flash_tmp_buffer[custom_info_temp * flash_page_len] + + (flash_tmp_buffer[custom_info_temp + * flash_page_len + 1] << 8) + + (flash_tmp_buffer[custom_info_temp + * flash_page_len + 2] << 16) + + (flash_tmp_buffer[custom_info_temp + * flash_page_len + 3] << 24); + + I("Now custom_info_temp = %d\n", custom_info_temp); + + I("Now size_buff[0]=0x%02X,[1]=0x%02X,[2]=0x%02X,[3]=0x%02X\n", + flash_tmp_buffer[custom_info_temp*flash_page_len], + flash_tmp_buffer[custom_info_temp*flash_page_len + 1], + flash_tmp_buffer[custom_info_temp*flash_page_len + 2], + flash_tmp_buffer[custom_info_temp*flash_page_len + 3]); + + I("Now total length=%d\n", info_len); + + g_guest_info_data->g_guest_data_len[custom_info_temp] = + info_len; + + I("Now custom_info_id [0]=%d,[1]=%d,[2]=%d,[3]=%d\n", + flash_tmp_buffer[custom_info_temp*flash_page_len + 4], + flash_tmp_buffer[custom_info_temp*flash_page_len + 5], + flash_tmp_buffer[custom_info_temp*flash_page_len + 6], + flash_tmp_buffer[custom_info_temp*flash_page_len + 7]); + + g_guest_info_data->g_guest_data_type[custom_info_temp] = + flash_tmp_buffer[custom_info_temp * flash_page_len + + 7]; + + /* if(custom_info_temp < 3) { */ + if (info_len > 128) { + I("%s: info_len=%d\n", __func__, info_len); + info_len = 128; + } + for (i = 0; i < info_len; i++) + temp_str[i] = flash_tmp_buffer[custom_info_temp + * flash_page_len + + HX_GUEST_INFO_LEN_SIZE + + HX_GUEST_INFO_ID_SIZE + + i]; + + I("g_guest_info_data->g_guest_str_in_format[%d]size=%d\n", + custom_info_temp, info_len); + memcpy(&g_guest_info_data-> + g_guest_str_in_format[custom_info_temp][0], + temp_str, info_len); + /*}*/ + + for (i = 0; i < 128; i++) + temp_str[i] = flash_tmp_buffer[custom_info_temp + * flash_page_len + + i]; + + I("g_guest_info_data->g_guest_str[%d] size = %d\n", + custom_info_temp, 128); + memcpy(&g_guest_info_data->g_guest_str[custom_info_temp][0], + temp_str, 128); + /*if(custom_info_temp == 0) + *{ + * for ( i = 0; i< 256 ; i++) { + * if(i % 16 == 0 && i > 0) + * I("\n"); + * I("g_guest_info_data->g_guest_str[%d][%d] + = 0x%02X", custom_info_temp, i, + g_guest_info_data->g_guest_str[ + custom_info_temp][i]); + * } + *} + */ + } + /* himax_burst_enable(private_ts->client, 0); */ + g_core_fp.fp_sense_on(0x01); + + kfree(flash_tmp_buffer); + himax_guest_info_set_status(0); + return NO_ERR; +} +#endif +/* CORE_DRIVER */ + +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) +static void himax_mcu_resend_cmd_func(bool suspended) +{ +#if defined(HX_SMART_WAKEUP) || defined(HX_HIGH_SENSE) + struct himax_ts_data *ts = private_ts; +#endif +#if defined(HX_SMART_WAKEUP) + g_core_fp.fp_set_SMWP_enable(ts->SMWP_enable, suspended); +#endif +#if defined(HX_HIGH_SENSE) + g_core_fp.fp_set_HSEN_enable(ts->HSEN_enable, suspended); +#endif +#if defined(HX_USB_DETECT_GLOBAL) + himax_cable_detect_func(true); +#endif +} +#endif + +int hx_turn_on_mp_func(int on) +{ + int rslt = 0; + int retry = 3; + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + uint8_t tmp_read[4] = {0}; + /* char *tmp_chipname = private_ts->chip_name; */ + + if (strcmp(HX_83102D_SERIES_PWON, private_ts->chip_name) == 0) { + himax_parse_assign_cmd(fw_addr_ctrl_mpap_ovl, tmp_addr, + sizeof(tmp_addr)); + if (on) { + I("%s : Turn on MPAP mode!\n", __func__); + himax_parse_assign_cmd(fw_data_ctrl_mpap_ovl_on, + tmp_data, sizeof(tmp_data)); + do { + g_core_fp.fp_register_write(tmp_addr, tmp_data, + 4); + usleep_range(10000, 10001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, + 4); + + I("%s:read2=0x%02X,read1=0x%02X,read0=0x%02X\n", + __func__, tmp_read[2], tmp_read[1], + tmp_read[0]); + + retry--; + } while (((retry > 0) + && (tmp_read[2] != tmp_data[2] + && tmp_read[1] != tmp_data[1] + && tmp_read[0] != tmp_data[0]))); + } else { + I("%s : Turn off MPAP mode!\n", __func__); + himax_parse_assign_cmd(fw_data_clear, tmp_data, + sizeof(tmp_data)); + do { + g_core_fp.fp_register_write(tmp_addr, tmp_data, + 4); + usleep_range(10000, 10001); + g_core_fp.fp_register_read(tmp_addr, tmp_read, + 4); + + I("%s:read2=0x%02X,read1=0x%02X,read0=0x%02X\n", + __func__, tmp_read[2], tmp_read[1], + tmp_read[0]); + + retry--; + } while ((retry > 0) + && (tmp_read[2] != tmp_data[2] + && tmp_read[1] != tmp_data[1] + && tmp_read[0] != tmp_data[0])); + } + } else { + I("%s Nothing to be done!\n", __func__); + } + + return rslt; +} + +#if defined(HX_ZERO_FLASH) +int G_POWERONOF = 1; +EXPORT_SYMBOL(G_POWERONOF); +void hx_dis_rload_0f(int disable) +{ + /*Diable Flash Reload*/ + g_core_fp.fp_register_write(pdriver_op->addr_fw_define_flash_reload, + pzf_op->data_dis_flash_reload, DATA_LEN_4); +} + +void himax_mcu_clean_sram_0f(uint8_t *addr, int write_len, int type) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int address = 0; + int i = 0; + + uint8_t fix_data = 0x00; + uint8_t tmp_addr[4]; + uint8_t tmp_data[MAX_I2C_TRANS_SZ] = {0}; + + I("%s, Entering\n", __func__); + + max_bus_size = (write_len > HX_MAX_WRITE_SZ) + ? HX_MAX_WRITE_SZ : write_len; + + total_size_temp = write_len; + + g_core_fp.fp_burst_enable(1); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s:addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + + switch (type) { + case 0: + fix_data = 0x00; + break; + case 1: + fix_data = 0xAA; + break; + case 2: + fix_data = 0xBB; + break; + } + + for (i = 0; i < MAX_I2C_TRANS_SZ; i++) + tmp_data[i] = fix_data; + + I("%s, total size=%d\n", __func__, total_size_temp); + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + for (i = 0; i < (total_read_times); i++) { + I("[log]write %d time start!\n", i); + if (total_size_temp >= max_bus_size) { + g_core_fp.fp_register_write(tmp_addr, tmp_data, + max_bus_size); + total_size_temp = total_size_temp - max_bus_size; + } else { + I("last total_size_temp=%d\n", total_size_temp); + g_core_fp.fp_register_write(tmp_addr, tmp_data, + total_size_temp % max_bus_size); + } + address = ((i+1) * max_bus_size); + tmp_addr[1] = addr[1] + (uint8_t) ((address>>8) & 0x00FF); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + usleep_range(10000, 11000); + } + + I("%s, END\n", __func__); +} + +void himax_mcu_write_sram_0f(uint8_t *addr, const uint8_t *data, uint32_t len) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int address = 0; + int i = 0; + + uint8_t tmp_addr[4]; + uint8_t *tmp_data; + + total_size_temp = len; + I("%s, Entering - total write size=%d\n", __func__, total_size_temp); + + max_bus_size = (len > HX_MAX_WRITE_SZ) + ? HX_MAX_WRITE_SZ : len; + + g_core_fp.fp_burst_enable(1); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s, write addr = 0x%02X%02X%02X%02X\n", __func__, + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]); + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + for (i = 0; i < (total_read_times); i++) { + + if (total_size_temp >= max_bus_size) { + + tmp_data = (uint8_t *)(data + i*max_bus_size); + g_core_fp.fp_register_write(tmp_addr, tmp_data, + max_bus_size); + total_size_temp = total_size_temp - max_bus_size; + } else { + + tmp_data = (uint8_t *)(data + i*max_bus_size); + I("last total_size_temp=%d\n", + total_size_temp % max_bus_size); + g_core_fp.fp_register_write(tmp_addr, tmp_data, + total_size_temp % max_bus_size); + } + + address = ((i+1) * max_bus_size); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + if (tmp_addr[0] < addr[0]) + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF) + 1; + else + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF); + + udelay(100); + } + I("%s, End\n", __func__); + /* kfree(tmp_data); */ +} + +int himax_sram_write_crc_check(uint8_t *addr, const uint8_t *data, uint32_t len) +{ + int retry = 0; + int crc = -1; + + do { + g_core_fp.fp_write_sram_0f(addr, data, len); + crc = g_core_fp.fp_check_CRC(addr, len); + retry++; + I("%s, HW CRC %s in %d time\n", __func__, + (crc == 0) ? "OK" : "Fail", retry); + } while (crc != 0 && retry < 3); + + return crc; +} + +int himax_zf_part_info(const struct firmware *fw, int type) +{ + uint32_t table_addr = CFG_TABLE_FLASH_ADDR; + int pnum = 0; + int ret = 0; + uint8_t buf[16]; + struct zf_info *info; + uint8_t *cfg_buf; + uint8_t sram_min[4]; + int cfg_sz = 0; + int cfg_crc_sw = 0; + int cfg_crc_hw = 0; + uint8_t i = 0; + int i_max = 0; + int i_min = 0; + uint32_t dsram_base = 0xFFFFFFFF; + uint32_t dsram_max = 0; + int retry = 0; + +#if defined(HX_ALG_OVERLAY) || defined(HX_CODE_OVERLAY) + uint8_t tmp_addr[4] = {0xFC, 0x7F, 0x00, 0x10}; + uint8_t rdata[4] = {0}; + int allovlidx = 0; +#endif +#if defined(HX_ALG_OVERLAY) + uint8_t alg_sdata[4] = {0xA5, 0x5A, 0x5A, 0xA5}; + uint8_t alg_idx_t = 0; + uint8_t data[4] = {0x01, 0x00, 0x00, 0x00}; +#endif +#if defined(HX_CODE_OVERLAY) + uint8_t code_sdata[4] = {0}; + uint8_t code_idx_t = 0; + uint8_t j = 0; +#endif + + /* 1. initial check */ + pnum = fw->data[table_addr + 12]; + if (pnum < 2) { + E("%s: partition number is not correct\n", __func__); + return FW_NOT_READY; + } + + info = kcalloc(pnum, sizeof(struct zf_info), GFP_KERNEL); + if (info == NULL) { + E("%s: memory allocation fail[info]!!\n", __func__); + return 1; + } + memset(info, 0, pnum * sizeof(struct zf_info)); + +#if defined(HX_CODE_OVERLAY) + if (ovl_idx == NULL) { + ovl_idx = kzalloc(ovl_section_num, GFP_KERNEL); + if (ovl_idx == NULL) { + E("%s, ovl_idx alloc failed!\n", __func__); + return 1; + } + } else { + memset(ovl_idx, 0, ovl_section_num); + } +#endif + + /* 2. record partition information */ + memcpy(buf, &fw->data[table_addr], 16); + memcpy(info[0].sram_addr, buf, 4); + info[0].write_size = buf[7] << 24 | buf[6] << 16 | buf[5] << 8 | buf[4]; + info[0].fw_addr = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8]; + + for (i = 1; i < pnum; i++) { + memcpy(buf, &fw->data[i*0x10 + table_addr], 16); + + memcpy(info[i].sram_addr, buf, 4); + info[i].write_size = buf[7] << 24 | buf[6] << 16 + | buf[5] << 8 | buf[4]; + info[i].fw_addr = buf[11] << 24 | buf[10] << 16 + | buf[9] << 8 | buf[8]; + info[i].cfg_addr = info[i].sram_addr[0]; + info[i].cfg_addr += info[i].sram_addr[1] << 8; + info[i].cfg_addr += info[i].sram_addr[2] << 16; + info[i].cfg_addr += info[i].sram_addr[3] << 24; + + if (info[i].cfg_addr % 4 != 0) + info[i].cfg_addr -= (info[i].cfg_addr % 4); + + I("%s,[%d]SRAM addr=%08X, fw_addr=%08X, write_size=%d\n", + __func__, i, info[i].cfg_addr, info[i].fw_addr, + info[i].write_size); + +#if defined(HX_ALG_OVERLAY) + /* alg overlay section */ + if ((buf[15] == 0x77 && buf[14] == 0x88)) { + I("%s: find alg overlay section in index %d\n", + __func__, i); + /* record index of alg overlay section */ + allovlidx |= 1<<i; + alg_idx_t = i; + continue; + } +#endif + +#if defined(HX_CODE_OVERLAY) + /* code overlay section */ + if ((buf[15] == 0x55 && buf[14] == 0x66) + || (buf[3] == 0x20 && buf[2] == 0x00 + && buf[1] == 0x8C && buf[0] == 0xE0)) { + I("%s: find code overlay section in index %d\n", + __func__, i); + /* record index of code overlay section */ + allovlidx |= 1<<i; + if (buf[15] == 0x55 && buf[14] == 0x66) { + /* current mechanism */ + j = buf[13]; + if (j < ovl_section_num) + ovl_idx[j] = i; + } else { + /* previous mechanism */ + if (j < ovl_section_num) + ovl_idx[j++] = i; + } + continue; + } +#endif + + if (dsram_base > info[i].cfg_addr) { + dsram_base = info[i].cfg_addr; + i_min = i; + } + if (dsram_max < info[i].cfg_addr) { + dsram_max = info[i].cfg_addr; + i_max = i; + } + } + + /* 3. prepare data to update */ +#if defined(HX_ALG_OVERLAY) + if (alg_idx_t == 0 || info[alg_idx_t].write_size == 0) { + E("%s: wrong alg overlay section[%d, %d]!\n", __func__, + alg_idx_t, info[alg_idx_t].write_size); + ret = FW_NOT_READY; + goto ALOC_CFG_BUF_FAIL; + } +#endif +#if defined(HX_CODE_OVERLAY) + /* ovl_idx[0] - sorting */ + /* ovl_idx[1] - gesture */ + /* ovl_idx[2] - border */ + + code_idx_t = ovl_idx[0]; + code_sdata[0] = ovl_sorting_reply; + + if (type == 0) { +#if defined(HX_SMART_WAKEUP) + if (private_ts->suspended && private_ts->SMWP_enable) { + code_idx_t = ovl_idx[1]; + code_sdata[0] = ovl_gesture_reply; + } else { + code_idx_t = ovl_idx[2]; + code_sdata[0] = ovl_border_reply; + } +#else + code_idx_t = ovl_idx[2]; + code_sdata[0] = ovl_border_reply; +#endif + } + + if (code_idx_t == 0 || info[code_idx_t].write_size == 0) { + E("%s: wrong code overlay section[%d, %d]!\n", __func__, + code_idx_t, info[code_idx_t].write_size); + ret = FW_NOT_READY; + goto ALOC_CFG_BUF_FAIL; + } +#endif + + for (i = 0; i < ADDR_LEN_4; i++) + sram_min[i] = (info[i_min].cfg_addr>>(8*i)) & 0xFF; + + cfg_sz = (dsram_max - dsram_base) + info[i_max].write_size; + if (cfg_sz % 16 != 0) + cfg_sz = cfg_sz + 16 - (cfg_sz % 16); + + I("%s, cfg_sz = %d!, dsram_base = %X, dsram_max = %X\n", __func__, + cfg_sz, dsram_base, dsram_max); + + /* config size should be smaller than DSRAM size */ + if (cfg_sz > DSRAM_SIZE) { + E("%s: config size error[%d, %d]!!\n", __func__, + cfg_sz, DSRAM_SIZE); + ret = LENGTH_FAIL; + goto ALOC_CFG_BUF_FAIL; + } + + cfg_buf = kcalloc(cfg_sz, sizeof(uint8_t), GFP_KERNEL); + if (cfg_buf == NULL) { + E("%s: memory allocation fail[cfg_buf]!!\n", __func__); + ret = 1; + goto ALOC_CFG_BUF_FAIL; + } + + for (i = 1; i < pnum; i++) { + +#if defined(HX_ALG_OVERLAY) || defined(HX_CODE_OVERLAY) + /* overlay section */ + if (allovlidx & (1<<i)) { + I("%s: skip overlay section %d\n", __func__, i); + continue; + } +#endif + memcpy(&cfg_buf[info[i].cfg_addr - dsram_base], + &fw->data[info[i].fw_addr], info[i].write_size); + } + + /* 4. write to sram */ + /* FW entity */ + if (himax_sram_write_crc_check(info[0].sram_addr, + &fw->data[info[0].fw_addr], info[0].write_size) != 0) { + E("%s: HW CRC FAIL\n", __func__); + ret = 2; + goto BURN_SRAM_FAIL; + } + + cfg_crc_sw = g_core_fp.fp_Calculate_CRC_with_AP(cfg_buf, 0, cfg_sz); + do { + g_core_fp.fp_write_sram_0f(sram_min, cfg_buf, cfg_sz); + cfg_crc_hw = g_core_fp.fp_check_CRC(sram_min, cfg_sz); + if (cfg_crc_hw != cfg_crc_sw) { + E("Cfg CRC FAIL,HWCRC=%X,SWCRC=%X,retry=%d\n", + cfg_crc_hw, cfg_crc_sw, retry); + } + } while (cfg_crc_hw != cfg_crc_sw && retry++ < 3); + + if (retry > 3) { + ret = 2; + goto BURN_SRAM_FAIL; + } + + /*write back system config*/ + if (type == 0) { +#if defined(HX_SMART_WAKEUP) || defined(HX_HIGH_SENSE) \ + || defined(HX_USB_DETECT_GLOBAL) + g_core_fp.fp_resend_cmd_func(private_ts->suspended); +#endif + } + +#if defined(HX_ALG_OVERLAY) + // clear handshaking to 0xA55A5AA5 + retry = 0; + do { + g_core_fp.fp_register_write(tmp_addr, alg_sdata, DATA_LEN_4); + usleep_range(1000, 1100); + g_core_fp.fp_register_read(tmp_addr, rdata, DATA_LEN_4); + } while ((rdata[0] != alg_sdata[0] + || rdata[1] != alg_sdata[1] + || rdata[2] != alg_sdata[2] + || rdata[3] != alg_sdata[3]) + && retry++ < HIMAX_REG_RETRY_TIMES); + + if (retry > HIMAX_REG_RETRY_TIMES) { + E("%s: init handshaking data FAIL[%02X%02X%02X%02X]!!\n", + __func__, rdata[0], rdata[1], rdata[2], rdata[3]); + } + + alg_sdata[3] = ovl_alg_reply; + alg_sdata[2] = ovl_alg_reply; + alg_sdata[1] = ovl_alg_reply; + alg_sdata[0] = ovl_alg_reply; + + g_core_fp.fp_reload_disable(0); + + /*g_core_fp.fp_power_on_init();*/ + /*Rawout Sel initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + /* reset N frame back to default for normal mode */ + g_core_fp.fp_register_write(pfw_op->addr_set_frame_addr, data, 4); + /*FW reload done initial*/ + g_core_fp.fp_register_write(pdriver_op->addr_fw_define_2nd_flash_reload, + pfw_op->data_clear, sizeof(pfw_op->data_clear)); + + g_core_fp.fp_sense_on(0x00); + + retry = 0; + do { + usleep_range(3000, 3100); + g_core_fp.fp_register_read(tmp_addr, rdata, DATA_LEN_4); + } while ((rdata[0] != ovl_alg_request + || rdata[1] != ovl_alg_request + || rdata[2] != ovl_alg_request + || rdata[3] != ovl_alg_request) + && retry++ < 30); + + if (retry > 30) { + E("%s: fail req data = 0x%02X%02X%02X%02X\n", __func__, + rdata[0], rdata[1], rdata[2], rdata[3]); + /* monitor FW status for debug */ + for (i = 0; i < 10; i++) { + usleep_range(10000, 10100); + g_core_fp.fp_register_read(tmp_addr, rdata, DATA_LEN_4); + I("%s: req data = 0x%02X%02X%02X%02X\n", + __func__, rdata[0], rdata[1], rdata[2], + rdata[3]); + g_core_fp.fp_read_FW_status(); + } + ret = 3; + goto BURN_OVL_FAIL; + } + + I("%s: upgrade alg overlay section[%d]\n", __func__, alg_idx_t); + + if (himax_sram_write_crc_check(info[alg_idx_t].sram_addr, + &fw->data[info[alg_idx_t].fw_addr], info[alg_idx_t].write_size) != 0) { + E("%s: Alg Overlay HW CRC FAIL\n", __func__); + ret = 2; + } +#endif + +#if defined(HX_CODE_OVERLAY) + I("%s: upgrade code overlay section[%d]\n", __func__, code_idx_t); + + if (himax_sram_write_crc_check(info[code_idx_t].sram_addr, + &fw->data[info[code_idx_t].fw_addr], + info[code_idx_t].write_size) != 0) { + E("%s: code overlay HW CRC FAIL\n", __func__); + code_sdata[0] = ovl_fault; + ret = 2; + } + + retry = 0; + do { + g_core_fp.fp_register_write(tmp_addr, code_sdata, DATA_LEN_4); + usleep_range(1000, 1100); + g_core_fp.fp_register_read(tmp_addr, rdata, DATA_LEN_4); + retry++; + } while ((code_sdata[3] != rdata[3] + || code_sdata[2] != rdata[2] + || code_sdata[1] != rdata[1] + || code_sdata[0] != rdata[0]) + && retry < HIMAX_REG_RETRY_TIMES); + + if (retry >= HIMAX_REG_RETRY_TIMES) { + E("%s: fail code rpl data = 0x%02X%02X%02X%02X\n", + __func__, rdata[0], rdata[1], rdata[2], rdata[3]); + } +#endif + +#if defined(HX_ALG_OVERLAY) + retry = 0; + do { + g_core_fp.fp_register_write(tmp_addr, alg_sdata, DATA_LEN_4); + usleep_range(1000, 1100); + g_core_fp.fp_register_read(tmp_addr, rdata, DATA_LEN_4); + } while ((alg_sdata[3] != rdata[3] + || alg_sdata[2] != rdata[2] + || alg_sdata[1] != rdata[1] + || alg_sdata[0] != rdata[0]) + && retry++ < HIMAX_REG_RETRY_TIMES); + + if (retry > HIMAX_REG_RETRY_TIMES) { + E("%s: fail rpl data = 0x%02X%02X%02X%02X\n", __func__, + rdata[0], rdata[1], rdata[2], rdata[3]); + // maybe need to reset + } else { + I("%s: waiting for FW reload data", __func__); + + retry = 0; + while (retry++ < 30) { + g_core_fp.fp_register_read( + pdriver_op->addr_fw_define_2nd_flash_reload, + data, DATA_LEN_4); + + /* use all 4 bytes to compare */ + if ((data[3] == 0x00 && data[2] == 0x00 && + data[1] == 0x72 && data[0] == 0xC0)) { + I("%s: FW reload done\n", __func__); + break; + } + I("%s: wait FW reload %d times\n", __func__, retry); + g_core_fp.fp_read_FW_status(); + usleep_range(10000, 11000); + } + } +#endif +#if defined(HX_ALG_OVERLAY) +BURN_OVL_FAIL: +#endif +BURN_SRAM_FAIL: + kfree(cfg_buf); +ALOC_CFG_BUF_FAIL: + kfree(info); + + return ret; +/* ret = 1, memory allocation fail + * = 2, crc fail + * = 3, flow control error + */ +} + +int himax_mcu_firmware_update_0f(const struct firmware *fw, int type) +{ + int ret = 0; + + I("%s,Entering - total FW size=%d\n", __func__, (int)fw->size); + + g_core_fp.fp_register_write(pzf_op->addr_system_reset, + pzf_op->data_system_reset, 4); + + g_core_fp.fp_sense_off(false); + + if ((int)fw->size > HX64K) { + ret = himax_zf_part_info(fw, type); + } else { + /* first 48K */ + ret = himax_sram_write_crc_check(pzf_op->data_sram_start_addr, + &fw->data[0], HX_48K_SZ); + if (ret != 0) + E("%s, HW CRC FAIL - Main SRAM 48K\n", __func__); + + /*config info*/ + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(pzf_op->data_cfg_info, + &fw->data[0xC000], 128); + if (ret != 0) + E("Config info CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_cfg_info, + 128, 2); + } + + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(pzf_op->data_fw_cfg_1, + &fw->data[0xC0FE], 528); + if (ret != 0) + E("FW config 1 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_fw_cfg_1, + 528, 1); + } + + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(pzf_op->data_fw_cfg_3, + &fw->data[0xCA00], 128); + if (ret != 0) + E("FW config 3 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_fw_cfg_3, + 128, 2); + } + + /*ADC config*/ + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(pzf_op->data_adc_cfg_1, + &fw->data[0xD640], 1200); + if (ret != 0) + E("ADC config 1 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_adc_cfg_1, + 1200, 2); + } + + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(pzf_op->data_adc_cfg_2, + &fw->data[0xD320], 800); + if (ret != 0) + E("ADC config 2 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_adc_cfg_2, + 800, 2); + } + + /*mapping table*/ + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(pzf_op->data_map_table, + &fw->data[0xE000], 1536); + if (ret != 0) + E("Mapping table CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_map_table, + 1536, 2); + } + } + + I("%s, End\n", __func__); + + return ret; +} + +int hx_0f_op_file_dirly(char *file_name) +{ + const struct firmware *fw = NULL; + int ret = -1; + int type = 0; /* FW type: 0, normal; 1, MPAP */ + + if (g_f_0f_updat == 1) { + W("%s: Other thread is updating now!\n", __func__); + return ret; + } + g_f_0f_updat = 1; + I("%s: Preparing to update %s!\n", __func__, file_name); + + ret = request_firmware(&fw, file_name, private_ts->dev); + if (ret < 0) { +#if defined(__EMBEDDED_FW__) + fw = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)\n", + __func__, g_embedded_fw.size); +#else + E("%s: request firmware fail, code[%d]!!\n", __func__, ret); + goto END; +#endif + } + + if (strcmp(file_name, MPAP_FWNAME) == 0) + type = 1; + + ret = g_core_fp.fp_firmware_update_0f(fw, type); + + release_firmware(fw); + + if (ret < 0) + goto END; + +#if !defined(HX_ALG_OVERLAY) + if (type == 1) + g_core_fp.fp_turn_on_mp_func(1); + else + g_core_fp.fp_turn_on_mp_func(0); + g_core_fp.fp_reload_disable(0); + g_core_fp.fp_power_on_init(); +#endif + +END: + g_f_0f_updat = 0; + + I("%s: END\n", __func__); + return ret; +} + +static int himax_mcu_0f_excp_check(void) +{ + return NO_ERR; +} + +#if defined(HX_0F_DEBUG) +void himax_mcu_read_sram_0f(const struct firmware *fw_entry, + uint8_t *addr, int start_index, int read_len) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int total_size = 0; + int address = 0; + int i = 0, j = 0; + int not_same = 0; + + uint8_t tmp_addr[4]; + uint8_t *temp_info_data = NULL; + int *not_same_buff = NULL; + + I("%s, Entering\n", __func__); + + /*g_core_fp.fp_burst_enable(1);*/ + + total_size = read_len; + + total_size_temp = read_len; + +#if defined(HX_SPI_OPERATION) + if (read_len > 2048) + max_bus_size = 2048; + else + max_bus_size = read_len; +#else + if (read_len > 240) + max_bus_size = 240; + else + max_bus_size = read_len; +#endif + + if (total_size % max_bus_size == 0) + total_read_times = total_size / max_bus_size; + else + total_read_times = total_size / max_bus_size + 1; + + I("%s, total size=%d, bus size=%d, read time=%d\n", + __func__, + total_size, + max_bus_size, + total_read_times); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s,addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + + temp_info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (temp_info_data == NULL) { + E("%s, Failed to allocate temp_info_data\n", __func__); + goto err_malloc_temp_info_data; + } + + not_same_buff = kcalloc(total_size, sizeof(int), GFP_KERNEL); + if (not_same_buff == NULL) { + E("%s, Failed to allocate not_same_buff\n", __func__); + goto err_malloc_not_same_buff; + } + + g_core_fp.fp_burst_enable(1); + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_bus_size) { + g_core_fp.fp_register_read(tmp_addr, + &temp_info_data[i*max_bus_size], max_bus_size); + total_size_temp = total_size_temp - max_bus_size; + } else { + g_core_fp.fp_register_read(tmp_addr, + &temp_info_data[i*max_bus_size], + total_size_temp % max_bus_size); + } + + address = ((i+1) * max_bus_size); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + if (tmp_addr[0] < addr[0]) + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF) + 1; + else + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF); + + /*msleep (10);*/ + } + I("%s,READ Start, start_index = %d\n", __func__, start_index); + + j = start_index; + for (i = 0; i < read_len; i++, j++) { + if (fw_entry->data[j] != temp_info_data[i]) { + not_same++; + not_same_buff[i] = 1; + } + + I("0x%2.2X, ", temp_info_data[i]); + + if (i > 0 && i%16 == 15) + pr_info("\n"); + + } + I("%s,READ END,Not Same count=%d\n", __func__, not_same); + + if (not_same != 0) { + j = start_index; + for (i = 0; i < read_len; i++, j++) { + if (not_same_buff[i] == 1) + I("bin=[%d] 0x%2.2X\n", i, fw_entry->data[j]); + } + for (i = 0; i < read_len; i++, j++) { + if (not_same_buff[i] == 1) + I("sram=[%d] 0x%2.2X\n", i, temp_info_data[i]); + } + } + I("%s,READ END, Not Same count=%d\n", __func__, not_same); + + kfree(not_same_buff); +err_malloc_not_same_buff: + kfree(temp_info_data); +err_malloc_temp_info_data: + return; +} + +void himax_mcu_read_all_sram(uint8_t *addr, int read_len) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int total_size = 0; + int address = 0; + int i = 0; + /* struct file *fn; */ + /* struct filename *vts_name; */ + + uint8_t tmp_addr[4]; + uint8_t *temp_info_data; + + I("%s, Entering\n", __func__); + + /*g_core_fp.fp_burst_enable(1);*/ + + total_size = read_len; + + total_size_temp = read_len; + + if (total_size % max_bus_size == 0) + total_read_times = total_size / max_bus_size; + else + total_read_times = total_size / max_bus_size + 1; + + I("%s, total size=%d\n", __func__, total_size); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s:addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + + temp_info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (temp_info_data == NULL) { + E("%s, Failed to allocate temp_info_data\n", __func__); + return; + } + + g_core_fp.fp_burst_enable(1); + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_bus_size) { + g_core_fp.fp_register_read(tmp_addr, + &temp_info_data[i*max_bus_size], max_bus_size); + total_size_temp = total_size_temp - max_bus_size; + } else { + g_core_fp.fp_register_read(tmp_addr, + &temp_info_data[i*max_bus_size], + total_size_temp % max_bus_size); + } + + address = ((i+1) * max_bus_size); + tmp_addr[1] = addr[1] + (uint8_t) ((address>>8) & 0x00FF); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + /*msleep (10);*/ + } + I("%s,addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + /*for(i = 0;i<read_len;i++) + *{ + * I("0x%2.2X, ", temp_info_data[i]); + * + * if (i > 0 && i%16 == 15) + * printk("\n"); + *} + */ + + /* need modify + * I("Now Write File start!\n"); + * vts_name = kp_getname_kernel("/sdcard/dump_dsram.txt"); + * fn = kp_file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + * if (!IS_ERR (fn)) { + * I("%s create file and ready to write\n", __func__); + * fn->f_op->write(fn, temp_info_data, read_len*sizeof (uint8_t), + * &fn->f_pos); + * filp_close (fn, NULL); + * } + * I("Now Write File End!\n"); + */ + + kfree(temp_info_data); + + I("%s, END\n", __func__); + +} + +void himax_mcu_firmware_read_0f(const struct firmware *fw_entry, int type) +{ + uint8_t tmp_addr[4]; + + I("%s, Entering\n", __func__); + if (type == 0) { /* first 48K */ + g_core_fp.fp_read_sram_0f(fw_entry, + pzf_op->data_sram_start_addr, + 0, + HX_48K_SZ); + g_core_fp.fp_read_all_sram(tmp_addr, 0xC000); + } else { /*last 16k*/ + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_cfg_info, + 0xC000, 132); + + /*FW config*/ + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_fw_cfg_1, + 0xC0FE, 484); + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_fw_cfg_2, + 0xC9DE, 36); + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_fw_cfg_3, + 0xCA00, 72); + + /*ADC config*/ + + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_adc_cfg_1, + 0xD630, 1188); + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_adc_cfg_2, + 0xD318, 792); + + + /*mapping table*/ + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_map_table, + 0xE000, 1536); + + /* set n frame=0*/ + g_core_fp.fp_read_sram_0f(fw_entry, pfw_op->addr_set_frame_addr, + 0xC30C, 4); + } + + I("%s, END\n", __func__); +} +#endif + +#if defined(HX_CODE_OVERLAY) +int himax_mcu_0f_overlay(int ovl_type, int mode) +{ + return NO_ERR; +} +#endif + +#endif + +/* CORE_INIT */ +/* init start */ +static void himax_mcu_fp_init(void) +{ +/* CORE_IC */ + g_core_fp.fp_burst_enable = himax_mcu_burst_enable; + g_core_fp.fp_register_read = himax_mcu_register_read; + /* + * g_core_fp.fp_flash_write_burst = himax_mcu_flash_write_burst; + */ + /* + * g_core_fp.fp_flash_write_burst_lenth = + * himax_mcu_flash_write_burst_lenth; + */ + g_core_fp.fp_register_write = himax_mcu_register_write; + g_core_fp.fp_interface_on = himax_mcu_interface_on; + g_core_fp.fp_sense_on = himax_mcu_sense_on; + g_core_fp.fp_sense_off = himax_mcu_sense_off; + g_core_fp.fp_wait_wip = himax_mcu_wait_wip; + g_core_fp.fp_init_psl = himax_mcu_init_psl; + g_core_fp.fp_resume_ic_action = himax_mcu_resume_ic_action; + g_core_fp.fp_suspend_ic_action = himax_mcu_suspend_ic_action; + g_core_fp.fp_power_on_init = himax_mcu_power_on_init; +/* CORE_IC */ +/* CORE_FW */ + g_core_fp.fp_system_reset = himax_mcu_system_reset; + g_core_fp.fp_Calculate_CRC_with_AP = himax_mcu_Calculate_CRC_with_AP; + g_core_fp.fp_check_CRC = himax_mcu_check_CRC; + g_core_fp.fp_set_reload_cmd = himax_mcu_set_reload_cmd; + g_core_fp.fp_program_reload = himax_mcu_program_reload; +#if defined(HX_ULTRA_LOW_POWER) + g_core_fp.fp_ulpm_in = himax_mcu_ulpm_in; + g_core_fp.fp_black_gest_ctrl = himax_mcu_black_gest_ctrl; +#endif + g_core_fp.fp_set_SMWP_enable = himax_mcu_set_SMWP_enable; + g_core_fp.fp_set_HSEN_enable = himax_mcu_set_HSEN_enable; + g_core_fp.fp_usb_detect_set = himax_mcu_usb_detect_set; + g_core_fp.fp_diag_register_set = himax_mcu_diag_register_set; + g_core_fp.fp_chip_self_test = himax_mcu_chip_self_test; + g_core_fp.fp_idle_mode = himax_mcu_idle_mode; + g_core_fp.fp_reload_disable = himax_mcu_reload_disable; + g_core_fp.fp_check_chip_version = himax_mcu_check_chip_version; + g_core_fp.fp_read_ic_trigger_type = himax_mcu_read_ic_trigger_type; + g_core_fp.fp_read_i2c_status = himax_mcu_read_i2c_status; + g_core_fp.fp_read_FW_ver = himax_mcu_read_FW_ver; + g_core_fp.fp_read_event_stack = himax_mcu_read_event_stack; + g_core_fp.fp_return_event_stack = himax_mcu_return_event_stack; + g_core_fp.fp_calculateChecksum = himax_mcu_calculateChecksum; + g_core_fp.fp_read_FW_status = himax_mcu_read_FW_status; + g_core_fp.fp_irq_switch = himax_mcu_irq_switch; + g_core_fp.fp_assign_sorting_mode = himax_mcu_assign_sorting_mode; + g_core_fp.fp_check_sorting_mode = himax_mcu_check_sorting_mode; + g_core_fp.fp_read_DD_status = himax_mcu_read_DD_status; + g_core_fp._clr_fw_reord_dd_sts = hx_clr_fw_reord_dd_sts; + g_core_fp._ap_notify_fw_sus = hx_ap_notify_fw_sus; +/* CORE_FW */ +/* CORE_FLASH */ + g_core_fp.fp_chip_erase = himax_mcu_chip_erase; + g_core_fp.fp_block_erase = himax_mcu_block_erase; + g_core_fp.fp_sector_erase = himax_mcu_sector_erase; + g_core_fp.fp_flash_programming = himax_mcu_flash_programming; + g_core_fp.fp_flash_page_write = himax_mcu_flash_page_write; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_32k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_60k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_64k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_124k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_255k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_255k; + g_core_fp.fp_flash_dump_func = himax_mcu_flash_dump_func; + g_core_fp.fp_flash_lastdata_check = himax_mcu_flash_lastdata_check; + g_core_fp.fp_bin_desc_get = hx_mcu_bin_desc_get; + g_core_fp._diff_overlay_flash = hx_mcu_diff_overlay_flash; +/* CORE_FLASH */ +/* CORE_SRAM */ + g_core_fp.fp_sram_write = himax_mcu_sram_write; + g_core_fp.fp_sram_verify = himax_mcu_sram_verify; + g_core_fp.fp_get_DSRAM_data = himax_mcu_get_DSRAM_data; +/* CORE_SRAM */ +/* CORE_DRIVER */ + g_core_fp.fp_chip_init = himax_mcu_init_ic; +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_pin_reset = himax_mcu_pin_reset; + g_core_fp.fp_ic_reset = himax_mcu_ic_reset; +#endif + g_core_fp.fp_tp_info_check = himax_mcu_tp_info_check; + g_core_fp.fp_touch_information = himax_mcu_touch_information; + g_core_fp.fp_calc_touch_data_size = himax_mcu_calcTouchDataSize; + /*g_core_fp.fp_reload_config = himax_mcu_reload_config;*/ + g_core_fp.fp_get_touch_data_size = himax_mcu_get_touch_data_size; + g_core_fp.fp_hand_shaking = himax_mcu_hand_shaking; + g_core_fp.fp_determin_diag_rawdata = himax_mcu_determin_diag_rawdata; + g_core_fp.fp_determin_diag_storage = himax_mcu_determin_diag_storage; + g_core_fp.fp_cal_data_len = himax_mcu_cal_data_len; + g_core_fp.fp_diag_check_sum = himax_mcu_diag_check_sum; + g_core_fp.fp_diag_parse_raw_data = himax_mcu_diag_parse_raw_data; +#if defined(HX_EXCP_RECOVERY) + g_core_fp.fp_ic_excp_recovery = himax_mcu_ic_excp_recovery; + g_core_fp.fp_excp_ic_reset = himax_mcu_excp_ic_reset; +#endif +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) + g_core_fp.fp_resend_cmd_func = himax_mcu_resend_cmd_func; +#endif +#if defined(HX_TP_PROC_GUEST_INFO) + g_core_fp.guest_info_get_status = himax_guest_info_get_status; + g_core_fp.read_guest_info = hx_read_guest_info; +#endif +/* CORE_DRIVER */ + g_core_fp.fp_turn_on_mp_func = hx_turn_on_mp_func; +#if defined(HX_ZERO_FLASH) + g_core_fp.fp_reload_disable = hx_dis_rload_0f; + g_core_fp.fp_clean_sram_0f = himax_mcu_clean_sram_0f; + g_core_fp.fp_write_sram_0f = himax_mcu_write_sram_0f; + g_core_fp.fp_write_sram_0f_crc = himax_sram_write_crc_check; + g_core_fp.fp_firmware_update_0f = himax_mcu_firmware_update_0f; + g_core_fp.fp_0f_op_file_dirly = hx_0f_op_file_dirly; + g_core_fp.fp_0f_excp_check = himax_mcu_0f_excp_check; +#if defined(HX_0F_DEBUG) + g_core_fp.fp_read_sram_0f = himax_mcu_read_sram_0f; + g_core_fp.fp_read_all_sram = himax_mcu_read_all_sram; + g_core_fp.fp_firmware_read_0f = himax_mcu_firmware_read_0f; +#endif +#if defined(HX_CODE_OVERLAY) + g_core_fp.fp_0f_overlay = himax_mcu_0f_overlay; +#endif +#endif +} + +void himax_mcu_in_cmd_struct_free(void) +{ + pic_op = NULL; + pfw_op = NULL; + pflash_op = NULL; + psram_op = NULL; + pdriver_op = NULL; + kfree(g_internal_buffer); + g_internal_buffer = NULL; +#if defined(HX_ZERO_FLASH) + kfree(g_core_cmd_op->zf_op); + g_core_cmd_op->zf_op = NULL; +#endif + kfree(g_core_cmd_op->driver_op); + g_core_cmd_op->driver_op = NULL; + kfree(g_core_cmd_op->sram_op); + g_core_cmd_op->sram_op = NULL; + kfree(g_core_cmd_op->flash_op); + g_core_cmd_op->flash_op = NULL; + kfree(g_core_cmd_op->fw_op); + g_core_cmd_op->fw_op = NULL; + kfree(g_core_cmd_op->ic_op); + g_core_cmd_op->ic_op = NULL; + kfree(g_core_cmd_op); + g_core_cmd_op = NULL; + + I("%s: release completed\n", __func__); +} + +int himax_mcu_in_cmd_struct_init(void) +{ + int err = 0; + + I("%s: Entering!\n", __func__); + himax_mcu_cmd_struct_free = himax_mcu_in_cmd_struct_free; + + g_core_cmd_op = kzalloc(sizeof(struct himax_core_command_operation), + GFP_KERNEL); + if (g_core_cmd_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_fail; + } + + g_core_cmd_op->ic_op = kzalloc(sizeof(struct ic_operation), GFP_KERNEL); + if (g_core_cmd_op->ic_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_ic_op_fail; + } + + g_core_cmd_op->fw_op = kzalloc(sizeof(struct fw_operation), GFP_KERNEL); + if (g_core_cmd_op->fw_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_fw_op_fail; + } + + g_core_cmd_op->flash_op = kzalloc(sizeof(struct flash_operation), + GFP_KERNEL); + if (g_core_cmd_op->flash_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_flash_op_fail; + } + + g_core_cmd_op->sram_op = kzalloc(sizeof(struct sram_operation), + GFP_KERNEL); + if (g_core_cmd_op->sram_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_sram_op_fail; + } + + g_core_cmd_op->driver_op = kzalloc(sizeof(struct driver_operation), + GFP_KERNEL); + if (g_core_cmd_op->driver_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_driver_op_fail; + } + + pic_op = g_core_cmd_op->ic_op; + pfw_op = g_core_cmd_op->fw_op; + pflash_op = g_core_cmd_op->flash_op; + psram_op = g_core_cmd_op->sram_op; + pdriver_op = g_core_cmd_op->driver_op; +#if defined(HX_ZERO_FLASH) + g_core_cmd_op->zf_op = kzalloc(sizeof(struct zf_operation), + GFP_KERNEL); + if (g_core_cmd_op->zf_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_zf_op_fail; + } + pzf_op = g_core_cmd_op->zf_op; + +#endif + + /* command[2] + address[4] + data[] */ + g_internal_buffer = kzalloc(sizeof(uint8_t)*(HX_MAX_WRITE_SZ+6), + GFP_KERNEL); + + if (g_internal_buffer == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_g_internal_buffer_fail; + } + himax_mcu_fp_init(); + + return NO_ERR; + +err_g_core_cmd_op_g_internal_buffer_fail: +#if defined(HX_ZERO_FLASH) + kfree(g_core_cmd_op->zf_op); + g_core_cmd_op->zf_op = NULL; +err_g_core_cmd_op_zf_op_fail: +#endif + kfree(g_core_cmd_op->driver_op); + g_core_cmd_op->driver_op = NULL; +err_g_core_cmd_op_driver_op_fail: + kfree(g_core_cmd_op->sram_op); + g_core_cmd_op->sram_op = NULL; +err_g_core_cmd_op_sram_op_fail: + kfree(g_core_cmd_op->flash_op); + g_core_cmd_op->flash_op = NULL; +err_g_core_cmd_op_flash_op_fail: + kfree(g_core_cmd_op->fw_op); + g_core_cmd_op->fw_op = NULL; +err_g_core_cmd_op_fw_op_fail: + kfree(g_core_cmd_op->ic_op); + g_core_cmd_op->ic_op = NULL; +err_g_core_cmd_op_ic_op_fail: + kfree(g_core_cmd_op); + g_core_cmd_op = NULL; +err_g_core_cmd_op_fail: + + return err; +} +EXPORT_SYMBOL(himax_mcu_in_cmd_struct_init); + +void himax_mcu_in_cmd_init(void) +{ + I("%s: Entering!\n", __func__); +/* CORE_IC */ + himax_parse_assign_cmd(ic_adr_ahb_addr_byte_0, + pic_op->addr_ahb_addr_byte_0, + sizeof(pic_op->addr_ahb_addr_byte_0)); + himax_parse_assign_cmd(ic_adr_ahb_rdata_byte_0, + pic_op->addr_ahb_rdata_byte_0, + sizeof(pic_op->addr_ahb_rdata_byte_0)); + himax_parse_assign_cmd(ic_adr_ahb_access_direction, + pic_op->addr_ahb_access_direction, + sizeof(pic_op->addr_ahb_access_direction)); + himax_parse_assign_cmd(ic_adr_conti, pic_op->addr_conti, + sizeof(pic_op->addr_conti)); + himax_parse_assign_cmd(ic_adr_incr4, pic_op->addr_incr4, + sizeof(pic_op->addr_incr4)); + himax_parse_assign_cmd(ic_adr_i2c_psw_lb, pic_op->adr_i2c_psw_lb, + sizeof(pic_op->adr_i2c_psw_lb)); + himax_parse_assign_cmd(ic_adr_i2c_psw_ub, pic_op->adr_i2c_psw_ub, + sizeof(pic_op->adr_i2c_psw_ub)); + himax_parse_assign_cmd(ic_cmd_ahb_access_direction_read, + pic_op->data_ahb_access_direction_read, + sizeof(pic_op->data_ahb_access_direction_read)); + himax_parse_assign_cmd(ic_cmd_conti, pic_op->data_conti, + sizeof(pic_op->data_conti)); + himax_parse_assign_cmd(ic_cmd_incr4, pic_op->data_incr4, + sizeof(pic_op->data_incr4)); + himax_parse_assign_cmd(ic_cmd_i2c_psw_lb, pic_op->data_i2c_psw_lb, + sizeof(pic_op->data_i2c_psw_lb)); + himax_parse_assign_cmd(ic_cmd_i2c_psw_ub, pic_op->data_i2c_psw_ub, + sizeof(pic_op->data_i2c_psw_ub)); + himax_parse_assign_cmd(ic_adr_tcon_on_rst, pic_op->addr_tcon_on_rst, + sizeof(pic_op->addr_tcon_on_rst)); + himax_parse_assign_cmd(ic_addr_adc_on_rst, pic_op->addr_adc_on_rst, + sizeof(pic_op->addr_adc_on_rst)); + himax_parse_assign_cmd(ic_adr_psl, pic_op->addr_psl, + sizeof(pic_op->addr_psl)); + himax_parse_assign_cmd(ic_adr_cs_central_state, + pic_op->addr_cs_central_state, + sizeof(pic_op->addr_cs_central_state)); + himax_parse_assign_cmd(ic_cmd_rst, pic_op->data_rst, + sizeof(pic_op->data_rst)); + himax_parse_assign_cmd(ic_adr_osc_en, pic_op->adr_osc_en, + sizeof(pic_op->adr_osc_en)); + himax_parse_assign_cmd(ic_adr_osc_pw, pic_op->adr_osc_pw, + sizeof(pic_op->adr_osc_pw)); +/* CORE_IC */ +/* CORE_FW */ + himax_parse_assign_cmd(fw_addr_system_reset, + pfw_op->addr_system_reset, + sizeof(pfw_op->addr_system_reset)); + himax_parse_assign_cmd(fw_addr_ctrl_fw, + pfw_op->addr_ctrl_fw_isr, + sizeof(pfw_op->addr_ctrl_fw_isr)); + himax_parse_assign_cmd(fw_addr_flag_reset_event, + pfw_op->addr_flag_reset_event, + sizeof(pfw_op->addr_flag_reset_event)); + himax_parse_assign_cmd(fw_addr_hsen_enable, + pfw_op->addr_hsen_enable, + sizeof(pfw_op->addr_hsen_enable)); + himax_parse_assign_cmd(fw_addr_smwp_enable, + pfw_op->addr_smwp_enable, + sizeof(pfw_op->addr_smwp_enable)); + himax_parse_assign_cmd(fw_addr_program_reload_from, + pfw_op->addr_program_reload_from, + sizeof(pfw_op->addr_program_reload_from)); + himax_parse_assign_cmd(fw_addr_program_reload_to, + pfw_op->addr_program_reload_to, + sizeof(pfw_op->addr_program_reload_to)); + himax_parse_assign_cmd(fw_addr_program_reload_page_write, + pfw_op->addr_program_reload_page_write, + sizeof(pfw_op->addr_program_reload_page_write)); + himax_parse_assign_cmd(fw_addr_raw_out_sel, + pfw_op->addr_raw_out_sel, + sizeof(pfw_op->addr_raw_out_sel)); + himax_parse_assign_cmd(fw_addr_reload_status, + pfw_op->addr_reload_status, + sizeof(pfw_op->addr_reload_status)); + himax_parse_assign_cmd(fw_addr_reload_crc32_result, + pfw_op->addr_reload_crc32_result, + sizeof(pfw_op->addr_reload_crc32_result)); + himax_parse_assign_cmd(fw_addr_reload_addr_from, + pfw_op->addr_reload_addr_from, + sizeof(pfw_op->addr_reload_addr_from)); + himax_parse_assign_cmd(fw_addr_reload_addr_cmd_beat, + pfw_op->addr_reload_addr_cmd_beat, + sizeof(pfw_op->addr_reload_addr_cmd_beat)); + himax_parse_assign_cmd(fw_addr_selftest_addr_en, + pfw_op->addr_selftest_addr_en, + sizeof(pfw_op->addr_selftest_addr_en)); + himax_parse_assign_cmd(fw_addr_criteria_addr, + pfw_op->addr_criteria_addr, + sizeof(pfw_op->addr_criteria_addr)); + himax_parse_assign_cmd(fw_addr_set_frame_addr, + pfw_op->addr_set_frame_addr, + sizeof(pfw_op->addr_set_frame_addr)); + himax_parse_assign_cmd(fw_addr_selftest_result_addr, + pfw_op->addr_selftest_result_addr, + sizeof(pfw_op->addr_selftest_result_addr)); + himax_parse_assign_cmd(fw_addr_sorting_mode_en, + pfw_op->addr_sorting_mode_en, + sizeof(pfw_op->addr_sorting_mode_en)); + himax_parse_assign_cmd(fw_addr_fw_mode_status, + pfw_op->addr_fw_mode_status, + sizeof(pfw_op->addr_fw_mode_status)); + himax_parse_assign_cmd(fw_addr_icid_addr, + pfw_op->addr_icid_addr, + sizeof(pfw_op->addr_icid_addr)); + himax_parse_assign_cmd(fw_addr_fw_ver_addr, + pfw_op->addr_fw_ver_addr, + sizeof(pfw_op->addr_fw_ver_addr)); + himax_parse_assign_cmd(fw_addr_fw_cfg_addr, + pfw_op->addr_fw_cfg_addr, + sizeof(pfw_op->addr_fw_cfg_addr)); + himax_parse_assign_cmd(fw_addr_fw_vendor_addr, + pfw_op->addr_fw_vendor_addr, + sizeof(pfw_op->addr_fw_vendor_addr)); + himax_parse_assign_cmd(fw_addr_cus_info, + pfw_op->addr_cus_info, + sizeof(pfw_op->addr_cus_info)); + himax_parse_assign_cmd(fw_addr_proj_info, + pfw_op->addr_proj_info, + sizeof(pfw_op->addr_proj_info)); + himax_parse_assign_cmd(fw_addr_fw_state_addr, + pfw_op->addr_fw_state_addr, + sizeof(pfw_op->addr_fw_state_addr)); + himax_parse_assign_cmd(fw_addr_fw_dbg_msg_addr, + pfw_op->addr_fw_dbg_msg_addr, + sizeof(pfw_op->addr_fw_dbg_msg_addr)); + himax_parse_assign_cmd(fw_addr_chk_fw_status, + pfw_op->addr_chk_fw_status, + sizeof(pfw_op->addr_chk_fw_status)); + himax_parse_assign_cmd(fw_addr_dd_handshak_addr, + pfw_op->addr_dd_handshak_addr, + sizeof(pfw_op->addr_dd_handshak_addr)); + himax_parse_assign_cmd(fw_addr_dd_data_addr, + pfw_op->addr_dd_data_addr, + sizeof(pfw_op->addr_dd_data_addr)); + himax_parse_assign_cmd(fw_addr_clr_fw_record_dd_sts, + pfw_op->addr_clr_fw_record_dd_sts, + sizeof(pfw_op->addr_clr_fw_record_dd_sts)); + himax_parse_assign_cmd(fw_addr_ap_notify_fw_sus, + pfw_op->addr_ap_notify_fw_sus, + sizeof(pfw_op->addr_ap_notify_fw_sus)); + himax_parse_assign_cmd(fw_data_ap_notify_fw_sus_en, + pfw_op->data_ap_notify_fw_sus_en, + sizeof(pfw_op->data_ap_notify_fw_sus_en)); + himax_parse_assign_cmd(fw_data_ap_notify_fw_sus_dis, + pfw_op->data_ap_notify_fw_sus_dis, + sizeof(pfw_op->data_ap_notify_fw_sus_dis)); + himax_parse_assign_cmd(fw_data_system_reset, + pfw_op->data_system_reset, + sizeof(pfw_op->data_system_reset)); + himax_parse_assign_cmd(fw_data_safe_mode_release_pw_active, + pfw_op->data_safe_mode_release_pw_active, + sizeof(pfw_op->data_safe_mode_release_pw_active)); + himax_parse_assign_cmd(fw_data_clear, + pfw_op->data_clear, + sizeof(pfw_op->data_clear)); + himax_parse_assign_cmd(fw_data_clear, + pfw_op->data_clear, + sizeof(pfw_op->data_clear)); + himax_parse_assign_cmd(fw_data_fw_stop, + pfw_op->data_fw_stop, + sizeof(pfw_op->data_fw_stop)); + himax_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, + pfw_op->data_safe_mode_release_pw_reset, + sizeof(pfw_op->data_safe_mode_release_pw_reset)); + himax_parse_assign_cmd(fw_data_program_reload_start, + pfw_op->data_program_reload_start, + sizeof(pfw_op->data_program_reload_start)); + himax_parse_assign_cmd(fw_data_program_reload_compare, + pfw_op->data_program_reload_compare, + sizeof(pfw_op->data_program_reload_compare)); + himax_parse_assign_cmd(fw_data_program_reload_break, + pfw_op->data_program_reload_break, + sizeof(pfw_op->data_program_reload_break)); + himax_parse_assign_cmd(fw_data_selftest_request, + pfw_op->data_selftest_request, + sizeof(pfw_op->data_selftest_request)); + himax_parse_assign_cmd(fw_data_criteria_aa_top, + pfw_op->data_criteria_aa_top, + sizeof(pfw_op->data_criteria_aa_top)); + himax_parse_assign_cmd(fw_data_criteria_aa_bot, + pfw_op->data_criteria_aa_bot, + sizeof(pfw_op->data_criteria_aa_bot)); + himax_parse_assign_cmd(fw_data_criteria_key_top, + pfw_op->data_criteria_key_top, + sizeof(pfw_op->data_criteria_key_top)); + himax_parse_assign_cmd(fw_data_criteria_key_bot, + pfw_op->data_criteria_key_bot, + sizeof(pfw_op->data_criteria_key_bot)); + himax_parse_assign_cmd(fw_data_criteria_avg_top, + pfw_op->data_criteria_avg_top, + sizeof(pfw_op->data_criteria_avg_top)); + himax_parse_assign_cmd(fw_data_criteria_avg_bot, + pfw_op->data_criteria_avg_bot, + sizeof(pfw_op->data_criteria_avg_bot)); + himax_parse_assign_cmd(fw_data_set_frame, + pfw_op->data_set_frame, + sizeof(pfw_op->data_set_frame)); + himax_parse_assign_cmd(fw_data_selftest_ack_hb, + pfw_op->data_selftest_ack_hb, + sizeof(pfw_op->data_selftest_ack_hb)); + himax_parse_assign_cmd(fw_data_selftest_ack_lb, + pfw_op->data_selftest_ack_lb, + sizeof(pfw_op->data_selftest_ack_lb)); + himax_parse_assign_cmd(fw_data_selftest_pass, + pfw_op->data_selftest_pass, + sizeof(pfw_op->data_selftest_pass)); + himax_parse_assign_cmd(fw_data_normal_cmd, + pfw_op->data_normal_cmd, + sizeof(pfw_op->data_normal_cmd)); + himax_parse_assign_cmd(fw_data_normal_status, + pfw_op->data_normal_status, + sizeof(pfw_op->data_normal_status)); + himax_parse_assign_cmd(fw_data_sorting_cmd, + pfw_op->data_sorting_cmd, + sizeof(pfw_op->data_sorting_cmd)); + himax_parse_assign_cmd(fw_data_sorting_status, + pfw_op->data_sorting_status, + sizeof(pfw_op->data_sorting_status)); + himax_parse_assign_cmd(fw_data_dd_request, + pfw_op->data_dd_request, + sizeof(pfw_op->data_dd_request)); + himax_parse_assign_cmd(fw_data_dd_ack, + pfw_op->data_dd_ack, + sizeof(pfw_op->data_dd_ack)); + himax_parse_assign_cmd(fw_data_idle_dis_pwd, + pfw_op->data_idle_dis_pwd, + sizeof(pfw_op->data_idle_dis_pwd)); + himax_parse_assign_cmd(fw_data_idle_en_pwd, + pfw_op->data_idle_en_pwd, + sizeof(pfw_op->data_idle_en_pwd)); + himax_parse_assign_cmd(fw_data_rawdata_ready_hb, + pfw_op->data_rawdata_ready_hb, + sizeof(pfw_op->data_rawdata_ready_hb)); + himax_parse_assign_cmd(fw_data_rawdata_ready_lb, + pfw_op->data_rawdata_ready_lb, + sizeof(pfw_op->data_rawdata_ready_lb)); + himax_parse_assign_cmd(fw_addr_ahb_addr, + pfw_op->addr_ahb_addr, + sizeof(pfw_op->addr_ahb_addr)); + himax_parse_assign_cmd(fw_data_ahb_dis, + pfw_op->data_ahb_dis, + sizeof(pfw_op->data_ahb_dis)); + himax_parse_assign_cmd(fw_data_ahb_en, + pfw_op->data_ahb_en, + sizeof(pfw_op->data_ahb_en)); + himax_parse_assign_cmd(fw_addr_event_addr, + pfw_op->addr_event_addr, + sizeof(pfw_op->addr_event_addr)); + himax_parse_assign_cmd(fw_usb_detect_addr, + pfw_op->addr_usb_detect, + sizeof(pfw_op->addr_usb_detect)); +#if defined(HX_ULTRA_LOW_POWER) + himax_parse_assign_cmd(fw_addr_ulpm_33, pfw_op->addr_ulpm_33, + sizeof(pfw_op->addr_ulpm_33)); + himax_parse_assign_cmd(fw_addr_ulpm_34, pfw_op->addr_ulpm_34, + sizeof(pfw_op->addr_ulpm_34)); + himax_parse_assign_cmd(fw_data_ulpm_11, pfw_op->data_ulpm_11, + sizeof(pfw_op->data_ulpm_11)); + himax_parse_assign_cmd(fw_data_ulpm_22, pfw_op->data_ulpm_22, + sizeof(pfw_op->data_ulpm_22)); + himax_parse_assign_cmd(fw_data_ulpm_33, pfw_op->data_ulpm_33, + sizeof(pfw_op->data_ulpm_33)); + himax_parse_assign_cmd(fw_data_ulpm_aa, pfw_op->data_ulpm_aa, + sizeof(pfw_op->data_ulpm_aa)); +#endif +/* CORE_FW */ +/* CORE_FLASH */ + himax_parse_assign_cmd(flash_addr_spi200_trans_fmt, + pflash_op->addr_spi200_trans_fmt, + sizeof(pflash_op->addr_spi200_trans_fmt)); + himax_parse_assign_cmd(flash_addr_spi200_trans_ctrl, + pflash_op->addr_spi200_trans_ctrl, + sizeof(pflash_op->addr_spi200_trans_ctrl)); + himax_parse_assign_cmd(flash_addr_spi200_fifo_rst, + pflash_op->addr_spi200_fifo_rst, + sizeof(pflash_op->addr_spi200_fifo_rst)); + himax_parse_assign_cmd(flash_addr_spi200_flash_speed, + pflash_op->addr_spi200_flash_speed, + sizeof(pflash_op->addr_spi200_flash_speed)); + himax_parse_assign_cmd(flash_addr_spi200_rst_status, + pflash_op->addr_spi200_rst_status, + sizeof(pflash_op->addr_spi200_rst_status)); + himax_parse_assign_cmd(flash_addr_spi200_cmd, + pflash_op->addr_spi200_cmd, + sizeof(pflash_op->addr_spi200_cmd)); + himax_parse_assign_cmd(flash_addr_spi200_addr, + pflash_op->addr_spi200_addr, + sizeof(pflash_op->addr_spi200_addr)); + himax_parse_assign_cmd(flash_addr_spi200_data, + pflash_op->addr_spi200_data, + sizeof(pflash_op->addr_spi200_data)); + himax_parse_assign_cmd(flash_addr_spi200_bt_num, + pflash_op->addr_spi200_bt_num, + sizeof(pflash_op->addr_spi200_bt_num)); + himax_parse_assign_cmd(flash_data_spi200_trans_fmt, + pflash_op->data_spi200_trans_fmt, + sizeof(pflash_op->data_spi200_trans_fmt)); + himax_parse_assign_cmd(flash_data_spi200_txfifo_rst, + pflash_op->data_spi200_txfifo_rst, + sizeof(pflash_op->data_spi200_txfifo_rst)); + himax_parse_assign_cmd(flash_data_spi200_rxfifo_rst, + pflash_op->data_spi200_rxfifo_rst, + sizeof(pflash_op->data_spi200_rxfifo_rst)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_1, + pflash_op->data_spi200_trans_ctrl_1, + sizeof(pflash_op->data_spi200_trans_ctrl_1)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_2, + pflash_op->data_spi200_trans_ctrl_2, + sizeof(pflash_op->data_spi200_trans_ctrl_2)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_3, + pflash_op->data_spi200_trans_ctrl_3, + sizeof(pflash_op->data_spi200_trans_ctrl_3)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_4, + pflash_op->data_spi200_trans_ctrl_4, + sizeof(pflash_op->data_spi200_trans_ctrl_4)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_5, + pflash_op->data_spi200_trans_ctrl_5, + sizeof(pflash_op->data_spi200_trans_ctrl_5)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_6, + pflash_op->data_spi200_trans_ctrl_6, + sizeof(pflash_op->data_spi200_trans_ctrl_6)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_7, + pflash_op->data_spi200_trans_ctrl_7, + sizeof(pflash_op->data_spi200_trans_ctrl_7)); + himax_parse_assign_cmd(flash_data_spi200_cmd_1, + pflash_op->data_spi200_cmd_1, + sizeof(pflash_op->data_spi200_cmd_1)); + himax_parse_assign_cmd(flash_data_spi200_cmd_2, + pflash_op->data_spi200_cmd_2, + sizeof(pflash_op->data_spi200_cmd_2)); + himax_parse_assign_cmd(flash_data_spi200_cmd_3, + pflash_op->data_spi200_cmd_3, + sizeof(pflash_op->data_spi200_cmd_3)); + himax_parse_assign_cmd(flash_data_spi200_cmd_4, + pflash_op->data_spi200_cmd_4, + sizeof(pflash_op->data_spi200_cmd_4)); + himax_parse_assign_cmd(flash_data_spi200_cmd_5, + pflash_op->data_spi200_cmd_5, + sizeof(pflash_op->data_spi200_cmd_5)); + himax_parse_assign_cmd(flash_data_spi200_cmd_6, + pflash_op->data_spi200_cmd_6, + sizeof(pflash_op->data_spi200_cmd_6)); + himax_parse_assign_cmd(flash_data_spi200_cmd_7, + pflash_op->data_spi200_cmd_7, + sizeof(pflash_op->data_spi200_cmd_7)); + himax_parse_assign_cmd(flash_data_spi200_cmd_8, + pflash_op->data_spi200_cmd_8, + sizeof(pflash_op->data_spi200_cmd_8)); + himax_parse_assign_cmd(flash_data_spi200_addr, + pflash_op->data_spi200_addr, + sizeof(pflash_op->data_spi200_addr)); +/* CORE_FLASH */ +/* CORE_SRAM */ + /* sram start*/ + himax_parse_assign_cmd(sram_adr_mkey, + psram_op->addr_mkey, + sizeof(psram_op->addr_mkey)); + himax_parse_assign_cmd(sram_adr_rawdata_addr, + psram_op->addr_rawdata_addr, + sizeof(psram_op->addr_rawdata_addr)); + himax_parse_assign_cmd(sram_adr_rawdata_end, + psram_op->addr_rawdata_end, + sizeof(psram_op->addr_rawdata_end)); + himax_parse_assign_cmd(sram_passwrd_start, + psram_op->passwrd_start, + sizeof(psram_op->passwrd_start)); + himax_parse_assign_cmd(sram_passwrd_end, + psram_op->passwrd_end, + sizeof(psram_op->passwrd_end)); + /* sram end*/ +/* CORE_SRAM */ +/* CORE_DRIVER */ + himax_parse_assign_cmd(driver_addr_fw_define_flash_reload, + pdriver_op->addr_fw_define_flash_reload, + sizeof(pdriver_op->addr_fw_define_flash_reload)); + himax_parse_assign_cmd(driver_addr_fw_define_2nd_flash_reload, + pdriver_op->addr_fw_define_2nd_flash_reload, + sizeof(pdriver_op->addr_fw_define_2nd_flash_reload)); + himax_parse_assign_cmd(driver_addr_fw_define_int_is_edge, + pdriver_op->addr_fw_define_int_is_edge, + sizeof(pdriver_op->addr_fw_define_int_is_edge)); + himax_parse_assign_cmd(driver_addr_fw_define_rxnum_txnum, + pdriver_op->addr_fw_define_rxnum_txnum, + sizeof(pdriver_op->addr_fw_define_rxnum_txnum)); + himax_parse_assign_cmd(driver_addr_fw_define_maxpt_xyrvs, + pdriver_op->addr_fw_define_maxpt_xyrvs, + sizeof(pdriver_op->addr_fw_define_maxpt_xyrvs)); + himax_parse_assign_cmd(driver_addr_fw_define_x_y_res, + pdriver_op->addr_fw_define_x_y_res, + sizeof(pdriver_op->addr_fw_define_x_y_res)); + himax_parse_assign_cmd(driver_data_df_rx, + pdriver_op->data_df_rx, + sizeof(pdriver_op->data_df_rx)); + himax_parse_assign_cmd(driver_data_df_tx, + pdriver_op->data_df_tx, + sizeof(pdriver_op->data_df_tx)); + himax_parse_assign_cmd(driver_data_df_pt, + pdriver_op->data_df_pt, + sizeof(pdriver_op->data_df_pt)); + himax_parse_assign_cmd(driver_data_fw_define_flash_reload_dis, + pdriver_op->data_fw_define_flash_reload_dis, + sizeof(pdriver_op->data_fw_define_flash_reload_dis)); + himax_parse_assign_cmd(driver_data_fw_define_flash_reload_en, + pdriver_op->data_fw_define_flash_reload_en, + sizeof(pdriver_op->data_fw_define_flash_reload_en)); + himax_parse_assign_cmd( + driver_data_fw_define_rxnum_txnum_maxpt_sorting, + pdriver_op->data_fw_define_rxnum_txnum_maxpt_sorting, + sizeof(pdriver_op->data_fw_define_rxnum_txnum_maxpt_sorting)); + himax_parse_assign_cmd( + driver_data_fw_define_rxnum_txnum_maxpt_normal, + pdriver_op->data_fw_define_rxnum_txnum_maxpt_normal, + sizeof(pdriver_op->data_fw_define_rxnum_txnum_maxpt_normal)); +/* CORE_DRIVER */ +#if defined(HX_ZERO_FLASH) + himax_parse_assign_cmd(zf_data_dis_flash_reload, + pzf_op->data_dis_flash_reload, + sizeof(pzf_op->data_dis_flash_reload)); + himax_parse_assign_cmd(zf_addr_system_reset, + pzf_op->addr_system_reset, + sizeof(pzf_op->addr_system_reset)); + himax_parse_assign_cmd(zf_data_system_reset, + pzf_op->data_system_reset, + sizeof(pzf_op->data_system_reset)); + himax_parse_assign_cmd(zf_data_sram_start_addr, + pzf_op->data_sram_start_addr, + sizeof(pzf_op->data_sram_start_addr)); + himax_parse_assign_cmd(zf_data_cfg_info, + pzf_op->data_cfg_info, + sizeof(pzf_op->data_cfg_info)); + himax_parse_assign_cmd(zf_data_fw_cfg_1, + pzf_op->data_fw_cfg_1, + sizeof(pzf_op->data_fw_cfg_1)); + himax_parse_assign_cmd(zf_data_fw_cfg_2, + pzf_op->data_fw_cfg_2, + sizeof(pzf_op->data_fw_cfg_2)); + himax_parse_assign_cmd(zf_data_fw_cfg_3, + pzf_op->data_fw_cfg_3, + sizeof(pzf_op->data_fw_cfg_3)); + himax_parse_assign_cmd(zf_data_adc_cfg_1, + pzf_op->data_adc_cfg_1, + sizeof(pzf_op->data_adc_cfg_1)); + himax_parse_assign_cmd(zf_data_adc_cfg_2, + pzf_op->data_adc_cfg_2, + sizeof(pzf_op->data_adc_cfg_2)); + himax_parse_assign_cmd(zf_data_adc_cfg_3, + pzf_op->data_adc_cfg_3, + sizeof(pzf_op->data_adc_cfg_3)); + himax_parse_assign_cmd(zf_data_map_table, + pzf_op->data_map_table, + sizeof(pzf_op->data_map_table)); +/* himax_parse_assign_cmd(zf_data_mode_switch, + * pzf_op->data_mode_switch, + * sizeof(pzf_op->data_mode_switch)); + */ + himax_parse_assign_cmd(zf_addr_sts_chk, + pzf_op->addr_sts_chk, + sizeof(pzf_op->addr_sts_chk)); + himax_parse_assign_cmd(zf_data_activ_sts, + pzf_op->data_activ_sts, + sizeof(pzf_op->data_activ_sts)); + himax_parse_assign_cmd(zf_addr_activ_relod, + pzf_op->addr_activ_relod, + sizeof(pzf_op->addr_activ_relod)); + himax_parse_assign_cmd(zf_data_activ_in, + pzf_op->data_activ_in, + sizeof(pzf_op->data_activ_in)); +#endif +} +EXPORT_SYMBOL(himax_mcu_in_cmd_init); + +/* init end*/ +/* CORE_INIT */ diff --git a/himax_inspection.c b/himax_inspection.c new file mode 100644 index 0000000..6532bb5 --- /dev/null +++ b/himax_inspection.c @@ -0,0 +1,2853 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for inspection functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_inspection.h" + +static int g_gap_vertical_partial = 3; +static int *g_gap_vertical_part; +static int g_gap_horizontal_partial = 3; +static int *g_gap_horizontal_part; + +static int g_dc_max; + +static int g_1kind_raw_size; +uint32_t g_rslt_data_len; +int **g_inspection_criteria; +int *g_inspt_crtra_flag; +int *g_test_item_flag; +int do_lpwg_test; +int HX_CRITERIA_ITEM; +int HX_CRITERIA_SIZE; +char *g_rslt_data; +bool file_w_flag; +static char g_file_path[256]; +static char g_rslt_log[256]; +static char g_start_log[512]; +#define FAIL_IN_INDEX "%s: %s FAIL in index %d\n" +#define FAIL_IN_INDEX_CRTRA \ + "%s: %s FAIL in index %d,max=%d, min=%d, RAW=%d\n" +char *g_hx_head_str[] = { + "TP_Info", + "Project_Info", + "TestItem", + "TestCriteria", + NULL +}; + +/*Need to map THP_INSPECTION_ENUM*/ +char *g_himax_inspection_mode[] = { + "HIMAX_OPEN", + "HIMAX_MICRO_OPEN", + "HIMAX_SHORT", + "HIMAX_SC", + "HIMAX_WEIGHT_NOISE", + "HIMAX_ABS_NOISE", + "HIMAX_RAWDATA", + "HIMAX_BPN_RAWDATA", + "HIMAX_SORTING", + "HIMAX_GAPTEST_RAW", + /*"HIMAX_GAPTEST_RAW_X",*/ + /*"HIMAX_GAPTEST_RAW_Y",*/ + + "HIMAX_ACT_IDLE_NOISE", + "HIMAX_ACT_IDLE_RAWDATA", + "HIMAX_ACT_IDLE_BPN_RAWDATA", + + "HIMAX_LPWUG_WEIGHT_NOISE", + "HIMAX_LPWUG_ABS_NOISE", + "HIMAX_LPWUG_RAWDATA", + "HIMAX_LPWUG_BPN_RAWDATA", + + "HIMAX_LPWUG_IDLE_NOISE", + "HIMAX_LPWUG_IDLE_RAWDATA", + "HIMAX_LPWUG_IDLE_BPN_RAWDATA", + + "HIMAX_BACK_NORMAL", + NULL +}; + +/* for criteria */ +char *g_hx_inspt_crtra_name[] = { + "CRITERIA_RAW_MIN", + "CRITERIA_RAW_MAX", + "CRITERIA_RAW_BPN_MIN", + "CRITERIA_RAW_BPN_MAX", + "CRITERIA_SC_MIN", + "CRITERIA_SC_MAX", + "CRITERIA_SC_GOLDEN", + "CRITERIA_SHORT_MIN", + "CRITERIA_SHORT_MAX", + "CRITERIA_OPEN_MIN", + "CRITERIA_OPEN_MAX", + "CRITERIA_MICRO_OPEN_MIN", + "CRITERIA_MICRO_OPEN_MAX", + "CRITERIA_NOISE_WT_MIN", + "CRITERIA_NOISE_WT_MAX", + "CRITERIA_NOISE_ABS_MIN", + "CRITERIA_NOISE_ABS_MAX", + "CRITERIA_SORT_MIN", + "CRITERIA_SORT_MAX", + + "CRITERIA_GAP_RAW_HOR_MIN", + "CRITERIA_GAP_RAW_HOR_MAX", + "CRITERIA_GAP_RAW_VER_MIN", + "CRITERIA_GAP_RAW_VER_MAX", + + "ACT_IDLE_NOISE_MIN", + "ACT_IDLE_NOISE_MAX", + "ACT_IDLE_RAWDATA_MIN", + "ACT_IDLE_RAWDATA_MAX", + "ACT_IDLE_RAW_BPN_MIN", + "ACT_IDLE_RAW_BPN_MAX", + + "LPWUG_NOISE_WT_MIN", + "LPWUG_NOISE_WT_MAX", + "LPWUG_NOISE_ABS_MIN", + "LPWUG_NOISE_ABS_MAX", + "LPWUG_RAWDATA_MIN", + "LPWUG_RAWDATA_MAX", + "LPWUG_RAW_BPN_MIN", + "LPWUG_RAW_BPN_MAX", + + "LPWUG_IDLE_NOISE_MIN", + "LPWUG_IDLE_NOISE_MAX", + "LPWUG_IDLE_RAWDATA_MIN", + "LPWUG_IDLE_RAWDATA_MAX", + "LPWUG_IDLE_RAW_BPN_MIN", + "LPWUG_IDLE_RAW_BPN_MAX", + NULL +}; + +/* for other setting */ +char *g_hx_inspt_setting_name[] = { + "RAW_BS_FRAME", + "NOISE_BS_FRAME", + "ACT_IDLE_BS_FRAME", + "LP_BS_FRAME", + "LP_IDLE_BS_FRAME", + + "NORMAL_N_FRAME", + "IDLE_N_FRAME", + "LP_RAW_N_FRAME", + "LP_NOISE_N_FRAME", + "LP_IDLE_RAW_N_FRAME", + "LP_IDLE_NOISE_N_FRAME", + NULL +}; + +int *g_hx_inspt_setting_val; + +void (*fp_himax_self_test_init)(void) = himax_inspection_init; + + +static void himax_press_powerkey(void) +{ + I(" %s POWER KEY event %x press\n", __func__, KEY_POWER); + input_report_key(private_ts->input_dev, KEY_POWER, 1); + input_sync(private_ts->input_dev); + + msleep(100); + + I(" %s POWER KEY event %x release\n", __func__, KEY_POWER); + input_report_key(private_ts->input_dev, KEY_POWER, 0); + input_sync(private_ts->input_dev); +} + + +static uint16_t NOISEMAX; +static uint16_t g_recal_thx; + +static int arraydata_max1, arraydata_max2, arraydata_max3; +static int arraydata_min1, arraydata_min2, arraydata_min3; + +void himax_get_arraydata_edge(int *RAW) +{ + int temp, i, j; + int len = ic_data->HX_RX_NUM * ic_data->HX_TX_NUM; + int *ArrayData; + + ArrayData = kcalloc(len, sizeof(int), GFP_KERNEL); + if (ArrayData == NULL) { + E("%s: allocate ArrayData failed\n", __func__); + return; + } + + for (i = 0; i < len; i++) + ArrayData[i] = RAW[i]; + for (j = len-1; j > 0; j--) { /*min to max*/ + for (i = 0; i < j; i++) { + if (ArrayData[i] > ArrayData[i+1]) { + temp = ArrayData[i]; + ArrayData[i] = ArrayData[i+1]; + ArrayData[i+1] = temp; + } + } + } + + arraydata_min1 = ArrayData[0]; + arraydata_min2 = ArrayData[1]; + arraydata_min3 = ArrayData[2]; + arraydata_max1 = ArrayData[len-3]; + arraydata_max2 = ArrayData[len-2]; + arraydata_max3 = ArrayData[len-1]; + +} + +static int hx_test_data_get(int RAW[], char *start_log, char *result, + int now_item) +{ + uint32_t i; + + ssize_t len = 0; + char *testdata = NULL; + uint32_t SZ_SIZE = g_1kind_raw_size; + + I("%s: Entering, Now type=%s!\n", __func__, + g_himax_inspection_mode[now_item]); + + testdata = kzalloc(sizeof(char) * SZ_SIZE, GFP_KERNEL); + if (testdata == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return MEM_ALLOC_FAIL; + } + + len += snprintf((testdata + len), SZ_SIZE - len, "%s", start_log); + for (i = 0; i < ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; i++) { + if (i > 1 && ((i + 1) % ic_data->HX_RX_NUM) == 0) + len += snprintf((testdata + len), SZ_SIZE - len, + "%5d,\n", RAW[i]); + else + len += snprintf((testdata + len), SZ_SIZE - len, + "%5d,", RAW[i]); + } + len += snprintf((testdata + len), SZ_SIZE - len, "\n%s", result); + + memcpy(&g_rslt_data[0], testdata, len); + g_rslt_data_len = len; + I("%s: g_rslt_data_len=%d!\n", __func__, g_rslt_data_len); + + /* dbg */ + /* for(i = 0; i < SZ_SIZE; i++) + * { + * I("0x%04X, ", g_rslt_data[i + (now_item * SZ_SIZE)]); + * if(i > 0 && (i % 16 == 15)) + * PI("\n"); + * } + */ + + kfree(testdata); + I("%s: End!\n", __func__); + return NO_ERR; +} + +static int himax_switch_mode_inspection(int mode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4] = {0}; + + I("%s: Entering\n", __func__); + + /*Stop Handshaking*/ + himax_parse_assign_cmd(sram_adr_rawdata_addr, tmp_addr, + sizeof(tmp_addr)); + g_core_fp.fp_register_write(tmp_addr, tmp_data, 4); + + /*Swtich Mode*/ + switch (mode) { + case HX_SORTING: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_SORTING_START; + tmp_data[0] = PWD_SORTING_START; + break; + case HX_OPEN: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_OPEN_START; + tmp_data[0] = PWD_OPEN_START; + break; + case HX_MICRO_OPEN: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_OPEN_START; + tmp_data[0] = PWD_OPEN_START; + break; + case HX_SHORT: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_SHORT_START; + tmp_data[0] = PWD_SHORT_START; + break; + + case HX_GAPTEST_RAW: + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_RAWDATA_START; + tmp_data[0] = PWD_RAWDATA_START; + break; + + case HX_WT_NOISE: + case HX_ABS_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_NOISE_START; + tmp_data[0] = PWD_NOISE_START; + break; + + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_ACT_IDLE_START; + tmp_data[0] = PWD_ACT_IDLE_START; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_LP_START; + tmp_data[0] = PWD_LP_START; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_LP_IDLE_START; + tmp_data[0] = PWD_LP_IDLE_START; + break; + + default: + I("%s,Nothing to be done!\n", __func__); + break; + } + + if (g_core_fp.fp_assign_sorting_mode != NULL) + g_core_fp.fp_assign_sorting_mode(tmp_data); + I("%s: End of setting!\n", __func__); + + return 0; + +} + +static void himax_raw_data_dbg(int RAW[]) +{ + uint32_t i = 0; + uint32_t j = 0; + uint32_t index = 0; + + for (j = 0; j < ic_data->HX_RX_NUM; j++) { + if (j == 0) + PI(" RX%2d", j + 1); + else + PI(" RX%2d", j + 1); + } + PI("\n"); + + for (i = 0; i < ic_data->HX_TX_NUM; i++) { + PI("TX%2d", i + 1); + for (j = 0; j < ic_data->HX_RX_NUM; j++) { + PI("%5d ", RAW[index]); + index++; + } + PI("\n"); + } + + for (i = 0; i < ic_data->HX_RX_NUM; i++) { + if (i == 0) + PI("RX: %2d", RAW[index]); + else + PI(", %2d", RAW[index]); + index++; + } + PI("\n"); + + for (i = 0; i < ic_data->HX_TX_NUM; i++) { + if (i == 0) + PI("TX: %2d", RAW[index]); + else + PI(", %2d", RAW[index]); + index++; + } + +} + +static uint32_t himax_get_rawdata(int RAW[], uint32_t len, uint8_t checktype) +{ + uint8_t *tmp_rawdata; + bool get_raw_rlst; + uint32_t i = 0; + int Min_DATA = 99999; + int Max_DATA = -99999; + + /* We use two bytes to combine a value of rawdata.*/ + tmp_rawdata = kzalloc(sizeof(uint8_t) * (len * 2), GFP_KERNEL); + if (tmp_rawdata == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return HX_INSP_MEMALLCTFAIL; + } + + get_raw_rlst = g_core_fp.fp_get_DSRAM_data(tmp_rawdata, false); + if (!get_raw_rlst) + goto DIRECT_END; + + /* Copy Data*/ + for (i = 0; i < len; i++) { + if (checktype == HX_WT_NOISE || + checktype == HX_ABS_NOISE || + checktype == HX_ACT_IDLE_NOISE || + checktype == HX_LP_WT_NOISE || + checktype == HX_LP_ABS_NOISE || + checktype == HX_LP_IDLE_NOISE) + RAW[i] = ((int8_t)tmp_rawdata[(i * 2) + 1]<<8) + + tmp_rawdata[(i * 2)]; + else + RAW[i] = tmp_rawdata[(i * 2) + 1]<<8 | + tmp_rawdata[(i * 2)]; + + if (i < (len - ic_data->HX_RX_NUM - ic_data->HX_TX_NUM)) { + if (i == 0) + Min_DATA = Max_DATA = RAW[0]; + else if (RAW[i] > Max_DATA) + Max_DATA = RAW[i]; + else if (RAW[i] < Min_DATA) + Min_DATA = RAW[i]; + } + } + I("Max = %5d, Min = %5d\n", Max_DATA, Min_DATA); + + if (private_ts->debug_log_level & BIT(4)) + himax_raw_data_dbg(RAW); + +DIRECT_END: + kfree(tmp_rawdata); + + if (get_raw_rlst) + return HX_INSP_OK; + else + return HX_INSP_EGETRAW; + +} + +static void himax_switch_data_type(uint8_t checktype) +{ + uint8_t datatype = 0x00; + + if (private_ts->debug_log_level & BIT(4)) { + I("%s,Expected type[%d]=%s" + , __func__ + , checktype, g_himax_inspection_mode[checktype]); + } + switch (checktype) { + case HX_SORTING: + datatype = DATA_SORTING; + break; + case HX_OPEN: + datatype = DATA_OPEN; + break; + case HX_MICRO_OPEN: + datatype = DATA_MICRO_OPEN; + break; + case HX_SHORT: + datatype = DATA_SHORT; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_GAPTEST_RAW: + datatype = DATA_RAWDATA; + break; + + case HX_WT_NOISE: + case HX_ABS_NOISE: + datatype = DATA_NOISE; + break; + case HX_BACK_NORMAL: + datatype = DATA_BACK_NORMAL; + break; + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + datatype = DATA_ACT_IDLE_RAWDATA; + break; + case HX_ACT_IDLE_NOISE: + datatype = DATA_ACT_IDLE_NOISE; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + datatype = DATA_LP_RAWDATA; + break; + case HX_LP_WT_NOISE: + case HX_LP_ABS_NOISE: + datatype = DATA_LP_NOISE; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + datatype = DATA_LP_IDLE_RAWDATA; + break; + case HX_LP_IDLE_NOISE: + datatype = DATA_LP_IDLE_NOISE; + break; + + default: + E("Wrong type=%d\n", checktype); + break; + } + g_core_fp.fp_diag_register_set(datatype, 0x00, false); +} + +static void himax_bank_search_set(uint16_t Nframe, uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + /*skip frame 0x100070F4*/ + himax_parse_assign_cmd(addr_skip_frame, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + + switch (checktype) { + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + if (g_hx_inspt_setting_val[ACT_IDLE_BS_FRAME] > 0) + tmp_data[0] = g_hx_inspt_setting_val[ACT_IDLE_BS_FRAME]; + else + tmp_data[0] = BS_ACT_IDLE; + break; + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + if (g_hx_inspt_setting_val[LP_BS_FRAME] > 0) + tmp_data[0] = g_hx_inspt_setting_val[LP_BS_FRAME]; + else + tmp_data[0] = BS_LPWUG; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + if (g_hx_inspt_setting_val[LP_IDLE_BS_FRAME] > 0) + tmp_data[0] = g_hx_inspt_setting_val[LP_IDLE_BS_FRAME]; + else + tmp_data[0] = BS_LP_dile; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + if (g_hx_inspt_setting_val[RAW_BS_FRAME] > 0) + tmp_data[0] = g_hx_inspt_setting_val[RAW_BS_FRAME]; + else + tmp_data[0] = BS_RAWDATA; + break; + case HX_WT_NOISE: + case HX_ABS_NOISE: + if (g_hx_inspt_setting_val[NOISE_BS_FRAME] > 0) + tmp_data[0] = g_hx_inspt_setting_val[NOISE_BS_FRAME]; + else + tmp_data[0] = BS_NOISE; + break; + default: + tmp_data[0] = BS_OPENSHORT; + break; + } + if (private_ts->debug_log_level & BIT(4)) { + I("%s,Now BankSearch Value=%d\n", + __func__, tmp_data[0]); + } + g_core_fp.fp_register_write(tmp_addr, tmp_data, 4); +} + +static void himax_neg_noise_sup(uint8_t *data) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + /*0x10007FD8 Check support negative value or not */ + himax_parse_assign_cmd(addr_neg_noise_sup, tmp_addr, + sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + + if ((tmp_data[3] & 0x04) == 0x04) { + himax_parse_assign_cmd(data_neg_noise, tmp_data, + sizeof(tmp_data)); + data[2] = tmp_data[2]; data[3] = tmp_data[3]; + } else + I("%s Not support negative noise\n", __func__); +} + +static void himax_set_N_frame(uint16_t Nframe, uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_bank_search_set(Nframe, checktype); + + /*IIR MAX - 0x10007294*/ + himax_parse_assign_cmd(fw_addr_set_frame_addr, + tmp_addr, sizeof(tmp_addr)); + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)((Nframe & 0xFF00) >> 8); + tmp_data[0] = (uint8_t)(Nframe & 0x00FF); + g_core_fp.fp_register_write(tmp_addr, tmp_data, 4); + + if (checktype == HX_WT_NOISE || + checktype == HX_ABS_NOISE || + checktype == HX_LP_WT_NOISE || + checktype == HX_LP_ABS_NOISE) + himax_neg_noise_sup(tmp_data); + if (private_ts->debug_log_level & BIT(4)) { + I("%s,Now N frame Value=0x%02X%02X\n", + __func__, tmp_data[1], tmp_data[0]); + } + g_core_fp.fp_register_write(tmp_addr, tmp_data, 4); +} + +static void himax_get_noise_base(uint8_t checktype)/*Normal Threshold*/ +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t tmp_addr2[4]; + uint8_t tmp_data2[4]; + + switch (checktype) { + case HX_WT_NOISE: + himax_parse_assign_cmd(addr_normal_noise_thx, + tmp_addr, sizeof(tmp_addr)); + break; + case HX_LP_WT_NOISE: + himax_parse_assign_cmd(addr_lpwug_noise_thx, + tmp_addr, sizeof(tmp_addr)); + break; + default: + I("%s Not support type\n", __func__); + } + himax_parse_assign_cmd(addr_noise_scale, + tmp_addr2, sizeof(tmp_addr2)); + g_core_fp.fp_register_read(tmp_addr2, tmp_data2, 4); + tmp_data2[1] = tmp_data2[1]>>4; + if (tmp_data2[1] == 0) + tmp_data2[1] = 1; + + /*normal : 0x1000708F, LPWUG:0x10007093*/ + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + NOISEMAX = tmp_data[3] * tmp_data2[1]; + + himax_parse_assign_cmd(addr_recal_thx, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + g_recal_thx = tmp_data[2] * tmp_data2[1];/*0x10007092*/ + I("%s: NOISEMAX = %d, g_recal_thx = %d\n", __func__, + NOISEMAX, g_recal_thx); +} + +static uint16_t himax_get_palm_num(void)/*Palm Number*/ +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint16_t palm_num; + + himax_parse_assign_cmd(addr_palm_num, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + palm_num = tmp_data[3];/*0x100070AB*/ + I("%s: palm_num = %d ", __func__, palm_num); + + return palm_num; +} + +static int himax_get_noise_weight_test(uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint16_t weight = 0; + uint16_t value = 0; + + himax_parse_assign_cmd(addr_weight_sup, + tmp_addr, sizeof(tmp_addr)); + + /*0x100072C8 weighting value*/ + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + if (tmp_data[3] != 0x72 || tmp_data[2] != 0xC8) + return FW_NOT_READY; + + value = (tmp_data[1] << 8) | tmp_data[0]; + I("%s: value = %d, %d, %d ", __func__, value, tmp_data[2], tmp_data[3]); + + switch (checktype) { + case HX_WT_NOISE: + himax_parse_assign_cmd(addr_normal_weight_a, + tmp_addr, sizeof(tmp_addr)); + break; + case HX_LP_WT_NOISE: + himax_parse_assign_cmd(addr_lpwug_weight_a, + tmp_addr, sizeof(tmp_addr)); + break; + default: + I("%s Not support type\n", __func__); + } + + /*Normal:0x1000709C, LPWUG:0x100070A0 weighting threshold*/ + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + weight = tmp_data[0]; + + himax_parse_assign_cmd(addr_weight_b, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + tmp_data[1] = tmp_data[1]&0x0F; + if (tmp_data[1] == 0) + tmp_data[1] = 1; + weight = tmp_data[1] * weight;/*0x10007095 weighting threshold*/ + I("%s: weight = %d ", __func__, weight); + + if (value > weight) + return ERR_TEST_FAIL; + else + return 0; +} + +static uint32_t himax_check_mode(uint8_t checktype) +{ + int ret = 0; + uint8_t tmp_data[4] = {0}; + uint8_t wait_pwd[2] = {0}; + + switch (checktype) { + case HX_SORTING: + wait_pwd[0] = PWD_SORTING_END; + wait_pwd[1] = PWD_SORTING_END; + break; + case HX_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_MICRO_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_SHORT: + wait_pwd[0] = PWD_SHORT_END; + wait_pwd[1] = PWD_SHORT_END; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_GAPTEST_RAW: + wait_pwd[0] = PWD_RAWDATA_END; + wait_pwd[1] = PWD_RAWDATA_END; + break; + + case HX_WT_NOISE: + case HX_ABS_NOISE: + wait_pwd[0] = PWD_NOISE_END; + wait_pwd[1] = PWD_NOISE_END; + break; + + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + wait_pwd[0] = PWD_ACT_IDLE_END; + wait_pwd[1] = PWD_ACT_IDLE_END; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + wait_pwd[0] = PWD_LP_END; + wait_pwd[1] = PWD_LP_END; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + wait_pwd[0] = PWD_LP_IDLE_END; + wait_pwd[1] = PWD_LP_IDLE_END; + break; + + default: + E("Wrong type=%d\n", checktype); + break; + } + + if (g_core_fp.fp_check_sorting_mode != NULL) { + ret = g_core_fp.fp_check_sorting_mode(tmp_data); + if (ret != NO_ERR) + return ret; + } + + if ((wait_pwd[0] == tmp_data[0]) && (wait_pwd[1] == tmp_data[1])) { + I("%s,It had been changed to [%d]=%s\n", + __func__, + checktype, g_himax_inspection_mode[checktype]); + return NO_ERR; + } else { + return 1; + } +} + +#define TEMP_LOG \ +"%s:%s,tmp_data[0]=%x,tmp_data[1]=%x,tmp_data[2]=%x,tmp_data[3]=%x\n" + +static uint32_t himax_wait_sorting_mode(uint8_t checktype) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + uint8_t wait_pwd[2] = {0}; + int count = 0; + + if (private_ts->debug_log_level & BIT(4)) + I("%s:start!\n", __func__); + + switch (checktype) { + case HX_SORTING: + wait_pwd[0] = PWD_SORTING_END; + wait_pwd[1] = PWD_SORTING_END; + break; + case HX_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_MICRO_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_SHORT: + wait_pwd[0] = PWD_SHORT_END; + wait_pwd[1] = PWD_SHORT_END; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_GAPTEST_RAW: + wait_pwd[0] = PWD_RAWDATA_END; + wait_pwd[1] = PWD_RAWDATA_END; + break; + case HX_WT_NOISE: + case HX_ABS_NOISE: + wait_pwd[0] = PWD_NOISE_END; + wait_pwd[1] = PWD_NOISE_END; + break; + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + wait_pwd[0] = PWD_ACT_IDLE_END; + wait_pwd[1] = PWD_ACT_IDLE_END; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + wait_pwd[0] = PWD_LP_END; + wait_pwd[1] = PWD_LP_END; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + wait_pwd[0] = PWD_LP_IDLE_END; + wait_pwd[1] = PWD_LP_IDLE_END; + break; + + default: + I("No Change Mode and now type=%d\n", checktype); + break; + } + I("%s:NowType[%d] = %s, Expected=0x%02X%02X\n", + __func__, checktype, g_himax_inspection_mode[checktype], + wait_pwd[1], wait_pwd[0]); + do { + if (private_ts->debug_log_level & BIT(4)) + I("%s:start check_sorting_mode!\n", __func__); + if (g_core_fp.fp_check_sorting_mode != NULL) + g_core_fp.fp_check_sorting_mode(tmp_data); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end check_sorting_mode!\n", __func__); + if ((wait_pwd[0] == tmp_data[0]) && + (wait_pwd[1] == tmp_data[1])) + return HX_INSP_OK; + if (private_ts->debug_log_level & BIT(4)) { + himax_parse_assign_cmd(fw_addr_chk_fw_status, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + I(TEMP_LOG, __func__, "0x900000A8", + tmp_data[0], tmp_data[1], + tmp_data[2], tmp_data[3]); + + himax_parse_assign_cmd(fw_addr_flag_reset_event, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + I(TEMP_LOG, __func__, "0x900000E4", + tmp_data[0], tmp_data[1], + tmp_data[2], tmp_data[3]); + + himax_parse_assign_cmd(fw_addr_fw_dbg_msg_addr, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, tmp_data, 4); + I(TEMP_LOG, __func__, "0x10007F40", + tmp_data[0], tmp_data[1], + tmp_data[2], tmp_data[3]); + + I("Now retry %d times!\n", count); + } + count++; + msleep(50); + } while (count < 50); + + if (private_ts->debug_log_level & BIT(4)) + I("%s:end\n", __func__); + return HX_INSP_ESWITCHMODE; +} + +/* HX_GAP START gap test function */ +/* extern int himax_write_to_ic_flash_flow(uint32_t start_addr,*/ +/* uint32_t *write_data, uint32_t write_len);*/ + +static int himax_gap_test_vertical_setting(void) +{ + g_gap_vertical_part[0] = 0; + g_gap_vertical_part[1] = 4; + g_gap_vertical_part[2] = 8; + + return NO_ERR; +} + +static void himax_cal_gap_data_vertical(int start, int end_idx, int direct, + uint32_t *org_raw, uint32_t *result_raw) +{ + int i = 0; + int rx_num = ic_data->HX_RX_NUM; + + I("%s:start=%d,end_idx=%d\n", __func__, start, end_idx); + + for (i = start; i < (start + rx_num*end_idx); i++) { + if (direct == 0) { /* up - down */ + if (i < start+rx_num) + result_raw[i] = 0; + else + result_raw[i] = org_raw[i-rx_num] - org_raw[i]; + + } else { /* down - up */ + if (i > (start + rx_num*(end_idx-1)-1)) + result_raw[i] = 0; + else + result_raw[i] = org_raw[i+rx_num] - org_raw[i]; + + } + } +} + +static int himax_gap_test_vertical_raw(int test_type, int *org_raw) +{ + int i_partial = 0; + int tmp_start = 0; + int tmp_end_idx = 0; + uint32_t *result_raw = NULL; + int i = 0; + int ret_val = NO_ERR; + + int tx_num = ic_data->HX_TX_NUM; + int rx_num = ic_data->HX_RX_NUM; + + g_gap_vertical_part = kcalloc(g_gap_vertical_partial, + sizeof(int), GFP_KERNEL); + if (g_gap_vertical_part == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return MEM_ALLOC_FAIL; + } + + result_raw = kcalloc(tx_num*rx_num, sizeof(uint32_t), GFP_KERNEL); + if (result_raw == NULL) { + E("%s: Memory allocation falied!\n", __func__); + ret_val = MEM_ALLOC_FAIL; + goto alloc_result_raw_failed; + } + + himax_gap_test_vertical_setting(); + + I("Print vertical ORG RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", org_raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i_partial = 0; i_partial < g_gap_vertical_partial; i_partial++) { + + tmp_start = g_gap_vertical_part[i_partial]*rx_num; + if (i_partial+1 == g_gap_vertical_partial) + tmp_end_idx = tx_num - g_gap_vertical_part[i_partial]; + else + tmp_end_idx = g_gap_vertical_part[i_partial+1] - + g_gap_vertical_part[i_partial]; + + if (i_partial % 2 == 0) + himax_cal_gap_data_vertical(tmp_start, tmp_end_idx, 0, + org_raw, result_raw); + else + himax_cal_gap_data_vertical(tmp_start, tmp_end_idx, 1, + org_raw, result_raw); + + } + + I("Print Vertical New RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", result_raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i = 0; i < tx_num*rx_num; i++) { + if (result_raw[i] < g_inspection_criteria[IDX_GAP_VER_RAWMIN][i] + && + result_raw[i] > g_inspection_criteria[IDX_GAP_VER_RAWMAX][i]) { + ret_val = NO_ERR - i; + break; + } + } + + /* himax_write_to_ic_flash_flow(0x1A000,result_raw,tx_num*rx_num); */ + kfree(result_raw); +alloc_result_raw_failed: + kfree(g_gap_vertical_part); + g_gap_vertical_part = NULL; + + return ret_val; +} + +static int himax_gap_test_horizontal_setting(void) +{ + g_gap_horizontal_part[0] = 0; + g_gap_horizontal_part[1] = 8; + g_gap_horizontal_part[2] = 24; + + return NO_ERR; +} + +static void himax_cal_gap_data_horizontal(int start, int end_idx, int direct, + uint32_t *org_raw, uint32_t *result_raw) +{ + int i = 0; + int j = 0; + int rx_num = ic_data->HX_RX_NUM; + int tx_num = ic_data->HX_TX_NUM; + + I("start=%d,end_idx=%d\n", start, end_idx); + + for (j = 0; j < tx_num; j++) { + for (i = (start + (j*rx_num)); + i < (start + (j*rx_num) + end_idx); i++) { + /* left - right */ + if (direct == 0) { + if (i == (start + (j*rx_num))) + result_raw[i] = 0; + else + result_raw[i] = + org_raw[i-1] - org_raw[i]; + + } else { /* right - left */ + if (i == ((start + (j*rx_num) + end_idx) - 1)) + result_raw[i] = 0; + else + result_raw[i] = + org_raw[i + 1] - org_raw[i]; + } + } + } +} + +static int himax_gap_test_honrizontal_raw(int test_type, int *raw) +{ + int rx_num = ic_data->HX_RX_NUM; + int tx_num = ic_data->HX_TX_NUM; + int tmp_start = 0; + int tmp_end_idx = 0; + int i_partial = 0; + int *result_raw; + int i = 0; + int ret_val = NO_ERR; + + g_gap_horizontal_part = kcalloc(g_gap_horizontal_partial, + sizeof(int), GFP_KERNEL); + if (g_gap_horizontal_part == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return MEM_ALLOC_FAIL; + } + + result_raw = kcalloc(tx_num*rx_num, sizeof(int), GFP_KERNEL); + if (result_raw == NULL) { + E("%s: Memory allocation falied!\n", __func__); + ret_val = MEM_ALLOC_FAIL; + goto alloc_result_raw_failed; + } + + himax_gap_test_horizontal_setting(); + + I("Print Horizontal ORG RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i_partial = 0; + i_partial < g_gap_horizontal_partial; + i_partial++) { + tmp_start = g_gap_horizontal_part[i_partial]; + if (i_partial+1 == g_gap_horizontal_partial) + tmp_end_idx = rx_num - g_gap_horizontal_part[i_partial]; + else + tmp_end_idx = g_gap_horizontal_part[i_partial+1] - + g_gap_horizontal_part[i_partial]; + + if (i_partial % 2 == 0) + himax_cal_gap_data_horizontal(tmp_start, tmp_end_idx, + 0, raw, result_raw); + else + himax_cal_gap_data_horizontal(tmp_start, tmp_end_idx, + 1, raw, result_raw); + + } + I("Print Horizontal New RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", result_raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i = 0; i < tx_num*rx_num; i++) { + if (result_raw[i] < g_inspection_criteria[IDX_GAP_HOR_RAWMIN][i] + && + result_raw[i] > g_inspection_criteria[IDX_GAP_HOR_RAWMAX][i]) { + ret_val = NO_ERR - i; + break; + } + } + + /* himax_write_to_ic_flash_flow(0x1A800,result_raw,tx_num*rx_num); */ + kfree(result_raw); +alloc_result_raw_failed: + kfree(g_gap_horizontal_part); + g_gap_horizontal_part = NULL; + + return ret_val; +} + +static uint32_t himax_data_compare(uint8_t checktype, int *RAW, + int ret_val) +{ + int i = 0; + int idx_max = 0; + int idx_min = 0; + int block_num = ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; + uint16_t palm_num = 0; + uint16_t noise_count = 0; + + switch (checktype) { + case HX_SORTING: + idx_min = IDX_SORTMIN; + break; + case HX_OPEN: + idx_max = IDX_OPENMAX; + idx_min = IDX_OPENMIN; + break; + + case HX_MICRO_OPEN: + idx_max = IDX_M_OPENMAX; + idx_min = IDX_M_OPENMIN; + break; + + case HX_SHORT: + idx_max = IDX_SHORTMAX; + idx_min = IDX_SHORTMIN; + break; + + case HX_RAWDATA: + idx_max = IDX_RAWMAX; + idx_min = IDX_RAWMIN; + break; + + case HX_BPN_RAWDATA: + idx_max = IDX_BPN_RAWMAX; + idx_min = IDX_BPN_RAWMIN; + break; + case HX_SC: + idx_max = IDX_SCMAX; + idx_min = IDX_SCMIN; + break; + case HX_WT_NOISE: + idx_max = IDX_WT_NOISEMAX; + idx_min = IDX_WT_NOISEMIN; + break; + case HX_ABS_NOISE: + idx_max = IDX_ABS_NOISEMAX; + idx_min = IDX_ABS_NOISEMIN; + break; + case HX_GAPTEST_RAW: + break; + + case HX_ACT_IDLE_RAWDATA: + idx_max = IDX_ACT_IDLE_RAWDATA_MAX; + idx_min = IDX_ACT_IDLE_RAWDATA_MIN; + break; + + case HX_ACT_IDLE_BPN_RAWDATA: + idx_max = IDX_ACT_IDLE_RAW_BPN_MAX; + idx_min = IDX_ACT_IDLE_RAW_BPN_MIN; + break; + + case HX_ACT_IDLE_NOISE: + idx_max = IDX_ACT_IDLE_NOISE_MAX; + idx_min = IDX_ACT_IDLE_NOISE_MIN; + break; + + case HX_LP_RAWDATA: + idx_max = IDX_LP_RAWDATA_MAX; + idx_min = IDX_LP_RAWDATA_MIN; + break; + + case HX_LP_BPN_RAWDATA: + idx_max = IDX_LP_RAW_BPN_MAX; + idx_min = IDX_LP_RAW_BPN_MIN; + break; + + case HX_LP_WT_NOISE: + idx_max = IDX_LP_WT_NOISEMAX; + idx_min = IDX_LP_WT_NOISEMIN; + break; + + case HX_LP_ABS_NOISE: + idx_max = IDX_LP_NOISE_ABS_MAX; + idx_min = IDX_LP_NOISE_ABS_MIN; + break; + + case HX_LP_IDLE_RAWDATA: + idx_max = IDX_LP_IDLE_RAWDATA_MAX; + idx_min = IDX_LP_IDLE_RAWDATA_MIN; + break; + + case HX_LP_IDLE_BPN_RAWDATA: + idx_max = IDX_LP_IDLE_RAW_BPN_MAX; + idx_min = IDX_LP_IDLE_RAW_BPN_MIN; + break; + + case HX_LP_IDLE_NOISE: + idx_max = IDX_LP_IDLE_NOISE_MAX; + idx_min = IDX_LP_IDLE_NOISE_MIN; + break; + + default: + E("Wrong type=%d\n", checktype); + break; + } + + /*data process*/ + switch (checktype) { + case HX_SORTING: + for (i = 0; i < block_num; i++) + g_inspection_criteria[idx_max][i] = 999999; + break; + case HX_BPN_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + for (i = 0; i < block_num; i++) + RAW[i] = (int)RAW[i] * 100 / g_dc_max; + break; + case HX_SC: + for (i = 0; i < block_num; i++) { + RAW[i] = ((int)RAW[i] + - g_inspection_criteria[IDX_SC_GOLDEN][i]) + * 100 / g_inspection_criteria[IDX_SC_GOLDEN][i]; + } + break; + } + + /*data campare*/ + switch (checktype) { + case HX_GAPTEST_RAW: + if ( + himax_gap_test_vertical_raw(HX_GAPTEST_RAW, RAW) != NO_ERR) { + E("%s: HX_GAPTEST_RAW FAIL\n", __func__); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + if (himax_gap_test_honrizontal_raw(HX_GAPTEST_RAW, RAW) + != NO_ERR) { + E("%s: HX_GAPTEST_RAW FAIL\n", __func__); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + break; + + case HX_WT_NOISE: + case HX_LP_WT_NOISE: + noise_count = 0; + himax_get_noise_base(checktype); + palm_num = himax_get_palm_num(); + for (i = 0; i < (ic_data->HX_TX_NUM * ic_data->HX_RX_NUM); + i++) { + if ((int)RAW[i] > NOISEMAX) + noise_count++; + } + I("noise_count=%d\n", noise_count); + if (noise_count > palm_num) { + E("%s: noise test FAIL\n", __func__); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + snprintf(g_start_log, 256 * sizeof(char), "\n Threshold = %d\n", + NOISEMAX); + /*Check weightingt*/ + if (himax_get_noise_weight_test(checktype) < 0) { + I("%s: %s FAIL %X\n", __func__, + g_himax_inspection_mode[checktype], ret_val); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + + /*Check negative side noise*/ + for (i = 0; i < block_num; i++) { + if ((int)RAW[i] + > (g_inspection_criteria[idx_max][i] + * NOISEMAX / 100) + || (int)RAW[i] + < (g_inspection_criteria[idx_min][i] + * g_recal_thx / 100)) { + E(FAIL_IN_INDEX, __func__, + g_himax_inspection_mode[checktype], i); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + } + break; + + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + block_num = ic_data->ic_adc_num; + case HX_SORTING: + case HX_OPEN: + case HX_MICRO_OPEN: + case HX_SHORT: + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_ABS_NOISE: + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + for (i = 0; i < block_num; i++) { + if ((int)RAW[i] > g_inspection_criteria[idx_max][i] + || (int)RAW[i] < g_inspection_criteria[idx_min][i]) { + if (private_ts->debug_log_level & BIT(4)) { + E(FAIL_IN_INDEX_CRTRA, __func__, + g_himax_inspection_mode[checktype], i + , g_inspection_criteria[idx_max][i] + , g_inspection_criteria[idx_min][i] + , RAW[i]); + ret_val |= 1 << (checktype + ERR_SFT); + } else { + E(FAIL_IN_INDEX, __func__, + g_himax_inspection_mode[checktype], i); + ret_val |= 1 << (checktype + ERR_SFT); + } + break; + } +#ifdef HX_INSPT_DBG + if ((private_ts->debug_log_level & BIT(4))) { + I("%s,type=%s, idx[%d]=%d\n", + __func__, + g_himax_inspection_mode[checktype], + i, RAW[i]); + I("%s, crteria,max=%d,min=%d\n", + __func__, + g_inspection_criteria[idx_max][i], + g_inspection_criteria[idx_min][i]); + } +#endif + } + break; + default: + E("Wrong type[%d] = %s\n", + checktype, g_himax_inspection_mode[checktype]); + break; + } + + I("%s: %s %s\n", __func__, g_himax_inspection_mode[checktype], + (ret_val == HX_INSP_OK)?"PASS":"FAIL"); + + return ret_val; +} + +static int himax_get_max_dc(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_addr[DATA_LEN_4]; + int dc_max = 0; + + himax_parse_assign_cmd(addr_max_dc, tmp_addr, sizeof(tmp_addr)); + + g_core_fp.fp_register_read(tmp_addr, tmp_data, DATA_LEN_4); + I("%s: tmp_data[0-3] = %02x%02x%02x%02x\n", __func__, + tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + dc_max = tmp_data[3]<<24 | tmp_data[2]<<16 | + tmp_data[1]<<8 | tmp_data[0]; + I("%s: dc max = %d\n", __func__, dc_max); + return dc_max; +} + +/* HX_GAP END*/ +static uint32_t mpTestFunc(uint8_t checktype, uint32_t datalen) +{ + uint32_t len = 0; + uint32_t *RAW = NULL; + int n_frame = 0; + uint32_t ret_val = NO_ERR; + int check_sort_sts = NO_ERR; + + /*uint16_t* pInspectGridData = &gInspectGridData[0];*/ + /*uint16_t* pInspectNoiseData = &gInspectNoiseData[0];*/ + + I("Now Check type = %d\n", checktype); + + RAW = kcalloc(datalen, sizeof(uint32_t), GFP_KERNEL); + if (RAW == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return HX_INSP_MEMALLCTFAIL; + } + + if (checktype >= HX_LP_WT_NOISE) { + I("%s,Check status in Screen-Off test items\n", __func__); + if (private_ts->suspended) { + if (private_ts->debug_log_level & BIT(4)) + I("%s, in Suspend!\n", __func__); + } else { + E("%s, Now is resume,Fail!\n", __func__); + ret_val = HX_INSP_FAIL; + goto fail_wait_sorting_mode; + } + } else { + I("%s,Check status in Screen-On test items\n", __func__); + if (private_ts->suspended) { + E("%s, Now is Suspend ,Fail!\n", __func__); + ret_val = HX_INSP_FAIL; + goto fail_wait_sorting_mode; + } else { + if (private_ts->debug_log_level & BIT(4)) + I("%s, in Resume!\n", __func__); + } + } + + check_sort_sts = himax_check_mode(checktype); + if (check_sort_sts < NO_ERR) { + ret_val = HX_INSP_FAIL; + goto fail_wait_sorting_mode; + } + if (check_sort_sts) { + /*himax_check_mode(checktype);*/ + + I("Need Change Mode ,target=%s\n", + g_himax_inspection_mode[checktype]); + + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense off!\n", __func__); + g_core_fp.fp_sense_off(true); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense off!\n", __func__); +#if !defined(HX_ZERO_FLASH) + g_core_fp.fp_turn_on_mp_func(1); + if (g_core_fp.fp_reload_disable != NULL) + g_core_fp.fp_reload_disable(1); +#endif + + himax_switch_mode_inspection(checktype); + + switch (checktype) { + case HX_WT_NOISE: + case HX_ABS_NOISE: + if (g_hx_inspt_setting_val[NFRAME] > 0) + n_frame = g_hx_inspt_setting_val[NFRAME]; + else + n_frame = NOISEFRAME; + break; + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_NOISE: + case HX_ACT_IDLE_BPN_RAWDATA: + if (g_hx_inspt_setting_val[IDLE_NFRAME] > 0) + n_frame = g_hx_inspt_setting_val[IDLE_NFRAME]; + else + n_frame = NORMAL_IDLE_RAWDATA_NOISEFRAME; + break; + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + if (g_hx_inspt_setting_val[LP_RAW_NFRAME] > 0) + n_frame = g_hx_inspt_setting_val[LP_RAW_NFRAME]; + else + n_frame = LP_RAWDATAFRAME; + break; + case HX_LP_WT_NOISE: + case HX_LP_ABS_NOISE: + if (g_hx_inspt_setting_val[LP_NOISE_NFRAME] > 0) + n_frame = + g_hx_inspt_setting_val[LP_NOISE_NFRAME]; + else + n_frame = LP_NOISEFRAME; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + if (g_hx_inspt_setting_val[LP_IDLE_RAW_NFRAME] > 0) + n_frame = + g_hx_inspt_setting_val[LP_IDLE_RAW_NFRAME]; + else + n_frame = LP_IDLE_RAWDATAFRAME; + break; + case HX_LP_IDLE_NOISE: + if (g_hx_inspt_setting_val[LP_IDLE_NOISE_NFRAME] > 0) + n_frame = + g_hx_inspt_setting_val[LP_IDLE_NOISE_NFRAME]; + else + n_frame = LP_IDLE_NOISEFRAME; + break; + default: + n_frame = OTHERSFRAME; + } + himax_set_N_frame(n_frame, checktype); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(1); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); + + } + + ret_val |= himax_wait_sorting_mode(checktype); + if (ret_val) { + E("%s: himax_wait_sorting_mode FAIL\n", __func__); + ret_val |= (1 << (checktype + ERR_SFT)); + goto fail_wait_sorting_mode; + } + himax_switch_data_type(checktype); + + ret_val |= himax_get_rawdata(RAW, datalen, checktype); + + /* back to normal */ + himax_switch_data_type(HX_BACK_NORMAL); + + if (ret_val) { + E("%s: himax_get_rawdata FAIL\n", __func__); + ret_val |= (1 << (checktype + ERR_SFT)); + goto fail_get_rawdata; + } + + /*get Max DC from FW*/ + g_dc_max = himax_get_max_dc(); + + I("%s: Init OK, start to test!\n", __func__); + + len += snprintf(g_start_log+len, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ": data as follow!\n"); + + ret_val |= himax_data_compare(checktype, RAW, ret_val); + + himax_get_arraydata_edge(RAW); + + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + "\n arraydata_min1 = %d,", arraydata_min1); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_min2 = %d,", arraydata_min2); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_min3 = %d,", arraydata_min3); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + "\n arraydata_max1 = %d,", arraydata_max1); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_max2 = %d,", arraydata_max2); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_max3 = %d\n", arraydata_max3); + + if (!ret_val) {/*PASS*/ + snprintf(g_rslt_log, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ":Test Pass!"); + I("pass write log\n"); + } else {/*FAIL*/ + snprintf(g_rslt_log, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ":Test Fail!"); + I("fail write log\n"); + } + + hx_test_data_get(RAW, g_start_log, g_rslt_log, checktype); +fail_get_rawdata: +fail_wait_sorting_mode: + kfree(RAW); + return ret_val; +} + +/* claculate 10's power function */ +static int himax_power_cal(int pow, int number) +{ + int i = 0; + int result = 1; + + for (i = 0; i < pow; i++) + result *= 10; + result = result * number; + + return result; + +} + +/* String to int */ +static int hiamx_parse_str2int(char *str) +{ + int i = 0; + int temp_cal = 0; + int result = -948794; + unsigned int str_len = strlen(str); + int negtive_flag = 0; + + for (i = 0; i < str_len; i++) { + if (i == 0) + result = 0; + if (str[i] != '-' && str[i] > '9' && str[i] < '0') { + E("%s: Parsing fail!\n", __func__); + result = -9487; + negtive_flag = 0; + break; + } + if (str[i] == '-') { + negtive_flag = 1; + continue; + } + temp_cal = str[i] - '0'; + result += himax_power_cal(str_len-i-1, temp_cal); + /* str's the lowest char is the number's the highest number + * So we should reverse this number before using the power + * function + * -1: starting number is from 0 ex:10^0 = 1,10^1=10 + */ + } + + if (negtive_flag == 1) + result = 0 - result; + + return result; +} + + + + +/* get idx of criteria whe parsing file */ +int hx_find_crtra_id(char *input) +{ + int i = 0; + int result = 0; + + for (i = 0 ; i < HX_CRITERIA_SIZE ; i++) { + if (strcmp(g_hx_inspt_crtra_name[i], input) == 0) { + result = i; + I("find the str=%s,idx=%d\n", + g_hx_inspt_crtra_name[i], i); + break; + } + } + if (i > (HX_CRITERIA_SIZE - 1)) { + E("%s: find Fail!\n", __func__); + return LENGTH_FAIL; + } + + return result; +} +#ifdef HX_INSPT_DBG +int hx_print_crtra_after_parsing(void) +{ + int i = 0, j = 0; + int all_mut_len = ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + I("Now is %s\n", g_hx_inspt_crtra_name[i]); + if (g_inspt_crtra_flag[i] == 1) { + for (j = 0; j < all_mut_len; j++) { + PI("%d, ", g_inspection_criteria[i][j]); + if (j % 16 == 15) + PI("\n"); + } + } else { + I("No this Item in this criteria file!\n"); + } + PI("\n"); + } + + return 0; +} +#endif + +static int hx_crtra_get(char *result, int himax_count_type, int comprae_data) +{ + int temp = 0; + + temp = hiamx_parse_str2int(result); + + if (temp != -9487) + g_inspection_criteria[himax_count_type][comprae_data] = temp; + else { + I("%s: Parsing Fail in %d, rslt = %d\n", + __func__, comprae_data, temp); + return HX_INSP_EFILE; + } + +#ifdef HX_INSPT_DBG + /* dbg:print all of criteria from parsing file */ + hx_print_crtra_after_parsing(); +#endif + + return HX_INSP_OK; +} +static int hx_check_char_val(char input) +{ + int result = NO_ERR; + + if (input >= 'A' && input <= 'Z') { + result = -1; + goto END; + } + if (input >= 'a' && input <= 'z') { + result = -1; + goto END; + } + if (input >= '0' && input <= '9') { + result = 1; + goto END; + } +END: + return result; +} +static int hx_check_criteria(const struct firmware *file_entry, + char *start_str, int tx_num, int rx_num) +{ + int now_pos = 0; + int result = NO_ERR; + int rx_count = 0; + int tx_count = 0; + int i = 0; + + now_pos = (int) (start_str - (char *)file_entry->data); + + /* Count RX number in criteria */ + for (i = 0; now_pos + i < file_entry->size; i++) { + if (*(file_entry->data + (now_pos + i)) >= 'A' + && *(file_entry->data + (now_pos + i)) <= 'Z') { + I("%s, get the character: %c!\n", + __func__, *(file_entry->data + (now_pos + i))); + break; + } + if (*(file_entry->data + (now_pos + i)) == ',') + rx_count++; + /* reduce the last of sign:',' + * but now determine it is the fail format + * if (*(file_entry->data + (now_pos + i - 1 )) == ',' + * && *(file_entry->data + (now_pos + i)) == '\n') + * rx_count--; + * if (*(file_entry->data + (now_pos + i - 1 )) == ',' + * && *(file_entry->data + (now_pos + i)) == '\r') + * rx_count--; + */ + if (*(file_entry->data + (now_pos + i)) == '\n') { + rx_count++; + break; + } + } + + if (rx_count != rx_num) { + E("%s,RX Error, parse size is %d, but this is %d!\n", + __func__, rx_count, rx_num); + result = HX_INSP_EFILE; + goto END; + } + + /* Count TX number in criteria*/ + for (i = 0; now_pos + i < file_entry->size; i++) { + if (hx_check_char_val(*(file_entry->data + (now_pos + i))) + < NO_ERR) { + I("%s,TX collect over, get the character: %c!\n", + __func__, *(file_entry->data + (now_pos + i))); + break; + } + if (*(file_entry->data + (now_pos + i)) == '\n') + tx_count++; + } + + if (tx_count != tx_num) { + E("%s,TX Error, parse size is %d, but this is %d!\n", + __func__, tx_count, tx_num); + result = HX_INSP_EFILE; + goto END; + } + + I("%s:parse TX count is %d, RX count is %d!\n", + __func__, tx_count, rx_count); +END: + return result; +} + +static int himax_parse_criteria_str(int match_start, int hx_str_len, + const struct firmware *file_entry, int tx_num, int rx_num) +{ + int err = HX_INSP_OK; + char result[100] = {0}; + char str_rslt[100] = {0}; + char str_len = 0; + char *str_addr = NULL; + int str_flag = 1; + int i, j = 0; //, k + int crtra_id = 0; + int mul_num = tx_num * rx_num; + int flag = 1; + int temp; + char *str_data; + int now_pointer_file = 0; + + if (private_ts->debug_log_level & BIT(4)) + I("%s,Entering\n", __func__); + + str_data = (char *)(file_entry->data + match_start); + memcpy(&str_rslt[0], str_data, hx_str_len); + + crtra_id = hx_find_crtra_id(str_rslt); + if (crtra_id == -1) { + E("Please check criteria file again!\n"); + return HX_INSP_EFILE; + } + g_inspt_crtra_flag[crtra_id] = 1; + + str_data = str_data + hx_str_len + 1; + + /* Check the criteria file OK or not */ + if (hx_check_criteria(file_entry, str_data, tx_num, rx_num) + == HX_INSP_EFILE) + return HX_INSP_EFILE; + for (i = 0; i < mul_num; i++) { + if (i <= mul_num - 2) { + now_pointer_file = (int) (str_data - + (char *)file_entry->data); + /* if the search counter is over than file size, + * broken the work + */ + if ((now_pointer_file >= file_entry->size) + && now_pointer_file > 0) { + E("Over file size 1 !\n"); + return HX_INSP_EFILE; + } + while (flag) { + /* Check search counter is over + * than file size or not, + * broken the work + */ + if (now_pointer_file + flag + >= (int)file_entry->size) { + E("Over file size 2!\n"); + return HX_INSP_EFILE; + } + if (hx_check_char_val(*(str_data+flag)) + < NO_ERR) { + E("%s,Need INT but it's str=%s:%c\n", + __func__, str_rslt, + *(str_data+flag)); + return HX_INSP_EFILE; + } + /* the starting of value must be ',' + * so using this sign to start get content value + */ + if (*(str_data + flag) == ',') { + str_addr = str_data + flag; + flag = 1; + break; + } + flag++; + } + + if (str_addr == NULL) + continue; + /* determine the full content + * and assign to other container + */ + str_flag = 1; + str_len = str_addr - str_data; + for (j = 1; j <= str_len; j++) { + if ((*(str_data + j) == '\r' + || *(str_data + j) == '\n' + || *(str_data + j) == '\0')) { + memset(result, 0, 100); + memcpy(&result[0], str_data, j); + str_flag = 0; + break; + } + } + if (str_flag) { + memset(result, 0, 100); + memcpy(&result[0], str_data, str_len); + } + /* parse to content string */ + err = hx_crtra_get(result, crtra_id, i); + if (err != HX_INSP_OK) { + E("%s:Get crrteria Fail!!\n", __func__); + return HX_INSP_EFILE; + } + str_data = str_addr + 1; + } else{ + /* last data of mutual */ + temp = 1; + while (hx_check_char_val((*(str_data + temp))) + > NO_ERR) + temp++; + str_len = temp; + memset(result, 0, 100); + memcpy(&result[0], str_data, str_len); + err = hx_crtra_get(result, crtra_id, mul_num - 1); + if (err != HX_INSP_OK) { + E("%s:Get crrteria Fail!\n", __func__); + return HX_INSP_EFILE; + } + } + } + + if (private_ts->debug_log_level & BIT(4)) + I("%s,END\n", __func__); + return err; + /* parsing Criteria end */ +} + +static int himax_test_item_parse(char *str_data, int str_size) +{ + int size = str_size; + char *str_ptr = str_data; + char *end_ptr = NULL; + int i = 0; + int ret = HX_INSP_EFILE; + + I("%s,str_data: %p, str_size: %d\n", __func__, str_data, str_size); + + do { + str_ptr = strnstr(str_ptr, "HIMAX", size); + end_ptr = strnstr(str_ptr, "\x0d\x0a", size); + if (str_ptr != NULL && end_ptr != NULL) { + while (g_himax_inspection_mode[i]) { + if (strncmp(str_ptr, g_himax_inspection_mode[i], + end_ptr - str_ptr) == 0) { + I("%s,Find item : %s\n", __func__, + g_himax_inspection_mode[i]); + g_test_item_flag[i] = 1; + ret = HX_INSP_OK; + break; + } + i++; + } + size = str_size - (end_ptr - str_data); + str_ptr = end_ptr++; + i = 0; + } else { + I("%s,Can't find %s or %s\n", __func__, + "HIMAX", "\x0d\x0a"); + break; + } + } while (size > strlen("HIMAX")); + + return ret; +} + +static void strcpy_idx(char *str, char start, char end) +{ + int i = 0; + int start_idx = 0; + int end_idx = 0; + char *result; + + if (str == NULL) { + E("%s, input string is null!\n", __func__); + return; + } + + start_idx = (int)strcspn(str, &start); + end_idx = (int)strcspn(str, &end); + + if (private_ts->debug_log_level & BIT(4)) + I("%s:start_idx = %d, end_idx = %d\n", + __func__, start_idx, end_idx); + + if (end_idx < start_idx) { + E("%s, end < start, fail\n", __func__); + return; + } + result = kzalloc(sizeof(char) * (end_idx - start_idx), GFP_KERNEL); + + /* skip index 0, because start(char) doesn't include*/ + for (i = 0; *(str + i) != end; i++) + result[i] = str[(start_idx + 1) + i]; + + if (private_ts->debug_log_level & BIT(4)) + I("%s:result=%s\n", __func__, result); + memset(str, 0x00, strlen(str)); + memcpy(&str[0], &result[0], sizeof(char) * strlen(result)); + kfree(result); +} +static int himax_parse_criteria_setting(const struct firmware *file_entry) +{ + int i = 0, j = 0; + int result = -1; + int match_start = -1; + int match_end = -1; + char *find; + char *line; + int test_int = 0; + int comm_1st = -1; + + line = kzalloc(sizeof(char) * 128, GFP_KERNEL); + + /* check all of item in the csv with g_hx_inspt_setting_name */ + while (g_hx_inspt_setting_name[i] != NULL) { + memset(line, 0x00, sizeof(char) * 128); + + /* check the name of item */ + find = strnstr(file_entry->data, + g_hx_inspt_setting_name[i], file_entry->size); + if (find == NULL) { + I("%s, Can't find %s, skip\n", + __func__, g_hx_inspt_setting_name[i]); + result = -1; + i++; + continue; + } else { + match_start = (int) (find - (char *)file_entry->data); + memcpy(line, &file_entry->data[match_start], + sizeof(char) * 128); + } + + /* get 1 line with saperate by NewLine sign */ + match_end = strcspn(line, "\n"); + if (match_end == strlen(line)) { + /* may find the entire line.. */ + I("%s, Can't find end of match with LF in %s, skip\n", + __func__, g_hx_inspt_setting_name[i]); + result = -1; + i++; + continue; + } + + /* Define the end of Line, + * before NewLine will be \r(windows), ',' (format, 2nd) + * it should remove this fr parsing easily + */ + for (j = 0; j < match_end; j++) { + if (comm_1st < 0 && line[j] == ',') { + comm_1st = j; + continue; + } else if (line[j] == 0x0D /* CF, \r */ + || line[j] == 0x0A /* LF, new line */ + || line[j] == ',') { /* 2nd ,*/ + line[j] = '\0'; + match_end = j; + break; + } + } + comm_1st = -1; + if (private_ts->debug_log_level & BIT(4)) + I("Line=%s,start = %d, end=%d\n", + line, match_start, match_end); + + /* get the number string, and set the end sign for line end */ + strcpy_idx(line, ',', '\0'); + if (line == NULL) { + E("%s, get value fail for %s!\n", + __func__, g_hx_inspt_setting_name[i]); + result = -1; + i++; + continue; + } + if (private_ts->debug_log_level & BIT(4)) + I("last..Line=%s\n", line); + test_int = hiamx_parse_str2int(line); + g_hx_inspt_setting_val[i] = test_int; + I("%s:[%d] %s,result value=%d\n", __func__, + i, g_hx_inspt_setting_name[i], + g_hx_inspt_setting_val[i]); + if (private_ts->debug_log_level & BIT(4)) + I("%s:test_int=%d\n", __func__, test_int); + if (test_int <= -9487) { + result = HX_INSP_EFILE; + break; + } + i++; + } + + kfree(line); + return result; +} + + +static int himax_parse_criteria(const struct firmware *file_entry) +{ + int ret = 0; + int i = 0; + int start_str_len = 0; + int match_start = -1; + char *start_ptr = NULL; + int tx_num = ic_data->HX_TX_NUM; + int rx_num = ic_data->HX_RX_NUM; + + if (himax_parse_criteria_setting(file_entry) == HX_INSP_EFILE) { + ret = HX_INSP_EFILE; + goto END; + } + + i = 0; + while (g_hx_inspt_crtra_name[i] != NULL) { + start_ptr = strnstr(file_entry->data, + g_hx_inspt_crtra_name[i], file_entry->size); + if (start_ptr != NULL) { + I("g_hx_inspt_crtra_name[%d] = %s\n", + i, g_hx_inspt_crtra_name[i]); + start_str_len = strlen(g_hx_inspt_crtra_name[i]); + match_start = (int)(start_ptr - + (char *)(file_entry->data)); + ret |= himax_parse_criteria_str(match_start, + start_str_len, file_entry, + tx_num, rx_num); + if (ret >= HX_INSP_EFILE) + break; + } + i++; + } +END: + return ret; +} + + +static int himax_parse_test_dri_file(const struct firmware *file_entry) +{ + int start_str_len = 0; + int str_size = 0; + char *start_ptr = NULL; + char *end_ptr = NULL; + int i = 0; + int j = 0; + char str[2][60]; /*[0]->Start string, [1]->End string*/ + char *str_tail[2] = {"_Begin]\x0d\x0a", "_End]\x0d\x0a"}; + int ret = HX_INSP_OK; + + while (g_hx_head_str[i]) { + /*compose header string of .dri file*/ + for (j = 0; j < 2; j++) { + strlcpy(str[j], "[", sizeof(str[j])); + strlcat(str[j], g_hx_head_str[i], sizeof(str[j])); + strlcat(str[j], str_tail[j], sizeof(str[j])); + /*I("%s string[%d] : %s\n", __func__, j, str[j]);*/ + } + + /*find each group of .dri file*/ + start_str_len = strlen(str[0]); + start_ptr = strnstr(file_entry->data, str[0], file_entry->size); + end_ptr = strnstr(file_entry->data, str[1], file_entry->size); + + if (start_ptr == NULL || end_ptr == NULL) { + E("%s,Can't find string %s\n", __func__, + g_hx_head_str[i]); + } else { + /*parse each sub group string*/ + /*if (strncmp(g_hx_head_str[i], "Project_Info",*/ + /*strlen(g_hx_head_str[i])) == 0) {*/ + /* get project informaion - Not Use*/ + /*}*/ + str_size = end_ptr - start_ptr - start_str_len; + /*I("%s,String Length = %d\n", __func__, str_size);*/ + + if (strncmp(g_hx_head_str[i], "TestItem", + strlen(g_hx_head_str[i])) == 0) { + /*get Test Item*/ + I("%s,Start to parse %s\n", __func__, + g_hx_head_str[i]); + ret |= himax_test_item_parse(start_ptr + + start_str_len, + str_size); + } + /*if (strncmp(g_hx_head_str[i], "TestCriteria_Weight",*/ + /*strlen(g_hx_head_str[i])) == 0) {*/ + /*get Test Criteria Weight - Not Use*/ + /*}*/ + if (strncmp(g_hx_head_str[i], "TestCriteria", + strlen(g_hx_head_str[i])) == 0) { + /*get Test Criteria*/ + I("%s,Start to parse %s\n", __func__, + g_hx_head_str[i]); + ret |= himax_parse_criteria(file_entry); + } + } + i++; + } + + return ret; +} + +static void himax_test_item_chk(int csv_test) +{ + int i = 0; + + if (csv_test) + for (i = 0; i < HX_CRITERIA_ITEM - 1; i++) + g_test_item_flag[i] = 1; + + g_test_item_flag[HX_OPEN] &= + (g_inspt_crtra_flag[IDX_OPENMIN] == 1 + && g_inspt_crtra_flag[IDX_OPENMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_MICRO_OPEN] &= + (g_inspt_crtra_flag[IDX_M_OPENMIN] == 1 + && g_inspt_crtra_flag[IDX_M_OPENMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_SHORT] &= + (g_inspt_crtra_flag[IDX_SHORTMIN] == 1 + && g_inspt_crtra_flag[IDX_SHORTMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_RAWDATA] &= + (g_inspt_crtra_flag[IDX_RAWMIN] == 1 + && g_inspt_crtra_flag[IDX_RAWMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_BPN_RAWMIN] == 1 + && g_inspt_crtra_flag[IDX_BPN_RAWMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_SC] &= + (g_inspt_crtra_flag[IDX_SCMIN] == 1 + && g_inspt_crtra_flag[IDX_SCMAX] == 1 + && g_inspt_crtra_flag[IDX_SC_GOLDEN] == 1) ? 1 : 0; + + g_test_item_flag[HX_WT_NOISE] &= + (g_inspt_crtra_flag[IDX_WT_NOISEMIN] == 1 + && g_inspt_crtra_flag[IDX_WT_NOISEMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_ABS_NOISE] &= + (g_inspt_crtra_flag[IDX_ABS_NOISEMIN] == 1 + && g_inspt_crtra_flag[IDX_ABS_NOISEMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_SORTING] &= + (g_inspt_crtra_flag[IDX_SORTMIN] == 1 + && g_inspt_crtra_flag[IDX_SORTMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_GAPTEST_RAW] &= + (g_inspt_crtra_flag[IDX_GAP_HOR_RAWMAX] == 1 + && g_inspt_crtra_flag[IDX_GAP_HOR_RAWMIN] == 1 + && g_inspt_crtra_flag[IDX_GAP_VER_RAWMAX] == 1 + && g_inspt_crtra_flag[IDX_GAP_VER_RAWMIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_ACT_IDLE_RAWDATA] &= + (g_inspt_crtra_flag[IDX_ACT_IDLE_RAWDATA_MIN] == 1 + && g_inspt_crtra_flag[IDX_ACT_IDLE_RAWDATA_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_ACT_IDLE_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_ACT_IDLE_RAW_BPN_MIN] == 1 + && g_inspt_crtra_flag[IDX_ACT_IDLE_RAW_BPN_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_ACT_IDLE_NOISE] &= + (g_inspt_crtra_flag[IDX_ACT_IDLE_NOISE_MIN] == 1 + && g_inspt_crtra_flag[IDX_ACT_IDLE_NOISE_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_RAWDATA_MIN] == 1 + && g_inspt_crtra_flag[IDX_LP_RAWDATA_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_RAW_BPN_MIN] == 1 + && g_inspt_crtra_flag[IDX_LP_RAW_BPN_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_WT_NOISE] &= + (g_inspt_crtra_flag[IDX_LP_WT_NOISEMAX] == 1 + && g_inspt_crtra_flag[IDX_LP_WT_NOISEMIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_ABS_NOISE] &= + (g_inspt_crtra_flag[IDX_LP_NOISE_ABS_MAX] == 1 + && g_inspt_crtra_flag[IDX_LP_NOISE_ABS_MIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_IDLE_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_IDLE_RAWDATA_MAX] == 1 + && g_inspt_crtra_flag[IDX_LP_IDLE_RAWDATA_MIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_IDLE_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_IDLE_RAW_BPN_MIN] == 1 + && g_inspt_crtra_flag[IDX_LP_IDLE_RAW_BPN_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_IDLE_NOISE] &= + (g_inspt_crtra_flag[IDX_LP_IDLE_NOISE_MAX] == 1 + && g_inspt_crtra_flag[IDX_LP_IDLE_NOISE_MIN] == 1) ? 1 : 0; + + do_lpwg_test = g_test_item_flag[HX_LP_RAWDATA] + | g_test_item_flag[HX_LP_BPN_RAWDATA] + | g_test_item_flag[HX_LP_WT_NOISE] + | g_test_item_flag[HX_LP_ABS_NOISE] + | g_test_item_flag[HX_LP_IDLE_RAWDATA] + | g_test_item_flag[HX_LP_IDLE_BPN_RAWDATA] + | g_test_item_flag[HX_LP_IDLE_NOISE]; + + if (private_ts->debug_log_level & BIT(4)) { + for (i = 0; i < HX_CRITERIA_ITEM - 1; i++) + I("g_test_item_flag[%d] = %d\n", + i, g_test_item_flag[i]); + } +} + +int hx_get_size_str_arr(char **input) +{ + int i = 0; + int result = 0; + + while (input[i] != NULL) + i++; + + result = i; + if (private_ts->debug_log_level & BIT(4)) + I("There is %d in [0]=%s\n", result, input[0]); + + return result; +} + +#if defined(HX_ZERO_FLASH) +static void hx_print_fw_info(void) +{ + uint32_t len = 0; + char *prt_data = NULL; + int fw_ver; + int config_ver; + int touch_cfg_ver; + int display_cfg_ver; + int cid_maj_ver; + int cid_min_ver; + int panel_ver; + uint8_t cus_info[12]; + uint8_t proj_info[12]; + uint8_t data[12] = {0}; + uint8_t tmp_addr[4]; + int buf_size = 1024; + + prt_data = kzalloc(sizeof(char) * (buf_size), GFP_KERNEL); + if (prt_data == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return; + } + + himax_parse_assign_cmd(fw_addr_fw_ver_addr, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, data, DATA_LEN_4); + panel_ver = data[0]; + fw_ver = data[1] << 8 | data[2]; + + himax_parse_assign_cmd(fw_addr_fw_cfg_addr, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, data, DATA_LEN_4); + config_ver = data[2] << 8 | data[3]; + touch_cfg_ver = data[2]; + display_cfg_ver = data[3]; + + himax_parse_assign_cmd(fw_addr_fw_vendor_addr, tmp_addr, + sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, data, DATA_LEN_4); + cid_maj_ver = data[2]; + cid_min_ver = data[3]; + + himax_parse_assign_cmd(fw_addr_cus_info, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, data, 12); + memcpy(cus_info, data, 12); + + himax_parse_assign_cmd(fw_addr_proj_info, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, data, 12); + memcpy(proj_info, data, 12); + + len += snprintf(prt_data + len, buf_size - len, + "\nFW_VER = 0x%2.2X\n", fw_ver); + + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) { + len += snprintf(prt_data + len, buf_size - len, + "CONFIG_VER = 0x%2.2X\n", config_ver); + } else { + len += snprintf(prt_data + len, buf_size - len, + "TOUCH_VER = 0x%2.2X\n", touch_cfg_ver); + len += snprintf(prt_data + len, buf_size - len, + "DISPLAY_VER = 0x%2.2X\n", display_cfg_ver); + } + + if (cid_maj_ver < 0 && cid_min_ver < 0) { + len += snprintf(prt_data + len, buf_size - len, + "CID_VER = NULL\n"); + } else { + len += snprintf(prt_data + len, buf_size - len, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + } + + if (panel_ver < 0) { + len += snprintf(prt_data + len, buf_size - len, + "PANEL_VER = NULL\n"); + } else { + len += snprintf(prt_data + len, buf_size - len, + "PANEL_VER = 0x%2.2X\n", panel_ver); + } + + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + len += snprintf(prt_data + len, buf_size - len, + "Cusomer = %s\n", cus_info); + len += snprintf(prt_data + len, buf_size - len, + "Project = %s\n", proj_info); + } + + memcpy(&g_rslt_data[0], prt_data, len); + g_rslt_data_len = len; + I("%s: g_rslt_data_len=%d!\n", __func__, g_rslt_data_len); + + kfree(prt_data); +} +#endif + +static int himax_self_test_data_init(void) +{ + const struct firmware *file_entry = NULL; + struct himax_ts_data *ts = private_ts; + char *file_name_1 = "hx_criteria.dri"; + char *file_name_2 = "hx_criteria.csv"; + int setting_sz = -1; + int ret = HX_INSP_OK; + int err = 0; + int i = 0; + + /* + * 5: one value will not over than 99999, so get this size of string + * 2: get twice size + */ + g_1kind_raw_size = 5 * ic_data->HX_RX_NUM * ic_data->HX_TX_NUM * 2; + + /* get test item and its items of criteria*/ + HX_CRITERIA_ITEM = hx_get_size_str_arr(g_himax_inspection_mode); + HX_CRITERIA_SIZE = hx_get_size_str_arr(g_hx_inspt_crtra_name); + I("There is %d HX_CRITERIA_ITEM and %d HX_CRITERIA_SIZE\n", + HX_CRITERIA_ITEM, HX_CRITERIA_SIZE); + + /* init criteria data*/ + g_test_item_flag = kcalloc(HX_CRITERIA_ITEM, sizeof(int), GFP_KERNEL); + if (g_test_item_flag == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_test_item_flag; + } + + g_inspt_crtra_flag = kcalloc(HX_CRITERIA_SIZE, sizeof(int), GFP_KERNEL); + if (g_inspt_crtra_flag == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspt_crtra_flag; + } + + g_inspection_criteria = kcalloc(HX_CRITERIA_SIZE, + sizeof(int *), GFP_KERNEL); + if (g_inspection_criteria == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspection_criteria; + } + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + g_inspection_criteria[i] = kcalloc((ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM), + sizeof(int), GFP_KERNEL); + if (g_inspection_criteria[i] == NULL) { + E("%s,%d: Memory allocation %d falied!\n", + __func__, __LINE__, i); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspection_criteria2; + } + } + + g_rslt_data_len = 0; + if (g_rslt_data == NULL) { + g_rslt_data = kcalloc(g_1kind_raw_size, sizeof(char), + GFP_KERNEL); + if (g_rslt_data == NULL) { + E("%s,%d: Memory allocation falied!\n", + __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_rslt_data; + } + } + + setting_sz = hx_get_size_str_arr(g_hx_inspt_setting_name); + I("There are %d kinds of setting items\n", setting_sz); + g_hx_inspt_setting_val = kcalloc(setting_sz, sizeof(int), + GFP_KERNEL); + if (g_hx_inspt_setting_val == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspection_setting_val; + } + for (i = 0 ; i < setting_sz; i++) + g_hx_inspt_setting_val[i] = -1; + + I("%s: initialize g_rslt_data, length = %d\n", + __func__, g_1kind_raw_size); + memset(g_rslt_data, 0x00, g_1kind_raw_size * sizeof(char)); + + /* default path is /system/etc/firmware */ + /* request criteria file*/ + err = request_firmware(&file_entry, file_name_1, ts->dev); + if (err < 0) { + E("%s,Fail to get %s\n", __func__, file_name_1); + err = request_firmware(&file_entry, file_name_2, ts->dev); + if (err < 0) { + E("%s,Fail to get %s\n", __func__, file_name_2); + I("No criteria file"); + ret = HX_INSP_EFILE; + goto err_open_criteria_file; + } else { + I("%s,Success to get %s\n", __func__, file_name_2); + /* parsing criteria from file .csv*/ + ret = himax_parse_criteria(file_entry); + release_firmware(file_entry); + if (ret > 0) + goto err_open_criteria_file; + himax_test_item_chk(true); + } + } else { + /* parsing test file .dri*/ + I("%s,Success to get %s\n", __func__, file_name_1); + ret = himax_parse_test_dri_file(file_entry); + release_firmware(file_entry); + if (ret > 0) + goto err_open_criteria_file; + himax_test_item_chk(false); + } + + if (private_ts->debug_log_level & BIT(4)) { + /* print get criteria string */ + for (i = 0 ; i < HX_CRITERIA_SIZE ; i++) { + if (g_inspt_crtra_flag[i] != 0) + I("%s: [%d]There is String=%s\n", + __func__, i, g_hx_inspt_crtra_name[i]); + } + } + + snprintf(g_file_path, (int)(strlen(HX_RSLT_OUT_PATH) + + strlen(HX_RSLT_OUT_FILE)+1), + "%s%s", HX_RSLT_OUT_PATH, HX_RSLT_OUT_FILE); + + file_w_flag = true; + return ret; + +err_open_criteria_file: + kfree(g_hx_inspt_setting_val); + g_hx_inspt_setting_val = NULL; +err_malloc_inspection_setting_val: + kfree(g_rslt_data); + g_rslt_data = NULL; +err_malloc_rslt_data: + +err_malloc_inspection_criteria2: + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (g_inspection_criteria[i] != NULL) { + kfree(g_inspection_criteria[i]); + g_inspection_criteria[i] = NULL; + } + } + kfree(g_inspection_criteria); + g_inspection_criteria = NULL; +err_malloc_inspection_criteria: + kfree(g_inspt_crtra_flag); + g_inspt_crtra_flag = NULL; +err_malloc_inspt_crtra_flag: + kfree(g_test_item_flag); + g_test_item_flag = NULL; +err_malloc_test_item_flag: + return ret; +} + +static void himax_self_test_data_deinit(void) +{ + int i = 0; + + /*dbg*/ + /* for (i = 0; i < HX_CRITERIA_ITEM; i++) + * I("%s:[%d]%d\n", __func__, i, g_inspection_criteria[i]); + */ + + I("%s: release allocated memory\n", __func__); + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (g_inspection_criteria[i] != NULL) { + kfree(g_inspection_criteria[i]); + g_inspection_criteria[i] = NULL; + } + } + kfree(g_inspection_criteria); + g_inspection_criteria = NULL; + + kfree(g_inspt_crtra_flag); + g_inspt_crtra_flag = NULL; + + kfree(g_test_item_flag); + g_test_item_flag = NULL; + I("%s: release finished\n", __func__); + +} + +static int himax_chip_self_test(struct seq_file *s, void *v) +{ + uint32_t ret = HX_INSP_OK; + uint32_t test_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + ic_data->HX_RX_NUM; + int i = 0; +#if !defined(HX_ZERO_FLASH) + uint8_t tmp_addr[DATA_LEN_4] = {0x94, 0x72, 0x00, 0x10}; + uint8_t tmp_data[DATA_LEN_4] = {0x01, 0x00, 0x00, 0x00}; +#endif + struct file *raw_file = NULL; + struct filename *vts_name = NULL; +#if !defined(KERNEL_VER_ABOVE_5_10) + mm_segment_t fs; +#endif + loff_t pos = 0; + uint32_t rslt = HX_INSP_OK; + + I("%s:IN\n", __func__); + + private_ts->suspend_resume_done = 0; + + ret = himax_self_test_data_init(); + if (ret > 0) { + E("%s: initialize self test failed\n", __func__); + if (ret == HX_INSP_EFILE) { + seq_puts(s, "Self_Test Fail:\n" + "- Criteria file!\n"); + } + + goto END; + } + +#if defined(HX_ZERO_FLASH) + ret = g_core_fp.fp_0f_op_file_dirly(g_fw_mp_upgrade_name); + if (ret) { + E("%s: upgrade MPFW fail, code[%d]!!\n", __func__, ret); + goto UPDATE_MPFW_FAIL; + } +#endif + + if (!kp_getname_kernel) { + E("kp_getname_kernel is NULL, not open file!\n"); + file_w_flag = false; + } else + vts_name = kp_getname_kernel(g_file_path); + + if (!kp_file_open_name && raw_file == NULL && file_w_flag) { + raw_file = kp_file_open_name(vts_name, + O_TRUNC|O_CREAT|O_RDWR, 0660); + + if (IS_ERR(raw_file)) { + E("%s open file failed = %ld\n", + __func__, PTR_ERR(raw_file)); + file_w_flag = false; + } + } +#if !defined(KERNEL_VER_ABOVE_5_10) + fs = get_fs(); + set_fs(KERNEL_DS); +#endif + if (file_w_flag) { +#if defined(KERNEL_VER_ABOVE_5_10) + kernel_write(raw_file, g_rslt_data, g_rslt_data_len, &pos); +#else + vfs_write(raw_file, g_rslt_data, g_rslt_data_len, &pos); +#endif + pos += g_rslt_data_len; + } + + /*Do normal test items*/ + for (i = 0; i < HX_CRITERIA_ITEM; i++) { + if (i < HX_LP_WT_NOISE) { + if (g_test_item_flag[i] == 1) { + I("%d. %s Start\n", i, + g_himax_inspection_mode[i]); + rslt = mpTestFunc(i, test_size); + if (file_w_flag && + ((rslt & HX_INSP_EGETRAW) == 0) && + ((rslt & HX_INSP_ESWITCHMODE) == 0)) { +#if defined(KERNEL_VER_ABOVE_5_10) + kernel_write(raw_file, g_rslt_data, + g_rslt_data_len, &pos); +#else + vfs_write(raw_file, g_rslt_data, + g_rslt_data_len, &pos); +#endif + pos += g_rslt_data_len; + } + ret |= rslt; + + I("%d. %s End, ret = %d\n", i, + g_himax_inspection_mode[i], ret); + + if (ret) + goto SELF_TEST_FAIL; + } + } else { + break; + } + } + + /* Press power key and do LPWUG test items*/ + if (do_lpwg_test) { + himax_press_powerkey(); + /* Wait suspend done */ + while (private_ts->suspend_resume_done != 1) { + usleep_range(1000, 1001); + if (private_ts->debug_log_level & BIT(4)) + I("Waiting for tp suspend!\n"); + } + private_ts->suspend_resume_done = 0; + + for (; i < HX_CRITERIA_ITEM; i++) { + if (g_test_item_flag[i] == 1) { + I("%d.%s Start\n", i, + g_himax_inspection_mode[i]); + rslt = mpTestFunc(i, test_size); + if (file_w_flag && + ((rslt & HX_INSP_EGETRAW) == 0) && + ((rslt & HX_INSP_ESWITCHMODE) == 0)) { +#if defined(KERNEL_VER_ABOVE_5_10) + kernel_write(raw_file, g_rslt_data, + g_rslt_data_len, &pos); +#else + vfs_write(raw_file, g_rslt_data, + g_rslt_data_len, &pos); +#endif + pos += g_rslt_data_len; + } + ret |= rslt; + + I("%d.%s End\n", i, g_himax_inspection_mode[i]); + + if (ret) + goto SELF_TEST_LP_FAIL; + } + } + +SELF_TEST_LP_FAIL: + himax_press_powerkey(); + /* Wait resume done */ + while (private_ts->suspend_resume_done != 1) + usleep_range(1000, 1001); + } + +SELF_TEST_FAIL: + if (ret) { + for (; i < HX_CRITERIA_ITEM; i++) { + if (g_test_item_flag[i] == 1) + ret |= 1 << (i+ERR_SFT); + } + /* output FW version */ + #if defined(HX_ZERO_FLASH) + hx_print_fw_info(); +#if defined(KERNEL_VER_ABOVE_5_10) + kernel_write(raw_file, g_rslt_data, g_rslt_data_len, &pos); +#else + vfs_write(raw_file, g_rslt_data, g_rslt_data_len, &pos); +#endif + pos += g_rslt_data_len; + #endif + } + + if (file_w_flag) + filp_close(raw_file, NULL); + if (!kp_putname_kernel) { + E("kp_putname_kernel is NULL, not open file!\n"); + file_w_flag = false; + } else if (file_w_flag != false) + kp_putname_kernel(vts_name); + +#if !defined(KERNEL_VER_ABOVE_5_10) + set_fs(fs); +#endif + +#if defined(HX_ZERO_FLASH) +UPDATE_MPFW_FAIL: + g_core_fp.fp_0f_op_file_dirly(g_fw_boot_upgrade_name); +#else + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense off!\n", __func__); + g_core_fp.fp_sense_off(true); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense off!\n", __func__); + g_core_fp.fp_turn_on_mp_func(0); + /*himax_set_N_frame(1, HX_INSPECTION_WT_NOISE);*/ + /* set N frame back to default value 1*/ + g_core_fp.fp_register_write(tmp_addr, tmp_data, 4); + if (g_core_fp.fp_reload_disable != NULL) + g_core_fp.fp_reload_disable(0); + + if (himax_check_mode(HX_RAWDATA)) { + I("%s:try to Need to back to Normal!\n", __func__); + himax_switch_mode_inspection(HX_RAWDATA); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(0); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); + himax_wait_sorting_mode(HX_RAWDATA); + } else { + I("%s: It has been in Normal!\n", __func__); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(0); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); + } +#endif + + if (ret == HX_INSP_OK) + seq_puts(s, "Self_Test Pass:\n"); + else + seq_puts(s, "Self_Test Fail:\n"); + + for (i = 0; i < HX_CRITERIA_ITEM - 1; i++) { + if (g_test_item_flag[i] == 1) { + seq_printf(s, "%s : %s\n", + g_himax_inspection_mode[i], + ((ret & (1 << (i + ERR_SFT))) + == (1 << (i + ERR_SFT))) ? "Fail":"OK"); + } + } + + himax_self_test_data_deinit(); + +END: + I("running status = %X\n", ret); + + /*if (ret != 0)*/ + /*ret = 1;*/ + + I("%s:OUT\n", __func__); + return ret; +} + +void himax_inspect_data_clear(void) +{ + if (!g_rslt_data) { + kfree(g_rslt_data); + g_rslt_data = NULL; + } +} + +void himax_inspection_init(void) +{ + I("%s: enter, %d\n", __func__, __LINE__); + g_core_fp.fp_chip_self_test = himax_chip_self_test; +} diff --git a/himax_inspection.h b/himax_inspection.h new file mode 100644 index 0000000..55b4ee6 --- /dev/null +++ b/himax_inspection.h @@ -0,0 +1,311 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for inspection functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_platform.h" +#include "himax_common.h" +#include "himax_ic_core.h" + +/*#define HX_GAP_TEST*/ +/*#define HX_INSP_LP_TEST*/ +/*#define HX_ACT_IDLE_TEST*/ + +/*#define HX_INSPT_DBG*/ + +#define HX_RSLT_OUT_PATH "/sdcard/" +#define HX_RSLT_OUT_FILE "hx_test_result.txt" +#define PI(x...) pr_cont(x) +#define HX_SZ_ICID 60 + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif + +#define BS_RAWDATA 8 +#define BS_NOISE 8 +#define BS_OPENSHORT 0 +#define BS_LPWUG 1 +#define BS_LP_dile 1 +#define BS_ACT_IDLE 1 + +/* skip notch & dummy */ +#define SKIP_NOTCH_START 5 +#define SKIP_NOTCH_END 10 +/* TX+SKIP_NOTCH_START */ +#define SKIP_DUMMY_START 23 +/* TX+SKIP_NOTCH_END*/ +#define SKIP_DUMMY_END 28 + + +#define NOISEFRAME 60 +#define NORMAL_IDLE_RAWDATA_NOISEFRAME 10 +#define LP_RAWDATAFRAME 1 +#define LP_NOISEFRAME 1 +#define LP_IDLE_RAWDATAFRAME 1 +#define LP_IDLE_NOISEFRAME 1 + +#define OTHERSFRAME 2 + +#define UNIFMAX 500 + + +/*Himax MP Password*/ +#define PWD_OPEN_START 0x77 +#define PWD_OPEN_END 0x88 +#define PWD_SHORT_START 0x11 +#define PWD_SHORT_END 0x33 +#define PWD_RAWDATA_START 0x00 +#define PWD_RAWDATA_END 0x99 +#define PWD_NOISE_START 0x00 +#define PWD_NOISE_END 0x99 +#define PWD_SORTING_START 0xAA +#define PWD_SORTING_END 0xCC + + +#define PWD_ACT_IDLE_START 0x22 +#define PWD_ACT_IDLE_END 0x44 + + + +#define PWD_LP_START 0x55 +#define PWD_LP_END 0x66 + +#define PWD_LP_IDLE_START 0x50 +#define PWD_LP_IDLE_END 0x60 + +/*Himax DataType*/ +#define DATA_SORTING 0x0A +#define DATA_OPEN 0x0B +#define DATA_MICRO_OPEN 0x0C +#define DATA_SHORT 0x0A +#define DATA_RAWDATA 0x0A +#define DATA_NOISE 0x0F +#define DATA_BACK_NORMAL 0x00 +#define DATA_LP_RAWDATA 0x0C +#define DATA_LP_NOISE 0x0F +#define DATA_ACT_IDLE_RAWDATA 0x0A +#define DATA_ACT_IDLE_NOISE 0x0F +#define DATA_LP_IDLE_RAWDATA 0x0A +#define DATA_LP_IDLE_NOISE 0x0F + +/*Himax Data Ready Password*/ +#define Data_PWD0 0xA5 +#define Data_PWD1 0x5A + +/* ASCII format */ +#define ASCII_LF (0x0A) +#define ASCII_CR (0x0D) +#define ASCII_COMMA (0x2C) +#define ASCII_ZERO (0x30) +#define CHAR_EL '\0' +#define CHAR_NL '\n' +#define ACSII_SPACE (0x20) +/* INSOECTION Setting */ + +void himax_inspection_init(void); +extern int *g_test_item_flag; +extern int HX_CRITERIA_ITEM; +extern int *g_test_item_flag; +extern char *g_himax_inspection_mode[]; + +/*Inspection register*/ +#define addr_normal_noise_thx 0x1000708C +#define addr_lpwug_noise_thx 0x10007090 +#define addr_noise_scale 0x10007094 +#define addr_recal_thx 0x10007090 +#define addr_palm_num 0x100070A8 +#define addr_weight_sup 0x100072C8 +#define addr_normal_weight_a 0x1000709C +#define addr_lpwug_weight_a 0x100070A0 +#define addr_weight_b 0x10007094 +#define addr_max_dc 0x10007FC8 +#define addr_skip_frame 0x100070F4 +#define addr_neg_noise_sup 0x10007FD8 +#define data_neg_noise 0x7F0C0000 + +/*Need to map *g_himax_inspection_mode[]*/ +enum THP_INSPECTION_ENUM { + HX_OPEN, + HX_MICRO_OPEN, + HX_SHORT, + HX_SC, + HX_WT_NOISE, + HX_ABS_NOISE, + HX_RAWDATA, + HX_BPN_RAWDATA, + HX_SORTING, + + HX_GAPTEST_RAW, + /*HX_GAPTEST_RAW_X,*/ + /*HX_GAPTEST_RAW_Y,*/ + + HX_ACT_IDLE_NOISE, + HX_ACT_IDLE_RAWDATA, + HX_ACT_IDLE_BPN_RAWDATA, +/*LPWUG test must put after Normal test*/ + HX_LP_WT_NOISE, + HX_LP_ABS_NOISE, + HX_LP_RAWDATA, + HX_LP_BPN_RAWDATA, + + HX_LP_IDLE_NOISE, + HX_LP_IDLE_RAWDATA, + HX_LP_IDLE_BPN_RAWDATA, + + HX_BACK_NORMAL,/*Must put in the end*/ +}; + + +enum HX_CRITERIA_ENUM { + IDX_RAWMIN = 0, + IDX_RAWMAX, + IDX_BPN_RAWMIN, + IDX_BPN_RAWMAX, + IDX_SCMIN, + IDX_SCMAX, + IDX_SC_GOLDEN, + IDX_SHORTMIN, + IDX_SHORTMAX, + IDX_OPENMIN, + IDX_OPENMAX, + IDX_M_OPENMIN, + IDX_M_OPENMAX, + IDX_WT_NOISEMIN, + IDX_WT_NOISEMAX, + IDX_ABS_NOISEMIN, + IDX_ABS_NOISEMAX, + IDX_SORTMIN, + IDX_SORTMAX, + + IDX_GAP_HOR_RAWMAX, + IDX_GAP_HOR_RAWMIN, + IDX_GAP_VER_RAWMAX, + IDX_GAP_VER_RAWMIN, + + IDX_ACT_IDLE_NOISE_MIN, + IDX_ACT_IDLE_NOISE_MAX, + IDX_ACT_IDLE_RAWDATA_MIN, + IDX_ACT_IDLE_RAWDATA_MAX, + IDX_ACT_IDLE_RAW_BPN_MIN, + IDX_ACT_IDLE_RAW_BPN_MAX, + + IDX_LP_WT_NOISEMIN, + IDX_LP_WT_NOISEMAX, + IDX_LP_NOISE_ABS_MIN, + IDX_LP_NOISE_ABS_MAX, + IDX_LP_RAWDATA_MIN, + IDX_LP_RAWDATA_MAX, + IDX_LP_RAW_BPN_MIN, + IDX_LP_RAW_BPN_MAX, + + IDX_LP_IDLE_NOISE_MIN, + IDX_LP_IDLE_NOISE_MAX, + IDX_LP_IDLE_RAWDATA_MIN, + IDX_LP_IDLE_RAWDATA_MAX, + IDX_LP_IDLE_RAW_BPN_MIN, + IDX_LP_IDLE_RAW_BPN_MAX, +}; + +enum HX_INSPT_SETTING_IDX { + RAW_BS_FRAME = 0, + NOISE_BS_FRAME, + ACT_IDLE_BS_FRAME, + LP_BS_FRAME, + LP_IDLE_BS_FRAME, + + NFRAME, + IDLE_NFRAME, + LP_RAW_NFRAME, + LP_NOISE_NFRAME, + LP_IDLE_RAW_NFRAME, + LP_IDLE_NOISE_NFRAME, +}; + +#define ERR_SFT 4 +/* Error code of Inspection */ +enum HX_INSP_ERR_ENUM { + /* OK */ + HX_INSP_OK = 0, + + /* Criteria file error*/ + HX_INSP_EFILE = 1, + + /* Get raw data errors */ + HX_INSP_EGETRAW = 1 << 1, + + /* Memory allocate errors */ + HX_INSP_MEMALLCTFAIL = 1 << 2, + + /* Switch mode error*/ + HX_INSP_ESWITCHMODE = 1 << 3, + + /* Sensor open error */ + HX_EOPEN = 1 << (HX_OPEN + ERR_SFT), + + /* Sensor micro open error */ + HX_EMOPEN = 1 << (HX_MICRO_OPEN + ERR_SFT), + + /* Sensor short error */ + HX_ESHORT = 1 << (HX_SHORT + ERR_SFT), + + /* Raw data error */ + HX_ERAW = 1 << (HX_RAWDATA + ERR_SFT), + + /* Raw data BPN error */ + HX_EBPNRAW = 1 << (HX_BPN_RAWDATA + ERR_SFT), + + /* Get SC errors */ + HX_ESC = 1 << (HX_SC + ERR_SFT), + + /* Noise error */ + HX_WT_ENOISE = 1 << (HX_WT_NOISE + ERR_SFT), + + /* Noise error */ + HX_ABS_ENOISE = 1 << (HX_ABS_NOISE + ERR_SFT), + + /* Sorting error*/ + HX_ESORT = 1 << (HX_SORTING + ERR_SFT), + + /* Raw Data GAP */ + HX_EGAP_RAW = 1 << (HX_GAPTEST_RAW + ERR_SFT), + + /* ACT_IDLE RAW ERROR */ + HX_EACT_IDLE_RAW = 1 << (HX_ACT_IDLE_RAWDATA + ERR_SFT), + + /* ACT_IDLE NOISE ERROR */ + HX_EACT_IDLE_NOISE = 1 << (HX_ACT_IDLE_NOISE + ERR_SFT), + + /* LPWUG RAW ERROR */ + HX_ELP_RAW = 1 << (HX_LP_RAWDATA + ERR_SFT), + + /* LPWUG NOISE ERROR */ + HX_ELP_WT_NOISE = 1 << (HX_LP_WT_NOISE + ERR_SFT), + + /* LPWUG NOISE ERROR */ + HX_ELP_ABS_NOISE = 1 << (HX_LP_ABS_NOISE + ERR_SFT), + + /* LPWUG IDLE RAW ERROR */ + HX_ELP_IDLE_RAW = 1 << (HX_LP_IDLE_RAWDATA + ERR_SFT), + + /* LPWUG IDLE NOISE ERROR */ + HX_ELP_IDLE_NOISE = 1 << (HX_LP_IDLE_NOISE + ERR_SFT), + HX_EACT_IDLE_BPNRAW = 1 << (HX_ACT_IDLE_BPN_RAWDATA + ERR_SFT), + HX_ELP_BPNRAW = 1 << (HX_LP_BPN_RAWDATA + ERR_SFT), + HX_ELP_IDLE_BPNRAW = 1 << (HX_LP_IDLE_BPN_RAWDATA + ERR_SFT), + + /* FAIL */ + HX_INSP_FAIL = -1, +}; + +extern void himax_inspect_data_clear(void); diff --git a/himax_modular.h b/himax_modular.h new file mode 100644 index 0000000..fc33bf8 --- /dev/null +++ b/himax_modular.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for modularize functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HIMAX_IC_USAGE_H__ +#define __HIMAX_IC_USAGE_H__ + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xH) +extern bool _hx852xH_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xG) +extern bool _hx852xG_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xJ) +extern bool _hx852xJ_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83102) +extern bool _hx83102_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83103) +extern bool _hx83103_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83106) +extern bool _hx83106_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83108) +extern bool _hx83108_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83111) +extern bool _hx83111_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112) +extern bool _hx83112_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83113) +extern bool _hx83113_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83121) +extern bool _hx83121_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83191) +extern bool _hx83191_init(void); +#endif +#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83192) +extern bool _hx83192_init(void); +#endif + +#if !defined(__HIMAX_HX852xH_MOD__) && !defined(__HIMAX_HX852xG_MOD__) +#if !defined(__HIMAX_HX852xJ_MOD__) + +extern struct fw_operation *pfw_op; +extern struct ic_operation *pic_op; +extern struct flash_operation *pflash_op; +extern struct driver_operation *pdriver_op; +#endif +#endif + +#if defined(HX_ZERO_FLASH) && defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +extern struct zf_operation *pzf_op; +extern int G_POWERONOF; +#endif + +extern unsigned char IC_CHECKSUM; + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif + +#if defined(HX_ZERO_FLASH) && defined(HX_CODE_OVERLAY) +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +extern uint8_t *ovl_idx; +#endif +#endif + +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +extern unsigned long CID_VER_MAJ_FLASH_ADDR; +extern unsigned long CID_VER_MIN_FLASH_ADDR; +extern uint32_t CFG_TABLE_FLASH_ADDR; +extern uint32_t CFG_TABLE_FLASH_ADDR_T; + +#if defined(HX_TP_PROC_2T2R) + // static bool Is_2T2R; +#endif + +#if defined(HX_USB_DETECT_GLOBAL) + extern void (himax_cable_detect_func)(bool force_renew); +#endif + +#if defined(HX_RST_PIN_FUNC) + extern void (himax_rst_gpio_set)(int pinnum, uint8_t value); +#endif + +extern struct himax_ts_data *private_ts; +extern struct himax_core_fp g_core_fp; +extern struct himax_ic_data *ic_data; + +#if !defined(__HIMAX_HX852xH_MOD__) && !defined(__HIMAX_HX852xG_MOD__) + #if !defined(__HIMAX_HX852xJ_MOD__) + extern void himax_mcu_in_cmd_init(void); + extern int himax_mcu_in_cmd_struct_init(void); + #else + extern struct on_driver_operation *on_pdriver_op; + extern struct on_flash_operation *on_pflash_op; + + extern void himax_mcu_on_cmd_init(void); + extern int himax_mcu_on_cmd_struct_init(void); + #endif +#else + extern struct on_driver_operation *on_pdriver_op; + extern struct on_flash_operation *on_pflash_op; + + extern void himax_mcu_on_cmd_init(void); + extern int himax_mcu_on_cmd_struct_init(void); +#endif +extern void himax_parse_assign_cmd(uint32_t addr, uint8_t *cmd, + int len); + +extern int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length); +extern int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length); + +extern void himax_int_enable(int enable); + +#endif diff --git a/himax_platform.c b/himax_platform.c new file mode 100644 index 0000000..f4bf58a --- /dev/null +++ b/himax_platform.c @@ -0,0 +1,1321 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for QCT platform + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "himax_platform.h" +#include "himax_common.h" + +int i2c_error_count; +bool ic_boot_done; +struct spi_device *spi; + +static uint8_t *g_w_xfer_data; +static uint8_t *g_r_xfer_data; + +int himax_dev_set(struct himax_ts_data *ts) +{ + int ret = 0; + + ts->input_dev = input_allocate_device(); + + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device\n", __func__); + return ret; + } + + ts->input_dev->name = "himax-touchscreen"; + + if (!ic_data->HX_STYLUS_FUNC) + goto skip_stylus_operation; + + ts->stylus_dev = input_allocate_device(); + + if (ts->stylus_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device-stylus_dev\n", __func__); + input_free_device(ts->input_dev); + return ret; + } + + ts->stylus_dev->name = "himax-stylus"; +skip_stylus_operation: + + return ret; +} +int himax_input_register_device(struct input_dev *input_dev) +{ + return input_register_device(input_dev); +} + +void himax_vk_parser(struct device_node *dt, struct himax_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + node = of_parse_phandle(dt, "virtualkey", 0); + + if (node == NULL) { + I(" DT-No vk info in DT\n"); + return; + } + while ((pp = of_get_next_child(node, pp))) + cnt++; + + if (!cnt) + return; + + vk = kcalloc(cnt, sizeof(struct himax_virtual_key), GFP_KERNEL); + if (vk == NULL) { + E("%s, vk init fail!\n", __func__); + return; + } + pp = NULL; + + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + + if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { + vk[i].x_range_min = coords[0]; + vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2]; + vk[i].y_range_max = coords[3]; + } else { + I(" range faile\n"); + } + + i++; + } + + pdata->virtual_key = vk; + + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d\n", i, + pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, + pdata->virtual_key[i].y_range_max); + +} + +#if defined(HX_CONFIG_DRM_PANEL) +struct drm_panel *active_panel; + +int himax_ts_check_dt(struct device_node *np) +{ + int i = 0; + int count = 0; + struct device_node *node = NULL; + struct drm_panel *panel = NULL; + + I("%s start\n", __func__); + count = of_count_phandle_with_args(np, "panel", NULL); + if (count <= 0) { + I("%s count= %d\n", __func__, count); + return 0; + } + + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "panel", i); + panel = of_drm_find_panel(node); + of_node_put(node); + if (!IS_ERR(panel)) { + I("%s find drm_panel successfully\n", __func__); + active_panel = panel; + I("active_panel=%s\n", active_panel); + return 0; + } + } + E("%s find drm_panel failed\n", __func__); + return PTR_ERR(panel); +} +#endif + +int himax_parse_dt(struct himax_ts_data *ts, struct himax_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = ts->dev->of_node; + u32 data = 0; + int ret = 0; +#if defined(HX_CONFIG_DRM) +#if defined(HX_CONFIG_DRM_PANEL) + ret = himax_ts_check_dt(dt); + if (ret == -EPROBE_DEFER) + E("himax_ts_check_dt failed\n"); +#endif +#endif + + prop = of_find_property(dt, "himax,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid panel coords size %d\n", + __func__, coords_size); + } + + ret = of_property_read_u32_array(dt, "himax,panel-coords", + coords, coords_size); + if (ret == 0) { + pdata->abs_x_min = coords[0]; + pdata->abs_x_max = (coords[1] - 1); + pdata->abs_y_min = coords[2]; + pdata->abs_y_max = (coords[3] - 1); + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, + pdata->abs_x_min, + pdata->abs_x_max, + pdata->abs_y_min, + pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid display coords size %d\n", + __func__, coords_size); + } + + rc = of_property_read_u32_array(dt, "himax,display-coords", + coords, coords_size); + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", __func__, rc); + return rc; + } + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)\n", __func__, + pdata->screenWidth, + pdata->screenHeight); + + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) + I(" DT:gpio_irq value is not valid\n"); + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) + I(" DT:gpio_rst value is not valid\n"); + + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + if (!gpio_is_valid(pdata->gpio_3v3_en)) + I(" DT:gpio_3v3_en value is not valid\n"); + + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d\n", + pdata->gpio_irq, + pdata->gpio_reset, + pdata->gpio_3v3_en); + +#if defined(HX_PON_PIN_SUPPORT) + pdata->gpio_pon = of_get_named_gpio(dt, "himax,pon-gpio", 0); + + if (!gpio_is_valid(pdata->gpio_pon)) + I(" DT:gpio_pon value is not valid\n"); + + pdata->lcm_rst = of_get_named_gpio(dt, "himax,lcm-rst", 0); + + if (!gpio_is_valid(pdata->lcm_rst)) + I(" DT:tp-rst value is not valid\n"); + + I(" DT:pdata->gpio_pon=%d, pdata->lcm_rst=%d\n", + pdata->gpio_pon, pdata->lcm_rst); +#endif + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d\n", pdata->protocol_type); + } + himax_vk_parser(dt, pdata); + + return 0; +} +EXPORT_SYMBOL(himax_parse_dt); + +#if defined(HX_PARSE_FROM_DT) +static void hx_generate_ic_info_from_dt( + uint32_t proj_id, char *buff, char *main_str, char *item_str) +{ + if (proj_id == 0xffff) + snprintf(buff, 128, "%s,%s", main_str, item_str); + else + snprintf(buff, 128, "%s_%04X,%s", main_str, proj_id, item_str); + +} +static void hx_generate_fw_name_from_dt( + uint32_t proj_id, char *buff, char *main_str, char *item_str) +{ + if (proj_id == 0xffff) + snprintf(buff, 128, "%s_%s", main_str, item_str); + else + snprintf(buff, 128, "%s_%04X_%s", main_str, proj_id, item_str); + +} + +void himax_parse_dt_ic_info(struct himax_ts_data *ts, + struct himax_platform_data *pdata) +{ + struct device_node *dt = ts->dev->of_node; + u32 data = 0; + char *str_rx_num = "rx-num"; + char *str_tx_num = "tx-num"; + char *str_bt_num = "bt-num"; + char *str_max_pt = "max-pt"; + char *str_int_edge = "int-edge"; + char *str_stylus_func = "stylus-func"; + char *str_firmware_name_tail = "firmware.bin"; + char *str_mp_firmware_name_tail = "mpfw.bin"; + char buff[128] = {0}; + + hx_generate_ic_info_from_dt(g_proj_id, buff, ts->chip_name, str_rx_num); + if (of_property_read_u32(dt, buff, &data) == 0) { + ic_data->HX_RX_NUM = data; + I("%s,Now parse:%s=%d\n", __func__, buff, ic_data->HX_RX_NUM); + } else + I("%s, No definition: %s!\n", __func__, buff); + + hx_generate_ic_info_from_dt(g_proj_id, buff, ts->chip_name, str_tx_num); + if (of_property_read_u32(dt, buff, &data) == 0) { + ic_data->HX_TX_NUM = data; + I("%s,Now parse:%s=%d\n", __func__, buff, ic_data->HX_TX_NUM); + } else + I("%s, No definition: %s!\n", __func__, buff); + + hx_generate_ic_info_from_dt(g_proj_id, buff, ts->chip_name, str_bt_num); + if (of_property_read_u32(dt, buff, &data) == 0) { + ic_data->HX_BT_NUM = data; + I("%s,Now parse:%s=%d\n", __func__, buff, ic_data->HX_BT_NUM); + } else + I("%s, No definition: %s!\n", __func__, buff); + + hx_generate_ic_info_from_dt(g_proj_id, buff, ts->chip_name, str_max_pt); + if (of_property_read_u32(dt, buff, &data) == 0) { + ic_data->HX_MAX_PT = data; + I("%s,Now parse:%s=%d\n", __func__, buff, ic_data->HX_MAX_PT); + } else + I("%s, No definition: %s!\n", __func__, buff); + + hx_generate_ic_info_from_dt( + g_proj_id, buff, ts->chip_name, str_int_edge); + if (of_property_read_u32(dt, buff, &data) == 0) { + ic_data->HX_INT_IS_EDGE = data; + I("%s,Now parse:%s=%d\n", + __func__, buff, ic_data->HX_INT_IS_EDGE); + } else + I("%s, No definition: %s!\n", __func__, buff); + + hx_generate_ic_info_from_dt(g_proj_id, buff, + ts->chip_name, str_stylus_func); + if (of_property_read_u32(dt, buff, &data) == 0) { + ic_data->HX_STYLUS_FUNC = data; + I("%s,Now parse:%s=%d\n", + __func__, buff, ic_data->HX_STYLUS_FUNC); + } else + I("%s, No definition: %s!\n", __func__, buff); + + hx_generate_fw_name_from_dt(g_proj_id, buff, ts->chip_name, + str_firmware_name_tail); + I("%s,buff=%s!\n", __func__, buff); +#if defined(HX_BOOT_UPGRADE) + g_fw_boot_upgrade_name = kzalloc(sizeof(buff), GFP_KERNEL); + memcpy(&g_fw_boot_upgrade_name[0], &buff[0], sizeof(buff)); + I("%s,g_fw_boot_upgrade_name=%s!\n", + __func__, g_fw_boot_upgrade_name); +#endif + + hx_generate_fw_name_from_dt(g_proj_id, buff, ts->chip_name, + str_mp_firmware_name_tail); + I("%s,buff=%s!\n", __func__, buff); +#if defined(HX_ZERO_FLASH) + g_fw_mp_upgrade_name = kzalloc(sizeof(buff), GFP_KERNEL); + memcpy(&g_fw_mp_upgrade_name[0], &buff[0], sizeof(buff)); + I("%s,g_fw_mp_upgrade_name=%s!\n", __func__, g_fw_mp_upgrade_name); +#endif + + I(" DT:rx, tx, bt, pt, int, stylus\n"); + I(" DT:%d, %d, %d, %d, %d, %d\n", ic_data->HX_RX_NUM, + ic_data->HX_TX_NUM, ic_data->HX_BT_NUM, ic_data->HX_MAX_PT, + ic_data->HX_INT_IS_EDGE, ic_data->HX_STYLUS_FUNC); +} +EXPORT_SYMBOL(himax_parse_dt_ic_info); +#endif + +static int himax_spi_read(uint8_t *command, uint8_t command_len, uint8_t *data, + uint32_t length) +{ + struct spi_message m; + int result = NO_ERR; + int retry; + int error; + struct spi_transfer t = { + .len = command_len + length, + }; + + memset(g_w_xfer_data, 0, command_len + length); + memcpy(g_w_xfer_data, command, command_len); + + t.tx_buf = g_w_xfer_data; + t.rx_buf = g_r_xfer_data; + + if (length > HX_MAX_READ_SZ) { + E("%s, data length is over than MAX SIZE!\n", __func__); + result = -EIO; + goto END; + } + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + + for (retry = 0; retry < HIMAX_BUS_RETRY_TIMES; retry++) { + error = spi_sync(private_ts->spi, &m); + if (unlikely(error)) + E("SPI read error: %d\n", error); + else + break; + } + + if (retry == HIMAX_BUS_RETRY_TIMES) { + E("%s: SPI read error retry over %d\n", + __func__, HIMAX_BUS_RETRY_TIMES); + result = -EIO; + goto END; + } else { + memcpy(&data[0], &g_r_xfer_data[command_len], + sizeof(uint8_t) * length); + } + +END: + return result; +} + +static int himax_spi_write(uint8_t *buf, uint32_t length) +{ + int status; + struct spi_message m; + struct spi_transfer t = { + .tx_buf = buf, + .len = length, + }; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + status = spi_sync(private_ts->spi, &m); + + if (status == 0) { + status = m.status; + if (status == 0) + status = m.actual_length; + } + return status; + +} + +int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length) +{ + int result = 0; + uint8_t *spi_format_buf = g_r_xfer_data; + + mutex_lock(&(private_ts->rw_lock)); + spi_format_buf[0] = 0xF3; + spi_format_buf[1] = command; + spi_format_buf[2] = 0x00; + + result = himax_spi_read(&spi_format_buf[0], 3, data, length); + mutex_unlock(&(private_ts->rw_lock)); + + return result; +} +EXPORT_SYMBOL(himax_bus_read); + +int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length) +{ + uint8_t *spi_format_buf = g_w_xfer_data; + int result = 0; + + mutex_lock(&(private_ts->rw_lock)); + spi_format_buf[0] = 0xF2; + spi_format_buf[1] = command; + + memcpy(spi_format_buf + 2, data, length); + + result = himax_spi_write(spi_format_buf, length + 2); + mutex_unlock(&(private_ts->rw_lock)); + + return result; +} +EXPORT_SYMBOL(himax_bus_write); + +void himax_int_enable(int enable) +{ + struct himax_ts_data *ts = private_ts; + unsigned long irqflags = 0; + int irqnum = ts->hx_irq; + + spin_lock_irqsave(&ts->irq_lock, irqflags); + I("%s: Entering! irqnum = %d\n", __func__, irqnum); + if (enable == 1 && atomic_read(&ts->irq_state) == 0) { + atomic_set(&ts->irq_state, 1); + enable_irq(irqnum); + private_ts->irq_enabled = 1; + } else if (enable == 0 && atomic_read(&ts->irq_state) == 1) { + atomic_set(&ts->irq_state, 0); + disable_irq_nosync(irqnum); + private_ts->irq_enabled = 0; + } + + I("enable = %d\n", enable); + spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} +EXPORT_SYMBOL(himax_int_enable); + +#if defined(HX_RST_PIN_FUNC) +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} +EXPORT_SYMBOL(himax_rst_gpio_set); +#endif + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int himax_regulator_configure(struct himax_platform_data *pdata) +{ + int retval; + /* struct i2c_client *client = private_ts->client; */ + + pdata->vcc_dig = regulator_get(private_ts->dev, "vdd"); + + if (IS_ERR(pdata->vcc_dig)) { + E("%s: Failed to get regulator vdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + + pdata->vcc_ana = regulator_get(private_ts->dev, "avdd"); + + if (IS_ERR(pdata->vcc_ana)) { + E("%s: Failed to get regulator avdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_dig); + return retval; + } + + return 0; +}; + +static void himax_regulator_deinit(struct himax_platform_data *pdata) +{ + I("%s: entered.\n", __func__); + + if (!IS_ERR(pdata->vcc_ana)) + regulator_put(pdata->vcc_ana); + + if (!IS_ERR(pdata->vcc_dig)) + regulator_put(pdata->vcc_dig); + + I("%s: regulator put, completed.\n", __func__); +}; + +static int himax_power_on(struct himax_platform_data *pdata, bool on) +{ + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + + if (retval) { + E("%s: Failed to enable regulator vdd\n", + __func__); + return retval; + } + + /*msleep(100);*/ + usleep_range(1000, 1001); + retval = regulator_enable(pdata->vcc_ana); + + if (retval) { + E("%s: Failed to enable regulator avdd\n", + __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } else { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + + return 0; +} + +int himax_gpio_power_config(struct himax_platform_data *pdata) +{ + int error; + /* struct i2c_client *client = private_ts->client; */ + + error = himax_regulator_configure(pdata); + + if (error) { + E("Failed to intialize hardware\n"); + goto err_regulator_not_on; + } + +#if defined(HX_RST_PIN_FUNC) + + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_reset); + goto err_gpio_reset_req; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_dir; + } + } + +#endif +#if defined(HX_PON_PIN_SUPPORT) + if (pdata->lcm_rst >= 0) { + error = gpio_direction_output(pdata->lcm_rst, 0); + if (error) { + E("unable to set direction for lcm_rst [%d]\n", + pdata->lcm_rst); + } + } +#endif + error = himax_power_on(pdata, true); + + if (error) { + E("Failed to power on hardware\n"); + goto err_power_on; + } + + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_irq); + goto err_req_irq_gpio; + } + + error = gpio_direction_input(pdata->gpio_irq); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_set_gpio_irq; + } + + private_ts->hx_irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_req_irq_gpio; + } +#if defined(HX_PON_PIN_SUPPORT) + if (pdata->lcm_rst >= 0) { + error = gpio_direction_output(pdata->lcm_rst, 1); + + if (error) { + E("lcm_rst unable to set direction for gpio [%d]\n", + pdata->lcm_rst); + } + } +#endif + /*msleep(20);*/ + usleep_range(2000, 2001); +#if defined(HX_RST_PIN_FUNC) + + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_set_high; + } + } + +#endif + return 0; +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_set_high: +#endif +err_set_gpio_irq: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + +err_req_irq_gpio: + himax_power_on(pdata, false); +err_power_on: +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_dir: + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); + +err_gpio_reset_req: +#endif + himax_regulator_deinit(pdata); +err_regulator_not_on: + return error; +} + +#else +int himax_gpio_power_config(struct himax_platform_data *pdata) +{ + int error = 0; + /* struct i2c_client *client = private_ts->client; */ +#if defined(HX_RST_PIN_FUNC) + + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + + if (error < 0) { + E("%s: request reset pin failed\n", __func__); + goto err_gpio_reset_req; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_dir; + } + } + +#endif + +#if defined(HX_PON_PIN_SUPPORT) + if (pdata->lcm_rst >= 0) { + error = gpio_direction_output(pdata->lcm_rst, 0); + if (error) { + E("unable to set direction for lcm_rst [%d]\n", + pdata->lcm_rst); + } + } + + if (gpio_is_valid(pdata->gpio_pon)) { + error = gpio_request(pdata->gpio_pon, "hmx_pon_gpio"); + + if (error) { + E("unable to request pon gpio [%d]\n", pdata->gpio_pon); + goto err_gpio_pon_req; + } + + error = gpio_direction_output(pdata->gpio_pon, 0); + + I("gpio_pon LOW [%d]\n", pdata->gpio_pon); + + if (error) { + E("unable to set direction for pon gpio [%d]\n", + pdata->gpio_pon); + goto err_gpio_pon_dir; + } + } +#endif + + + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + goto err_gpio_3v3_req; + } + + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en set 1 get pin = %d\n", + gpio_get_value(pdata->gpio_3v3_en)); + } + + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + goto err_gpio_irq_req; + } + + error = gpio_direction_input(pdata->gpio_irq); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_set_input; + } + + private_ts->hx_irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_gpio_irq_req; + } + + usleep_range(2000, 2001); + +#if defined(HX_PON_PIN_SUPPORT) + msleep(20); + + if (pdata->lcm_rst >= 0) { + error = gpio_direction_output(pdata->lcm_rst, 1); + + if (error) { + E("lcm_rst unable to set direction for gpio [%d]\n", + pdata->lcm_rst); + } + } + msleep(20); +#endif + +#if defined(HX_RST_PIN_FUNC) + + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_set_high; + } + } +#endif + +#if defined(HX_PON_PIN_SUPPORT) + msleep(800); + + if (gpio_is_valid(pdata->gpio_pon)) { + + error = gpio_direction_output(pdata->gpio_pon, 1); + + I("gpio_pon HIGH [%d]\n", pdata->gpio_pon); + + if (error) { + E("gpio_pon unable to set direction for gpio [%d]\n", + pdata->gpio_pon); + goto err_gpio_pon_set_high; + } + } +#endif + return error; + +#if defined(HX_PON_PIN_SUPPORT) +err_gpio_pon_set_high: +#endif +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_set_high: +#endif +err_gpio_irq_set_input: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_gpio_irq_req: + if (pdata->gpio_3v3_en >= 0) + gpio_free(pdata->gpio_3v3_en); +err_gpio_3v3_req: +#if defined(HX_PON_PIN_SUPPORT) +err_gpio_pon_dir: + if (gpio_is_valid(pdata->gpio_pon)) + gpio_free(pdata->gpio_pon); +err_gpio_pon_req: +#endif +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_dir: + if (pdata->gpio_reset >= 0) + gpio_free(pdata->gpio_reset); +err_gpio_reset_req: +#endif + return error; +} + +#endif + +void himax_gpio_power_deconfig(struct himax_platform_data *pdata) +{ + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + +#if defined(HX_RST_PIN_FUNC) + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +#endif + +#if defined(CONFIG_HMX_DB) + himax_power_on(pdata, false); + himax_regulator_deinit(pdata); +#else + if (pdata->gpio_3v3_en >= 0) + gpio_free(pdata->gpio_3v3_en); + +#if defined(HX_PON_PIN_SUPPORT) + if (gpio_is_valid(pdata->gpio_pon)) + gpio_free(pdata->gpio_pon); +#endif + +#endif +} + +static void himax_ts_isr_func(struct himax_ts_data *ts) +{ + himax_ts_work(ts); +} + +irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + himax_ts_isr_func((struct himax_ts_data *)ptr); + + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, + struct himax_ts_data, work); + + himax_ts_work(ts); +} + +int himax_int_register_trigger(void) +{ + int ret = 0; + struct himax_ts_data *ts = private_ts; + + if (ic_data->HX_INT_IS_EDGE) { + I("%s edge triiger falling\n", __func__); + ret = request_threaded_irq(ts->hx_irq, NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + HIMAX_common_NAME, ts); + } else { + I("%s level trigger low\n", __func__); + ret = request_threaded_irq(ts->hx_irq, NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, HIMAX_common_NAME, ts); + } + + return ret; +} + +int himax_int_en_set(void) +{ + int ret = NO_ERR; + + ret = himax_int_register_trigger(); + return ret; +} + +int himax_ts_register_interrupt(void) +{ + struct himax_ts_data *ts = private_ts; + /* struct i2c_client *client = private_ts->client; */ + int ret = 0; + + ts->irq_enabled = 0; + + /* Work functon */ + if (private_ts->hx_irq) {/*INT mode*/ + ts->use_irq = 1; + ret = himax_int_register_trigger(); + + if (ret == 0) { + ts->irq_enabled = 1; + atomic_set(&ts->irq_state, 1); + I("%s: irq enabled at gpio: %d\n", __func__, + private_ts->hx_irq); +#if defined(HX_SMART_WAKEUP) + irq_set_irq_wake(private_ts->hx_irq, 1); +#endif + } else { + ts->use_irq = 0; + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: private_ts->hx_irq is empty, use polling mode.\n", + __func__); + } + + /*if use polling mode need to disable HX_ESD_RECOVERY function*/ + if (!ts->use_irq) { + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + INIT_WORK(&ts->work, himax_ts_work_func); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + + return ret; +} + +int himax_ts_unregister_interrupt(void) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + I("%s: entered.\n", __func__); + + /* Work functon */ + if (private_ts->hx_irq && ts->use_irq) {/*INT mode*/ +#if defined(HX_SMART_WAKEUP) + irq_set_irq_wake(ts->hx_irq, 0); +#endif + free_irq(ts->hx_irq, ts); + I("%s: irq disabled at qpio: %d\n", __func__, + private_ts->hx_irq); + } + + /*if use polling mode need to disable HX_ESD_RECOVERY function*/ + if (!ts->use_irq) { + hrtimer_cancel(&ts->timer); + cancel_work_sync(&ts->work); + if (ts->himax_wq != NULL) + destroy_workqueue(ts->himax_wq); + I("%s: polling mode destroyed", __func__); + } + + return ret; +} + +static int himax_common_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); +#if defined(HX_CONFIG_DRM) && !defined(HX_CONFIG_FB) + if (!ts->initialized) + return -ECANCELED; +#endif + himax_chip_common_suspend(ts); + return 0; +} +#if !defined(HX_CONTAINER_SPEED_UP) +static int himax_common_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); +#if defined(HX_CONFIG_DRM) && !defined(HX_CONFIG_FB) + /* + * wait until device resume for TDDI + * TDDI: Touch and display Driver IC + */ + if (!ts->initialized) { + if (himax_chip_common_init()) + return -ECANCELED; + } +#endif + himax_chip_common_resume(ts); + return 0; +} +#endif + +#if defined(HX_CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts = + container_of(self, struct himax_ts_data, fb_notif); + + I(" %s\n", __func__); + + if (ic_boot_done != 1) { + E("%s: IC is booting\n", __func__); + return -ECANCELED; + } + + if (evdata && evdata->data && +#if defined(HX_CONTAINER_SPEED_UP) + event == FB_EARLY_EVENT_BLANK +#else + event == FB_EVENT_BLANK +#endif + && ts != NULL && + ts->dev != NULL) { + blank = evdata->data; + + switch (*blank) { + case FB_BLANK_UNBLANK: +#if defined(HX_CONTAINER_SPEED_UP) + queue_delayed_work(ts->ts_int_workqueue, + &ts->ts_int_work, + msecs_to_jiffies(DELAY_TIME)); +#else + himax_common_resume(ts->dev); +#endif + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax_common_suspend(ts->dev); + break; + } + } + + return 0; +} +#elif defined(HX_CONFIG_DRM_PANEL) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct drm_panel_notifier *evdata = data; + int *blank; + struct himax_ts_data *ts = + container_of(self, struct himax_ts_data, fb_notif); + + if (!evdata) + return 0; + + D("DRM %s\n", __func__); + + if (ic_boot_done != 1) { + E("%s: IC is booting\n", __func__); + return -ECANCELED; + } + + if (evdata->data + && event == DRM_PANEL_EARLY_EVENT_BLANK + && ts + && ts->client) { + blank = evdata->data; + switch (*blank) { + case DRM_PANEL_BLANK_POWERDOWN: + if (!ts->initialized) + return -ECANCELED; + himax_common_suspend(&ts->client->dev); + break; + } + } + + if (evdata->data + && event == DRM_PANEL_EVENT_BLANK + && ts + && ts->client) { + blank = evdata->data; + switch (*blank) { + case DRM_PANEL_BLANK_UNBLANK: + himax_common_resume(&ts->client->dev); + break; + } + } + + return 0; +} +#elif defined(HX_CONFIG_DRM) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct msm_drm_notifier *evdata = data; + int *blank; + struct himax_ts_data *ts = + container_of(self, struct himax_ts_data, fb_notif); + + if (!evdata || (evdata->id != 0)) + return 0; + + D("DRM %s\n", __func__); + + if (ic_boot_done != 1) { + E("%s: IC is booting\n", __func__); + return -ECANCELED; + } + + if (evdata->data + && event == MSM_DRM_EARLY_EVENT_BLANK + && ts != NULL + && ts->dev != NULL) { + blank = evdata->data; + switch (*blank) { + case MSM_DRM_BLANK_POWERDOWN: + if (!ts->initialized) + return -ECANCELED; + himax_common_suspend(ts->dev); + break; + } + } + + if (evdata->data + && event == MSM_DRM_EVENT_BLANK + && ts != NULL + && ts->dev != NULL) { + blank = evdata->data; + switch (*blank) { + case MSM_DRM_BLANK_UNBLANK: + himax_common_resume(ts->dev); + break; + } + } + + return 0; +} +#endif + +int himax_chip_common_probe(struct spi_device *spi) +{ + struct himax_ts_data *ts; + int ret = 0; + + I("Enter %s\n", __func__); + if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) { + dev_err(&spi->dev, + "%s: Full duplex not supported by host\n", + __func__); + return -EIO; + } + + /* command[2] + address[4] + data[] */ + g_w_xfer_data = kzalloc(sizeof(uint8_t) * (HX_MAX_WRITE_SZ+6), + GFP_KERNEL); + if (g_w_xfer_data == NULL) { + E("%s: allocate g_w_xfer_data failed\n", __func__); + ret = -ENOMEM; + goto err_alloc_g_w_xfer_data_failed; + } + + g_r_xfer_data = kzalloc(sizeof(uint8_t) * HX_MAX_READ_SZ, + GFP_KERNEL); + if (g_r_xfer_data == NULL) { + E("%s, allocate g_r_xfer_data fail!\n", __func__); + ret = -ENOMEM; + goto err_alloc_g_r_xfer_data_failed; + } + + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + ret = -ENOMEM; + goto err_alloc_data_failed; + } + + private_ts = ts; + spi->bits_per_word = 8; + spi->mode = SPI_MODE_3; + spi->chip_select = 0; + + ts->spi = spi; + mutex_init(&ts->rw_lock); + ts->dev = &spi->dev; + dev_set_drvdata(&spi->dev, ts); + spi_set_drvdata(spi, ts); + + ts->initialized = false; + ret = himax_chip_common_init(); + if (ret < 0) + goto err_common_init_failed; + + return ret; + +err_common_init_failed: + kfree(ts); +err_alloc_data_failed: + kfree(g_r_xfer_data); + g_r_xfer_data = NULL; +err_alloc_g_r_xfer_data_failed: + kfree(g_w_xfer_data); + g_w_xfer_data = NULL; +err_alloc_g_w_xfer_data_failed: + + return ret; +} + +int himax_chip_common_remove(struct spi_device *spi) +{ + struct himax_ts_data *ts = spi_get_drvdata(spi); + + if (g_hx_chip_inited) + himax_chip_common_deinit(); + + ts->spi = NULL; + /* spin_unlock_irq(&ts->spi_lock); */ + spi_set_drvdata(spi, NULL); + kfree(g_w_xfer_data); + kfree(g_r_xfer_data); + + I("%s: completed.\n", __func__); + + return 0; +} + +static const struct dev_pm_ops himax_common_pm_ops = { +#if (!defined(HX_CONFIG_FB)) && (!defined(HX_CONFIG_DRM)) + .suspend = himax_common_suspend, + .resume = himax_common_resume, +#endif +}; + +#if defined(CONFIG_OF) +static const struct of_device_id himax_match_table[] = { + {.compatible = "himax,hxcommon" }, + {}, +}; +#else +#define himax_match_table NULL +#endif + +static struct spi_driver himax_common_driver = { + .driver = { + .name = HIMAX_common_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, + }, + .probe = himax_chip_common_probe, + .remove = himax_chip_common_remove, +}; + +static int __init himax_common_init(void) +{ + I("Himax common touch panel driver init\n"); + D("Himax check double loading\n"); + if (g_mmi_refcnt++ > 0) { + I("Himax driver has been loaded! ignoring....\n"); + return 0; + } + spi_register_driver(&himax_common_driver); + + return 0; +} + +static void __exit himax_common_exit(void) +{ +#if !defined(KERNEL_VER_ABOVE_5_10) + if (spi) { + spi_unregister_device(spi); + spi = NULL; + } +#endif + spi_unregister_driver(&himax_common_driver); +} + +late_initcall(himax_common_init); +module_exit(himax_common_exit); + +MODULE_DESCRIPTION("Himax_common driver"); +MODULE_LICENSE("GPL"); diff --git a/himax_platform.h b/himax_platform.h new file mode 100644 index 0000000..c677e05 --- /dev/null +++ b/himax_platform.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for QCT platform + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/gpio.h> +#include <linux/types.h> +#include <linux/spi/spi.h> +#include <linux/interrupt.h> +#if defined(CONFIG_HMX_DB) + #include <linux/regulator/consumer.h> +#endif + +#define HIMAX_SPI_FIFO_POLLING +#define HIMAX_BUS_RETRY_TIMES 3 + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_debug("[HXTP] " x) +#define I(x...) pr_info("[HXTP] " x) +#define W(x...) pr_warn("[HXTP][WARNING] " x) +#define E(x...) pr_err("[HXTP][ERROR] " x) +#define DIF(x...) \ +do { \ + if (debug_flag) \ + pr_debug("[HXTP][DEBUG] " x) \ + } while (0) +#else +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif + +#if defined(CONFIG_HMX_DB) + /* Analog voltage @2.7 V */ +#define HX_VTG_MIN_UV 2700000 +#define HX_VTG_MAX_UV 3300000 +#define HX_ACTIVE_LOAD_UA 15000 +#define HX_LPM_LOAD_UA 10 +/* Digital voltage @1.8 V */ +#define HX_VTG_DIG_MIN_UV 1800000 +#define HX_VTG_DIG_MAX_UV 1800000 +#define HX_ACTIVE_LOAD_DIG_UA 10000 +#define HX_LPM_LOAD_DIG_UA 10 + +#define HX_I2C_VTG_MIN_UV 1800000 +#define HX_I2C_VTG_MAX_UV 1800000 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 +#endif + +#define HIMAX_common_NAME "himax_tp" +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" + +struct himax_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int gpio_pon; + int lcm_rst; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + + int hx_config_size; +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + + struct regulator *vcc_ana; /* For Dragon Board */ + struct regulator *vcc_dig; /* For Dragon Board */ + struct regulator *vcc_i2c; /* For Dragon Board */ +#endif +}; + +extern struct himax_ic_data *ic_data; +extern struct himax_ts_data *private_ts; +int himax_chip_common_init(void); +void himax_chip_common_deinit(void); + +void himax_ts_work(struct himax_ts_data *ts); +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length); +extern int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length); +extern void himax_int_enable(int enable); +extern int himax_ts_register_interrupt(void); +int himax_ts_unregister_interrupt(void); +extern uint8_t himax_int_gpio_read(int pinnum); + +extern int himax_gpio_power_config(struct himax_platform_data *pdata); +void himax_gpio_power_deconfig(struct himax_platform_data *pdata); + +#if defined(HX_CONFIG_FB) +extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(HX_CONFIG_DRM) +extern int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#endif + +#endif |