862 lines
26 KiB
C
Executable file
862 lines
26 KiB
C
Executable file
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Himax Android Driver Sample Code for HX83108 chipset
|
|
*
|
|
* Copyright (C) 2022 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_HX83108.h"
|
|
#include "himax_modular.h"
|
|
#include "himax_inspection.h"
|
|
|
|
static void hx83108_chip_init(void)
|
|
{
|
|
hx_s_ts->chip_cell_type = CHIP_IS_IN_CELL;
|
|
I("%s:IC cell type = %d\n", __func__,
|
|
hx_s_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;
|
|
(CFG_TABLE_FLASH_ADDR_T) = (CFG_TABLE_FLASH_ADDR);
|
|
}
|
|
|
|
struct ic_setup_collect g_hx83108_setup = {
|
|
|
|
._addr_psl = ADDR_PSL,
|
|
._addr_cs_central_state = ADDR_CS_CENTRAL_STATE,
|
|
|
|
._addr_system_reset = ADDR_SYSTEM_RESET,
|
|
._addr_ctrl_fw = ADDR_CTRL_FW,
|
|
._addr_flag_reset_event = ADDR_FLAG_RESET_EVENT,
|
|
._addr_leave_safe_mode = ADDR_LEAVE_SAFE_MODE,
|
|
._func_hsen = FUNC_HSEN,
|
|
._func_smwp = FUNC_SMWP,
|
|
._func_headphone = FUNC_HEADPHONE,
|
|
._func_usb_detect = FUNC_USB_DETECT,
|
|
._func_ap_notify_fw_sus = FUNC_AP_NOTIFY_FW_SUS,
|
|
._func_en = FUNC_EN,
|
|
._func_dis = FUNC_DIS,
|
|
|
|
._addr_program_reload_from = ADDR_PROGRAM_RELOAD_FROM,
|
|
._addr_program_reload_to = ADDR_PROGRAM_RELOAD_TO,
|
|
._addr_program_reload_page_write = ADDR_PROGRAM_RELOAD_PAGE_WRITE,
|
|
._addr_rawout_sel = HX83108_ADDR_RAWOUT_SEL,
|
|
._addr_reload_status = ADDR_RELOAD_STATUS,
|
|
._addr_reload_crc32_result = ADDR_RELOAD_CRC32_RESULT,
|
|
._addr_reload_addr_from = ADDR_RELOAD_ADDR_FROM,
|
|
._addr_reload_addr_cmd_beat = ADDR_RELOAD_ADDR_CMD_BEAT,
|
|
._data_system_reset = DATA_SYSTEM_RESET,
|
|
._data_leave_safe_mode = DATA_LEAVE_SAFE_MODE,
|
|
._data_fw_stop = DATA_FW_STOP,
|
|
._data_program_reload_start = DATA_PROGRAM_RELOAD_START, //useless
|
|
._data_program_reload_compare = DATA_PROGRAM_RELOAD_COMPARE, //useless
|
|
._data_program_reload_break = DATA_PROGRAM_RELOAD_BREAK, //useless
|
|
|
|
._addr_set_frame = ADDR_SET_FRAME,
|
|
._data_set_frame = DATA_SET_FRAME,
|
|
|
|
._para_idle_dis = PARA_IDLE_DIS,
|
|
._para_idle_en = PARA_IDLE_EN,
|
|
._addr_sorting_mode_en = ADDR_SORTING_MODE_EN,
|
|
._addr_fw_mode_status = ADDR_FW_MODE_STATUS,
|
|
._addr_fw_ver = ADDR_FW_VER,
|
|
._addr_fw_cfg = ADDR_FW_CFG,
|
|
._addr_fw_vendor = ADDR_FW_VENDOR,
|
|
._addr_cus_info = ADDR_CUS_INFO,
|
|
._addr_proj_info = ADDR_PROJ_INFO,
|
|
._addr_fw_state = ADDR_FW_STATE, //useless
|
|
._addr_fw_dbg_msg = ADDR_FW_DBG_MSG,
|
|
|
|
._data_rawdata_ready_hb = DATA_RAWDATA_READY_HB,
|
|
._data_rawdata_ready_lb = DATA_RAWDATA_READY_LB,
|
|
._addr_ahb = ADDR_AHB,
|
|
._data_ahb_dis = DATA_AHB_DIS,
|
|
._data_ahb_en = DATA_AHB_EN,
|
|
._addr_event_stack = ADDR_EVENT_STACK,
|
|
|
|
._data_handshaking_end = DATA_HANDSHAKING_END,
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
._addr_ulpm_33 = ADDR_ULPM_33,
|
|
._addr_ulpm_34 = ADDR_ULPM_34,
|
|
._data_ulpm_11 = DATA_ULPM_11,
|
|
._data_ulpm_22 = DATA_ULPM_22,
|
|
._data_ulpm_33 = DATA_ULPM_33,
|
|
._data_ulpm_aa = DATA_ULPM_AA,
|
|
#endif
|
|
._addr_ctrl_mpap_ovl = ADDR_CTRL_MPAP_OVL,
|
|
._data_ctrl_mpap_ovl_on = DATA_CTRL_MPAP_OVL_ON,
|
|
|
|
._addr_flash_spi200_trans_fmt = (ADDR_FLASH_CTRL_BASE + 0x10),
|
|
._addr_flash_spi200_trans_ctrl = (ADDR_FLASH_CTRL_BASE + 0x20),
|
|
._addr_flash_spi200_cmd = (ADDR_FLASH_CTRL_BASE + 0x24),
|
|
._addr_flash_spi200_addr = (ADDR_FLASH_CTRL_BASE + 0x28),
|
|
._addr_flash_spi200_data = (ADDR_FLASH_CTRL_BASE + 0x2c),
|
|
._addr_flash_spi200_flash_speed = (ADDR_FLASH_CTRL_BASE + 0x40),
|
|
|
|
._data_flash_spi200_txfifo_rst = DATA_FLASH_SPI200_TXFIFO_RST,
|
|
._data_flash_spi200_rxfifo_rst = DATA_FLASH_SPI200_RXFIFO_RST,
|
|
._data_flash_spi200_trans_fmt = DATA_FLASH_SPI200_TRANS_FMT,
|
|
._data_flash_spi200_trans_ctrl_1 = DATA_FLASH_SPI200_TRANS_CTRL_1,
|
|
._data_flash_spi200_trans_ctrl_2 = DATA_FLASH_SPI200_TRANS_CTRL_2,
|
|
._data_flash_spi200_trans_ctrl_3 = DATA_FLASH_SPI200_TRANS_CTRL_3,
|
|
._data_flash_spi200_trans_ctrl_4 = DATA_FLASH_SPI200_TRANS_CTRL_4,
|
|
._data_flash_spi200_trans_ctrl_5 = DATA_FLASH_SPI200_TRANS_CTRL_5,
|
|
._data_flash_spi200_trans_ctrl_6 = DATA_FLASH_SPI200_TRANS_CTRL_6,
|
|
._data_flash_spi200_trans_ctrl_7 = DATA_FLASH_SPI200_TRANS_CTRL_7,
|
|
|
|
._data_flash_spi200_cmd_1 = DATA_FLASH_SPI200_CMD_1,
|
|
._data_flash_spi200_cmd_2 = DATA_FLASH_SPI200_CMD_2,
|
|
._data_flash_spi200_cmd_3 = DATA_FLASH_SPI200_CMD_3,
|
|
._data_flash_spi200_cmd_4 = DATA_FLASH_SPI200_CMD_4,
|
|
._data_flash_spi200_cmd_5 = DATA_FLASH_SPI200_CMD_5,
|
|
._data_flash_spi200_cmd_6 = DATA_FLASH_SPI200_CMD_6,
|
|
._data_flash_spi200_cmd_7 = DATA_FLASH_SPI200_CMD_7,
|
|
._data_flash_spi200_cmd_8 = DATA_FLASH_SPI200_CMD_8,
|
|
|
|
|
|
._addr_mkey = ADDR_MKEY,
|
|
._addr_rawdata_buf = ADDR_RAWDATA_BUF,
|
|
._data_rawdata_end = DATA_RAWDATA_END,
|
|
._pwd_get_rawdata_start = PWD_GET_RAWDATA_START,
|
|
._pwd_get_rawdata_end = PWD_GET_RAWDATA_END,
|
|
|
|
._addr_chk_fw_reload = ADDR_CHK_FW_RELOAD,
|
|
._addr_chk_fw_reload2 = ADDR_CHK_FW_RELOAD2,
|
|
#if !defined(HX_ZERO_FLASH)
|
|
._data_fw_reload_dis = DATA_FW_RELOAD_DIS,
|
|
#else
|
|
._data_fw_reload_dis = DATA_ZF_FW_RELOAD_DIS,
|
|
#endif
|
|
._data_fw_reload_en = DATA_FW_RELOAD_EN,
|
|
._addr_chk_irq_edge = ADDR_CHK_IRQ_EDGE,
|
|
._addr_info_channel_num = ADDR_INFO_CHANNEL_NUM,
|
|
._addr_info_max_pt = ADDR_INFO_MAX_PT,
|
|
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
._addr_reload_to_active = ADDR_RELOAD_TO_ACTIVE,
|
|
._data_reload_to_active = DATA_RELOAD_TO_ACTIVE,
|
|
._ovl_addr_handshake = OVL_ADDR_HANDSHAKE,
|
|
._ovl_section_num = OVL_SECTION_NUM,
|
|
._ovl_gesture_request = OVL_GESTURE_REQUEST,
|
|
._ovl_gesture_reply = OVL_GESTURE_REPLY,
|
|
._ovl_border_request = OVL_BORDER_REQUEST,
|
|
._ovl_border_reply = OVL_BORDER_REPLY,
|
|
._ovl_sorting_request = OVL_SORTING_REQUEST,
|
|
._ovl_sorting_reply = OVL_SORTING_REPLY,
|
|
._ovl_fault = OVL_FAULT,
|
|
._ovl_alg_request = OVL_ALG_REQUEST,
|
|
._ovl_alg_reply = OVL_ALG_REPLY,
|
|
._ovl_alg_fault = OVL_ALG_FAULT,
|
|
#endif
|
|
|
|
/* for inspection */
|
|
._addr_normal_noise_thx = ADDR_NORMAL_NOISE_THX,
|
|
._addr_lpwug_noise_thx = ADDR_LPWUG_NOISE_THX,
|
|
._addr_noise_scale = ADDR_NOISE_SCALE,
|
|
._addr_recal_thx = ADDR_RECAL_THX,
|
|
._addr_palm_num = ADDR_PALM_NUM,
|
|
._addr_weight_sup = ADDR_WEIGHT_SUP,
|
|
._addr_normal_weight_a = ADDR_NORMAL_WEIGHT_A,
|
|
._addr_lpwug_weight_a = ADDR_LPWUG_WEIGHT_A,
|
|
._addr_weight_b = ADDR_WEIGHT_B,
|
|
._addr_max_dc = ADDR_MAX_DC,
|
|
._addr_skip_frame = ADDR_SKIP_FRAME,
|
|
._addr_neg_noise_sup = ADDR_NEG_NOISE_SUP,
|
|
._data_neg_noise = DATA_NEG_NOISE,
|
|
|
|
};
|
|
|
|
|
|
void hx83108_burst_enable(uint8_t auto_add_4_byte)
|
|
{
|
|
uint8_t tmp_data[DATA_LEN_4];
|
|
uint8_t tmp_addr[DATA_LEN_4];
|
|
|
|
/*I("%s,Entering\n", __func__);*/
|
|
hx_parse_assign_cmd(ADDR_AHB_CONTINOUS, tmp_addr, DATA_LEN_1);
|
|
hx_parse_assign_cmd(PARA_AHB_CONTINOUS, tmp_data, DATA_LEN_1);
|
|
|
|
|
|
if (himax_bus_write(tmp_addr[0], NUM_NULL, tmp_data, 1) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
hx_parse_assign_cmd(ADDR_AHB_INC4, tmp_addr, DATA_LEN_1);
|
|
hx_parse_assign_cmd(PARA_AHB_INC4, tmp_data, DATA_LEN_1);
|
|
tmp_data[0] = (tmp_data[0] | auto_add_4_byte);
|
|
if (himax_bus_write(tmp_addr[0], NUM_NULL, tmp_data, 1) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
return;
|
|
}
|
|
}
|
|
|
|
int hx83108_register_write(uint32_t addr, uint8_t *val, uint32_t len)
|
|
{
|
|
// uint8_t tmp_addr[DATA_LEN_4];
|
|
|
|
mutex_lock(&hx_s_ts->reg_lock);
|
|
|
|
|
|
if (addr == ADDR_FLASH_SPI200_DATA)
|
|
hx83108_burst_enable(0);
|
|
else if (len > DATA_LEN_4)
|
|
hx83108_burst_enable(1);
|
|
else
|
|
hx83108_burst_enable(0);
|
|
|
|
if (himax_bus_write(ADDR_AHB_ADDRESS_BYTE_0, addr, val,
|
|
len + DATA_LEN_4) < 0) {
|
|
E("%s: xfer fail!\n", __func__);
|
|
mutex_unlock(&hx_s_ts->reg_lock);
|
|
return BUS_FAIL;
|
|
}
|
|
|
|
mutex_unlock(&hx_s_ts->reg_lock);
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
static int hx83108_register_read(uint32_t addr, uint8_t *buf, uint32_t len)
|
|
{
|
|
uint8_t tmp_addr[DATA_LEN_4];
|
|
uint8_t tmp_data[DATA_LEN_4];
|
|
|
|
|
|
mutex_lock(&hx_s_ts->reg_lock);
|
|
|
|
if (addr == ADDR_FLASH_SPI200_DATA)
|
|
hx83108_burst_enable(0);
|
|
else if (len > DATA_LEN_4)
|
|
hx83108_burst_enable(1);
|
|
else
|
|
hx83108_burst_enable(0);
|
|
|
|
// hx_parse_assign_cmd(ADDR_AHB_ADDRESS_BYTE_0, tmp_addr, DATA_LEN_1);
|
|
if (himax_bus_write(ADDR_AHB_ADDRESS_BYTE_0, addr, NULL, 4) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
mutex_unlock(&hx_s_ts->reg_lock);
|
|
return BUS_FAIL;
|
|
}
|
|
|
|
hx_parse_assign_cmd(
|
|
ADDR_AHB_ACCESS_DIRECTION,
|
|
tmp_addr,
|
|
DATA_LEN_1);
|
|
hx_parse_assign_cmd(
|
|
PARA_AHB_ACCESS_DIRECTION_READ,
|
|
tmp_data,
|
|
DATA_LEN_1);
|
|
if (himax_bus_write(ADDR_AHB_ACCESS_DIRECTION, NUM_NULL,
|
|
&tmp_data[0], 1) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
mutex_unlock(&hx_s_ts->reg_lock);
|
|
return BUS_FAIL;
|
|
}
|
|
|
|
if (himax_bus_read(ADDR_AHB_RDATA_BYTE_0, buf, len) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
mutex_unlock(&hx_s_ts->reg_lock);
|
|
return BUS_FAIL;
|
|
}
|
|
|
|
mutex_unlock(&hx_s_ts->reg_lock);
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
void hx83108_system_reset(void)
|
|
{
|
|
uint8_t tmp_data[DATA_LEN_4];
|
|
|
|
#if defined(HX_TP_TRIGGER_LCM_RST)
|
|
hx_parse_assign_cmd(DATA_SYSTEM_RESET, tmp_data, DATA_LEN_4);
|
|
hx83108_register_write(ADDR_SYSTEM_RESET,
|
|
tmp_data, DATA_LEN_4);
|
|
#else
|
|
/* cmd reset */
|
|
int retry = 0;
|
|
|
|
himax_mcu_interface_on();
|
|
do {
|
|
/* reset code*/
|
|
/**
|
|
* I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27
|
|
*/
|
|
/**
|
|
* I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95
|
|
*/
|
|
tmp_data[0] = PARA_SENSE_OFF_0;
|
|
tmp_data[1] = PARA_SENSE_OFF_1;
|
|
if (himax_bus_write(ADDR_SENSE_ON_OFF_0, NUM_NULL, tmp_data,
|
|
DATA_LEN_2) < 0)
|
|
E("%s: bus access fail!\n", __func__);
|
|
|
|
usleep_range(20000, 21000);
|
|
|
|
/**
|
|
* I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x00
|
|
*/
|
|
tmp_data[0] = 0x00;
|
|
if (himax_bus_write(ADDR_SENSE_ON_OFF_0, NUM_NULL, tmp_data,
|
|
DATA_LEN_1) < 0)
|
|
E("%s: bus access fail!\n", __func__);
|
|
|
|
usleep_range(10000, 11000);
|
|
hx83108_register_read(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 bool hx83108_sense_off(bool check_en)
|
|
{
|
|
uint8_t cnt = 0;
|
|
uint8_t tmp_data[DATA_LEN_4];
|
|
uint8_t tmp_addr[DATA_LEN_4];
|
|
|
|
do {
|
|
if (cnt == 0
|
|
|| (tmp_data[0] != 0xA5
|
|
&& tmp_data[0] != 0x00
|
|
&& tmp_data[0] != 0x87)) {
|
|
hx_parse_assign_cmd(DATA_FW_STOP,
|
|
tmp_data,
|
|
DATA_LEN_4);
|
|
hx83108_register_write(ADDR_CTRL_FW,
|
|
tmp_data,
|
|
DATA_LEN_4);
|
|
}
|
|
|
|
/* check fw status */
|
|
hx83108_register_read(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;
|
|
}
|
|
|
|
usleep_range(10000, 10001);
|
|
|
|
hx83108_register_read(ADDR_CTRL_FW, 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
|
|
* I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95
|
|
*/
|
|
tmp_data[0] = PARA_SENSE_OFF_0;
|
|
tmp_data[1] = PARA_SENSE_OFF_1;
|
|
hx_parse_assign_cmd(ADDR_SENSE_ON_OFF_0, tmp_addr, DATA_LEN_1);
|
|
if (himax_bus_write(tmp_addr[0],
|
|
NUM_NULL, tmp_data, 2) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check enter_save_mode
|
|
*/
|
|
hx83108_register_read(ADDR_CS_CENTRAL_STATE,
|
|
tmp_data, DATA_LEN_4);
|
|
I("%s: Check enter_save_mode data[0]=%X\n", __func__,
|
|
tmp_data[0]);
|
|
|
|
if (tmp_data[0] == 0x0C) {
|
|
/**
|
|
* Reset TCON
|
|
*/
|
|
|
|
hx_parse_assign_cmd(DATA_CLEAR, tmp_data, DATA_LEN_4);
|
|
hx83108_register_write(ADDR_TCON_ON_RST,
|
|
tmp_data, DATA_LEN_4);
|
|
usleep_range(1000, 1001);
|
|
/**
|
|
* Reset ADC
|
|
*/
|
|
hx_parse_assign_cmd(DATA_CLEAR, tmp_data, DATA_LEN_4);
|
|
hx83108_register_write(ADDR_ADC_ON_RST,
|
|
tmp_data, DATA_LEN_4);
|
|
usleep_range(1000, 1001);
|
|
tmp_data[0] = tmp_data[0] | 0x01;
|
|
hx83108_register_write(ADDR_ADC_ON_RST,
|
|
tmp_data, DATA_LEN_4);
|
|
goto SUCCEED;
|
|
} else {
|
|
/*msleep(10);*/
|
|
#if defined(HX_RST_PIN_FUNC)
|
|
himax_mcu_pin_reset(3);
|
|
#else
|
|
hx83108_system_reset();
|
|
#endif
|
|
}
|
|
} while (cnt++ < 5);
|
|
|
|
return false;
|
|
SUCCEED:
|
|
return true;
|
|
}
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
static void hx83108_opt_hw_crc(void)
|
|
{
|
|
uint8_t data[DATA_LEN_4] = {0};
|
|
int retry_cnt = 0;
|
|
|
|
I("%s: Entering\n", __func__);
|
|
|
|
if (g_zf_opt_crc.fw_addr != 0) {
|
|
I("%s: Start opt crc\n", __func__);
|
|
|
|
do {
|
|
hx_s_core_fp._register_write(g_zf_opt_crc.start_addr,
|
|
g_zf_opt_crc.start_data, DATA_LEN_4);
|
|
usleep_range(1000, 1100);
|
|
hx_s_core_fp._register_read(g_zf_opt_crc.start_addr,
|
|
data, DATA_LEN_4);
|
|
I("%s: 0x%02X%02X%02X%02X, retry_cnt=%d\n", __func__,
|
|
data[3], data[2], data[1], data[0], retry_cnt);
|
|
retry_cnt++;
|
|
} while ((data[1] != g_zf_opt_crc.start_data[1]
|
|
|| data[0] != g_zf_opt_crc.start_data[0])
|
|
&& retry_cnt < HIMAX_REG_RETRY_TIMES);
|
|
|
|
retry_cnt = 0;
|
|
do {
|
|
|
|
hx_s_core_fp._register_write(g_zf_opt_crc.end_addr,
|
|
g_zf_opt_crc.end_data, DATA_LEN_4);
|
|
usleep_range(1000, 1100);
|
|
hx_s_core_fp._register_read(g_zf_opt_crc.end_addr,
|
|
data, DATA_LEN_4);
|
|
I("%s: 0x%02X%02X%02X%02X, retry_cnt=%d\n", __func__,
|
|
data[3], data[2], data[1], data[0], retry_cnt);
|
|
retry_cnt++;
|
|
} while ((data[1] != g_zf_opt_crc.end_data[1]
|
|
|| data[0] != g_zf_opt_crc.end_data[0])
|
|
&& retry_cnt < HIMAX_REG_RETRY_TIMES);
|
|
}
|
|
}
|
|
static void hx83108_setup_opt_hw_crc(const struct firmware *fw)
|
|
{
|
|
uint32_t tmp_p_addr;
|
|
|
|
if (g_zf_opt_crc.fw_addr != 0) {
|
|
g_zf_opt_crc.en_start_addr = true;
|
|
g_zf_opt_crc.en_end_addr = true;
|
|
g_zf_opt_crc.en_switch_addr = false;
|
|
g_zf_opt_crc.start_addr =
|
|
fw->data[g_zf_opt_crc.fw_addr + 3] << 24 |
|
|
fw->data[g_zf_opt_crc.fw_addr + 2] << 16 |
|
|
fw->data[g_zf_opt_crc.fw_addr + 1] << 8 |
|
|
fw->data[g_zf_opt_crc.fw_addr];
|
|
|
|
g_zf_opt_crc.start_data[3] = fw->data[g_zf_opt_crc.fw_addr + 7];
|
|
g_zf_opt_crc.start_data[2] = fw->data[g_zf_opt_crc.fw_addr + 6];
|
|
g_zf_opt_crc.start_data[1] = fw->data[g_zf_opt_crc.fw_addr + 5];
|
|
g_zf_opt_crc.start_data[0] = fw->data[g_zf_opt_crc.fw_addr + 4];
|
|
|
|
g_zf_opt_crc.end_addr =
|
|
fw->data[g_zf_opt_crc.fw_addr + 11] << 24 |
|
|
fw->data[g_zf_opt_crc.fw_addr + 10] << 16 |
|
|
fw->data[g_zf_opt_crc.fw_addr + 9] << 8 |
|
|
fw->data[g_zf_opt_crc.fw_addr + 8];
|
|
|
|
g_zf_opt_crc.end_data[3] = fw->data[g_zf_opt_crc.fw_addr + 15];
|
|
g_zf_opt_crc.end_data[2] = fw->data[g_zf_opt_crc.fw_addr + 14];
|
|
g_zf_opt_crc.end_data[1] = fw->data[g_zf_opt_crc.fw_addr + 13];
|
|
g_zf_opt_crc.end_data[0] = fw->data[g_zf_opt_crc.fw_addr + 12];
|
|
|
|
tmp_p_addr = g_zf_opt_crc.end_data[3] << 24
|
|
| g_zf_opt_crc.end_data[2] << 16
|
|
| g_zf_opt_crc.end_data[1] << 8
|
|
| g_zf_opt_crc.end_data[0];
|
|
tmp_p_addr = tmp_p_addr - (tmp_p_addr % 4) - 1;
|
|
|
|
g_zf_opt_crc.end_data[3] = (tmp_p_addr >> 24) & 0xFF;
|
|
g_zf_opt_crc.end_data[2] = (tmp_p_addr >> 16) & 0xFF;
|
|
g_zf_opt_crc.end_data[1] = (tmp_p_addr >> 8) & 0xFF;
|
|
g_zf_opt_crc.end_data[0] = tmp_p_addr & 0xFF;
|
|
|
|
I("%s: opt_crc start: R%08XH <= 0x%02X%02X%02X%02X\n", __func__,
|
|
g_zf_opt_crc.start_addr,
|
|
g_zf_opt_crc.start_data[3], g_zf_opt_crc.start_data[2],
|
|
g_zf_opt_crc.start_data[1], g_zf_opt_crc.start_data[0]);
|
|
|
|
I("%s: opt_crc end: R%08XH <= 0x%02X%02X%02X%02X\n", __func__,
|
|
g_zf_opt_crc.end_addr,
|
|
g_zf_opt_crc.end_data[3], g_zf_opt_crc.end_data[2],
|
|
g_zf_opt_crc.end_data[1], g_zf_opt_crc.end_data[0]);
|
|
}
|
|
}
|
|
static void hx83108_opt_crc_clear(void)
|
|
{
|
|
uint8_t data[DATA_LEN_4] = {0};
|
|
uint8_t wrt_data[DATA_LEN_4] = {0};
|
|
int retry_cnt = 0;
|
|
|
|
I("%s: Entering\n", __func__);
|
|
|
|
hx_parse_assign_cmd(hx83108_data_crc_s1, data, DATA_LEN_4);
|
|
hx_s_core_fp._register_write(hx83108_addr_crc_s1, data, DATA_LEN_4);
|
|
|
|
hx_parse_assign_cmd(hx83108_data_crc_s2, data, DATA_LEN_4);
|
|
hx_s_core_fp._register_write(hx83108_addr_crc_s2, data, DATA_LEN_4);
|
|
|
|
hx_parse_assign_cmd(hx83108_data_crc_s3, data, DATA_LEN_4);
|
|
hx_s_core_fp._register_write(hx83108_addr_crc_s3, data, DATA_LEN_4);
|
|
|
|
do {
|
|
hx_parse_assign_cmd(hx83108_data_crc_s4,
|
|
wrt_data, DATA_LEN_4);
|
|
hx_s_core_fp._register_write(hx83108_addr_crc_s4,
|
|
wrt_data, DATA_LEN_4);
|
|
|
|
usleep_range(1000, 1100);
|
|
hx_s_core_fp._register_read(hx83108_addr_crc_s4,
|
|
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[0] != 0x00
|
|
&& retry_cnt < 5);
|
|
}
|
|
static void hx83108_reload_to_active(void)
|
|
{
|
|
uint8_t data[DATA_LEN_4] = {0};
|
|
uint8_t read[DATA_LEN_4] = {0};
|
|
uint8_t retry_cnt = 0;
|
|
|
|
|
|
hx83108_opt_hw_crc();
|
|
hx83108_opt_crc_clear();
|
|
|
|
|
|
hx_parse_assign_cmd(hx_s_ic_setup._data_reload_to_active,
|
|
data, DATA_LEN_4);
|
|
do {
|
|
hx_s_core_fp._register_write(
|
|
hx_s_ic_setup._addr_reload_to_active,
|
|
data,
|
|
DATA_LEN_4);
|
|
usleep_range(1000, 1100);
|
|
hx_s_core_fp._register_read(
|
|
hx_s_ic_setup._addr_reload_to_active,
|
|
read,
|
|
DATA_LEN_4);
|
|
I("%s: read[1]=%d, read[0]=%d, retry_cnt=%d\n", __func__,
|
|
read[1], read[0], retry_cnt);
|
|
retry_cnt++;
|
|
} while ((read[1] != 0x01
|
|
|| read[0] != data[0])
|
|
&& retry_cnt < HIMAX_REG_RETRY_TIMES);
|
|
}
|
|
|
|
static void hx83108_resume_ic_action(void)
|
|
{
|
|
#if !defined(HX_RESUME_HW_RESET)
|
|
hx83108_reload_to_active();
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
static void hx83108_sense_on(uint8_t FlashMode)
|
|
{
|
|
uint8_t tmp_data[DATA_LEN_4];
|
|
uint8_t tmp_addr[DATA_LEN_4];
|
|
int retry = 0;
|
|
|
|
I("Enter %s\n", __func__);
|
|
hx_s_core_fp._interface_on();
|
|
hx_parse_assign_cmd(DATA_CLEAR, tmp_data, DATA_LEN_4);
|
|
hx_s_core_fp._register_write(ADDR_CTRL_FW, tmp_data, DATA_LEN_4);
|
|
/*msleep(20);*/
|
|
usleep_range(10000, 10001);
|
|
if (!FlashMode) {
|
|
hx_s_core_fp._ic_reset(0);
|
|
|
|
} else {
|
|
do {
|
|
hx_parse_assign_cmd(
|
|
hx_s_ic_setup._addr_flag_reset_event,
|
|
tmp_addr,
|
|
DATA_LEN_4);
|
|
hx_s_core_fp._register_read(
|
|
hx_s_ic_setup._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__);
|
|
hx_s_core_fp._ic_reset(0);
|
|
} 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;
|
|
tmp_data[1] = 0x00;
|
|
hx_parse_assign_cmd(ADDR_SENSE_ON_OFF_0,
|
|
tmp_addr,
|
|
DATA_LEN_4);
|
|
if (himax_bus_write(tmp_addr[0], NUM_NULL,
|
|
tmp_data, 2) < 0) {
|
|
E("%s: cmd=%x bus access fail!\n",
|
|
__func__,
|
|
tmp_addr[0]);
|
|
}
|
|
}
|
|
}
|
|
#if defined(HX_ZERO_FLASH)
|
|
hx83108_reload_to_active();
|
|
#endif
|
|
}
|
|
|
|
|
|
void hx83108_init(void)
|
|
{
|
|
hx_s_core_fp._interface_on = himax_mcu_interface_on;
|
|
hx_s_core_fp._wait_wip = himax_mcu_wait_wip;
|
|
hx_s_core_fp._init_psl = himax_mcu_init_psl;
|
|
#if !defined(HX_ZERO_FLASH)
|
|
hx_s_core_fp._resume_ic_action = himax_mcu_resume_ic_action;
|
|
#endif
|
|
hx_s_core_fp._suspend_ic_action = himax_mcu_suspend_ic_action;
|
|
hx_s_core_fp._power_on_init = himax_mcu_power_on_init;
|
|
|
|
hx_s_core_fp._calc_crc_by_ap = himax_mcu_calc_crc_by_ap;
|
|
hx_s_core_fp._calc_crc_by_hw = himax_mcu_calc_crc_by_hw;
|
|
hx_s_core_fp._set_reload_cmd = himax_mcu_set_reload_cmd;
|
|
hx_s_core_fp._program_reload = himax_mcu_program_reload;
|
|
#if defined(HX_ULTRA_LOW_POWER)
|
|
hx_s_core_fp._ulpm_in = himax_mcu_ulpm_in;
|
|
hx_s_core_fp._black_gest_ctrl = himax_mcu_black_gest_ctrl;
|
|
#endif
|
|
hx_s_core_fp._set_SMWP_enable = himax_mcu_set_SMWP_enable;
|
|
hx_s_core_fp._set_HSEN_enable = himax_mcu_set_HSEN_enable;
|
|
hx_s_core_fp._set_headphone_en = himax_mcu_set_headphone_en;
|
|
hx_s_core_fp._usb_detect_set = himax_mcu_usb_detect_set;
|
|
hx_s_core_fp._diag_register_set = himax_mcu_diag_register_set;
|
|
// hx_s_core_fp._chip_self_test = himax_mcu_chip_self_test;
|
|
hx_s_core_fp._idle_mode = himax_mcu_idle_mode;
|
|
#if !defined(HX_ZERO_FLASH)
|
|
hx_s_core_fp._reload_disable = himax_mcu_reload_disable;
|
|
#endif
|
|
hx_s_core_fp._read_ic_trigger_type = himax_mcu_read_ic_trigger_type;
|
|
hx_s_core_fp._read_i2c_status = himax_mcu_read_i2c_status;
|
|
hx_s_core_fp._read_FW_ver = himax_mcu_read_FW_ver;
|
|
hx_s_core_fp._show_FW_ver = himax_mcu_show_FW_ver;
|
|
hx_s_core_fp._read_event_stack = himax_mcu_read_event_stack;
|
|
hx_s_core_fp._return_event_stack = himax_mcu_return_event_stack;
|
|
hx_s_core_fp._calculateChecksum = himax_mcu_calculateChecksum;
|
|
hx_s_core_fp._read_FW_status = himax_mcu_read_FW_status;
|
|
hx_s_core_fp._irq_switch = himax_mcu_irq_switch;
|
|
hx_s_core_fp._assign_sorting_mode = himax_mcu_assign_sorting_mode;
|
|
hx_s_core_fp._check_sorting_mode = himax_mcu_check_sorting_mode;
|
|
hx_s_core_fp._ap_notify_fw_sus = hx_ap_notify_fw_sus;
|
|
|
|
hx_s_core_fp._chip_erase = himax_mcu_chip_erase;
|
|
hx_s_core_fp._block_erase = himax_mcu_block_erase;
|
|
hx_s_core_fp._sector_erase = himax_mcu_sector_erase;
|
|
hx_s_core_fp._flash_programming = himax_mcu_flash_programming;
|
|
hx_s_core_fp._flash_page_write = himax_mcu_flash_page_write;
|
|
hx_s_core_fp._fts_ctpm_fw_upgrade_with_sys_fs =
|
|
himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs;
|
|
hx_s_core_fp._flash_dump_func = himax_mcu_flash_dump_func;
|
|
hx_s_core_fp._flash_lastdata_check = himax_mcu_flash_lastdata_check;
|
|
hx_s_core_fp._bin_desc_data_get = hx_bin_desc_data_get;
|
|
hx_s_core_fp._bin_desc_get = hx_mcu_bin_desc_get;
|
|
hx_s_core_fp._diff_overlay_flash = hx_mcu_diff_overlay_flash;
|
|
|
|
hx_s_core_fp._get_DSRAM_data = himax_mcu_get_DSRAM_data;
|
|
|
|
#if defined(HX_RST_PIN_FUNC)
|
|
hx_s_core_fp._pin_reset = himax_mcu_pin_reset;
|
|
#endif
|
|
hx_s_core_fp._system_reset = hx83108_system_reset;
|
|
hx_s_core_fp._leave_safe_mode = himax_mcu_leave_safe_mode;
|
|
hx_s_core_fp._ic_reset = himax_mcu_ic_reset;
|
|
hx_s_core_fp._tp_info_check = himax_mcu_tp_info_check;
|
|
hx_s_core_fp._touch_information = himax_mcu_touch_information;
|
|
hx_s_core_fp._calc_touch_data_size = himax_mcu_calcTouchDataSize;
|
|
hx_s_core_fp._get_touch_data_size = himax_mcu_get_touch_data_size;
|
|
hx_s_core_fp._hand_shaking = himax_mcu_hand_shaking;
|
|
hx_s_core_fp._determin_diag_rawdata = himax_mcu_determin_diag_rawdata;
|
|
hx_s_core_fp._determin_diag_storage = himax_mcu_determin_diag_storage;
|
|
hx_s_core_fp._cal_data_len = himax_mcu_cal_data_len;
|
|
hx_s_core_fp._diag_check_sum = himax_mcu_diag_check_sum;
|
|
hx_s_core_fp._diag_parse_raw_data = himax_mcu_diag_parse_raw_data;
|
|
#if defined(HX_EXCP_RECOVERY)
|
|
hx_s_core_fp._ic_excp_recovery = himax_mcu_ic_excp_recovery;
|
|
hx_s_core_fp._excp_ic_reset = himax_mcu_excp_ic_reset;
|
|
#endif
|
|
|
|
hx_s_core_fp._resend_cmd_func = himax_mcu_resend_cmd_func;
|
|
|
|
#if defined(HX_TP_PROC_GUEST_INFO)
|
|
hx_s_core_fp.guest_info_get_status = himax_guest_info_get_status;
|
|
hx_s_core_fp.read_guest_info = hx_read_guest_info;
|
|
#endif
|
|
hx_s_core_fp._turn_on_mp_func = hx_turn_on_mp_func;
|
|
#if defined(HX_ZERO_FLASH)
|
|
hx_s_core_fp._reload_disable = hx_dis_rload_0f;
|
|
hx_s_core_fp._clean_sram_0f = himax_mcu_clean_sram_0f;
|
|
hx_s_core_fp._write_sram_0f = himax_mcu_write_sram_0f;
|
|
hx_s_core_fp._write_sram_0f_crc = himax_sram_write_crc_check;
|
|
hx_s_core_fp._firmware_update_0f = himax_mcu_firmware_update_0f;
|
|
hx_s_core_fp._0f_op_file_dirly = hx_0f_op_file_dirly;
|
|
hx_s_core_fp._0f_excp_check = himax_mcu_0f_excp_check;
|
|
#if defined(HX_0F_DEBUG)
|
|
hx_s_core_fp._read_sram_0f = himax_mcu_read_sram_0f;
|
|
hx_s_core_fp._read_all_sram = himax_mcu_read_all_sram;
|
|
#endif
|
|
|
|
#endif
|
|
hx_s_core_fp._get_noise_base = himax_get_noise_base;
|
|
hx_s_core_fp._neg_noise_sup = himax_neg_noise_sup;
|
|
hx_s_core_fp._get_noise_weight_test = himax_get_noise_weight_test;
|
|
hx_s_core_fp._get_palm_num = himax_get_palm_num;
|
|
|
|
hx_s_core_fp._suspend_proc = himax_suspend_proc;
|
|
hx_s_core_fp._resume_proc = himax_resume_proc;
|
|
|
|
hx_s_core_fp._burst_enable = hx83108_burst_enable;
|
|
hx_s_core_fp._register_read = hx83108_register_read;
|
|
hx_s_core_fp._register_write = hx83108_register_write;
|
|
|
|
hx_s_core_fp._sense_off = hx83108_sense_off;
|
|
hx_s_core_fp._sense_on = hx83108_sense_on;
|
|
hx_s_core_fp._chip_init = hx83108_chip_init;
|
|
|
|
#if defined(HX_ZERO_FLASH)
|
|
hx_s_core_fp._resume_ic_action = hx83108_resume_ic_action;
|
|
hx_s_core_fp._0f_reload_to_active = hx83108_reload_to_active;
|
|
hx_s_core_fp._en_hw_crc = NULL;
|
|
hx_s_core_fp._setup_opt_hw_crc = hx83108_setup_opt_hw_crc;
|
|
hx_s_core_fp._opt_crc_clear = hx83108_opt_crc_clear;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* init end*/
|
|
/* CORE_INIT */
|
|
|
|
|
|
static bool hx83108_chip_detect(void)
|
|
{
|
|
uint8_t tmp_data[DATA_LEN_4];
|
|
bool ret = false;
|
|
int i = 0;
|
|
|
|
if (himax_bus_read(ADDR_AHB_CONTINOUS, tmp_data, 1) < 0) {
|
|
E("%s: bus access fail!\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
if (hx83108_sense_off(false) == false) {
|
|
ret = false;
|
|
E("%s:_sense_off Fail:\n", __func__);
|
|
return ret;
|
|
}
|
|
for (i = 0; i < 5; i++) {
|
|
ret = hx83108_register_read(HX83108_REG_ICID,
|
|
tmp_data, DATA_LEN_4);
|
|
|
|
if (ret != 0) {
|
|
ret = false;
|
|
E("%s:_register_read Fail:\n", __func__);
|
|
return ret;
|
|
}
|
|
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] == 0x8a ||
|
|
tmp_data[1] == 0x8b ||
|
|
tmp_data[1] == 0x8c))) {
|
|
strlcpy(hx_s_ts->chip_name,
|
|
HX_83108_SERIES_PWON, 30);
|
|
hx_s_ic_data->ic_adc_num =
|
|
HX83108_DATA_ADC_NUM;
|
|
hx_s_ic_data->isram_sz =
|
|
HX83108_ISRAM_SZ;
|
|
hx_s_ic_data->dsram_sz =
|
|
HX83108_DSRAM_SZ;
|
|
hx_s_ic_data->flash_size =
|
|
HX83108_FLASH_SIZE;
|
|
|
|
hx_s_ic_data->dbg_reg_ary[0] = ADDR_FW_DBG_MSG;
|
|
hx_s_ic_data->dbg_reg_ary[1] = ADDR_CHK_FW_STATUS;
|
|
hx_s_ic_data->dbg_reg_ary[2] = ADDR_CHK_DD_STATUS;
|
|
hx_s_ic_data->dbg_reg_ary[3] = ADDR_FLAG_RESET_EVENT;
|
|
#if defined(HX_ZERO_FLASH)
|
|
g_zf_opt_crc.fw_addr = 0x15400;
|
|
g_zf_opt_crc.en_opt_hw_crc = OPT_CRC_RANGE;
|
|
g_zf_opt_crc.en_crc_clear = true;
|
|
#endif
|
|
hx83108_init();
|
|
hx_s_ic_setup = g_hx83108_setup;
|
|
|
|
|
|
I("%s:IC name = %s\n", __func__,
|
|
hx_s_ts->chip_name);
|
|
|
|
I("Himax IC package %x%x%x in\n", tmp_data[3],
|
|
tmp_data[2], tmp_data[1]);
|
|
ret = true;
|
|
goto FINAL;
|
|
} else {
|
|
ret = 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");
|
|
}
|
|
}
|
|
FINAL:
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool _hx83108_init(void)
|
|
{
|
|
bool ret = false;
|
|
|
|
I("%s\n", __func__);
|
|
ret = hx83108_chip_detect();
|
|
return ret;
|
|
}
|
|
|
|
|