summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormasonwang <masonwang@google.com>2021-07-27 09:54:47 +0800
committermasonwang <masonwang@google.com>2021-07-27 18:09:28 +0800
commitcdc58ea5242971d8a7995f98627db5fe4d0a589b (patch)
tree06709fd11236509f378c50bd2f61b933f508bdce
parent23a3369a44f3378bb545aa7fca5fc770e262a519 (diff)
downloadhimax_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--Kbuild146
-rw-r--r--Kconfig140
-rw-r--r--Makefile24
-rw-r--r--himax_common.c3547
-rw-r--r--himax_common.h643
-rw-r--r--himax_debug.c3485
-rw-r--r--himax_debug.h240
-rw-r--r--himax_debug_info.h98
-rw-r--r--himax_ic_HX83102.c1616
-rw-r--r--himax_ic_HX83102.h53
-rw-r--r--himax_ic_core.h1020
-rw-r--r--himax_ic_incell_core.c4585
-rw-r--r--himax_inspection.c2853
-rw-r--r--himax_inspection.h311
-rw-r--r--himax_modular.h137
-rw-r--r--himax_platform.c1321
-rw-r--r--himax_platform.h142
17 files changed, 20361 insertions, 0 deletions
diff --git a/Kbuild b/Kbuild
new file mode 100644
index 0000000..8475a65
--- /dev/null
+++ b/Kbuild
@@ -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
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..e4d0f60
--- /dev/null
+++ b/Kconfig
@@ -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