Added ITE IT7259 touch sensor.
continuous-integration/drone/push Build is passing Details

Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
Yilin Sun 2024-03-16 18:10:43 +08:00
parent 954c38ac5a
commit dd9e014464
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
3 changed files with 348 additions and 0 deletions

View File

@ -12,6 +12,7 @@ set(IMSENSORS_SRCS
"src/imu/imu_lsm6dsl.c"
"src/magnetic/magnetic_bmm150.c"
"src/ppg/ppg_pah8001.c"
"src/touch/tp_it7259.c"
)
set(IMSENSORS_INCS
@ -22,6 +23,7 @@ set(IMSENSORS_INCS
"include/imsensors/imu"
"include/imsensors/magnetic"
"include/imsensors/ppg"
"include/imsensors/touch"
)
set(IMSENSORS_INTF_INCS

View File

@ -0,0 +1,46 @@
#ifndef TP_IT7259_H
#define TP_IT7259_H
#include "imsensors/common/sensors_common.h"
typedef enum {
IT7259_PRES_NONE = 0U,
IT7259_PRES_HOVER = 1U,
IT7259_PRES_LIGHT = 2U,
IT7259_PRES_NORMAL = 4U,
IT7259_PRES_HIGH = 8U,
IT7259_PRES_HEAVY = 0x0FU,
} ims_it7259_pres_t;
typedef struct {
ims_i2c_xfer_t i2c_xfer;
ims_delay_t delay;
} ims_it7259_cb_t;
typedef struct {
uint32_t rom_version;
uint32_t fw_version;
uint8_t vendor_fw_version;
} ims_it7259_sensor_fw_info_t;
typedef struct {
uint8_t id;
uint16_t pos_x;
uint16_t pos_y;
ims_it7259_pres_t pres;
} ims_it7259_point_t;
typedef struct {
ims_it7259_cb_t cb;
void *pdev;
ims_it7259_sensor_fw_info_t fw_info;
uint16_t resolution_x;
uint16_t resolution_y;
} ims_it7259_t;
ims_ret_t ims_it7259_init(ims_it7259_t *tp);
ims_ret_t ims_it7259_read_points(ims_it7259_t *tp, uint8_t *num_tp, ims_it7259_point_t *points);
#endif // TP_IT7259_H

300
src/touch/tp_it7259.c Normal file
View File

@ -0,0 +1,300 @@
#include "tp_it7259.h"
#define ITE_BUF_LEN (18) /* This assumes the maximum payload length does not exceed this value */
#define ITE_QUERY_TIMEOUT (10) /* The device sometimes gives NAK for query command */
#define ITE_BUF_Pos (5U)
#define ITE_BUF_Msk (7U << ITE_BUF_Pos)
#define ITE_QUERY_STAT_Pos (0U)
#define ITE_QUERY_STAT_Msk (3U << ITE_QUERY_STAT_Pos)
#define ITE_CMD_DEVICE_NAME (0x00U)
#define ITE_CMD_DEVICE_NAME_LEN (0x0AU)
#define ITE_CMD_SENSOR_INFO (0x01U)
#define ITE_SUBCMD_FW_INFO (0x00U)
#define ITE_SUBCMD_FW_INFO_LEN (0x0AU)
#define ITE_SUBCMD_2D_RES (0x02U)
#define ITE_SUBCMD_2D_RES_LEN (0x0CU)
#define ITE_POINT_INFO_LEN (0x0EU)
typedef enum {
ITE_BUF_CMD = 1U,
ITE_BUF_QUERY = 4U,
ITE_BUF_CMD_RESP = 5U,
ITE_BUF_POINT = 7U,
} ite_buf_type_t;
typedef enum {
ITE_STAT_DONE = 0U,
ITE_STAT_BUSY = 1U,
ITE_STAT_ERROR = 2U,
ITE_STAT_RESERVED = 3U,
} ite_query_stat_t;
typedef struct __packed {
uint8_t cmd;
uint8_t sub;
uint8_t params[ITE_BUF_LEN - 2];
uint8_t sub_len;
uint8_t params_len;
} ite_cmd_t;
static const uint8_t ims_it7259_dev_name[] = {'I', 'T', 'E', '7', '2', '5', '9'};
static ims_ret_t ims_it7259_validate_device_name(ims_it7259_t *tp);
static ims_ret_t ims_it7259_sensor_fw_info(ims_it7259_t *tp, ims_it7259_sensor_fw_info_t *info);
static ims_ret_t ims_it7259_sensor_resoluion(ims_it7259_t *tp, uint16_t *res_x, uint16_t *res_y);
static ims_ret_t ims_it7259_buf_read(ims_it7259_t *tp, ite_buf_type_t type, uint8_t *data, uint8_t len);
static ims_ret_t ims_it7259_buf_write(ims_it7259_t *tp, ite_buf_type_t type, uint8_t *data, uint8_t len);
static ims_ret_t ims_it7259_query(ims_it7259_t *tp, uint8_t *query_result);
static ims_ret_t ims_it7259_command_send(ims_it7259_t *tp, ite_cmd_t *cmd);
static ims_ret_t ims_it7259_command_recv(ims_it7259_t *tp, uint8_t *data, uint8_t len);
static ims_ret_t ims_it7259_command_wait(ims_it7259_t *tp);
ims_ret_t ims_it7259_init(ims_it7259_t *tp) {
ims_ret_t ret = ims_it7259_validate_device_name(tp);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_sensor_fw_info(tp, &tp->fw_info);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_sensor_resoluion(tp, &tp->resolution_x, &tp->resolution_y);
if (ret != IMS_SUCCESS) {
return ret;
}
return IMS_SUCCESS;
}
ims_ret_t ims_it7259_read_points(ims_it7259_t *tp, uint8_t *num_tp, ims_it7259_point_t *points) {
uint8_t rx_buf[ITE_POINT_INFO_LEN];
uint8_t query;
ims_ret_t ret = ims_it7259_query(tp, &query);
if (ret != IMS_SUCCESS) {
return ret;
}
if ((query >> 6U) == 0U) {
*num_tp = 0U;
return IMS_SUCCESS;
}
/* Two conditions on query [7:6]: 1xb: New touch, 01b: Still touched */
ret = ims_it7259_buf_read(tp, ITE_BUF_POINT, rx_buf, ITE_POINT_INFO_LEN);
if (ret != IMS_SUCCESS) {
return ret;
}
/* Check whether this is a Point Data report */
if ((rx_buf[0] & 0xF0) != 0x00) {
return IMS_FAIL;
}
uint8_t array_num = *num_tp;
uint8_t current_id = 0;
uint8_t i;
for (i = 0; i < 3; i++) {
if (rx_buf[0] & (1U << i)) {
points[current_id].id = i;
points[current_id].pos_x = rx_buf[i + 2] | (rx_buf[i + 3] & 0x0FU) << 8U;
points[current_id].pos_y = rx_buf[i + 4] | (rx_buf[i + 3] & 0xF0U) << 4U;
points[current_id].pres = rx_buf[i + 5] & 0x0FU;
current_id++;
/* Do not exceed buffer length */
if (array_num == current_id) {
break;
}
}
}
*num_tp = current_id;
return IMS_SUCCESS;
}
static ims_ret_t ims_it7259_validate_device_name(ims_it7259_t *tp) {
uint8_t name[ITE_CMD_DEVICE_NAME_LEN];
ite_cmd_t cmd = {
.cmd = ITE_CMD_DEVICE_NAME,
.sub_len = 0,
.params_len = 0,
};
ims_ret_t ret = ims_it7259_command_send(tp, &cmd);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_command_wait(tp);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_command_recv(tp, name, ITE_CMD_DEVICE_NAME_LEN);
if (ret != IMS_SUCCESS) {
return ret;
}
/* Compare string revision. */
for (uint8_t i = 0; i < sizeof(ims_it7259_dev_name); i++) {
/* The first byte is length */
if (name[i + 1] != ims_it7259_dev_name[i]) {
return IMS_FAIL;
}
}
return IMS_SUCCESS;
}
static ims_ret_t ims_it7259_sensor_fw_info(ims_it7259_t *tp, ims_it7259_sensor_fw_info_t *info) {
uint8_t rx_buf[ITE_SUBCMD_FW_INFO_LEN];
ite_cmd_t cmd = {
.cmd = ITE_CMD_SENSOR_INFO,
.sub = ITE_SUBCMD_FW_INFO,
.sub_len = 1,
.params_len = 0,
};
ims_ret_t ret = ims_it7259_command_send(tp, &cmd);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_command_wait(tp);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_command_recv(tp, rx_buf, ITE_SUBCMD_FW_INFO_LEN);
if (ret != IMS_SUCCESS) {
return ret;
}
info->rom_version = (rx_buf[1] << 24) | (rx_buf[2] << 16) | (rx_buf[3] << 8) | rx_buf[4];
info->fw_version = (rx_buf[5] << 24) | (rx_buf[6] << 16) | (rx_buf[7] << 8) | rx_buf[8];
info->vendor_fw_version = rx_buf[9];
return ret;
}
static ims_ret_t ims_it7259_sensor_resoluion(ims_it7259_t *tp, uint16_t *res_x, uint16_t *res_y) {
uint8_t rx_buf[ITE_SUBCMD_2D_RES_LEN];
ite_cmd_t cmd = {
.cmd = ITE_CMD_SENSOR_INFO,
.sub = ITE_SUBCMD_2D_RES,
.sub_len = 1,
.params_len = 0,
};
ims_ret_t ret = ims_it7259_command_send(tp, &cmd);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_command_wait(tp);
if (ret != IMS_SUCCESS) {
return ret;
}
ret = ims_it7259_command_recv(tp, rx_buf, ITE_SUBCMD_2D_RES_LEN);
if (ret != IMS_SUCCESS) {
return ret;
}
*res_x = ((rx_buf[3] << 16U) | rx_buf[2]) + 1;
*res_y = ((rx_buf[5] << 16U) | rx_buf[4]) + 1;
return IMS_SUCCESS;
}
static ims_ret_t ims_it7259_buf_read(ims_it7259_t *tp, ite_buf_type_t type, uint8_t *data, uint8_t len) {
uint8_t tx_buf[] = {(type << ITE_BUF_Pos) & ITE_BUF_Msk};
ims_i2c_xfer_desc_t xfer_desc = {
.tx_data = tx_buf,
.tx_size = 1U,
.rx_data = data,
.rx_size = len,
};
ims_ret_t ret = tp->cb.i2c_xfer(tp->pdev, &xfer_desc);
if (ret != IMS_SUCCESS) {
return ret;
}
return IMS_SUCCESS;
}
static ims_ret_t ims_it7259_buf_write(ims_it7259_t *tp, ite_buf_type_t type, uint8_t *data, uint8_t len) {
uint8_t tx_buf[ITE_BUF_LEN + 1] = {(type << ITE_BUF_Pos) & ITE_BUF_Msk};
memcpy(&tx_buf[1], data, len); /* ! WATCH BOUNDARY ! */
ims_i2c_xfer_desc_t xfer_desc = {
.tx_data = tx_buf,
.tx_size = len + 1,
.rx_data = NULL,
.rx_size = 0,
};
ims_ret_t ret = tp->cb.i2c_xfer(tp->pdev, &xfer_desc);
if (ret != IMS_SUCCESS) {
return ret;
}
return IMS_SUCCESS;
}
static ims_ret_t ims_it7259_query(ims_it7259_t *tp, uint8_t *query_result) {
return ims_it7259_buf_read(tp, ITE_BUF_QUERY, query_result, 0x01);
}
static ims_ret_t ims_it7259_command_send(ims_it7259_t *tp, ite_cmd_t *cmd) {
return ims_it7259_buf_write(tp, ITE_BUF_CMD, (uint8_t *)cmd, (cmd->sub_len + cmd->params_len + 1));
}
static ims_ret_t ims_it7259_command_recv(ims_it7259_t *tp, uint8_t *data, uint8_t len) {
return ims_it7259_buf_read(tp, ITE_BUF_CMD_RESP, data, len);
}
static ims_ret_t ims_it7259_command_wait(ims_it7259_t *tp) {
uint8_t query;
while (true) {
ims_ret_t ret = ims_it7259_query(tp, &query);
if (ret != IMS_SUCCESS) {
tp->cb.delay(tp->pdev, ITE_QUERY_TIMEOUT);
ret = ims_it7259_query(tp, &query);
if (ret != IMS_SUCCESS) {
return ret;
}
}
uint8_t stat = (query & ITE_QUERY_STAT_Msk) >> ITE_QUERY_STAT_Pos;
if (stat == ITE_STAT_ERROR) {
return IMS_FAIL;
}
if (stat == ITE_STAT_DONE) {
break;
}
}
return IMS_SUCCESS;
}