Files
2026-01-12 18:46:01 +08:00

366 lines
11 KiB
C

/**
* @file focaltech.c
* @focaltech touch ic driver file.
*
* @Copyright (c) 2022 Semidrive Semiconductor.
* @All rights reserved.
*
**/
#include <FreeRTOS.h>
#include <debug.h>
#include <task.h>
#include "event_groups.h"
#include <sdrv_gpio.h>
#include "focaltech.h"
#define FTS_INCELL 0x1
#define FTS_CHIP_TYPE_MAPPING {{0x12, 0x72, 0x51, 0x72, 0x51, 0x72, 0xA1, 0x00, 0x00}}
#define FTS_ONE_TCH_LEN 6
#define FTS_TOUCH_X_H_POS 3
#define FTS_TOUCH_X_L_POS 4
#define FTS_TOUCH_Y_H_POS 5
#define FTS_TOUCH_Y_L_POS 6
#define FTS_TOUCH_POINT_NUM 2
#define FTS_TOUCH_EVENT_POS 3
#define FTS_TOUCH_ID_POS 5
/*register address*/
#define FTS_REG_INT_CNT 0x8F
#define FTS_REG_FLOW_WORK_CNT 0x91
#define FTS_REG_WORKMODE 0x00
#define FTS_REG_WORKMODE_FACTORY_VALUE 0x40
#define FTS_REG_WORKMODE_WORK_VALUE 0x00
#define FTS_REG_ESDCHECK_DISABLE 0x8D
#define FTS_REG_CHIP_ID 0xA3
#define FTS_REG_CHIP_ID2 0x9F
#define FTS_REG_POWER_MODE 0xA5
#define FTS_REG_POWER_MODE_SLEEP 0x03
#define FTS_REG_FW_VER 0xA6
#define FTS_REG_VENDOR_ID 0xA8
#define FTS_REG_LCD_BUSY_NUM 0xAB
#define FTS_REG_FACE_DEC_MODE_EN 0xB0
#define FTS_REG_FACTORY_MODE_DETACH_FLAG 0xB4
#define FTS_REG_FACE_DEC_MODE_STATUS 0x01
#define FTS_REG_IDE_PARA_VER_ID 0xB5
#define FTS_REG_IDE_PARA_STATUS 0xB6
#define FTS_REG_GLOVE_MODE_EN 0xC0
#define FTS_REG_COVER_MODE_EN 0xC1
#define FTS_REG_CHARGER_MODE_EN 0x8B
#define FTS_REG_GESTURE_EN 0xD0
#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3
#define FTS_REG_MODULE_ID 0xE3
#define FTS_REG_LIC_VER 0xE4
#define FTS_REG_ESD_SATURATE 0xED
struct ft_chip_t {
uint32_t type;
uint8_t chip_idh;
uint8_t chip_idl;
uint8_t rom_idh;
uint8_t rom_idl;
uint8_t pb_idh;
uint8_t pb_idl;
uint8_t bl_idh;
uint8_t bl_idl;
};
struct fts_data {
struct ft_chip_t ids;
touch_dev_t *ts_dev;
EventGroupHandle_t ts_event;
} g_fts;
int fts_read(struct fts_data *fts, uint8_t *cmd, uint32_t cmdlen,
uint8_t *data, uint8_t datalen)
{
int ret = 0;
sdrv_i2cdrv_bus_stat_t bus_stat;
sdrv_i2cdrv_trans_stat_t trans_stat;
sdrv_i2c_t *ctrl = fts->ts_dev->i2c_ctrl;
int addr = fts->ts_dev->i2c_addr;
/* get bus stat, if busy can not use */
bus_stat = sdrv_i2c_get_bus_stat(ctrl);
if (bus_stat == SDRV_I2CDRV_BUS_BUSY) {
ssdk_printf(SSDK_CRIT, "i2c ctrl %u busy\r\n", ctrl->cfg->id);
return -1;
}
/* set bus stat to busy indicate bus be occupied now */
ret = sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_BUSY);
if (ret < 0) {
ssdk_printf(SSDK_CRIT, "i2c ctrl %u set bus stat fail\r\n",
ctrl->cfg->id);
return -2;
}
sdrv_i2c_write(ctrl, addr, cmd, cmdlen, 1000, false);
trans_stat = sdrv_i2c_get_trans_stat(ctrl);
if (trans_stat != SDRV_I2CDRV_TRANS_OK) {
ssdk_printf(SSDK_CRIT, "%s write fail\r\n", __func__);
ret = -3;
goto end;
}
sdrv_i2c_read(ctrl, addr, data, datalen, 1000, true);
trans_stat = sdrv_i2c_get_trans_stat(ctrl);
if (trans_stat != SDRV_I2CDRV_TRANS_OK) {
ssdk_printf(SSDK_CRIT, "%s, read fail\r\n", __func__);
ret = -4;
goto end;
}
end:
sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_IDLE);
return ret;
}
int fts_write(struct fts_data *fts, uint8_t *buf, uint32_t len)
{
int ret = 0;
sdrv_i2cdrv_bus_stat_t bus_stat;
sdrv_i2cdrv_trans_stat_t trans_stat;
sdrv_i2c_t *ctrl = fts->ts_dev->i2c_ctrl;
int addr = fts->ts_dev->i2c_addr;
/* get bus stat, if busy can not use */
bus_stat = sdrv_i2c_get_bus_stat(ctrl);
if (bus_stat == SDRV_I2CDRV_BUS_BUSY) {
ssdk_printf(SSDK_CRIT, "i2c ctrl %u busy\r\n", ctrl->cfg->id);
return -1;
}
/* set bus stat to busy indicate bus be occupied now */
ret = sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_BUSY);
if (ret < 0) {
ssdk_printf(SSDK_CRIT, "i2c ctrl %u set bus stat fail\r\n",
ctrl->cfg->id);
return -2;
}
sdrv_i2c_write(ctrl, addr, buf, len, 1000, true);
trans_stat = sdrv_i2c_get_trans_stat(ctrl);
if (trans_stat != SDRV_I2CDRV_TRANS_OK) {
ssdk_printf(SSDK_CRIT, "%s write fail\r\n", __func__);
ret = -3;
goto end;
}
end:
sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_IDLE);
return ret;
}
int fts_read_reg(struct fts_data *fts, uint8_t addr, uint8_t *value)
{
return fts_read(fts, &addr, 1, value, 1);
}
int fts_write_reg(struct fts_data *fts, uint8_t addr, uint8_t value)
{
uint8_t buf[2] = {0};
buf[0] = addr;
buf[1] = value;
return fts_write(fts, buf, sizeof(buf));
}
static int fts_get_chip_types(struct fts_data *fts,
uint8_t id_h, uint8_t id_l, bool fw_valid)
{
int i = 0;
struct ft_chip_t ctype[] = FTS_CHIP_TYPE_MAPPING;
uint32_t ctype_entries = sizeof(ctype) / sizeof(struct ft_chip_t);
if ((0x0 == id_h) || (0x0 == id_l)) {
ssdk_printf(SSDK_ERR, "id_h/id_l is 0\r\n");
return -1;
}
for (i = 0; i < ctype_entries; i++) {
if (true == fw_valid) {
if ((id_h == ctype[i].chip_idh) && (id_l == ctype[i].chip_idl))
break;
} else {
if (((id_h == ctype[i].rom_idh) && (id_l == ctype[i].rom_idl))
|| ((id_h == ctype[i].pb_idh) && (id_l == ctype[i].pb_idl))
|| ((id_h == ctype[i].bl_idh) && (id_l == ctype[i].bl_idl)))
break;
}
}
if (i >= ctype_entries) {
return -2;
}
fts->ids = ctype[i];
return 0;
}
static int fts_get_ic_info(struct fts_data *fts)
{
int ret = 0;
int cnt = 0;
uint8_t chip_id[2] = {0};
do {
ret = fts_read_reg(fts, FTS_REG_CHIP_ID, &chip_id[0]);
ret = fts_read_reg(fts, FTS_REG_CHIP_ID2, &chip_id[1]);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "i2c read chip fail\r\n");
} else {
ret = fts_get_chip_types(fts, chip_id[0], chip_id[1], true);
if (!ret)
break;
else
ssdk_printf(SSDK_ERR, "TP not ready, read:0x%02x%02x",
chip_id[0], chip_id[1]);
}
ts_mdelay(100);
} while (++cnt < 3);
if (cnt >= 3) {
ssdk_printf(SSDK_ERR, "%s: read chip id fail\r\n", __func__);
return -1;
}
ssdk_printf(SSDK_ERR, "%s: chip id = 0x%02x%02x\r\n", __func__,
fts->ids.chip_idh, fts->ids.chip_idl);
return 0;
}
static int fts_reset_device(struct fts_data *fts)
{
sdrv_gpio_set_pin_output_level(fts->ts_dev->rst, true);
ts_mdelay(10);
sdrv_gpio_set_pin_output_level(fts->ts_dev->irq, false);
ts_mdelay(2);
sdrv_gpio_set_pin_output_level(fts->ts_dev->rst, true);
ts_mdelay(100);
return 0;
}
static void fts_thread(void *arg)
{
int i;
int ret;
int base;
int point_num;
int point_num_down;
int point_num_flag[10];
struct fts_data *fts = arg;
uint8_t buf[FTS_ONE_TCH_LEN * 10 + 4];
touch_data_t *sdrv_datap = sdrv_touch_data_pointer();
while (1) {
xEventGroupWaitBits(fts->ts_event, 1, pdTRUE, pdFAIL, portMAX_DELAY);
for (i = 0; i < 64; i++)
buf[i] = 0xff;
buf[0] = 0x01;
ret = fts_read(fts, buf, 1, buf + 1, 63);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "read touch data failed, ret:%d", ret);
sdrv_gpio_pin_interrupt_enable(fts->ts_dev->irq);
continue;
}
point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F;
if (FTS_INCELL) {
if ((point_num == 0x0F) && (buf[2] == 0xFF) && (buf[3] == 0xFF)
&& (buf[4] == 0xFF) && (buf[5] == 0xFF) && (buf[6] == 0xFF)) {
ssdk_printf(SSDK_ERR, "buf is 0xff, need recovery state\r\n");
//fts_release_all_finger();
//fts_tp_state_recovery(data);
sdrv_gpio_pin_interrupt_enable(fts->ts_dev->irq);
continue;
}
}
point_num_down = point_num;
for (i = 0; i < point_num; i++) {
base = FTS_ONE_TCH_LEN * i;
sdrv_datap->touch_point[i].id = (buf[FTS_TOUCH_ID_POS + base]) >> 4;
sdrv_datap->touch_point[i].x = ((buf[FTS_TOUCH_X_H_POS + base] & 0x0F) << 8) +
(buf[FTS_TOUCH_X_L_POS + base] & 0xFF);
sdrv_datap->touch_point[i].y = ((buf[FTS_TOUCH_Y_H_POS + base] & 0x0F) << 8) +
(buf[FTS_TOUCH_Y_L_POS + base] & 0xFF);
point_num_flag[i] = buf[FTS_TOUCH_EVENT_POS + base] >> 6;
if (point_num_flag[i] == 1)
point_num_down--;
}
sdrv_datap->touch_num = point_num_down;
#if 0
for (i = 0; i < point_num; i++) {
ssdk_printf(SSDK_ERR, "%s, num=%d, id=%d, x=%d, y=%d, flag=%d\r\n", __func__,
sdrv_datap->touch_num, sdrv_datap->touch_point[i].id,
sdrv_datap->touch_point[i].x, sdrv_datap->touch_point[i].y,
point_num_flag[i]);
}
#endif
sdrv_gpio_pin_interrupt_enable(fts->ts_dev->irq);
}
}
static void fts_irq_handler(uint32_t irq, uint32_t pin, void *arg)
{
BaseType_t yield = pdFALSE;
struct fts_data *fts = (struct fts_data *)arg;
sdrv_gpio_pin_interrupt_disable(fts->ts_dev->irq);
//ssdk_printf(SSDK_ERR, "%s\r\n", __func__);
if (xEventGroupSetBitsFromISR(fts->ts_event, 1, &yield) != pdFAIL)
portYIELD_FROM_ISR (yield);
}
static int fts_config_device(struct fts_data *fts)
{
fts->ts_event = xEventGroupCreate();
xTaskCreate(fts_thread, "focaltech", configTASK_IDLE_STACK_SIZE, fts,
(tskIDLE_PRIORITY + 2), NULL);
sdrv_gpio_set_pin_interrupt(fts->ts_dev->irq, GPIO_INTR_FALLING_EDGE);
sdrv_gpio_register_interrupt_handler(fts->ts_dev->irq, fts_irq_handler, fts);
sdrv_gpio_pin_interrupt_enable(fts->ts_dev->irq);
return 0;
}
int focaltech_touch_init(touch_dev_t *touch_dev)
{
int ret = 0;
g_fts.ts_dev = touch_dev;
fts_reset_device(&g_fts);
ret = fts_get_ic_info(&g_fts);
if (ret) {
ssdk_printf(SSDK_ERR, "%s: read chip id fail\r\n", __func__);
return -1;
}
ret = fts_config_device(&g_fts);
if (ret) {
ssdk_printf(SSDK_ERR, "%s: confif device fail\r\n", __func__);
return -1;
}
ssdk_printf(SSDK_ERR, "%s, ===done ok===\r\n", __func__);
return 0;
}