diff --git a/drivers/input/touchscreen/himax_v2_mmi/Android.mk b/drivers/input/touchscreen/himax_v2_mmi/Android.mk index fd04d917ee1c..099321fa5cde 100644 --- a/drivers/input/touchscreen/himax_v2_mmi/Android.mk +++ b/drivers/input/touchscreen/himax_v2_mmi/Android.mk @@ -22,6 +22,10 @@ ifneq ($(BOARD_USES_HIMAX_MULTI_BIN),) KERNEL_CFLAGS += CONFIG_INPUT_HIMAX_V2_MMI_ENABLE_MULTI_BIN=y endif +ifeq ($(HIMAX_V2_MMI_HX83102D),true) + KERNEL_CFLAGS += CONFIG_INPUT_HIMAX_V2_MMI_IC_NAME_D=hx83102d +endif + include $(CLEAR_VARS) LOCAL_MODULE := himax_v2_mmi.ko LOCAL_MODULE_TAGS := optional diff --git a/drivers/input/touchscreen/himax_v2_mmi/Kbuild b/drivers/input/touchscreen/himax_v2_mmi/Kbuild index 64e5f682751b..9e764db0d1a4 100644 --- a/drivers/input/touchscreen/himax_v2_mmi/Kbuild +++ b/drivers/input/touchscreen/himax_v2_mmi/Kbuild @@ -16,6 +16,11 @@ ifneq ($(filter hx83102,$(CONFIG_INPUT_HIMAX_V2_MMI_IC_NAME)),) EXTRA_CFLAGS += -D__HIMAX_HX83102_MOD__ endif +ifneq ($(filter hx83102d,$(CONFIG_INPUT_HIMAX_V2_MMI_IC_NAME_D)),) + EXTRA_CFLAGS += -D__HIMAX_HX83102D_MOD__ + EXTRA_CFLAGS += -DHX_CODE_OVERLAY +endif + ifneq ($(filter m y,$(CONFIG_INPUT_TOUCHSCREEN_HIMAX_V2_MMI_ENABLE_PALM)),) EXTRA_CFLAGS += -DHIMAX_PALM_SENSOR_EN endif diff --git a/drivers/input/touchscreen/himax_v2_mmi/himax_common.c b/drivers/input/touchscreen/himax_v2_mmi/himax_common.c index 400312097fb6..a28c4a10b6ea 100644 --- a/drivers/input/touchscreen/himax_v2_mmi/himax_common.c +++ b/drivers/input/touchscreen/himax_v2_mmi/himax_common.c @@ -3154,6 +3154,10 @@ GET_TOUCH_FAIL: #else g_core_fp.fp_system_reset(); #endif +#if defined(HX_ZERO_FLASH) && defined(HX83102D) + 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); diff --git a/drivers/input/touchscreen/himax_v2_mmi/himax_common.h b/drivers/input/touchscreen/himax_v2_mmi/himax_common.h index c5a1360e98ae..556077a51da9 100755 --- a/drivers/input/touchscreen/himax_v2_mmi/himax_common.h +++ b/drivers/input/touchscreen/himax_v2_mmi/himax_common.h @@ -461,7 +461,7 @@ struct himax_ts_data { struct workqueue_struct *himax_diag_wq; struct delayed_work himax_diag_delay_wrok; -#ifdef HX_SMART_WAKEUP +#if defined (HX_SMART_WAKEUP) || defined (HX_CODE_OVERLAY) uint8_t SMWP_enable; uint8_t gesture_cust_en[26]; struct wakeup_source ts_SMWP_wake_lock; diff --git a/drivers/input/touchscreen/himax_v2_mmi/himax_debug.c b/drivers/input/touchscreen/himax_v2_mmi/himax_debug.c index db39252b7a81..b41724bd3cb2 100755 --- a/drivers/input/touchscreen/himax_v2_mmi/himax_debug.c +++ b/drivers/input/touchscreen/himax_v2_mmi/himax_debug.c @@ -1577,6 +1577,10 @@ static ssize_t himax_reset_write(char *buf, size_t len) g_core_fp.fp_ic_reset(true, true); /* else if (buf[0] == '5') */ /* ESD_HW_REST(); */ +#endif +#if defined(HX_ZERO_FLASH) && defined(HX83102D) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); #endif return len; } @@ -2337,6 +2341,10 @@ static ssize_t himax_debug_write(struct file *file, const char *buff, g_core_fp.fp_ic_reset(true, false); #else g_core_fp.fp_system_reset(); +#endif +#if defined(HX_ZERO_FLASH) && defined(HX83102D) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); #endif himax_int_enable(1); /* himax_check_chip_version(); */ @@ -2503,6 +2511,10 @@ static ssize_t himax_debug_write(struct file *file, const char *buff, return len; } else if (buf[0] == 'x') { g_core_fp.fp_system_reset(); +#if defined(HX_ZERO_FLASH) && defined(HX83102D) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif return len; #endif } else if (buf[0] == 'l' && buf[1] == 'o' && buf[2] == 't') { @@ -2522,6 +2534,10 @@ firmware_upgrade_done: g_core_fp.fp_touch_information(); #ifdef HX_RST_PIN_FUNC g_core_fp.fp_ic_reset(true, false); +#if defined(HX_ZERO_FLASH) && defined(HX83102D) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif #else g_core_fp.fp_sense_on(0x00); #endif diff --git a/drivers/input/touchscreen/himax_v2_mmi/himax_ic_core.h b/drivers/input/touchscreen/himax_v2_mmi/himax_ic_core.h index e6db83a413fb..f6010d6ac244 100644 --- a/drivers/input/touchscreen/himax_v2_mmi/himax_ic_core.h +++ b/drivers/input/touchscreen/himax_v2_mmi/himax_ic_core.h @@ -64,6 +64,11 @@ #define HX_MOD_KSYM_HX83102 HX_MOD_KSYM_HX83102 #endif +#if defined(__HIMAX_HX83102D_MOD__) +#define HX_MOD_KSYM_HX83102 HX_MOD_KSYM_HX83102 +#define HX83102D +#endif + #if defined(__HIMAX_HX83103_MOD__) #define HX_MOD_KSYM_HX83103 HX_MOD_KSYM_HX83103 #endif @@ -473,6 +478,16 @@ struct hx_guest_info { #define zf_data_activ_in 0xEC #if defined(HX_CODE_OVERLAY) +#if defined(HX83102D) + #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 +#else #define ovl_isram_addr 0x20008CE0 #define ovl_handshaking_addr 0x10007FFC #define ovl_gesture_request 0x11 @@ -480,6 +495,7 @@ struct hx_guest_info { #define ovl_border_request 0x55 #define ovl_border_reply 0x66 #endif +#endif struct zf_info { uint8_t sram_addr[4]; @@ -945,6 +961,9 @@ struct himax_core_fp { int (*fp_0f_op_file_dirly)(char *file_name); void (*fp_0f_operation)(struct work_struct *work); int (*fp_0f_esd_check)(void); +#if defined(HX83102D) + void (*fp_0f_reload_to_active)(void); +#endif #ifdef 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); diff --git a/drivers/input/touchscreen/himax_v2_mmi/himax_ic_incell_core.c b/drivers/input/touchscreen/himax_v2_mmi/himax_ic_incell_core.c index 6cdc7c5e69c9..6b24758c5ea7 100755 --- a/drivers/input/touchscreen/himax_v2_mmi/himax_ic_incell_core.c +++ b/drivers/input/touchscreen/himax_v2_mmi/himax_ic_incell_core.c @@ -30,6 +30,10 @@ EXPORT_SYMBOL(pdriver_op); #ifdef HX_ZERO_FLASH struct zf_operation *pzf_op; EXPORT_SYMBOL(pzf_op); +#if defined(HX_CODE_OVERLAY) && defined(HX83102D) +uint8_t *ovl_idx; +EXPORT_SYMBOL(ovl_idx); +#endif #endif void (*himax_mcu_cmd_struct_free)(void); @@ -2610,6 +2614,149 @@ int himax_sram_write_crc_check(const struct firmware *fw_entry, uint8_t *addr, i return crc; } +#if defined(HX83102D) +int hx_parse_bin_cfg_data(const struct firmware *fw_entry, struct zf_info *zf_info_arr, uint8_t *FW_buf, uint8_t *sram_min) +{ + int part_num = 0; + int i = 0; + uint8_t buf[16]; + int i_max = 0; + int i_min = 0; + uint32_t dsram_base = 0xFFFFFFFF; + uint32_t dsram_max = 0; + int cfg_sz = 0; +#if defined(HX_CODE_OVERLAY) + uint8_t j = 0; + int allovlidx = 0; + + 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 -ENOMEM; + } + } else { + memset(ovl_idx, 0, ovl_section_num); + } +#endif + /*1. get number of partition*/ + part_num = fw_entry->data[HX64K + 12]; + I("%s, Number of partition is %d\n", __func__, part_num); + if (part_num <= 1) { + E("%s, size of cfg part failed! part_num = %d\n", + __func__, part_num); + return LENGTH_FAIL; + } + + /* i = 0 is fw entity, it need to update by itself*/ + for (i = 1; i < part_num; i++) { + /*3. get all partition*/ + memcpy(buf, &fw_entry->data[i * 0x10 + HX64K], 16); + memcpy(zf_info_arr[i].sram_addr, buf, 4); + zf_info_arr[i].write_size = buf[7] << 24 + | buf[6] << 16 + | buf[5] << 8 + | buf[4]; + zf_info_arr[i].fw_addr = buf[11] << 24 + | buf[10] << 16 + | buf[9] << 8 + | buf[8]; + zf_info_arr[i].cfg_addr = zf_info_arr[i].sram_addr[0]; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[1] << 8; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[2] << 16; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[3] << 24; + +#if defined(HX_CODE_OVERLAY) + /*overlay section*/ + + if ((buf[15] == 0x55 && buf[14] == 0x66) + || (buf[3] == 0x20 && buf[2] == 0x00 + && buf[1] == 0x8C && buf[0] == 0xE0)) { + I("%s: catch overlay section in index %d\n", + __func__, i); + + /* record index of overlay section */ + allovlidx |= 1< zf_info_arr[i].cfg_addr) { + dsram_base = zf_info_arr[i].cfg_addr; + i_min = i; + } + if (dsram_max < zf_info_arr[i].cfg_addr) { + dsram_max = zf_info_arr[i].cfg_addr; + i_max = i; + } + } + for (i = 0; i < ADDR_LEN_4; i++) + sram_min[i] = zf_info_arr[i_min].sram_addr[i]; + + cfg_sz = (dsram_max - dsram_base) + zf_info_arr[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); + if (cfg_sz <= FW_BIN_16K_SZ) + memset(FW_buf, 0x00, sizeof(uint8_t) * cfg_sz); + else + memset(FW_buf, 0x00, sizeof(uint8_t) * FW_BIN_16K_SZ); + for (i = 1; i < part_num; i++) { + if (zf_info_arr[i].cfg_addr % 4 != 0) + zf_info_arr[i].cfg_addr = zf_info_arr[i].cfg_addr + - (zf_info_arr[i].cfg_addr % 4); + + I("%s,[%d]SRAM addr=%08X,[%d]fw_addr=%08X,[%d]write_size=%d\n", + __func__, + i, zf_info_arr[i].cfg_addr, + i, zf_info_arr[i].fw_addr, + i, zf_info_arr[i].write_size); + +#if defined(HX_CODE_OVERLAY) + /*overlay section*/ + if (allovlidx & (1<data[zf_info_arr[i].fw_addr], + zf_info_arr[i].write_size); + } + /* debug info */ + /* for (i = 1; i < part_num; i++) { + * different = 0; + * I("--cfg_addr = 0x%08X\n",zf_info_arr[i].cfg_addr); + * I("--bin_addr = 0x%08X\n",zf_info_arr[i].fw_addr); + * I("--write size = %d\n",zf_info_arr[i].write_size); + * for ( j = 0; j < zf_info_arr[i].write_size; j++) { + * if(FW_buf[zf_info_arr[i].cfg_addr - dsram_base + j] != + fw_entry->data[zf_info_arr[i].fw_addr + j]) + * different++; + * } + * I("--There are %d different\n", different); + * } + */ + + return cfg_sz; +} +#else int hx_parse_bin_cfg_data(const struct firmware *fw_entry, struct zf_info *zf_info_arr, uint8_t *FW_buf, uint8_t *sram_min, uint8_t *ovl_sidx) { int part_num = 0; @@ -2708,6 +2855,8 @@ int hx_parse_bin_cfg_data(const struct firmware *fw_entry, struct zf_info *zf_in return cfg_sz; } +#endif + int himax_zf_part_info(const struct firmware *fw_entry) { int part_num = fw_entry->data[HX64K + 12]; @@ -2722,12 +2871,21 @@ int himax_zf_part_info(const struct firmware *fw_entry) int retry = 3; uint8_t ovl_sidx = 0; +#if defined(HX83102D) + uint8_t ovl_idx_t; +#if defined(HX_SMART_WAKEUP) || defined(HX_CODE_OVERLAY) + uint8_t tmp_addr[4] = {0xFC, 0x7F, 0x00, 0x10}; + uint8_t send_data[4] = {0}; + uint8_t recv_data[4] = {0}; +#endif +#else #ifdef HX_CODE_OVERLAY #ifdef HX_SMART_WAKEUP uint8_t tmp_addr[4] = {0xFC, 0x7F, 0x00, 0x10}; uint8_t send_data[4] = {0}; uint8_t recv_data[4] = {0}; #endif +#endif #endif /*1. get number of partition*/ @@ -2753,7 +2911,11 @@ int himax_zf_part_info(const struct firmware *fw_entry) /*3. Find the data in the bin file */ /*CFG*/ +#if defined(HX83102D) + cfg_sz = hx_parse_bin_cfg_data(fw_entry, zf_info_arr, FW_buf, sram_min); +#else cfg_sz = hx_parse_bin_cfg_data(fw_entry, zf_info_arr, FW_buf, sram_min, &ovl_sidx); +#endif I("Now cfg_sz=%d\n", cfg_sz); if (cfg_sz < 0) { ret = LENGTH_FAIL; @@ -2788,6 +2950,28 @@ int himax_zf_part_info(const struct firmware *fw_entry) } while (cfg_crc_hw != cfg_crc_sw && retry-- > 0); #ifdef HX_CODE_OVERLAY +#if defined(HX83102D) + /* ovl_idx[0] - sorting */ + /* ovl_idx[1] - gesture */ + /* ovl_idx[2] - border */ + + ovl_idx_t = ovl_idx[0]; + send_data[0] = ovl_sorting_reply; + + if (private_ts->in_self_test == 0) { +#if defined(HX_SMART_WAKEUP) + if (private_ts->suspended && private_ts->SMWP_enable) { + ovl_idx_t = ovl_idx[1]; + send_data[0] = ovl_gesture_reply; + } else { + ovl_idx_t = ovl_idx[2]; + send_data[0] = ovl_border_reply; + } +#else + ovl_idx_t = ovl_idx[2]; + send_data[0] = ovl_border_reply; +#endif +#else /*do nothing when self testing ??*/ if (private_ts->in_self_test == 0) { #ifdef HX_SMART_WAKEUP @@ -2800,6 +2984,7 @@ int himax_zf_part_info(const struct firmware *fw_entry) ovl_sidx = ovl_sidx + 2; #else ovl_sidx = ovl_sidx + 2; +#endif #endif if (himax_sram_write_crc_check(fw_entry, zf_info_arr[ovl_sidx].sram_addr, zf_info_arr[ovl_sidx].fw_addr, zf_info_arr[ovl_sidx].write_size) != 0) @@ -2812,6 +2997,35 @@ int himax_zf_part_info(const struct firmware *fw_entry) g_core_fp.fp_resend_cmd_func(private_ts->suspended); #endif +#if defined(HX83102D) + } + I("%s: prepare upgrade overlay section = %d\n", + __func__, ovl_idx_t); + + if (zf_info_arr[ovl_idx_t].write_size == 0) { + send_data[0] = ovl_fault; + E("%s, WRONG overlay section, plese check FW!\n", + __func__); + } else { + if (himax_sram_write_crc_check(fw_entry, + zf_info_arr[ovl_idx_t].sram_addr, + zf_info_arr[ovl_idx_t].fw_addr, + zf_info_arr[ovl_idx_t].write_size) != 0) { + send_data[0] = ovl_fault; + E("%s, Overlay HW CRC FAIL\n", __func__); + } else { + I("%s, Overlay HW CRC PASS\n", __func__); + } + } + + retry = 0; + + do { + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, send_data, 0); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, recv_data, 0); + retry++; + } while ((send_data[3] != recv_data[3] || send_data[2] != recv_data[2] || send_data[1] != recv_data[1] || send_data[0] != recv_data[0]) && retry < HIMAX_REG_RETRY_TIMES); +#else #if defined(HX_SMART_WAKEUP) /* write overlay handshaking password */ if (private_ts->SMWP_enable) { @@ -2831,7 +3045,7 @@ int himax_zf_part_info(const struct firmware *fw_entry) #endif } #endif - +#endif } else { g_core_fp.fp_clean_sram_0f(zf_info_arr[0].sram_addr, zf_info_arr[0].write_size, 2); } diff --git a/drivers/input/touchscreen/himax_v2_mmi/himax_inspection.c b/drivers/input/touchscreen/himax_v2_mmi/himax_inspection.c index 619aba95173c..f562b87fe0cf 100644 --- a/drivers/input/touchscreen/himax_v2_mmi/himax_inspection.c +++ b/drivers/input/touchscreen/himax_v2_mmi/himax_inspection.c @@ -1858,7 +1858,7 @@ static int himax_chip_self_test(void) uint8_t tmp_addr[DATA_LEN_4] = {0x94, 0x72, 0x00, 0x10}; uint8_t tmp_data[DATA_LEN_4] = {0x01, 0x00, 0x00, 0x00}; -#ifdef HIMAX_V2_MULTI_BIN +#if defined(HIMAX_V2_MULTI_BIN)||defined(HX_CODE_OVERLAY) uint8_t normalfw[32] = "Himax_firmware.bin"; uint8_t mpapfw[32] = "Himax_mpfw.bin"; if (private_ts->pdata->panel_supplier) { @@ -1871,7 +1871,7 @@ static int himax_chip_self_test(void) private_ts->suspend_resume_done = 0; -#ifdef HIMAX_V2_MULTI_BIN +#if defined(HIMAX_V2_MULTI_BIN)||defined(HX_CODE_OVERLAY) g_core_fp.fp_0f_op_file_dirly(mpapfw); g_core_fp.fp_reload_disable(0); g_core_fp.fp_sense_on(0x00); @@ -2176,7 +2176,7 @@ static int himax_chip_self_test(void) usleep_range(1000, 1001); #endif -#ifdef HIMAX_V2_MULTI_BIN +#if defined(HIMAX_V2_MULTI_BIN)||defined(HX_CODE_OVERLAY) private_ts->in_self_test = 0; g_core_fp.fp_0f_op_file_dirly(normalfw); hx_turn_on_mp_func(0); diff --git a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_modular.h b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_modular.h index 96563e43b636..3e7a43b9ed4e 100644 --- a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_modular.h +++ b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_modular.h @@ -107,6 +107,13 @@ static unsigned char *kp_IC_CHECKSUM; static u8 *kp_HX_ESD_RESET_ACTIVATE; #endif +#if defined(HX_ZERO_FLASH) && defined(HX_CODE_OVERLAY) +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +extern uint8_t *ovl_idx; +static uint8_t **kp_ovl_idx; +#endif +#endif + static unsigned long *kp_FW_VER_MAJ_FLASH_ADDR; static unsigned long *kp_FW_VER_MIN_FLASH_ADDR; static unsigned long *kp_CFG_VER_MAJ_FLASH_ADDR; @@ -254,6 +261,12 @@ static int32_t himax_ic_setup_external_symbols(void) #ifdef HX_ESD_RECOVERY assert_on_symbol(HX_ESD_RESET_ACTIVATE); +#endif + +#if defined(HX_ZERO_FLASH) && defined(HX_CODE_OVERLAY) +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) + assert_on_symbol(ovl_idx); +#endif #endif return ret; } diff --git a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Android.mk b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Android.mk new file mode 100644 index 000000000000..77ebf2321097 --- /dev/null +++ b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Android.mk @@ -0,0 +1,17 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true) +HIMAX_MMI_IC_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/ +else +HIMAX_MMI_IC_MODULE_PATH := $(KERNEL_MODULES_OUT) +endif + +KERNEL_CFLAGS += CONFIG_INPUT_HIMAX_V2_MMI_IC_NAME_D=hx83102d + +include $(CLEAR_VARS) +LOCAL_MODULE := himax_v2_mmi_hx83102d.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(HIMAX_MMI_IC_MODULE_PATH) +LOCAL_REQUIRED_MODULES := himax_v2_mmi.ko +include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Kbuild b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Kbuild new file mode 100644 index 000000000000..f495e15c50c8 --- /dev/null +++ b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Kbuild @@ -0,0 +1,20 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \ + -I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/himax_v2_mmi \ + -I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/himax_v2_mmi/support_ic \ + -I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d +EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_HIMAX_DEBUG \ + -DCONFIG_TOUCHSCREEN_HIMAX_INSPECT + +EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_HIMAX_INCELL +EXTRA_CFLAGS += -DCONFIG_HMX_DB + +ifneq ($(filter hx83102d,$(CONFIG_INPUT_HIMAX_V2_MMI_IC_NAME_D)),) + EXTRA_CFLAGS += -D__HIMAX_HX83102D_MOD__ + EXTRA_CFLAGS += -DHX_ZERO_FLASH + EXTRA_CFLAGS += -DHX_CODE_OVERLAY +endif + +obj-m := himax_v2_mmi_hx83102d.o +himax_v2_mmi_hx83102d-objs += himax_ic_HX83102d.o diff --git a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Makefile b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Makefile new file mode 100755 index 000000000000..4191dea22679 --- /dev/null +++ b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/Makefile @@ -0,0 +1,10 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/himax_ic_HX83102d.c b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/himax_ic_HX83102d.c new file mode 100644 index 000000000000..2ca679fbc37c --- /dev/null +++ b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/himax_ic_HX83102d.c @@ -0,0 +1,1449 @@ +/* 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_HX83102d.h" +#include "himax_modular.h" + +static void hx83102_chip_init(void) +{ + (*kp_private_ts)->chip_cell_type = CHIP_IS_IN_CELL; + I("%s:IC cell type = %d\n", __func__, (*kp_private_ts)->chip_cell_type); + (*kp_IC_CHECKSUM) = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + (*kp_FW_VER_MAJ_FLASH_ADDR) = 49157; /*0x00C005*/ + (*kp_FW_VER_MAJ_FLASH_LENG) = 1; + (*kp_FW_VER_MIN_FLASH_ADDR) = 49158; /*0x00C006*/ + (*kp_FW_VER_MIN_FLASH_LENG) = 1; + (*kp_CFG_VER_MAJ_FLASH_ADDR) = 49408; /*0x00C100*/ + (*kp_CFG_VER_MAJ_FLASH_LENG) = 1; + (*kp_CFG_VER_MIN_FLASH_ADDR) = 49409; /*0x00C101*/ + (*kp_CFG_VER_MIN_FLASH_LENG) = 1; + (*kp_CID_VER_MAJ_FLASH_ADDR) = 49154; /*0x00C002*/ + (*kp_CID_VER_MAJ_FLASH_LENG) = 1; + (*kp_CID_VER_MIN_FLASH_ADDR) = 49155; /*0x00C003*/ + (*kp_CID_VER_MIN_FLASH_LENG) = 1; + /*PANEL_VERSION_ADDR = 49156;*/ /*0x00C004*/ + /*PANEL_VERSION_LENG = 1;*/ +} + +static void hx83102e_chip_init(void) +{ + (*kp_private_ts)->chip_cell_type = CHIP_IS_IN_CELL; + I("%s:IC cell type = %d\n", __func__, (*kp_private_ts)->chip_cell_type); + (*kp_IC_CHECKSUM) = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + (*kp_FW_VER_MAJ_FLASH_ADDR) = 59397; /*0x00E805*/ + (*kp_FW_VER_MAJ_FLASH_LENG) = 1; + (*kp_FW_VER_MIN_FLASH_ADDR) = 59398; /*0x00E806*/ + (*kp_FW_VER_MIN_FLASH_LENG) = 1; + (*kp_CFG_VER_MAJ_FLASH_ADDR) = 59648; /*0x00E900*/ + (*kp_CFG_VER_MAJ_FLASH_LENG) = 1; + (*kp_CFG_VER_MIN_FLASH_ADDR) = 59649; /*0x00E901*/ + (*kp_CFG_VER_MIN_FLASH_LENG) = 1; + (*kp_CID_VER_MAJ_FLASH_ADDR) = 59394; /*0x00E802*/ + (*kp_CID_VER_MAJ_FLASH_LENG) = 1; + (*kp_CID_VER_MIN_FLASH_ADDR) = 59395; /*0x00E803*/ + (*kp_CID_VER_MIN_FLASH_LENG) = 1; + /*PANEL_VERSION_ADDR = 49156;*/ /*0x00C004*/ + /*PANEL_VERSION_LENG = 1;*/ +} + +void hx83102_burst_enable(uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + + tmp_data[0] = 0x31; + if (kp_himax_bus_write(0x13, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + if (kp_himax_bus_write(0x0D, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c 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; + + 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]; + + if (kp_himax_bus_write(0x00, data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + return 0; +} + +static int hx83102_register_read(uint8_t *read_addr, int read_length, uint8_t *read_data) +{ + uint8_t tmp_data[4]; + int i = 0; + int address = 0; + + if (read_length > 256) { + E("%s: read len over 256!\n", __func__); + return LENGTH_FAIL; + } + if (read_length > 4) + hx83102_burst_enable(1); + else + hx83102_burst_enable(0); + + address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_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); + if (kp_himax_bus_write(0x00, tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + tmp_data[0] = 0x00; + if (kp_himax_bus_write(0x0C, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + + if (kp_himax_bus_read(0x08, read_data, read_length, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + if (read_length > 4) + hx83102_burst_enable(0); + + return 0; +} + +#ifdef HX_RST_PIN_FUNC +static void hx83102_pin_reset(void) +{ + I("%s: Now reset the Touch chip.\n", __func__); + kp_himax_rst_gpio_set((*kp_private_ts)->rst_gpio, 0); + msleep(20); + kp_himax_rst_gpio_set((*kp_private_ts)->rst_gpio, 1); + msleep(50); +} +#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]; + + 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, DATA_LEN_4, tmp_data); + + 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, DATA_LEN_4, tmp_data); + 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; + if (kp_himax_bus_write(0x31, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /*=========================================== + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + *=========================================== + */ + tmp_data[0] = 0x95; + if (kp_himax_bus_write(0x32, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c 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, ADDR_LEN_4, tmp_data); + 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); +#ifdef 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]; + + do { + /*=========================================== + *I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + *=========================================== + */ + tmp_data[0] = 0x27; + if (kp_himax_bus_write(0x31, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /*=========================================== + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + *=========================================== + */ + tmp_data[0] = 0x95; + if (kp_himax_bus_write(0x32, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c 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, ADDR_LEN_4, tmp_data); + 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); +#ifdef HX_RST_PIN_FUNC + kp_himax_rst_gpio_set((*kp_private_ts)->rst_gpio, 0); + msleep(20); + kp_himax_rst_gpio_set((*kp_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; + + kp_g_core_fp->fp_sense_off(true); + + do { + if (SMWP_enable) { + kp_himax_in_parse_assign_cmd(fw_func_handshaking_pwd, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_smwp_enable, DATA_LEN_4, tmp_data, 0); + kp_himax_in_parse_assign_cmd(fw_func_handshaking_pwd, back_data, 4); + } else { + kp_himax_in_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_smwp_enable, DATA_LEN_4, tmp_data, 0); + kp_himax_in_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, back_data, 4); + } + + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_smwp_enable, DATA_LEN_4, tmp_data, false); + /*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); + + kp_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) { + kp_himax_in_parse_assign_cmd(fw_func_handshaking_pwd, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_hsen_enable, DATA_LEN_4, tmp_data, 0); + } else { + kp_himax_in_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_hsen_enable, DATA_LEN_4, tmp_data, 0); + } + + /*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) { + kp_himax_in_parse_assign_cmd(fw_func_handshaking_pwd, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_usb_detect, DATA_LEN_4, tmp_data, 0); + I("%s: USB detect status IN!\n", __func__); + } else { + kp_himax_in_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_usb_detect, DATA_LEN_4, tmp_data, 0); + 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] = (*kp_pfw_op)->data_dd_request[0]; + + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_dd_handshak_addr, DATA_LEN_4, cmd_set, 0); + I("%s: cmd_set[0] = 0x%02X,cmd_set[1] = 0x%02X,cmd_set[2] = 0x%02X,cmd_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++) { + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_dd_handshak_addr, DATA_LEN_4, tmp_data, false); + usleep_range(10000, 10001); + + if (tmp_data[3] == (*kp_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; + } + } + + kp_g_core_fp->fp_sense_off(true); + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_dd_data_addr, req_size, tmp_data, false); + kp_g_core_fp->fp_sense_on(0x01); + return NO_ERR; +} + +static int hx83102ab_read_FW_status(uint8_t *state_addr, uint8_t *tmp_addr) +{ + uint8_t i; + uint8_t req_size = 0; + uint8_t status_addr[DATA_LEN_4]; /*0x10007F44*/ + uint8_t cmd_addr[DATA_LEN_4]; /*0x900000F8*/ + + if (state_addr[0] == 0x01) { + state_addr[1] = 0x04; + + for (i = 0; i < DATA_LEN_4; i++) { + /* 0x10007F44 */ + state_addr[i + 2] = (*kp_pfw_op)->addr_fw_dbg_msg_addr[i]; + status_addr[i] = (*kp_pfw_op)->addr_fw_dbg_msg_addr[i]; + } + + req_size = 0x04; + kp_g_core_fp->fp_sense_off(true); + kp_g_core_fp->fp_register_read(status_addr, req_size, tmp_addr, false); + kp_g_core_fp->fp_sense_on(0x01); + } else if (state_addr[0] == 0x02) { + state_addr[1] = 0x30; + + for (i = 0; i < DATA_LEN_4; i++) { + /* 0x900000F8 */ + state_addr[i + 2] = (*kp_pfw_op)->addr_fw_state_addr[i]; + cmd_addr[i] = (*kp_pfw_op)->addr_fw_state_addr[i]; + } + + req_size = 0x30; + kp_g_core_fp->fp_register_read(cmd_addr, req_size, tmp_addr, false); + } + + return NO_ERR; +} + +static void hx83102ab_power_on_init(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + + I("%s:\n", __func__); + kp_himax_in_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_raw_out_sel, DATA_LEN_4, tmp_data, 0); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_sorting_mode_en, DATA_LEN_4, tmp_data, 0); + kp_g_core_fp->fp_touch_information(); + kp_g_core_fp->fp_sense_on(0x00); +} + +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]; + + if (len != FW_SIZE_64k) { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + +#ifdef HX_RST_PIN_FUNC + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + kp_g_core_fp->fp_sense_off(true); + kp_g_core_fp->fp_chip_erase(); + kp_g_core_fp->fp_flash_programming(fw, FW_SIZE_64k); + + if (kp_g_core_fp->fp_check_CRC((*kp_pfw_op)->addr_program_reload_from, FW_SIZE_64k) == 0) + burnFW_success = 1; + + kp_himax_in_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, tmp_data, 4); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_raw_out_sel, DATA_LEN_4, tmp_data, 0); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_sorting_mode_en, DATA_LEN_4, tmp_data, 0); +#ifdef HX_RST_PIN_FUNC + kp_g_core_fp->fp_ic_reset(false, false); +#else + /*System reset*/ + kp_g_core_fp->fp_system_reset(); +#endif + return burnFW_success; +} + +#ifdef HX_ESD_RECOVERY +static void hx83102ab_esd_ic_reset(void) +{ + (*kp_HX_ESD_RESET_ACTIVATE) = 1; +#ifdef HX_RST_PIN_FUNC + kp_g_core_fp->fp_pin_reset(); +#else + kp_g_core_fp->fp_system_reset(); +#endif + I("%s:\n", __func__); +} +#if defined(HX_ZERO_FLASH) +static int hx83102d_0f_esd_check(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + int ret = NO_ERR; + + I("Enter %s\n", __func__); + + kp_g_core_fp->fp_register_read((*kp_pzf_op)->addr_sts_chk, DATA_LEN_4, tmp_data, 0); + + if (tmp_data[0] != (*kp_pzf_op)->data_activ_sts[0]) { + ret = ERR_STS_WRONG; + I("%s:status : %8X = %2X\n", __func__, zf_addr_sts_chk, tmp_data[0]); + } + + kp_g_core_fp->fp_register_read((*kp_pzf_op)->addr_activ_relod, DATA_LEN_4, tmp_data, 0); + + if (tmp_data[0] != (*kp_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]; + + do { + if (cnt == 0 || (tmp_data[0] != 0xA5 && tmp_data[0] != 0x00 && tmp_data[0] != 0x87)) + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_ctrl_fw_isr, DATA_LEN_4, (*kp_pfw_op)->data_fw_stop, 0); + /*msleep(20);*/ + usleep_range(10000, 10001); + + /* check fw status */ + kp_g_core_fp->fp_register_read((*kp_pic_op)->addr_cs_central_state, ADDR_LEN_4, tmp_data, 0); + + if (tmp_data[0] != 0x05) { + I("%s: Do not need wait FW, Status = 0x%02X!\n", __func__, tmp_data[0]); + break; + } + + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_ctrl_fw_isr, 4, tmp_data, false); + 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; + if (kp_himax_bus_write(0x31, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /*=========================================== + *I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + *=========================================== + */ + tmp_data[0] = 0x95; + if (kp_himax_bus_write(0x32, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c 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, ADDR_LEN_4, tmp_data); + 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); +#ifdef HX_RST_PIN_FUNC + kp_himax_rst_gpio_set((*kp_private_ts)->rst_gpio, 0); + msleep(20); + kp_himax_rst_gpio_set((*kp_private_ts)->rst_gpio, 1); + msleep(50); +#endif + + } while (cnt++ < 5); + + return false; +} + +static bool hx83102d_dd_clk_set(bool enable) +{ + uint8_t data[4] = {0}; + + data[0] = (enable)?0xDD:0; + return (kp_g_core_fp->fp_register_write((*kp_pic_op)->adr_osc_en, + sizeof((*kp_pic_op)->adr_osc_en), data, 0) == NO_ERR); +} + +static void hx83102d_dd_reg_en(bool enable) +{ + uint8_t data[4] = {0}; + + data[0] = 0xA5; data[1] = 0x00; + data[2] = 0x00; data[3] = 0x00; + kp_g_core_fp->fp_register_write((*kp_pic_op)->adr_osc_pw, DATA_LEN_4, data, 0); + + data[0] = 0xA5; data[1] = 0x83; + data[2] = 0x10; data[3] = 0x2D; + kp_g_core_fp->fp_dd_reg_write(0xB9, 0, 4, data, 0); +} + +static bool hx83102d_ic_id_read(void) +{ + int i = 0; + uint8_t data[4] = {0}; + + kp_g_core_fp->fp_dd_clk_set(true); + kp_g_core_fp->fp_dd_reg_en(true); + + for (i = 0; i < 13; i++) { + data[0] = 0x2A + i; + kp_g_core_fp->fp_dd_reg_write(0xBB, 3, 1, data, 0); + data[0] = 0x08; + kp_g_core_fp->fp_dd_reg_write(0xBB, 1, 1, data, 0); + kp_g_core_fp->fp_dd_reg_read(0xBB, 6, 1, data, 0); + (*kp_ic_data)->vendor_ic_id[i] = data[0]; + I("ic_data->vendor_ic_id[%d] = %02X\n", i, (*kp_ic_data)->vendor_ic_id[i]); + } + + kp_g_core_fp->fp_dd_clk_set(false); + + return true; +} + +#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; + kp_g_core_fp->fp_register_write(addr, DATA_LEN_4, data, 0); + usleep_range(1000, 1100); + kp_g_core_fp->fp_register_read(addr, DATA_LEN_4, data, 0); + 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) +{ +#ifndef HX_RESUME_HW_RESET + himax_hx83102d_reload_to_active(); +#endif +} + +static void himax_hx83102d_suspend_ic_action(void) +{ +#ifndef 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; + + I("Enter %s\n", __func__); + + kp_g_core_fp->fp_interface_on(); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_ctrl_fw_isr, + sizeof((*kp_pfw_op)->data_clear), (*kp_pfw_op)->data_clear, 0); + /*msleep(20);*/ + usleep_range(10000, 10001); + if (!FlashMode) { +#ifdef HX_RST_PIN_FUNC + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + himax_hx83102d_reload_to_active(); + } else { + himax_hx83102d_reload_to_active(); + do { + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_safe_mode_release_pw, + sizeof((*kp_pfw_op)->data_safe_mode_release_pw_active), (*kp_pfw_op)->data_safe_mode_release_pw_active, 0); + + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_flag_reset_event, DATA_LEN_4, tmp_data, 0); + 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__); +#ifdef HX_RST_PIN_FUNC + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + himax_hx83102d_reload_to_active(); + } 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; + + if (kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_lb[0], tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) + E("%s: i2c access fail!\n", __func__); + + if (kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_ub[0], tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) + E("%s: i2c access fail!\n", __func__); + + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_safe_mode_release_pw, + sizeof((*kp_pfw_op)->data_safe_mode_release_pw_reset), (*kp_pfw_op)->data_safe_mode_release_pw_reset, 0); + } + } +} + +static void hx83102ab_firmware_update_0f(const struct firmware *fw_entry) +{ + uint8_t tmp_addr[4]; + + I("%s, Entering\n", __func__); + + kp_g_core_fp->fp_register_write((*kp_pzf_op)->addr_system_reset, 4, (*kp_pzf_op)->data_system_reset, 0); + + kp_g_core_fp->fp_sense_off(false); + + /* first 32K */ + /*bin file start*/ + /*isram*/ + kp_g_core_fp->fp_write_sram_0f(fw_entry, (*kp_pzf_op)->data_sram_start_addr, 0, HX_32K_SZ); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x73; + tmp_addr[0] = 0x00; + kp_g_core_fp->fp_write_sram_0f(fw_entry, tmp_addr, 0x8000, (0x200*4)); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x68; + tmp_addr[0] = 0x00; + kp_g_core_fp->fp_write_sram_0f(fw_entry, tmp_addr, 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*/ + kp_g_core_fp->fp_write_sram_0f(fw_entry, tmp_addr, 0xC178, (84)); + + /*FW config*/ + if ((*kp_G_POWERONOF) == 1) + kp_g_core_fp->fp_write_sram_0f(fw_entry, (*kp_pzf_op)->data_fw_cfg_1, 0xBFFE, 388); + else + kp_g_core_fp->fp_clean_sram_0f((*kp_pzf_op)->data_fw_cfg_1, 388, 1); + /*ADC config*/ + if ((*kp_G_POWERONOF) == 1) + kp_g_core_fp->fp_write_sram_0f(fw_entry, (*kp_pzf_op)->data_adc_cfg_1, 0xe000, (128 * 4)); + else + kp_g_core_fp->fp_clean_sram_0f((*kp_pzf_op)->data_adc_cfg_1, (128 * 4), 2); + + I("%s, END\n", __func__); +} +#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 */ + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_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; + kp_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; + kp_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*/ + kp_g_core_fp->fp_read_sram_0f(fw_entry, tmp_addr, 0xC178, (84)); + + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_fw_cfg_1, 0xBFFE, 388); + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_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: + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_sram_start_addr, 0, HX_40K_SZ); + break; + case 1: + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_cfg_info, 0xC000, 132); + break; + case 2: + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_fw_cfg_1, 0xC0FE, 484); + break; + case 3: + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_adc_cfg_1, 0xD000, 768); + break; + case 4: + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_adc_cfg_2, 0xD300, 1536); + break; + case 5: + kp_g_core_fp->fp_read_sram_0f(fw_entry, (*kp_pzf_op)->data_adc_cfg_3, 0xE000, 1536); + break; + case 6: + kp_himax_in_parse_assign_cmd(hx83102d_zf_data_bor_prevent_info, tmp_data, 4); + kp_g_core_fp->fp_read_sram_0f(fw_entry, tmp_data, 0xC9E0, 32); + break; + case 7: + kp_himax_in_parse_assign_cmd(hx83102d_zf_data_notch_info, tmp_data, 4); + kp_g_core_fp->fp_read_sram_0f(fw_entry, tmp_data, 0xCA00, 128); + break; + case 8: + kp_himax_in_parse_assign_cmd(hx83102d_zf_func_info_en, tmp_data, 4); + kp_g_core_fp->fp_read_sram_0f(fw_entry, tmp_data, 0xCB00, 12); + break; + case 9: + kp_himax_in_parse_assign_cmd(hx83102d_zf_po_sub_func, tmp_data, 4); + kp_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; + char fwname[32] = "Himax_firmware.bin"; + 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, fwname, (*kp_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 = *((*kp_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 (kp_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 { + kp_g_core_fp->fp_register_read(handshaking_addr, DATA_LEN_4, recv_data, 0); + } while (recv_data[0] != request && count++ < 10); + + if (count < 10) { + /*g_core_fp.fp_write_sram_0f(fwp, sram_addr, offset, size);*/ + if (kp_g_core_fp->fp_write_sram_0f_crc(fwp, sram_addr, 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 { + kp_g_core_fp->fp_register_write(handshaking_addr, DATA_LEN_4, send_data, 0); + usleep_range(1000, 1100); + kp_g_core_fp->fp_register_read(handshaking_addr, DATA_LEN_4, recv_data, 0); + } while (recv_data[0] != reply && count2++ < 10); + + if (ovl_type == 3) { +#ifdef HX_RST_PIN_FUNC + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_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) { + + kp_g_core_fp->fp_0f_op_file_dirly(fwname); + + kp_g_core_fp->fp_reload_disable(0); + + kp_g_core_fp->fp_sense_on(0x00); + + kp_himax_int_enable(1); + } + + return 0; +} +#endif +#endif + +#if defined(HX_AUTO_UPDATE_FW) || defined(HX_ZERO_FLASH) +#if defined(HX_EN_DYNAMIC_NAME) +static void hx83102a_read_ic_ver(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_addr[DATA_LEN_4]; + + (*kp_ic_data)->vendor_ic_ver = 0xFFFF; + /* Enable read DD */ + tmp_data[0] = 0x00; + tmp_data[1] = 0x83; + tmp_data[2] = 0x10; + tmp_data[3] = 0x2A; + kp_himax_in_parse_assign_cmd(hx83102_ic_b9_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + /* Read DD data */ + kp_himax_in_parse_assign_cmd(hx83102_ic_fw, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + I("E8=%X\n", tmp_data[0]); + (*kp_ic_data)->vendor_ic_ver = tmp_data[0]; + + I("VENDOR_IC_VER : %X\n", ((*kp_ic_data)->vendor_ic_ver)); +} + +static void hx83102b_read_ic_ver(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_addr[DATA_LEN_4]; + + (*kp_ic_data)->vendor_ic_ver = 0xFFFF; + /* Enable read DD */ + kp_himax_in_parse_assign_cmd(hx83102b_ic_osc_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + tmp_data[0] = 0x01; + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + tmp_data[0] = 0x00; + tmp_data[1] = 0x83; + tmp_data[2] = 0x10; + tmp_data[3] = 0x2B; + kp_himax_in_parse_assign_cmd(hx83102_ic_b9_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + /* Read DD data */ + kp_himax_in_parse_assign_cmd(hx83102_ic_fw, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + I("E8=%X\n", tmp_data[0]); + (*kp_ic_data)->vendor_ic_ver = tmp_data[0]; + + /* Disable read DD */ + kp_himax_in_parse_assign_cmd(hx83102b_ic_osc_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + tmp_data[0] = 0x00; + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + I("VENDOR_IC_VER : %X\n", ((*kp_ic_data)->vendor_ic_ver)); +} + +static void hx83102d_read_ic_ver(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_addr[DATA_LEN_4]; + + (*kp_ic_data)->vendor_ic_ver = 0xFFFF; + /* Enable read DD */ + kp_himax_in_parse_assign_cmd(hx83102d_ic_osc_pw, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + tmp_data[0] = 0xA5; + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + kp_himax_in_parse_assign_cmd(hx83102d_ic_osc_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + tmp_data[0] = 0xDD; + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + tmp_data[0] = 0x00; + tmp_data[1] = 0x83; + tmp_data[2] = 0x10; + tmp_data[3] = 0x2D; + kp_himax_in_parse_assign_cmd(hx83102_ic_b9_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + /* Read DD data */ + kp_himax_in_parse_assign_cmd(hx83102_ic_fw, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + I("E8=%X\n", tmp_data[0]); + (*kp_ic_data)->vendor_ic_ver = tmp_data[0]; + + /* Disable read DD */ + kp_himax_in_parse_assign_cmd(hx83102d_ic_osc_en, tmp_addr, sizeof(tmp_addr)); + kp_g_core_fp->fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + tmp_data[0] = 0x00; + kp_g_core_fp->fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + + I("VENDOR_IC_VER : %X\n", ((*kp_ic_data)->vendor_ic_ver)); +} + +static void hx83102_dynamic_fw_name(uint8_t ic_name) +{ + char firmware_name[64]; + + if (ic_name == 0x2a) + hx83102a_read_ic_ver(); + else if (ic_name == 0x2b) + hx83102b_read_ic_ver(); + else + hx83102d_read_ic_ver(); + + if ((*kp_i_CTPM_firmware_name) != NULL) { + kfree((*kp_i_CTPM_firmware_name)); + (*kp_i_CTPM_firmware_name) = NULL; + } + memset(firmware_name, 0x00, sizeof(firmware_name)); + + if (((*kp_ic_data)->vendor_ic_ver == 0x00) || ((*kp_ic_data)->vendor_ic_ver == 0x21)) { /* Cut 1 */ + memcpy(firmware_name, "Himax_firmware_1.bin", sizeof(char)*strlen("Himax_firmware_1.bin")); + } else if (((*kp_ic_data)->vendor_ic_ver == 0x01) || ((*kp_ic_data)->vendor_ic_ver == 0x11)) { /* Cut 2 */ + memcpy(firmware_name, "Himax_firmware_2.bin", sizeof(char)*strlen("Himax_firmware_2.bin")); + } else { /* Original */ + memcpy(firmware_name, "Himax_firmware.bin", sizeof(char)*strlen("Himax_firmware.bin")); + } + + (*kp_i_CTPM_firmware_name) = kzalloc((sizeof(char)*(strlen(firmware_name)+1)), GFP_KERNEL); + if ((*kp_i_CTPM_firmware_name) != NULL) + memcpy((*kp_i_CTPM_firmware_name), firmware_name, (sizeof(char)*(strlen(firmware_name)+1))); + I("(*kp_i_CTPM_firmware_name) : %s\n", (*kp_i_CTPM_firmware_name)); +} +#endif +#endif + +static bool hx83102e_read_event_stack(uint8_t *buf, uint8_t length) +{ + struct timespec t_start, t_end, t_delta; + int len = length; + int i2c_speed = 0; + + if ((*kp_private_ts)->debug_log_level & BIT(2)) + getnstimeofday(&t_start); + + kp_himax_bus_read((*kp_pfw_op)->addr_event_addr[0], buf, length, HIMAX_I2C_RETRY_TIMES); + + if ((*kp_private_ts)->debug_log_level & BIT(2)) { + getnstimeofday(&t_end); + 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; + (*kp_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__); + kp_himax_in_parse_assign_cmd(hx83102ab_fw_addr_sorting_mode_en, (*kp_pfw_op)->addr_sorting_mode_en, sizeof((*kp_pfw_op)->addr_sorting_mode_en)); + kp_himax_in_parse_assign_cmd(hx83102ab_fw_addr_selftest_addr_en, (*kp_pfw_op)->addr_selftest_addr_en, sizeof((*kp_pfw_op)->addr_selftest_addr_en)); +#ifdef HX_ZERO_FLASH + kp_himax_in_parse_assign_cmd(hx83102ab_data_adc_cfg_1, (*kp_pzf_op)->data_adc_cfg_1, sizeof((*kp_pzf_op)->data_adc_cfg_1)); +#endif + + if (ic_name == 0x2a) { + kp_himax_in_parse_assign_cmd(hx83102a_data_df_rx, (*kp_pdriver_op)->data_df_rx, sizeof((*kp_pdriver_op)->data_df_rx)); + kp_himax_in_parse_assign_cmd(hx83102a_data_df_tx, (*kp_pdriver_op)->data_df_tx, sizeof((*kp_pdriver_op)->data_df_tx)); + kp_himax_in_parse_assign_cmd(hx83102a_data_df_x_res, (*kp_pdriver_op)->data_df_x_res, sizeof((*kp_pdriver_op)->data_df_x_res)); + kp_himax_in_parse_assign_cmd(hx83102a_data_df_y_res, (*kp_pdriver_op)->data_df_y_res, sizeof((*kp_pdriver_op)->data_df_y_res)); + } else { + kp_himax_in_parse_assign_cmd(hx83102b_data_df_x_res, (*kp_pdriver_op)->data_df_x_res, sizeof((*kp_pdriver_op)->data_df_x_res)); + kp_himax_in_parse_assign_cmd(hx83102b_data_df_y_res, (*kp_pdriver_op)->data_df_y_res, sizeof((*kp_pdriver_op)->data_df_y_res)); + } +} + +static void himax_hx83102ab_func_re_init(void) +{ + I("%s:Entering!\n", __func__); + kp_g_core_fp->fp_chip_init = hx83102_chip_init; + kp_g_core_fp->fp_sense_off = hx83102ab_sense_off; + kp_g_core_fp->fp_set_SMWP_enable = hx83102ab_set_SMWP_enable; + kp_g_core_fp->fp_set_HSEN_enable = hx83102ab_set_HSEN_enable; + kp_g_core_fp->fp_usb_detect_set = hx83102ab_usb_detect_set; + kp_g_core_fp->fp_read_DD_status = hx83102ab_read_DD_status; + kp_g_core_fp->fp_read_FW_status = hx83102ab_read_FW_status; + kp_g_core_fp->fp_power_on_init = hx83102ab_power_on_init; + kp_g_core_fp->fp_fts_ctpm_fw_upgrade_with_sys_fs_64k = hx83102ab_fts_ctpm_fw_upgrade_with_sys_fs_64k; +#ifdef HX_ESD_RECOVERY + kp_g_core_fp->fp_esd_ic_reset = hx83102ab_esd_ic_reset; +#endif +#if defined(HX_ZERO_FLASH) + kp_g_core_fp->fp_firmware_update_0f = hx83102ab_firmware_update_0f; +#if defined(HX_0F_DEBUG) + kp_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__); + kp_himax_in_parse_assign_cmd(hx83102d_fw_addr_raw_out_sel, (*kp_pfw_op)->addr_raw_out_sel, sizeof((*kp_pfw_op)->addr_raw_out_sel)); +#if defined(HX_ZERO_FLASH) + kp_himax_in_parse_assign_cmd(hx83102d_zf_data_sram_start_addr, (*kp_pzf_op)->data_sram_start_addr, sizeof((*kp_pzf_op)->data_sram_start_addr)); + kp_himax_in_parse_assign_cmd(hx83102d_zf_data_adc_cfg_1, (*kp_pzf_op)->data_adc_cfg_1, sizeof((*kp_pzf_op)->data_adc_cfg_1)); + kp_himax_in_parse_assign_cmd(hx83102d_zf_data_adc_cfg_2, (*kp_pzf_op)->data_adc_cfg_2, sizeof((*kp_pzf_op)->data_adc_cfg_2)); + kp_himax_in_parse_assign_cmd(hx83102d_zf_data_adc_cfg_3, (*kp_pzf_op)->data_adc_cfg_3, sizeof((*kp_pzf_op)->data_adc_cfg_3)); +#endif + kp_himax_in_parse_assign_cmd(hx83102d_data_df_x_res, (*kp_pdriver_op)->data_df_x_res, sizeof((*kp_pdriver_op)->data_df_x_res)); + kp_himax_in_parse_assign_cmd(hx83102d_data_df_y_res, (*kp_pdriver_op)->data_df_y_res, sizeof((*kp_pdriver_op)->data_df_y_res)); + kp_himax_in_parse_assign_cmd(hx83102d_data_df_y_res, (*kp_pdriver_op)->data_df_y_res, sizeof((*kp_pdriver_op)->data_df_y_res)); + kp_himax_in_parse_assign_cmd(hx83102d_adr_osc_en, (*kp_pic_op)->adr_osc_en, sizeof((*kp_pic_op)->adr_osc_en)); + kp_himax_in_parse_assign_cmd(hx83102d_adr_osc_pw, (*kp_pic_op)->adr_osc_pw, sizeof((*kp_pic_op)->adr_osc_pw)); +} + +static void himax_hx83102d_func_re_init(void) +{ + I("%s:Entering!\n", __func__); + kp_g_core_fp->fp_chip_init = hx83102_chip_init; + kp_g_core_fp->fp_sense_off = hx83102d_sense_off; + kp_g_core_fp->fp_ic_id_read = hx83102d_ic_id_read; + kp_g_core_fp->fp_dd_clk_set = hx83102d_dd_clk_set; + kp_g_core_fp->fp_dd_reg_en = hx83102d_dd_reg_en; +#if defined(HX_ZERO_FLASH) + /*kp_g_core_fp->fp_firmware_update_0f = hx83102d_firmware_update_0f;*/ + kp_g_core_fp->fp_resume_ic_action = himax_hx83102d_resume_ic_action; + kp_g_core_fp->fp_suspend_ic_action = himax_hx83102d_suspend_ic_action; + kp_g_core_fp->fp_sense_on = himax_hx83102d_sense_on; + kp_g_core_fp->fp_0f_reload_to_active = himax_hx83102d_reload_to_active; +#if defined(HX_0F_DEBUG) + kp_g_core_fp->fp_firmware_read_0f = hx83102d_firmware_read_0f; +#endif +#if defined(HX_CODE_OVERLAY) + kp_g_core_fp->fp_0f_overlay = hx83102d_0f_overlay; +#endif +#ifdef HX_ESD_RECOVERY + kp_g_core_fp->fp_0f_esd_check = hx83102d_0f_esd_check; +#endif +#endif +} + +static void himax_hx83102e_reg_re_init(void) +{ + I("%s:Entering!\n", __func__); + kp_himax_in_parse_assign_cmd(hx83102e_fw_addr_raw_out_sel, (*kp_pfw_op)->addr_raw_out_sel, sizeof((*kp_pfw_op)->addr_raw_out_sel)); + kp_himax_in_parse_assign_cmd(hx83102e_data_df_rx, (*kp_pdriver_op)->data_df_rx, sizeof((*kp_pdriver_op)->data_df_rx)); + kp_himax_in_parse_assign_cmd(hx83102e_data_df_tx, (*kp_pdriver_op)->data_df_tx, sizeof((*kp_pdriver_op)->data_df_tx)); + kp_himax_in_parse_assign_cmd(hx83102e_data_df_x_res, (*kp_pdriver_op)->data_df_x_res, sizeof((*kp_pdriver_op)->data_df_x_res)); + kp_himax_in_parse_assign_cmd(hx83102e_data_df_y_res, (*kp_pdriver_op)->data_df_y_res, sizeof((*kp_pdriver_op)->data_df_y_res)); +} + +static void himax_hx83102e_func_re_init(void) +{ + I("%s:Entering!\n", __func__); + + kp_g_core_fp->fp_chip_init = hx83102e_chip_init; + kp_g_core_fp->fp_sense_off = hx83102d_sense_off; + kp_g_core_fp->fp_read_event_stack = hx83102e_read_event_stack; +} + + +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 (himax_ic_setup_external_symbols()) + return false; + +#ifdef HX_RST_PIN_FUNC + hx83102_pin_reset(); +#endif + if (kp_himax_bus_read(0x13, tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + if (hx83102_sense_off(false) == false) { + 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; + if (hx83102_register_read(tmp_addr, DATA_LEN_4, tmp_data) != 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((*kp_private_ts)->chip_name, HX_83102A_SERIES_PWON, 30); + I("%s:detect IC HX83102A successfully\n", __func__); + } else if (tmp_data[1] == 0x2b) { + strlcpy((*kp_private_ts)->chip_name, HX_83102B_SERIES_PWON, 30); + I("%s:detect IC HX83102B successfully\n", __func__); + } else if (tmp_data[1] == 0x2d) { + strlcpy((*kp_private_ts)->chip_name, HX_83102D_SERIES_PWON, 30); + I("%s:detect IC HX83102D successfully\n", __func__); + } else { + strlcpy((*kp_private_ts)->chip_name, HX_83102E_SERIES_PWON, 30); + I("%s:detect IC HX83102E successfully\n", __func__); + } + + ret = kp_himax_mcu_in_cmd_struct_init(); + if (ret < 0) { + ret_data = false; + E("%s:cmd_struct_init Fail:\n", __func__); + return ret_data; + } + + kp_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"); + + } + +#if defined(HX_AUTO_UPDATE_FW) || defined(HX_ZERO_FLASH) +#if defined(HX_EN_DYNAMIC_NAME) + hx83102_dynamic_fw_name(tmp_data[1]); +#endif +#endif + + return ret_data; +} + +DECLARE(HX_MOD_KSYM_HX83102); + +static int himax_hx83102_probe(void) +{ + I("%s:Enter\n", __func__); + himax_add_chip_dt(hx83102_chip_detect); + + return 0; +} + +static int himax_hx83102_remove(void) +{ + free_chip_dt_table(); + return 0; +} + +static int __init himax_hx83102_init(void) +{ + int ret = 0; + + I("%s\n", __func__); + ret = himax_hx83102_probe(); + return 0; +} + +static void __exit himax_hx83102_exit(void) +{ + himax_hx83102_remove(); +} + +module_init(himax_hx83102_init); +module_exit(himax_hx83102_exit); + +MODULE_DESCRIPTION("HIMAX HX83102 touch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/himax_ic_HX83102d.h b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/himax_ic_HX83102d.h new file mode 100644 index 000000000000..ceab657ecdd0 --- /dev/null +++ b/drivers/input/touchscreen/himax_v2_mmi/support_ic/himax_v2_mmi_hx83102d/himax_ic_HX83102d.h @@ -0,0 +1,65 @@ +/* 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 + +#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_df_x_res 2160 +#define hx83102a_data_df_y_res 3840 +#define hx83102b_data_df_x_res 720 +#define hx83102b_data_df_y_res 1280 + +#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_data_df_x_res 720 +#define hx83102d_data_df_y_res 1280 +#define hx83102d_adr_osc_en 0x9000009C +#define hx83102d_adr_osc_pw 0x90000280 + +#define hx83102e_fw_addr_raw_out_sel 0x100072EC +#define hx83102e_data_df_rx 48 +#define hx83102e_data_df_tx 30 +#define hx83102e_data_df_x_res 1200 +#define hx83102e_data_df_y_res 1920 + +#if defined(HX_AUTO_UPDATE_FW) || defined(HX_ZERO_FLASH) +#ifdef HX_EN_DYNAMIC_NAME +#define hx83102_ic_b9_en 0x300B9000 +#define hx83102_ic_fw 0x300E8006 + +#define hx83102b_ic_osc_en 0x900880A0 +#define hx83102d_ic_osc_en 0x9000009C +#define hx83102d_ic_osc_pw 0x90000280 +#endif +#endif + +#ifdef HX_ESD_RECOVERY + extern u8 HX_ESD_RESET_ACTIVATE; +#endif +