300 lines
8.2 KiB
C
300 lines
8.2 KiB
C
#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;
|
|
} |