mcu_hi3321_watch/tjd/driver/tp/cst820/tp_drv_cst820.c
2025-05-26 20:15:20 +08:00

605 lines
16 KiB
C

/*----------------------------------------------------------------------------
* 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;
}