/*---------------------------------------------------------------------------- * Copyright (c) TJD Technologies Co., Ltd. 2024. All rights reserved. * * Description: tp_drv_ft6146.c * * Author: luziquan@ss-tjd.com * * Create: 2024-04-18 *--------------------------------------------------------------------------*/ #include "tp_drv_ft6146.h" #include "cmsis_os2.h" #include "common_def.h" #include "osal_mutex.h" #include "osal_timer.h" #include "soc_errno.h" #include "sys_config.h" #include "tcxo.h" #include "tp_port_ctrl.h" #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_tp_log_i(__VA_ARGS__) // 一般信息打印宏控制 #define static_print_warn(...) sys_tp_log_w(__VA_ARGS__) // 警告信息打印一般常开 #define static_print_error(...) sys_tp_log_e(__VA_ARGS__) // 错误信息打印一般常开 #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #endif #ifndef FT6146_I2C_ADDR #define FT6146_I2C_ADDR 0x38 #endif ft6146_drv_data g_ft6146_drv = { .chip_status = FT6146_NOT_READY, .ops_mux = {0}, .work_status = TP_WORK_INVALID, .fw_upgrade_flag = TD_TRUE, .gesture_wakeup = TD_FALSE, }; ext_errno ft6146_get_rawdata(uint8_t *ret_buf) { ext_errno ret; ret = tp_i2c_data_read(FT6146_I2C_ADDR, TP_RAWDATA, 1, ret_buf, TP_DATA_LEN); if (ret != EXT_ERR_SUCCESS) { return ret; } return ret; } ext_errno ft6146_get_chip_id(uint16_t *ret_buf) { ext_errno ret; uint8_t hw_id_high = 0; uint8_t hw_id_low = 0; ret = tp_i2c_data_read(FT6146_I2C_ADDR, TP_CHIP_ID_HIGH, 1, &hw_id_high, TP_DATA_LEN); if (ret != EXT_ERR_SUCCESS) { return ret; } ret = tp_i2c_data_read(FT6146_I2C_ADDR, TP_CHIP_ID_LOW, 1, &hw_id_low, TP_DATA_LEN); if (ret != EXT_ERR_SUCCESS) { return ret; } *ret_buf = ((uint16_t)hw_id_high << OFFSET_8_BITS) | hw_id_low; return ret; } ext_errno ft6146_get_version(uint16_t *ret_buf) { ext_errno ret; uint8_t firm_vers[TP_FIRMWARE_VERSION_LEN]; ret = tp_i2c_data_read(FT6146_I2C_ADDR, TP_FIRMWARE_VERSION, 1, firm_vers, TP_FIRMWARE_VERSION_LEN); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } *ret_buf = ((firm_vers[TP_I2C_SEND_INDEX0] & 0x0F) << OFFSET_8_BITS) | firm_vers[TP_I2C_SEND_INDEX1]; return ret; } static ext_errno ft6146_parse_touch_input(void) { uint8_t touch_input[FT6146_TOUCHINFO_LEN] = {0}; uint32_t x_axis; uint32_t y_axis; ext_errno ret = tp_i2c_data_read(FT6146_I2C_ADDR, FT6146_TP_REG_X1, 1, touch_input, FT6146_TOUCHINFO_LEN); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: touch input read error! ret = 0x%x", ret); return EXT_ERR_FAILURE; } x_axis = (uint32_t)((touch_input[FT6146_XH_OFFSET] & 0X0F) << 8) | touch_input[FT6146_XL_OFFSET]; y_axis = (uint32_t)((touch_input[FT6146_YH_OFFSET] & 0X0F) << 8) | touch_input[FT6146_YL_OFFSET]; uint8_t event_value = touch_input[FT6146_EVENT_OFFSET] & 0XC0; switch (event_value) { case PRESS_DOWN: g_ft6146_drv.touch_msg.tp_event = MC_TP_PRESS; break; case LIFT_UP: g_ft6146_drv.touch_msg.tp_event = MC_TP_RELEASE; break; case CONTACT: g_ft6146_drv.touch_msg.tp_event = MC_TP_MOVE; break; default: return EXT_ERR_FAILURE; } g_ft6146_drv.touch_msg.tp_event_info.x_axis[FT6146_POINT1_INDEX] = x_axis; g_ft6146_drv.touch_msg.tp_event_info.y_axis[FT6146_POINT1_INDEX] = y_axis; g_ft6146_drv.touch_msg.tv_usec = (uint32_t)uapi_tcxo_get_ms(); return EXT_ERR_SUCCESS; } static ext_errno ft6146_parse_input(void) { ext_errno ret = EXT_ERR_FAILURE; uint16_t reg_write; ret = ft6146_parse_touch_input(); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: parse touch input fail 0x%x", ret); return EXT_ERR_FAILURE; } return EXT_ERR_SUCCESS; } ext_errno ft6146_irq_callback(uint8_t *data_buf, uint8_t data_len) { unused(data_len); ext_errno ret; int32_t mem_ret; uint16_t reg_write; g_ft6146_drv.touch_msg.tp_event = MC_TP_INVALID; if ((g_ft6146_drv.work_status == TP_WORK_NORMAL) || (g_ft6146_drv.work_status == TP_WORK_STANDBY)) { ret = ft6146_parse_input(); if (ret != EXT_ERR_SUCCESS) { ft6146_init(); static_print_error("TOUCH: touch parse input fail, ret = 0x%x", ret); return EXT_ERR_FAILURE; } } mem_ret = memcpy_s(data_buf, sizeof(input_event_info), &(g_ft6146_drv.touch_msg), sizeof(input_event_info)); if (mem_ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: mem cpy error, ret = 0x%x", mem_ret); return EXT_ERR_FAILURE; } return EXT_ERR_SUCCESS; } static ext_errno ft6146_write_power_mode(ft6146_event_status power_mode) { ext_errno ret; uint16_t reg_write; uint8_t retry_times = 0; /* Send Sleep Cmd */ reg_write = FT6146_POWER_MODE; for (retry_times = 0; retry_times < TP_INIT_RETRY_TIMERS; retry_times++) { ret = tp_i2c_reg_write(FT6146_I2C_ADDR, FT6146_POWER_MODE, 1, power_mode); if (ret == EXT_ERR_SUCCESS) { break; } tp_delay(FT6146_GENERAL_DELAY_10); } if (ret != EXT_ERR_SUCCESS) { return ret; } tp_delay(FT6146_GENERAL_DELAY_10); return EXT_ERR_SUCCESS; } static ext_errno ft6146_set_normal_mode(void) { ext_errno ret; if (g_ft6146_drv.work_status == TP_WORK_NORMAL) { static_print_info("TOUCH: alread normal"); return EXT_ERR_SUCCESS; } if (g_ft6146_drv.work_status == TP_WORK_SLEEP || g_ft6146_drv.work_status == TP_WORK_INVALID) { tp_reset(); } ret = ft6146_write_power_mode(WORK_MODE); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } g_ft6146_drv.work_status = WORK_MODE; static_print_info("TOUCH: normal mode"); return EXT_ERR_SUCCESS; } static ext_errno ft6146_set_standby_mode(void) { ext_errno ret; if (g_ft6146_drv.work_status == TP_WORK_STANDBY) { static_print_info("TOUCH: alread standby"); return EXT_ERR_SUCCESS; } if (g_ft6146_drv.work_status == TP_WORK_SLEEP || g_ft6146_drv.work_status == TP_WORK_INVALID) { tp_reset(); } ret = ft6146_write_power_mode(MONITOR_MODE); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } g_ft6146_drv.work_status = MONITOR_MODE; static_print_info("TOUCH: low power"); return EXT_ERR_SUCCESS; } static ext_errno ft6146_set_sleep_mode(void) { ext_errno ret; if (g_ft6146_drv.work_status == SLEEP_MODE) { static_print_info("TOUCH: alread sleep"); return EXT_ERR_SUCCESS; } ret = ft6146_write_power_mode(SLEEP_MODE); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } g_ft6146_drv.work_status = SLEEP_MODE; static_print_info("TOUCH: sleep"); return EXT_ERR_SUCCESS; } ext_errno ft6146_set_power_mode(uint8_t power_mode) { ext_errno ret = EXT_ERR_SUCCESS; switch (power_mode) { case TP_WORK_NORMAL: ret = ft6146_set_normal_mode(); break; case TP_WORK_SLEEP: ret = ft6146_set_sleep_mode(); break; case TP_WORK_STANDBY: ret = ft6146_set_standby_mode(); break; default: static_print_error("TOUCH: ft6146 not support powermode 0x%x", power_mode); ret = EXT_ERR_FAILURE; break; } return ret; } static ext_errno ft6146_configuration(void) { ext_errno ret; /* Read Firmware Version */ ret = ft6146_get_version(&g_ft6146_drv.firmware_version); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } /* Read Hw ID */ ret = ft6146_get_chip_id(&g_ft6146_drv.chip_id); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } static_print_info("TOUCH: TP_FIRMWARE_VERSION[0x%x] FT6146_CHIP_ID[0x%x]", g_ft6146_drv.firmware_version, g_ft6146_drv.chip_id); return EXT_ERR_SUCCESS; } static ext_errno ft6146_resource_deinit(void) { g_ft6146_drv.work_status = TP_WORK_INVALID; g_ft6146_drv.fw_upgrade_flag = TD_FALSE; osal_mutex_destroy(&g_ft6146_drv.ops_mux); return EXT_ERR_SUCCESS; } static ext_errno ft6146_config(void) { ext_errno ret; /* Step 1 hardware reset */ tp_reset(); /* Step 2 configuration */ ret = ft6146_configuration(); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: init config fail 0x%x", ret); return EXT_ERR_FAILURE; } /* Step 4 check upgrade */ if (g_ft6146_drv.fw_upgrade_flag == TD_TRUE) { ret = fts_fwupg_auto_upgrade(); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: auto upgrade fail 0x%x", ret); return EXT_ERR_FAILURE; } } /* Record Status For Init */ g_ft6146_drv.chip_status = FT6146_READY; g_ft6146_drv.work_status = TP_WORK_NORMAL; return EXT_ERR_SUCCESS; } ext_errno ft6146_init(void) { ext_errno ret = EXT_ERR_FAILURE; ext_errno err_ret; /* create tp operation mutex */ if (g_ft6146_drv.ops_mux.mutex == NULL) { ret = osal_mutex_init(&(g_ft6146_drv.ops_mux)); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: ft6146 init create mux lock fail 0x%x", ret); return EXT_ERR_FAILURE; } } /* get tp operater mutex */ ret = osal_mutex_lock_timeout(&g_ft6146_drv.ops_mux, FT6146_OPERATER_MUTEX_WAIT_TIME); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: ft6146 init wait mux lock fail 0x%x", ret); goto init_fail; } /* tp hardware reset and init */ ret = ft6146_config(); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: ft6146 init fail 0x%x", ret); goto init_fail; } /* release tp operater mutex */ osal_mutex_unlock(&g_ft6146_drv.ops_mux); static_print_info("TOUCH: FT6146 INIT Success!"); return EXT_ERR_SUCCESS; init_fail: /* release tp operater mutex */ osal_mutex_unlock(&g_ft6146_drv.ops_mux); err_ret = ft6146_resource_deinit(); if (err_ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: delete mux lock err! ret = 0x%x", err_ret); } return ret; } ext_errno ft6146_deinit(void) { ext_errno ret = ft6146_resource_deinit(); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: ft6146 deinit fail! ret = 0x%x", ret); return ret; } return EXT_ERR_SUCCESS; } ext_errno ft6146_resume(void) { ext_errno ret; uint8_t retry_times = 0; tp_reset(); if (retry_times == TP_INIT_RETRY_TIMERS) { static_print_error("resume: overtimes %d", retry_times); goto resume_exit; } g_ft6146_drv.work_status = TP_WORK_NORMAL; #ifdef FT6146_GESTURE_WAKEUP g_ft6146_drv.gesture_wakeup = TD_FALSE; #endif return EXT_ERR_SUCCESS; resume_exit: static_print_error("TOUCH: resume failed 0x%x", ret); return EXT_ERR_FAILURE; } ext_errno ft6146_suspend(void) { ext_errno ret; ret = ft6146_set_power_mode(TP_WORK_SLEEP); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: suspend fail 0x%x", ret); return EXT_ERR_FAILURE; } return EXT_ERR_SUCCESS; } ext_errno ft6146_sleep(void) { ext_errno ret; ret = ft6146_set_power_mode(TP_WORK_SLEEP); if (ret != EXT_ERR_SUCCESS) { static_print_error("TOUCH: sleep fail 0x%x", ret); return EXT_ERR_FAILURE; } return EXT_ERR_SUCCESS; }