/*---------------------------------------------------------------------------- * Copyright (c) TJD Technologies Co., Ltd. 2024. All rights reserved. * * Description: tp_drv_cst820.c * * Author: luziquan@ss-tjd.com * * Create: 2024-04-18 *--------------------------------------------------------------------------*/ #include "tp_drv_cst820.h" #include "cmsis_os2.h" #include "common_def.h" #include "osal_mutex.h" #include "soc_errno.h" #include "sys_config.h" #include "tcxo.h" #include "tp_port_ctrl.h" #include "capacitive_hynitron_CST820_update.h" #include "hal_gpio.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 typedef struct { uint16_t chip_id; uint16_t firmware_version; osal_mutex ops_mux; bool fw_upgrade_flag; bool gesture_wakeup; uint8_t work_status; input_event_info touch_msg; uint32_t tp_event; } cst820_drv_data; cst820_drv_data g_cst820_drv = { .ops_mux = {0}, .work_status = TP_WORK_INVALID, .fw_upgrade_flag = TD_TRUE, .gesture_wakeup = TD_FALSE, }; ext_errno cst820_get_rawdata(uint8_t *ret_buf) { ext_errno ret; uint8_t rawdata = 0; // ret = tp_i2c_data_read(CST820_I2C_ADDR, TP_RAWDATA, &rawdata, 1); // if (ret != EXT_ERR_SUCCESS) { // static_print_error("get cst820 rawdata read error! ret = 0x%x", ret); // return ret; // } *ret_buf = rawdata; return ret; } ext_errno cst820_get_chip_id(uint8_t *ret_buf) { ext_errno ret; ret = tp_i2c_data_read(CST820_I2C_ADDR, REG_CST820_CHIPID, 1, ret_buf, 1); if (ret != EXT_ERR_SUCCESS) { static_print_error("get cst820 chip id read error! ret = 0x%x", ret); return ret; } return ret; } ext_errno cst820_get_version(uint8_t *ret_buf) { ext_errno ret; ret = tp_i2c_data_read(CST820_I2C_ADDR, REG_CST820_FIRMWAREVERSION, 1, ret_buf, 1); if (ret != EXT_ERR_SUCCESS) { static_print_error("get cst820 firmware version read error! ret = 0x%x", ret); return EXT_ERR_FAILURE; } return ret; } void cst820_set_gesture_wakeup_enable(bool enable) { static_print_info("cst820 gesture wakeup enable: %d", enable); g_cst820_drv.gesture_wakeup = enable; } static void mdelay(uint32_t ms) { // uapi_tcxo_delay_ms(ms); osDelay(ms); } static void cst8xxT_rst(void) { uapi_gpio_set_val(TP_RESET_GPIO, GPIO_LEVEL_LOW); mdelay(10); uapi_gpio_set_val(TP_RESET_GPIO, GPIO_LEVEL_HIGH); } static int cst8xxT_enter_boot(void) { ext_errno ret; uint8_t boot_flag = 0; ret = tp_i2c_reg_write(CST820_BOOT_I2C_ADDR, 0xA001, 2, 0xAB); if (ret != EXT_ERR_SUCCESS) { static_print_error("enter boot write %x failed, ret = 0x%x", 0xA001, ret); return ret; } ret = tp_i2c_data_read(CST820_BOOT_I2C_ADDR, 0xA003, 2, &boot_flag, 1); if (ret != EXT_ERR_SUCCESS) { static_print_error("enter boot write %x failed, ret = 0x%x", 0xA003, ret); return ret; } if (boot_flag != 0xC1) { static_print_error("boot flag verify error 0x%x", boot_flag); return ret; } return EXT_ERR_SUCCESS; } static uint32_t cst8xxT_read_checksum(void) { uint32_t ret = EXT_ERR_SUCCESS; uint8_t i2c_buf[4] = {0}; uint32_t value = 0; int chip_checksum_ok = EXT_ERR_FAILURE; // firmware checksum ret = tp_i2c_reg_write(CST820_BOOT_I2C_ADDR, 0xA003, 2, 0); if (ret != EXT_ERR_SUCCESS) { static_print_error("read checksum failed"); return value; } mdelay(100); for (uint8_t i = 0; i < 10; i++) { mdelay(10); ret = tp_i2c_data_read(CST820_BOOT_I2C_ADDR, 0xA000, 2, i2c_buf, 1); if (ret != EXT_ERR_SUCCESS) { static_print_info("CST820_BOOT_I2C_ADDR 0xA000 read error"); continue; } if (i2c_buf[0] == 1) { chip_checksum_ok = EXT_ERR_SUCCESS; break; } else if (i2c_buf[0] == 2) { chip_checksum_ok = EXT_ERR_FAILURE; continue; } } if (chip_checksum_ok == EXT_ERR_FAILURE) { static_print_info("need update fw!!!"); } else { ret = tp_i2c_data_read(CST820_BOOT_I2C_ADDR, 0xA008, 2, i2c_buf, 2); if (ret != EXT_ERR_SUCCESS) { return value; } value = i2c_buf[0]; value |= (uint16_t)(i2c_buf[1]) << 8; } return value; } static int cst8xxT_updata_tpinfo(void) { uint8_t buf[8]; int ret = 0; ret = tp_i2c_data_read(CST820_I2C_ADDR, 0xA7, 1, buf, 4); if (ret != EXT_ERR_SUCCESS) { static_print_error("cst8xxT_updata_tpinfo failed"); return ret; } static_print_info("IC_info fw_project_id:%04x ictype:%04x fw_ver:%x", buf[1], buf[0], buf[2]); return TRUE; } static int write_code(uint8_t *bin_addr, uint8_t retry) { uint32_t ret = EXT_ERR_SUCCESS; uint8_t i2c_buf[512 + 2]; bin_addr += 6; for (uint16_t i = 0; i < CST8xxT_BIN_SIZE; i += 512) { i2c_buf[0] = 0xA0; i2c_buf[1] = 0x14; i2c_buf[2] = i; i2c_buf[3] = i >> 8; ret = tp_i2c_package_write(CST820_BOOT_I2C_ADDR, i2c_buf, 4); if (ret != EXT_ERR_SUCCESS) { static_print_error("write code failed 1"); break; } i2c_buf[0] = 0xA0; i2c_buf[1] = 0x18; memcpy(i2c_buf + 2, bin_addr + i, 512); ret = tp_i2c_package_write(CST820_BOOT_I2C_ADDR, i2c_buf, 514); if (ret != EXT_ERR_SUCCESS) { static_print_error("write code failed 2"); break; } ret = tp_i2c_reg_write(CST820_BOOT_I2C_ADDR, 0xA004, 2, 0xEE); if (ret != EXT_ERR_SUCCESS) { static_print_error("write code failed 3"); break; } tp_delay(100 * retry); for (uint16_t t = 0;; t++) { if (t >= 50) { return EXT_ERR_FAILURE; } tp_delay(5); ret = tp_i2c_data_read(CST820_BOOT_I2C_ADDR, 0xA005, 2, i2c_buf, 1); if (ret != EXT_ERR_SUCCESS) { continue; } if (i2c_buf[0] != 0x55) { continue; } break; } } return ret; } static int cst8xxT_updata_fw(uint8_t *bin_addr, uint16_t len) { int ok_copy = EXT_ERR_SUCCESS; uint32_t ret = EXT_ERR_SUCCESS; uint8_t i2c_buf[4]; uint32_t fw_checksum = U8TO16(bin_addr[5], bin_addr[4]); static_print_info("fw_checksum = 0x%x", fw_checksum); for (int retry = 0; retry < 3; retry++) { cst8xxT_rst(); mdelay(5 + 2 * retry); ret = cst8xxT_enter_boot(); if (ret != EXT_ERR_SUCCESS) { static_print_error("enter boot fail!"); continue; } ret = write_code(bin_addr, retry); if (ret != EXT_ERR_SUCCESS) { static_print_error("write code fail!"); continue; } uint32_t ic_fw_checksum = cst8xxT_read_checksum(); static_print_info("ic_fw_checksum = 0x%x", ic_fw_checksum); if (fw_checksum != ic_fw_checksum) { static_print_error("checksum error! fw_checksum = 0x%x, ic_fw_checksum = 0x%x", fw_checksum, ic_fw_checksum); continue; } break; } // hyn_boot_wr_reg(0xA006EE, 3, i2c_buf, 0); // tp_i2c_reg_write(CST820_BOOT_I2C_ADDR, 0xA006, 2, 0xEE); cst8xxT_rst(); tp_delay(10); return ok_copy; } static ext_errno cst820_parse_touch_input(void) { uint8_t touch_input[10] = {0}; uint16_t x_axis; uint16_t y_axis; uint8_t finger_num; uint8_t gesture_id; ext_errno ret; uint32_t cur_time = (uint32_t)uapi_tcxo_get_ms(); static uint32_t last_time = 0; ret = tp_i2c_data_read(CST820_I2C_ADDR, 0x00, 1, touch_input, 7); if (ret != EXT_ERR_SUCCESS) { static_print_error("touch input read error! ret = 0x%x", ret); return EXT_ERR_FAILURE; } gesture_id = touch_input[1]; finger_num = touch_input[2]; if (last_time != 0 && cur_time - last_time < 100) { // static_print_info("touch input time interval < 100ms"); return EXT_WAKEUP_THRESHOLD; } if (g_cst820_drv.gesture_wakeup && gesture_id == 0xAA) { last_time = cur_time; g_cst820_drv.touch_msg.tp_event = MC_TP_COVER; return EXT_ERR_SUCCESS; } last_time = 0; x_axis = ((uint16_t)(touch_input[3] & 0X0F) << 8) + (uint16_t)touch_input[4]; y_axis = ((uint16_t)(touch_input[5] & 0X0F) << 8) + (uint16_t)touch_input[6]; uint8_t event_value = (touch_input[3] & 0xC0) >> 6; // 提取touch_input[3]的第7和第6位 // static_print_info("gesture_wakeup = %d, x_axis = %d, y_axis = %d, GestureID %d, event_value %d", // g_cst820_drv.gesture_wakeup, x_axis, y_axis, gesture_id, event_value); switch (event_value) { case CST820_PRESS_DOWN: g_cst820_drv.touch_msg.tp_event = MC_TP_PRESS; break; case CST820_LIFT_UP: g_cst820_drv.touch_msg.tp_event = MC_TP_RELEASE; break; case CST820_CONTACT: g_cst820_drv.touch_msg.tp_event = MC_TP_MOVE; break; default: return EXT_ERR_FAILURE; } g_cst820_drv.touch_msg.tp_event_info.x_axis[0] = x_axis; g_cst820_drv.touch_msg.tp_event_info.y_axis[0] = y_axis; g_cst820_drv.touch_msg.tv_usec = (uint32_t)uapi_tcxo_get_ms(); return EXT_ERR_SUCCESS; } ext_errno cst820_irq_callback(uint8_t *data_buf, uint8_t data_len) { unused(data_len); ext_errno ret; int32_t mem_ret; g_cst820_drv.touch_msg.tp_event = MC_TP_INVALID; if ((g_cst820_drv.work_status == TP_WORK_NORMAL) || (g_cst820_drv.work_status == TP_WORK_STANDBY)) { ret = cst820_parse_touch_input(); if (ret != EXT_ERR_SUCCESS && ret != EXT_WAKEUP_THRESHOLD) { cst820_init(); static_print_error("touch parse input fail, ret = 0x%x", ret); return EXT_ERR_FAILURE; } } mem_ret = memcpy_s(data_buf, sizeof(input_event_info), &(g_cst820_drv.touch_msg), sizeof(input_event_info)); if (mem_ret != EXT_ERR_SUCCESS) { static_print_error("mem cpy error, ret = 0x%x", mem_ret); return EXT_ERR_FAILURE; } return EXT_ERR_SUCCESS; } static int cst8xxT_set_workmode(uint8_t mode) { ext_errno ret; uint8_t buf = 0; if (tp_i2c_data_read(CST820_I2C_ADDR, 0x00, 1, &buf, 1) != EXT_ERR_SUCCESS) { // check_lp mode cst8xxT_rst(); mdelay(80); } switch (mode) { case NOMAL_MODE: break; case GESTURE_MODE: /* 支持手势唤醒 */ ret = tp_i2c_reg_write(CST820_I2C_ADDR, 0xE5, 1, 0x01); if (ret != EXT_ERR_SUCCESS) { static_print_error("set gesture ret = 0x%x", ret); return ret; } break; case LP_MODE: break; case DIFF_MODE: case RAWDATA_MODE: ret = tp_i2c_reg_write(CST820_I2C_ADDR, 0xFE, 1, 0xF8); if (ret != EXT_ERR_SUCCESS) { static_print_error("set report ret = 0x%x", ret); return ret; } break; case FAC_TEST_MODE: break; case DEEPSLEEP: /* 休眠,无触摸唤醒 */ ret = tp_i2c_reg_write(CST820_I2C_ADDR, 0xE5, 1, 0x03); if (ret != EXT_ERR_SUCCESS) { static_print_error("set deepsleep ret = 0x%x", ret); return ret; } break; default: break; } return 0; } ext_errno cst820_set_power_mode(uint8_t power_mode) { ext_errno ret = EXT_ERR_SUCCESS; switch (power_mode) { case TP_WORK_NORMAL: break; case TP_WORK_SLEEP: return cst8xxT_set_workmode(DEEPSLEEP); break; case TP_WORK_STANDBY: break; default: static_print_error("cst820 not support powermode 0x%x", power_mode); ret = EXT_ERR_FAILURE; break; } return ret; } static ext_errno cst820_configuration(void) { ext_errno ret; /* Read Hw ID */ ret = cst820_get_chip_id(&g_cst820_drv.chip_id); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } /* Read Firmware Version */ ret = cst820_get_version(&g_cst820_drv.firmware_version); if (ret != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } static_print_info("TP_FIRMWARE_VERSION[0x%x] CST820_CHIP_ID[0x%x]", g_cst820_drv.firmware_version, g_cst820_drv.chip_id); /* 设置为报点模式 */ // ret = tp_i2c_reg_write(CST820_I2C_ADDR, 0xFA, 0x11); // if (ret != EXT_ERR_SUCCESS) { // static_print_error("set report ret = 0x%x", ret); // return ret; // } /* 设置为报点+手势模式 */ // ret = tp_i2c_reg_write(CST820_I2C_ADDR, 0xFA, 0x71); // if (ret != EXT_ERR_SUCCESS) { // static_print_error("set report ret = 0x%x", ret); // return ret; // } return EXT_ERR_SUCCESS; } static ext_errno cst820_resource_deinit(void) { g_cst820_drv.work_status = TP_WORK_INVALID; g_cst820_drv.fw_upgrade_flag = TD_FALSE; osal_mutex_destroy(&g_cst820_drv.ops_mux); return EXT_ERR_SUCCESS; } static ext_errno cst820_config(void) { ext_errno ret; /* Step 1 hardware reset */ cst8xxT_rst(); mdelay(80); static_print_info("cst820 config start, size = %d", sizeof(app_bin)); ret = cst8xxT_updata_fw(app_bin, sizeof(app_bin)); if (ret != EXT_ERR_SUCCESS) { static_print_error("cst820 cst8xxT_updata_fw 0x%x", ret); return ret; } cst8xxT_rst(); mdelay(80); cst8xxT_updata_tpinfo(); /* Step 2 configuration */ ret = cst820_configuration(); if (ret != EXT_ERR_SUCCESS) { static_print_error("init config fail 0x%x", ret); return ret; } /* Record Status For Init */ g_cst820_drv.work_status = TP_WORK_NORMAL; return EXT_ERR_SUCCESS; } ext_errno cst820_init(void) { ext_errno ret = EXT_ERR_FAILURE; ext_errno err_ret; /* create tp operation mutex */ if (g_cst820_drv.ops_mux.mutex == NULL) { ret = osal_mutex_init(&(g_cst820_drv.ops_mux)); if (ret != EXT_ERR_SUCCESS) { static_print_error("cst820 init create mux lock fail 0x%x", ret); return EXT_ERR_FAILURE; } } /* get tp operater mutex */ ret = osal_mutex_lock_timeout(&g_cst820_drv.ops_mux, 3000); if (ret != EXT_ERR_SUCCESS) { static_print_error("cst820 init wait mux lock fail 0x%x", ret); goto init_fail; } /* tp hardware reset and init */ ret = cst820_config(); if (ret != EXT_ERR_SUCCESS) { static_print_error("cst820 init fail 0x%x", ret); goto init_fail; } /* release tp operater mutex */ osal_mutex_unlock(&g_cst820_drv.ops_mux); static_print_info("cst820 init success!"); return EXT_ERR_SUCCESS; init_fail: /* release tp operater mutex */ osal_mutex_unlock(&g_cst820_drv.ops_mux); err_ret = cst820_resource_deinit(); if (err_ret != EXT_ERR_SUCCESS) { static_print_error("delete mux lock err! ret = 0x%x", err_ret); } return ret; } ext_errno cst820_deinit(void) { ext_errno ret = cst820_resource_deinit(); if (ret != EXT_ERR_SUCCESS) { static_print_error(" cst820 deinit fail! ret = 0x%x", ret); return ret; } return EXT_ERR_SUCCESS; } ext_errno cst820_resume(void) { ext_errno ret; cst8xxT_rst(); mdelay(50); g_cst820_drv.work_status = TP_WORK_NORMAL; return EXT_ERR_SUCCESS; } ext_errno cst820_suspend(void) { ext_errno ret; ret = cst820_set_power_mode(TP_WORK_SLEEP); if (ret != EXT_ERR_SUCCESS) { static_print_error("suspend fail 0x%x", ret); return EXT_ERR_FAILURE; } static_print_info("suspend success"); return EXT_ERR_SUCCESS; } ext_errno cst820_sleep(void) { ext_errno ret; ret = cst820_set_power_mode(TP_WORK_SLEEP); if (ret != EXT_ERR_SUCCESS) { static_print_error("sleep fail 0x%x", ret); return EXT_ERR_FAILURE; } static_print_info("sleep success"); return EXT_ERR_SUCCESS; }