1902 lines
49 KiB
C
1902 lines
49 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#define LOG_TAG "TCS"
|
|
|
|
#include "cts_config.h"
|
|
#include "cts_firmware.h"
|
|
#include "cts_platform.h"
|
|
#include "cts_tcs.h"
|
|
|
|
#define TCS_WR_ADDR (0xF0)
|
|
#define TCS_RD_ADDR (0xF1)
|
|
|
|
#define TCS_READ_BIT (14)
|
|
#define TCS_WRITE_BIT (13)
|
|
#define TCS_HEADER_SIZE sizeof(STRUCT_TCS_TX_HEAD)
|
|
#define TCS_TAIL_SIZE sizeof(STRUCT_TCS_RX_TAIL)
|
|
|
|
/* raw touch info without data */
|
|
#define TOUCH_INFO_SIZE sizeof(struct cts_device_touch_info)
|
|
#define INT_DATA_VALID_INDEX (174)
|
|
#define INT_DATA_HEADER_SIZE (180)
|
|
|
|
#define CTS_I2C_MAX_TRANS_SIZE (48)
|
|
|
|
#pragma pack(1)
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
typedef struct {
|
|
u16 cmd;
|
|
u16 datlen;
|
|
u8 check_l;
|
|
u8 check_h;
|
|
} STRUCT_TCS_TX_HEAD;
|
|
|
|
typedef struct {
|
|
u8 ecode;
|
|
u16 cmd;
|
|
u8 check_l;
|
|
u8 check_h;
|
|
} STRUCT_TCS_RX_TAIL;
|
|
#else /* CONFIG_CTS_I2C_HOST */
|
|
typedef struct {
|
|
u8 addr;
|
|
u16 cmd;
|
|
u16 datlen;
|
|
u16 crc16;
|
|
} STRUCT_TCS_TX_HEAD;
|
|
typedef struct {
|
|
u8 ecode;
|
|
u16 cmd;
|
|
u16 crc16;
|
|
} STRUCT_TCS_RX_TAIL;
|
|
#endif /* CONFIG_CTS_I2C_HOST */
|
|
#pragma pack()
|
|
|
|
#define CMD_INFO_CHIP_HW_ID_RO (0x4002)
|
|
#define CMD_INFO_CHIP_FW_ID_RO (0x4003)
|
|
#define CMD_INFO_FW_VER_RO (0x4005)
|
|
#define CMD_INFO_TOUCH_XY_INFO_RO (0x4007)
|
|
#define CMD_INFO_IC_INFO_RO (0x4009)
|
|
#define CMD_INFO_PAD_PANEL_INFO_RO (0x400a)
|
|
#define CMD_INFO_MODULE_ID_RO (0x4011)
|
|
#define CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW (0x6101)
|
|
#define CMD_TP_DATA_READ_START_RO (0x4102)
|
|
#define CMD_TP_DATA_COORDINATES_RO (0x4103)
|
|
#define CMD_TP_DATA_RAW_RO (0x4104)
|
|
#define CMD_TP_DATA_DIFF_RO (0x4105)
|
|
#define CMD_TP_DATA_BASE_RO (0x4106)
|
|
#define CMD_TP_DATA_CNEG_RO (0x410a)
|
|
|
|
#define CMD_TP_DATA_WR_REG_RAM_SEQUENCE_WO (0x2114)
|
|
#define CMD_TP_DATA_WR_REG_RAM_BATCH_WO (0x2115)
|
|
#define CMD_TP_DATA_WR_DDI_REG_SEQUENCE_WO (0x2116)
|
|
#define CMD_TP_STD_CMD_SET_KRANG_STOP (0x224a)
|
|
#define CMD_GET_DATA_BY_POLLING_RO (0x4123)
|
|
#define CMD_TP_DATA_STATUS_RO (0x4125)
|
|
#define CMD_SYS_STS_READ_RO (0x4200)
|
|
#define CMD_SYS_STS_WORK_MODE_RW (0x6201)
|
|
#define CMD_SYS_STS_DAT_RDY_FLAG_RW (0x6203)
|
|
#define CMD_SYS_STS_PWR_STATE_RW (0x6204)
|
|
#define CMD_SYS_STS_CHARGER_PLUGIN_RW (0x6205)
|
|
#define CMD_SYS_STS_DDI_CODE_VER_RO (0x4206)
|
|
#define CMD_SYS_STS_DAT_TRANS_IN_NORMAL_RW (0x6207)
|
|
#define CMD_SYS_STS_VSTIM_LVL_RW (0x6208)
|
|
#define CMD_SYS_STS_CNEG_RDY_FLAG_RW (0x6211)
|
|
#define CMD_SYS_STS_EP_PLUGIN_RW (0x6213)
|
|
#define CMD_SYS_STS_RESET_WO (0x2216)
|
|
#define CMD_SYS_STS_INT_TEST_EN_RW (0x6217)
|
|
#define CMD_SYS_STS_SET_INT_PIN_RW (0x6218)
|
|
#define CMD_SYS_STS_CNEG_RD_EN_RW (0x6219)
|
|
#define CMD_SYS_STS_HI_SENSE_EN_RW (0x621a)
|
|
#define CMD_SYS_STS_INT_MODE_RW (0x6223)
|
|
#define CMD_SYS_STS_INT_KEEP_TIME_RW (0x6224)
|
|
#define CMD_SYS_STS_CURRENT_WORKMODE_RO (0x4233)
|
|
#define CMD_SYS_STS_DATA_CAPTURE_SUPPORT_RO (0x423f)
|
|
#define CMD_SYS_STS_DATA_CAPTURE_EN_RW (0x6240)
|
|
#define CMD_SYS_STS_DATA_CAPTURE_FUNC_MAP_RW (0x6241)
|
|
#define CMD_SYS_STS_PANEL_DIRECTION_RW (0x6242)
|
|
#define CMD_SYS_STS_KRANG_WORK_MODE_RW (0x6243)
|
|
#define CMD_SYS_STS_KRANG_CURRENT_WORKMODE_RO (0x4244)
|
|
#define CMD_SYS_STS_GAME_MODE_RW (0x624e)
|
|
#define CMD_SYS_STS_POCKET_MODE_EN_RW (0x6250)
|
|
#define CMD_SYS_STS_PRODUCTION_TEST_EN_RW (0x6252)
|
|
#define CMD_SYS_STS_KRANG_WORK_STS_RO (0x4259)
|
|
|
|
#define CMD_GSTR_WAKEUP_EN_RW (0x6301)
|
|
#define CMD_GSTR_DAT_RDY_FLAG_GSTR_RW (0x631e)
|
|
#define CMD_GSTR_ENTER_MAP_RW (0x6328)
|
|
#define CMD_MNT_EN_RW (0x6401)
|
|
#define CMD_MNT_FORCE_EXIT_MNT_WO (0x2403)
|
|
#define CMD_DDI_ESD_EN_RW (0x6501)
|
|
#define CMD_DDI_ESD_OPTIONS_RW (0x6502)
|
|
#define CMD_CNEG_EN_RW (0x6601)
|
|
#define CMD_CNEG_OPTIONS_RW (0x6602)
|
|
#define CMD_COORD_FLIP_X_EN_RW (0x6702)
|
|
#define CMD_COORD_FLIP_Y_EN_RW (0x6703)
|
|
#define CMD_COORD_SWAP_AXES_EN_RW (0x6704)
|
|
#define CMD_PARA_PROXI_EN_RW (0x692a)
|
|
#define CMD_PARA_KUNCKLE_RW (0x694b)
|
|
#define CMD_OPENSHORT_EN_RW (0x6b01)
|
|
#define CMD_OPENSHORT_MODE_SEL_RW (0x6b02)
|
|
#define CMD_OPENSHORT_SHORT_SEL_RW (0x6b03)
|
|
#define CMD_OPENSHORT_SHORT_DISP_ON_EN_RW (0x6b04)
|
|
|
|
#if 0
|
|
static u8 str[1024 * 4];
|
|
|
|
void dump_spi(const char *prefix, u8 *data, size_t datalen)
|
|
{
|
|
|
|
int offset = 0;
|
|
int i;
|
|
|
|
offset += snprintf(str + offset, sizeof(str) - offset, "%s", prefix);
|
|
for (i = 0; i < datalen; i++) {
|
|
offset += snprintf(str + offset, sizeof(str) - offset, " %02x", data[i]);
|
|
}
|
|
cts_err("%s", str);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
static int cts_tcs_tail_check(u8 *buf, u16 cmd, int len)
|
|
{
|
|
STRUCT_TCS_RX_TAIL *tail;
|
|
u8 check_l = 0;
|
|
u8 check_h = 0x01;
|
|
int check_len = len - TCS_TAIL_SIZE;
|
|
int i;
|
|
|
|
tail = (STRUCT_TCS_RX_TAIL *)(buf + check_len);
|
|
if (tail->ecode != 0) {
|
|
cts_err("error code:0x%02x", tail->ecode);
|
|
return -EIO;
|
|
}
|
|
|
|
if (tail->cmd != cmd) {
|
|
cts_err("cmd error: recv %04x != %04x send", tail->cmd, cmd);
|
|
return -EIO;
|
|
}
|
|
|
|
for (i = 0; i < check_len + 3; i++) {
|
|
check_l += buf[i];
|
|
}
|
|
check_l = ~check_l;
|
|
if (tail->check_h != check_h || tail->check_l != check_l) {
|
|
cts_err("crc error: recv %02x%02x != %02x%02x calc",
|
|
tail->check_h, tail->check_l, check_h, check_l);
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cts_tcs_i2c_trans(struct cts_platform_data *pdata, u8 i2c_addr,
|
|
const u8 *wbuf, size_t wlen, void *rbuf, size_t rlen,
|
|
int retry, int delay)
|
|
{
|
|
int i, retries = 0;
|
|
int ret;
|
|
|
|
struct i2c_msg msgs[2] = {
|
|
{
|
|
.addr = i2c_addr,
|
|
.flags = 0,
|
|
.buf = (u8 *) wbuf,
|
|
.len = wlen,
|
|
},
|
|
{
|
|
.addr = i2c_addr,
|
|
.flags = I2C_M_RD,
|
|
.buf = (u8 *) rbuf,
|
|
.len = rlen,
|
|
}
|
|
};
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
for (retries = 0; retries < retry; retries++) {
|
|
ret = i2c_transfer(pdata->i2c_client->adapter, &msgs[i], 1);
|
|
if (ret == 1) {
|
|
ret = 0;
|
|
|
|
if (delay > 0)
|
|
mdelay(delay);
|
|
else
|
|
udelay(300);
|
|
|
|
break;
|
|
} else {
|
|
mdelay(10);
|
|
}
|
|
}
|
|
|
|
if (retries >= retry) {
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
ret = cts_tcs_tail_check(rbuf, get_unaligned_le16(wbuf), rlen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_i2c_trans_1_time(struct cts_platform_data *pdata, u8 i2c_addr,
|
|
const u8 *wbuf, size_t wlen, void *rbuf, size_t rlen,
|
|
int retry, int delay)
|
|
{
|
|
int retries = 0;
|
|
int ret;
|
|
|
|
struct i2c_msg msgs[2] = {
|
|
{
|
|
.addr = i2c_addr,
|
|
.flags = 0,
|
|
.buf = (u8 *) wbuf,
|
|
.len = wlen,
|
|
},
|
|
{
|
|
.addr = i2c_addr,
|
|
.flags = I2C_M_RD,
|
|
.buf = (u8 *) rbuf,
|
|
.len = rlen,
|
|
}
|
|
};
|
|
|
|
do {
|
|
ret = i2c_transfer(pdata->i2c_client->adapter, msgs, 2);
|
|
|
|
if (ret != 2) {
|
|
if (ret >= 0) {
|
|
ret = -EIO;
|
|
}
|
|
|
|
udelay(delay);
|
|
|
|
continue;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} while (++retries < retry);
|
|
|
|
ret = cts_tcs_tail_check(rbuf, get_unaligned_le16(wbuf), rlen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_i2c_read_pack(u8 *tx, u16 cmd, u16 rdatalen)
|
|
{
|
|
STRUCT_TCS_TX_HEAD *txhdr = (STRUCT_TCS_TX_HEAD *) tx;
|
|
u16 is_read;
|
|
int packlen = 0;
|
|
|
|
is_read = cmd & BIT(TCS_READ_BIT);
|
|
if (0 == is_read) {
|
|
return packlen;
|
|
}
|
|
txhdr->cmd = (cmd & ~BIT(TCS_WRITE_BIT));
|
|
txhdr->datlen = rdatalen;
|
|
txhdr->check_l = ~((txhdr->cmd & 0xff)
|
|
+ ((txhdr->cmd >> 8) & 0xff)
|
|
+ (rdatalen & 0xff)
|
|
+ ((rdatalen >> 8) & 0xff));
|
|
txhdr->check_h = 1;
|
|
packlen = TCS_HEADER_SIZE;
|
|
|
|
return packlen;
|
|
}
|
|
|
|
static int cts_tcs_i2c_write_pack(u8 *tx, u16 cmd, u8 *wdata, u16 wlen)
|
|
{
|
|
STRUCT_TCS_TX_HEAD *txhdr = (STRUCT_TCS_TX_HEAD *) tx;
|
|
int packlen = 0;
|
|
u8 check_l = 0;
|
|
u16 is_write;
|
|
int i;
|
|
|
|
is_write = cmd & BIT(TCS_WRITE_BIT);
|
|
if (0 == is_write) {
|
|
return packlen;
|
|
}
|
|
txhdr->cmd = (cmd & ~BIT(TCS_READ_BIT));
|
|
txhdr->datlen = wlen;
|
|
txhdr->check_l = ~((txhdr->cmd & 0xff)
|
|
+ ((txhdr->cmd >> 8) & 0xff)
|
|
+ (wlen & 0xff)
|
|
+ ((wlen >> 8) & 0xff));
|
|
txhdr->check_h = 1;
|
|
packlen += TCS_HEADER_SIZE;
|
|
|
|
if (wlen > 0) {
|
|
memcpy(tx + TCS_HEADER_SIZE, wdata, wlen);
|
|
for (i = 0; i < wlen; i++) {
|
|
check_l += wdata[i];
|
|
}
|
|
*(tx + TCS_HEADER_SIZE + wlen) = ~check_l;
|
|
*(tx + TCS_HEADER_SIZE + wlen + 1) = 1;
|
|
packlen += wlen + 2;
|
|
}
|
|
|
|
return packlen;
|
|
}
|
|
|
|
static int cts_tcs_i2c_read(struct cts_device *cts_dev, u16 cmd,
|
|
u8 *buf, size_t len)
|
|
{
|
|
int txlen;
|
|
int size;
|
|
int ret;
|
|
|
|
size = len + TCS_TAIL_SIZE;
|
|
|
|
txlen = cts_tcs_i2c_read_pack(cts_dev->pdata->i2c_fifo_buf, cmd, len);
|
|
|
|
ret = cts_tcs_i2c_trans(cts_dev->pdata, CTS_DEV_NORMAL_MODE_I2CADDR,
|
|
cts_dev->pdata->i2c_fifo_buf, txlen, cts_dev->pdata->i2c_rbuf, size,
|
|
3, 0);
|
|
|
|
if (ret == 0) {
|
|
memcpy(buf, cts_dev->pdata->i2c_rbuf, len);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_i2c_write(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *wbuf, size_t wlen)
|
|
{
|
|
int txlen = cts_tcs_i2c_write_pack(cts_dev->pdata->i2c_fifo_buf, cmd, wbuf, wlen);
|
|
return cts_tcs_i2c_trans(cts_dev->pdata, CTS_DEV_NORMAL_MODE_I2CADDR,
|
|
cts_dev->pdata->i2c_fifo_buf, txlen, cts_dev->pdata->i2c_rbuf, TCS_TAIL_SIZE,
|
|
3, 0);
|
|
}
|
|
|
|
static int cts_tcs_i2c_set_krang_stop(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *wbuf, size_t wlen)
|
|
{
|
|
int txlen = cts_tcs_i2c_write_pack(cts_dev->pdata->i2c_fifo_buf, cmd, wbuf, wlen);
|
|
return cts_tcs_i2c_trans(cts_dev->pdata, CTS_DEV_NORMAL_MODE_I2CADDR,
|
|
cts_dev->pdata->i2c_fifo_buf, txlen, cts_dev->pdata->i2c_rbuf, TCS_TAIL_SIZE,
|
|
3, 50);
|
|
}
|
|
|
|
static int cts_tcs_i2c_read_touch(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *buf, size_t len)
|
|
{
|
|
int txlen;
|
|
int rxlen_without_tail = len - TCS_TAIL_SIZE;
|
|
int ret;
|
|
|
|
txlen = cts_tcs_i2c_read_pack(cts_dev->pdata->i2c_fifo_buf,
|
|
cmd, len - TCS_TAIL_SIZE);
|
|
ret = cts_tcs_i2c_trans_1_time(cts_dev->pdata, CTS_DEV_NORMAL_MODE_I2CADDR,
|
|
cts_dev->pdata->i2c_fifo_buf, txlen, cts_dev->pdata->i2c_rbuf, len, 3, 10);
|
|
|
|
if (ret == 0) {
|
|
memcpy(buf, cts_dev->pdata->i2c_rbuf, rxlen_without_tail);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#else
|
|
static int cts_tcs_spi_xtrans(struct cts_device *cts_dev, u8 *tx,
|
|
size_t txlen, u8 *rx, size_t rxlen, int delay)
|
|
{
|
|
struct chipone_ts_data *cts_data = container_of(cts_dev,
|
|
struct chipone_ts_data, cts_dev);
|
|
struct spi_transfer xfer[2];
|
|
struct spi_message msg;
|
|
u16 crc16_recv, crc16_calc;
|
|
u16 cmd_recv, cmd_send;
|
|
int ret;
|
|
|
|
memset(&xfer[0], 0, sizeof(struct spi_transfer));
|
|
xfer[0].delay_usecs = 0;
|
|
xfer[0].speed_hz = cts_dev->pdata->spi_speed * 1000u;
|
|
xfer[0].tx_buf = tx;
|
|
xfer[0].rx_buf = NULL;
|
|
xfer[0].len = txlen;
|
|
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
#ifdef CFG_CTS_MANUAL_CS
|
|
cts_plat_set_cs(cts_dev->pdata, 0);
|
|
#endif
|
|
ret = spi_sync(cts_data->spi_client, &msg);
|
|
#ifdef CFG_CTS_MANUAL_CS
|
|
cts_plat_set_cs(cts_dev->pdata, 1);
|
|
#endif
|
|
if (ret < 0) {
|
|
cts_err("spi_sync xfer[0] failed: %d", ret);
|
|
return ret;
|
|
}
|
|
|
|
if (delay > 0)
|
|
mdelay(delay);
|
|
else
|
|
udelay(500);
|
|
|
|
memset(&xfer[1], 0, sizeof(struct spi_transfer));
|
|
xfer[1].delay_usecs = 0;
|
|
xfer[1].speed_hz = cts_dev->pdata->spi_speed * 1000u;
|
|
xfer[1].tx_buf = NULL;
|
|
xfer[1].rx_buf = rx;
|
|
xfer[1].len = rxlen;
|
|
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer[1], &msg);
|
|
#ifdef CFG_CTS_MANUAL_CS
|
|
cts_plat_set_cs(cts_dev->pdata, 0);
|
|
#endif
|
|
ret = spi_sync(cts_data->spi_client, &msg);
|
|
#ifdef CFG_CTS_MANUAL_CS
|
|
cts_plat_set_cs(cts_dev->pdata, 1);
|
|
#endif
|
|
if (ret < 0) {
|
|
cts_err("spi_sync xfer[1] failed: %d", ret);
|
|
return ret;
|
|
}
|
|
|
|
cmd_recv = get_unaligned_le16(rx +rxlen - 4);
|
|
cmd_send = get_unaligned_le16(tx + 1);
|
|
if (cmd_recv != cmd_send) {
|
|
cts_dbg("cmd check error, send %04x != %04x recv", cmd_send, cmd_recv);
|
|
// return -EIO;
|
|
}
|
|
|
|
crc16_recv = get_unaligned_le16(rx + rxlen - 2);
|
|
crc16_calc = cts_crc16(rx, rxlen - 2);
|
|
if (crc16_recv != crc16_calc) {
|
|
cts_err("crc error: recv %04x != %04x calc", crc16_recv, crc16_calc);
|
|
return -EIO;
|
|
}
|
|
udelay(100);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cts_tcs_spi_xtrans_1_cs(struct cts_device *cts_dev, u8 *tx,
|
|
size_t txlen, u8 *rx, size_t rxlen)
|
|
{
|
|
struct chipone_ts_data *cts_data = container_of(cts_dev,
|
|
struct chipone_ts_data, cts_dev);
|
|
struct spi_transfer xfer[1];
|
|
struct spi_message msg;
|
|
u16 crc16_recv, crc16_calc;
|
|
u16 cmd_recv, cmd_send;
|
|
int ret;
|
|
|
|
memset(&xfer[0], 0, sizeof(struct spi_transfer));
|
|
xfer[0].delay_usecs = 0;
|
|
xfer[0].speed_hz = cts_dev->pdata->spi_speed * 1000u;
|
|
xfer[0].tx_buf = tx;
|
|
xfer[0].rx_buf = rx;
|
|
xfer[0].len = txlen > rxlen ? txlen : rxlen;
|
|
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
#ifdef CFG_CTS_MANUAL_CS
|
|
cts_plat_set_cs(cts_dev->pdata, 0);
|
|
#endif
|
|
ret = spi_sync(cts_data->spi_client, &msg);
|
|
#ifdef CFG_CTS_MANUAL_CS
|
|
cts_plat_set_cs(cts_dev->pdata, 1);
|
|
#endif
|
|
if (ret < 0) {
|
|
cts_err("spi_sync xfer[0] failed: %d", ret);
|
|
return ret;
|
|
}
|
|
|
|
cmd_recv = get_unaligned_le16(rx + rxlen - 4);
|
|
cmd_send = get_unaligned_le16(tx + 1);
|
|
if (cmd_recv != cmd_send) {
|
|
cts_dbg("cmd check error, send %04x != %04x recv", cmd_send, cmd_recv);
|
|
// return -EIO;
|
|
}
|
|
|
|
crc16_recv = get_unaligned_le16(rx + rxlen - 2);
|
|
crc16_calc = cts_crc16(rx, rxlen - 2);
|
|
if (crc16_recv != crc16_calc) {
|
|
cts_err("1cs crc error: recv %04x != %04x calc", crc16_recv, crc16_calc);
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cts_tcs_spi_read_pack(u8 *tx, u16 cmd, u16 rdatalen)
|
|
{
|
|
STRUCT_TCS_TX_HEAD *txhdr = (STRUCT_TCS_TX_HEAD *) tx;
|
|
u16 is_read;
|
|
int packlen = 0;
|
|
u16 crc16;
|
|
|
|
is_read = cmd & BIT(TCS_READ_BIT);
|
|
if (0 == is_read) {
|
|
return packlen;
|
|
}
|
|
txhdr->addr = TCS_RD_ADDR;
|
|
txhdr->cmd = (cmd & ~BIT(TCS_WRITE_BIT));
|
|
txhdr->datlen = rdatalen;
|
|
crc16 = cts_crc16((const u8 *)txhdr, offsetof(STRUCT_TCS_TX_HEAD, crc16));
|
|
txhdr->crc16 = crc16;
|
|
packlen += TCS_HEADER_SIZE;
|
|
|
|
return packlen;
|
|
}
|
|
|
|
static int cts_tcs_spi_write_pack(u8 *tx, u16 cmd, u8 *wdata, u16 wdatalen)
|
|
{
|
|
STRUCT_TCS_TX_HEAD *txhdr = (STRUCT_TCS_TX_HEAD *) tx;
|
|
u16 is_write;
|
|
int packlen = 0;
|
|
u16 crc16;
|
|
|
|
is_write = cmd & BIT(TCS_WRITE_BIT);
|
|
if (0 == is_write) {
|
|
return packlen;
|
|
}
|
|
txhdr->addr = TCS_WR_ADDR;
|
|
txhdr->cmd = (cmd & ~BIT(TCS_READ_BIT));
|
|
txhdr->datlen = wdatalen;
|
|
crc16 = cts_crc16((const u8 *)txhdr, offsetof(STRUCT_TCS_TX_HEAD, crc16));
|
|
txhdr->crc16 = crc16;
|
|
packlen += TCS_HEADER_SIZE;
|
|
|
|
if (wdatalen > 0) {
|
|
memcpy(tx + TCS_HEADER_SIZE, wdata, wdatalen);
|
|
crc16 = cts_crc16(wdata, wdatalen);
|
|
*(tx + TCS_HEADER_SIZE + wdatalen) = ((crc16 >> 0) & 0xFF);
|
|
*(tx + TCS_HEADER_SIZE + wdatalen + 1) = ((crc16 >> 8) & 0xFF);
|
|
packlen += wdatalen + sizeof(crc16);
|
|
}
|
|
|
|
return packlen;
|
|
}
|
|
|
|
static int cts_tcs_spi_read(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *rdata, size_t rdatalen)
|
|
{
|
|
int txlen;
|
|
int ret;
|
|
|
|
txlen = cts_tcs_spi_read_pack(cts_dev->pdata->spi_tx_buf, cmd, rdatalen);
|
|
if (0 == txlen) {
|
|
cts_err("spi read pack len: %d", txlen);
|
|
return -EINVAL;
|
|
}
|
|
ret = cts_tcs_spi_xtrans(cts_dev, cts_dev->pdata->spi_tx_buf, txlen,
|
|
cts_dev->pdata->spi_rx_buf, rdatalen + TCS_TAIL_SIZE, 0);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
memcpy(rdata, cts_dev->pdata->spi_rx_buf, rdatalen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_spi_read_1_cs(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *rdata, size_t rdatalen)
|
|
{
|
|
int txlen;
|
|
int ret;
|
|
|
|
txlen = cts_tcs_spi_read_pack(cts_dev->pdata->spi_tx_buf, cmd, rdatalen);
|
|
if (0 == txlen) {
|
|
cts_err("spi read pack len: %d", txlen);
|
|
return -EINVAL;
|
|
}
|
|
ret = cts_tcs_spi_xtrans_1_cs(cts_dev, cts_dev->pdata->spi_tx_buf, txlen,
|
|
cts_dev->pdata->spi_rx_buf, rdatalen);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
memcpy(rdata, cts_dev->pdata->spi_rx_buf, rdatalen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_spi_write(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *data, size_t wlen)
|
|
{
|
|
int txlen;
|
|
int ret;
|
|
|
|
txlen = cts_tcs_spi_write_pack(cts_dev->pdata->spi_tx_buf, cmd, data, wlen);
|
|
if (0 == txlen) {
|
|
cts_err("spi write pack len: %d", txlen);
|
|
return -EINVAL;
|
|
}
|
|
ret = cts_tcs_spi_xtrans(cts_dev, cts_dev->pdata->spi_tx_buf, txlen,
|
|
cts_dev->pdata->spi_rx_buf, TCS_TAIL_SIZE, 0);
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_spi_set_krang_stop(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *data, size_t wlen)
|
|
{
|
|
int txlen;
|
|
int ret;
|
|
|
|
txlen = cts_tcs_spi_write_pack(cts_dev->pdata->spi_tx_buf, cmd, data, wlen);
|
|
if (0 == txlen) {
|
|
cts_err("spi write pack len: %d", txlen);
|
|
return -EINVAL;
|
|
}
|
|
ret = cts_tcs_spi_xtrans(cts_dev, cts_dev->pdata->spi_tx_buf, txlen,
|
|
cts_dev->pdata->spi_rx_buf, TCS_TAIL_SIZE, 50);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
int cts_tcs_tool_xtrans(struct cts_device *cts_dev, u8 *tx, size_t txlen,
|
|
u8 *rx, size_t rxlen)
|
|
{
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
int ret;
|
|
memcpy(cts_dev->pdata->i2c_fifo_buf, tx, txlen);
|
|
|
|
ret = cts_tcs_i2c_trans(cts_dev->pdata, CTS_DEV_NORMAL_MODE_I2CADDR,
|
|
cts_dev->pdata->i2c_fifo_buf, txlen, cts_dev->pdata->i2c_rbuf, rxlen,
|
|
3, 1);
|
|
if (ret == 0)
|
|
memcpy(rx, cts_dev->pdata->i2c_rbuf, rxlen);
|
|
|
|
return ret;
|
|
#else
|
|
return cts_tcs_spi_xtrans(cts_dev, tx, txlen, rx, rxlen, 1);
|
|
#endif
|
|
}
|
|
|
|
int cts_tcs_read(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *buf, size_t len)
|
|
{
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
return cts_tcs_i2c_read(cts_dev, cmd, buf, len);
|
|
#else
|
|
return cts_tcs_spi_read(cts_dev, cmd, buf, len);
|
|
#endif
|
|
}
|
|
int cts_tcs_write(struct cts_device *cts_dev,
|
|
u16 cmd, u8 *buf, size_t len)
|
|
{
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
return cts_tcs_i2c_write(cts_dev, cmd, buf, len);
|
|
#else
|
|
return cts_tcs_spi_write(cts_dev, cmd, buf, len);
|
|
#endif
|
|
}
|
|
|
|
static int cts_tcs_set_krang_stop(struct cts_device *cts_dev)
|
|
{
|
|
uint8_t stop = 1;
|
|
int ret;
|
|
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
ret = cts_tcs_i2c_set_krang_stop(cts_dev, CMD_TP_STD_CMD_SET_KRANG_STOP,
|
|
&stop, sizeof(stop));
|
|
#else
|
|
ret = cts_tcs_spi_set_krang_stop(cts_dev, CMD_TP_STD_CMD_SET_KRANG_STOP,
|
|
&stop, sizeof(stop));
|
|
#endif
|
|
if (ret < 0) {
|
|
cts_err("Set krang stop failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_hwid_info(struct cts_device *cts_dev, u8 *info)
|
|
{
|
|
u8 buf[12] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_CHIP_HW_ID_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
memcpy(info, buf, sizeof(buf));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_fw_ver(struct cts_device *cts_dev, u16 *fwver)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_FW_VER_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*fwver = buf[0] | (buf[1] << 8);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_lib_ver(struct cts_device *cts_dev, u16 *libver)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_FW_VER_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*libver = buf[2] | (buf[3] << 8);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_fw_id(struct cts_device *cts_dev, u16 *fwid)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_CHIP_FW_ID_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*fwid = buf[0] | (buf[1] << 8);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_ddi_ver(struct cts_device *cts_dev, u8 *ddiver)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_DDI_CODE_VER_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*ddiver = buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_res_x(struct cts_device *cts_dev, u16 *res_x)
|
|
{
|
|
u8 buf[10] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_TOUCH_XY_INFO_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*res_x = buf[0] | (buf[1] << 8);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_res_y(struct cts_device *cts_dev, u16 *res_y)
|
|
{
|
|
u8 buf[10] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_TOUCH_XY_INFO_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*res_y = buf[2] | (buf[3] << 8);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_rows(struct cts_device *cts_dev, u8 *rows)
|
|
{
|
|
u8 buf[10] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_TOUCH_XY_INFO_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*rows = buf[5];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_cols(struct cts_device *cts_dev, u8 *cols)
|
|
{
|
|
u8 buf[10] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_TOUCH_XY_INFO_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*cols = buf[4];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_rx_tx_info(struct cts_device *cts_dev, u8 *info)
|
|
{
|
|
u8 buf[8] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_IC_INFO_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
memcpy(info, buf, sizeof(buf));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_panel_rx_tx_info(struct cts_device *cts_dev, u8 *info)
|
|
{
|
|
u8 buf[15] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_PAD_PANEL_INFO_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
memcpy(info, buf, sizeof(buf));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_flip_x(struct cts_device *cts_dev, bool *flip_x)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_COORD_FLIP_X_EN_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*flip_x = !!buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_flip_y(struct cts_device *cts_dev, bool *flip_y)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_COORD_FLIP_Y_EN_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*flip_y = !!buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_swap_axes(struct cts_device *cts_dev, bool *swap_axes)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_COORD_SWAP_AXES_EN_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*swap_axes = !!buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_int_mode(struct cts_device *cts_dev, u8 *int_mode)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_INT_MODE_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*int_mode = buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_int_keep_time(struct cts_device *cts_dev,
|
|
u16 *int_keep_time)
|
|
{
|
|
u8 buf[2] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_INT_KEEP_TIME_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*int_keep_time = (buf[0] | (buf[1] << 8));
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
int cts_tcs_get_rawdata_target(struct cts_device *cts_dev,
|
|
u16 *rawdata_target)
|
|
{
|
|
u8 buf[2] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_CNEG_OPTIONS_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*rawdata_target = (buf[0] | (buf[1] << 8));
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
int cts_tcs_get_esd_method(struct cts_device *cts_dev, u8 *esd_method)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_DDI_ESD_OPTIONS_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*esd_method = buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_esd_protection(struct cts_device *cts_dev,
|
|
u8 *esd_protection)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
buf[0] = 0x01;
|
|
buf[1] = 0x56;
|
|
buf[2] = 0x81;
|
|
buf[3] = 0x00;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW,
|
|
buf, sizeof(buf));
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW,
|
|
esd_protection, sizeof(u8));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_get_data_ready_flag(struct cts_device *cts_dev, u8 *ready)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_DAT_RDY_FLAG_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*ready = buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_clr_gstr_ready_flag(struct cts_device *cts_dev)
|
|
{
|
|
u8 ready = 0;
|
|
|
|
return cts_tcs_write(cts_dev, CMD_GSTR_DAT_RDY_FLAG_GSTR_RW,
|
|
&ready, sizeof(ready));
|
|
}
|
|
|
|
static int cts_tcs_clr_data_ready_flag(struct cts_device *cts_dev)
|
|
{
|
|
u8 ready = 0;
|
|
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_DAT_RDY_FLAG_RW,
|
|
&ready, sizeof(ready));
|
|
}
|
|
|
|
int cts_tcs_read_hw_reg(struct cts_device *cts_dev, u32 addr,
|
|
u8 *regbuf, size_t size)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
buf[0] = 1;
|
|
buf[1] = ((addr >> 0) & 0xFF);
|
|
buf[2] = ((addr >> 8) & 0xFF);
|
|
buf[3] = ((addr >> 16) & 0xFF);
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW,
|
|
buf, sizeof(buf));
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_TP_DATA_READ_START_RO, regbuf, size);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_write_hw_reg(struct cts_device *cts_dev, u32 addr,
|
|
u8 *regbuf, size_t size)
|
|
{
|
|
u8 *buf;
|
|
int ret;
|
|
|
|
buf = kmalloc(size + 6, GFP_KERNEL);
|
|
if (buf == NULL)
|
|
return -ENOMEM;
|
|
|
|
buf[0] = ((size >> 0) & 0xFF);
|
|
buf[1] = ((size >> 8) & 0xFF);
|
|
buf[2] = ((addr >> 0) & 0xFF);
|
|
buf[3] = ((addr >> 8) & 0xFF);
|
|
buf[4] = ((addr >> 16) & 0xFF);
|
|
buf[5] = 0x00;
|
|
memcpy(buf + 6, regbuf, size);
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_WR_REG_RAM_SEQUENCE_WO,
|
|
buf, size + 6);
|
|
if (ret != 0) {
|
|
kfree(buf);
|
|
return ret;
|
|
}
|
|
|
|
kfree(buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_read_ddi_reg(struct cts_device *cts_dev, u32 addr,
|
|
u8 *regbuf, size_t size)
|
|
{
|
|
u8 buf[2] = { 0 };
|
|
int ret;
|
|
|
|
buf[0] = 2;
|
|
buf[1] = addr;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW,
|
|
buf, sizeof(buf));
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_TP_DATA_READ_START_RO, regbuf, size);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cts_tcs_write_ddi_reg(struct cts_device *cts_dev, u32 addr,
|
|
u8 *regbuf, size_t size)
|
|
{
|
|
u8 *buf;
|
|
int ret;
|
|
|
|
buf = kmalloc(size + 6, GFP_KERNEL);
|
|
if (buf == NULL)
|
|
return -ENOMEM;
|
|
|
|
buf[0] = ((size >> 0) & 0xFF);
|
|
buf[1] = ((size >> 8) & 0xFF);
|
|
buf[2] = addr;
|
|
buf[3] = 0;
|
|
buf[4] = 0;
|
|
buf[5] = 0;
|
|
memcpy(buf + 6, regbuf, size);
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_WR_DDI_REG_SEQUENCE_WO,
|
|
buf, size + 6);
|
|
if (ret != 0) {
|
|
kfree(buf);
|
|
return ret;
|
|
}
|
|
|
|
kfree(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int cts_tcs_read_reg(struct cts_device *cts_dev, u32 addr,
|
|
u8 *regbuf, size_t size)
|
|
{
|
|
return cts_tcs_read(cts_dev, CMD_SYS_STS_READ_RO, regbuf, size);
|
|
}
|
|
|
|
int cts_tcs_write_reg(struct cts_device *cts_dev, u32 addr,
|
|
u8 *regbuf, size_t size)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
buf[0] = 0x01;
|
|
buf[1] = ((addr >> 0) & 0xFF);
|
|
buf[2] = ((addr >> 8) & 0xFF);
|
|
buf[3] = ((addr >> 16) & 0xFF);
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW,
|
|
buf, sizeof(buf));
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_TP_DATA_OFFSET_AND_TYPE_CFG_RW,
|
|
regbuf, sizeof(buf));
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_calc_int_data_size(struct cts_device *cts_dev)
|
|
{
|
|
#define INT_DATA_TYPE_U8_SIZ \
|
|
(cts_dev->hwdata->num_row * cts_dev->hwdata->num_col * sizeof(u8))
|
|
#define INT_DATA_TYPE_U16_SIZ \
|
|
(cts_dev->hwdata->num_row * cts_dev->hwdata->num_col * sizeof(u16))
|
|
|
|
u16 data_types = cts_dev->fwdata.int_data_types;
|
|
bool is_stylus = !!(cts_dev->fwdata.int_data_types & BIT(14));
|
|
u8 data_method = cts_dev->fwdata.int_data_method;
|
|
|
|
u8 pen_freq_num = cts_dev->fwdata.pen_freq_num;
|
|
u8 cascade_num = cts_dev->fwdata.cascade_num;
|
|
u8 pc_cols = cts_dev->fwdata.pc_cols;
|
|
u8 pc_rows = cts_dev->fwdata.pc_rows;
|
|
u8 pr_cols = cts_dev->fwdata.pr_cols;
|
|
u8 pr_rows = cts_dev->fwdata.pr_rows;
|
|
|
|
cts_dev->fwdata.int_data_size = (TOUCH_INFO_SIZE + TCS_TAIL_SIZE);
|
|
|
|
if (data_method == INT_DATA_METHOD_NONE) {
|
|
return 0;
|
|
} else if (data_method == INT_DATA_METHOD_DEBUG) {
|
|
cts_dev->fwdata.int_data_size += INT_DATA_TYPE_U16_SIZ;
|
|
return 0;
|
|
}
|
|
|
|
if (data_types != INT_DATA_TYPE_NONE) {
|
|
cts_dev->fwdata.int_data_size = INT_DATA_HEADER_SIZE;
|
|
if (is_stylus) {
|
|
cts_dev->fwdata.int_data_size += (pr_rows * pr_cols + pc_rows * pc_cols)
|
|
* pen_freq_num * sizeof(u16) * cascade_num;
|
|
} else {
|
|
if ((data_types & INT_DATA_TYPE_CNEGDATA)) {
|
|
cts_dev->fwdata.int_data_size += INT_DATA_TYPE_U8_SIZ;
|
|
} else {
|
|
cts_dev->fwdata.int_data_size += INT_DATA_TYPE_U16_SIZ;
|
|
}
|
|
}
|
|
|
|
cts_dev->fwdata.int_data_size += TCS_TAIL_SIZE;
|
|
}
|
|
|
|
cts_info("data_method:%d, data_type:%04x", data_method, data_types);
|
|
cts_info("data_size:%d", cts_dev->fwdata.int_data_size);
|
|
return 0;
|
|
}
|
|
|
|
int cts_tcs_polling_data(struct cts_device *cts_dev,
|
|
u8 *buf, size_t size)
|
|
{
|
|
int retries = 100;
|
|
u8 ready = 0;
|
|
int ret;
|
|
|
|
size_t data_size = cts_dev->fwdata.int_data_size;
|
|
|
|
do {
|
|
ret = cts_tcs_get_data_ready_flag(cts_dev, &ready);
|
|
if (!ret && ready)
|
|
break;
|
|
mdelay(10);
|
|
} while (!ready && --retries);
|
|
cts_info("get data rdy, retries left %d", retries);
|
|
|
|
if (!ready) {
|
|
cts_err("time out wait for data rdy");
|
|
return -EIO;
|
|
}
|
|
|
|
retries = 3;
|
|
do {
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
ret = cts_tcs_i2c_read_touch(cts_dev, CMD_GET_DATA_BY_POLLING_RO,
|
|
cts_dev->int_data, data_size);
|
|
#else
|
|
ret = cts_tcs_spi_read_1_cs(cts_dev, CMD_GET_DATA_BY_POLLING_RO,
|
|
cts_dev->int_data, data_size);
|
|
#endif
|
|
mdelay(1);
|
|
} while (ret && --retries);
|
|
|
|
if (cts_tcs_clr_data_ready_flag(cts_dev))
|
|
cts_err("Clear data ready flag failed");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void cts_rotate_data(struct cts_device *cts_dev,
|
|
u8 *dst, u8 *src, enum int_data_type type)
|
|
{
|
|
int rows = cts_dev->fwdata.rows;
|
|
int cols = cts_dev->fwdata.cols;
|
|
u16 *u16dst = (u16 *)dst;
|
|
u16 *u16src = (u16 *)src;
|
|
int i, j;
|
|
|
|
if ((type & 0x3f) ==INT_DATA_TYPE_CNEGDATA) {
|
|
for (i = 0; i < cols; i++) {
|
|
for (j = 0; j < rows; j++) {
|
|
*dst++ = src[j * cols + i];
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < cols; i++) {
|
|
for (j = 0; j < rows; j++) {
|
|
*u16dst++ = u16src[j * cols + i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int tool_polling_data(struct cts_device *cts_dev, u8 *buf,
|
|
enum int_data_type type)
|
|
{
|
|
u8 old_int_data_method;
|
|
u16 old_int_data_types;
|
|
int retries = 5;
|
|
int ret;
|
|
|
|
old_int_data_types = cts_dev->fwdata.int_data_types;
|
|
old_int_data_method = cts_dev->fwdata.int_data_method;
|
|
|
|
cts_set_int_data_types(cts_dev, type);
|
|
cts_set_int_data_method(cts_dev, INT_DATA_METHOD_POLLING);
|
|
|
|
while (retries--) {
|
|
ret = cts_tcs_polling_data(cts_dev, buf, 0);
|
|
if (!ret) {
|
|
memcpy(buf, cts_dev->int_data, cts_dev->fwdata.int_data_size);
|
|
break;
|
|
}
|
|
}
|
|
|
|
cts_set_int_data_types(cts_dev, old_int_data_types);
|
|
cts_set_int_data_method(cts_dev, old_int_data_method);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int polling_data(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
enum int_data_type type)
|
|
{
|
|
u8 old_int_data_method;
|
|
u16 old_int_data_types;
|
|
int offset = INT_DATA_HEADER_SIZE;
|
|
int retries = 5;
|
|
int ret;
|
|
|
|
old_int_data_types = cts_dev->fwdata.int_data_types;
|
|
old_int_data_method = cts_dev->fwdata.int_data_method;
|
|
|
|
cts_set_int_data_types(cts_dev, type);
|
|
cts_set_int_data_method(cts_dev, INT_DATA_METHOD_POLLING);
|
|
|
|
while (retries--) {
|
|
ret = cts_tcs_polling_data(cts_dev, buf, size);
|
|
if (!ret) {
|
|
if (cts_dev->hwdata->hwid == CTS_DEV_HWID_ICNL9951R) {
|
|
cts_rotate_data(cts_dev, buf, cts_dev->int_data + offset, type);
|
|
} else {
|
|
memcpy(buf, cts_dev->int_data + offset, size);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
cts_set_int_data_types(cts_dev, old_int_data_types);
|
|
cts_set_int_data_method(cts_dev, old_int_data_method);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int cts_polling_test_data(struct cts_device *cts_dev,
|
|
u8 *buf, size_t size, enum int_data_type type)
|
|
{
|
|
int offset = INT_DATA_HEADER_SIZE;
|
|
int retries = 5;
|
|
int ret;
|
|
|
|
while (retries--) {
|
|
ret = cts_tcs_polling_data(cts_dev, buf, size);
|
|
if (!ret) {
|
|
if (cts_dev->int_data[INT_DATA_VALID_INDEX]) {
|
|
memcpy(buf, cts_dev->int_data + offset, size);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_tool_get_rawdata(struct cts_device *cts_dev, u8 *buf, u16 data_source)
|
|
{
|
|
return tool_polling_data(cts_dev, buf, data_source | INT_DATA_TYPE_RAWDATA);
|
|
}
|
|
|
|
int cts_tcs_tool_get_manual_diff(struct cts_device *cts_dev, u8 *buf, u16 data_source)
|
|
{
|
|
return tool_polling_data(cts_dev, buf, data_source | INT_DATA_TYPE_MANUAL_DIFF);
|
|
}
|
|
|
|
int cts_tcs_tool_get_real_diff(struct cts_device *cts_dev, u8 *buf, u16 data_source)
|
|
{
|
|
return tool_polling_data(cts_dev, buf, data_source | INT_DATA_TYPE_REAL_DIFF);
|
|
}
|
|
|
|
int cts_tcs_tool_get_basedata(struct cts_device *cts_dev, u8 *buf, u16 data_source)
|
|
{
|
|
return tool_polling_data(cts_dev, buf, data_source | INT_DATA_TYPE_BASEDATA);
|
|
}
|
|
|
|
|
|
int cts_tcs_top_get_rawdata(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
u16 data_source)
|
|
{
|
|
return polling_data(cts_dev, buf, size, data_source | INT_DATA_TYPE_RAWDATA);
|
|
}
|
|
|
|
int cts_tcs_top_get_manual_diff(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
u16 data_source)
|
|
{
|
|
return polling_data(cts_dev, buf, size, data_source | INT_DATA_TYPE_MANUAL_DIFF);
|
|
}
|
|
|
|
int cts_tcs_top_get_real_diff(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
u16 data_source)
|
|
{
|
|
return polling_data(cts_dev, buf, size, data_source | INT_DATA_TYPE_REAL_DIFF);
|
|
}
|
|
|
|
int cts_tcs_top_get_noise_diff(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
u16 data_source)
|
|
{
|
|
return polling_data(cts_dev, buf, size, data_source | INT_DATA_TYPE_NOISE_DIFF);
|
|
}
|
|
|
|
int cts_tcs_top_get_basedata(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
u16 data_source)
|
|
{
|
|
return polling_data(cts_dev, buf, size, data_source | INT_DATA_TYPE_BASEDATA);
|
|
}
|
|
|
|
int cts_tcs_top_get_cnegdata(struct cts_device *cts_dev, u8 *buf, size_t size,
|
|
u16 data_source)
|
|
{
|
|
return polling_data(cts_dev, buf, size, data_source | INT_DATA_TYPE_CNEGDATA);
|
|
}
|
|
|
|
int cts_tcs_reset_device(struct cts_device *cts_dev)
|
|
{
|
|
#ifdef CONFIG_CTS_ICTYPE_ICNL9922
|
|
u8 buf[2] = { 0x01, 0xfe };
|
|
int ret;
|
|
|
|
cts_info("ICNL9922 use software reset");
|
|
/* normal */
|
|
cts_info("tp reset in normal mode");
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_RESET_WO,
|
|
buf, sizeof(buf));
|
|
if (!ret) {
|
|
mdelay(40);
|
|
return 0;
|
|
}
|
|
/* program */
|
|
cts_info("tp reset in program mode");
|
|
ret = cts_hw_reg_writeb(cts_dev, CTS_DEV_HW_REG_RESET_CONFIG, 0xfd);
|
|
if (!ret) {
|
|
mdelay(40);
|
|
return 0;
|
|
}
|
|
return ret;
|
|
#else
|
|
return cts_plat_reset_device(cts_dev->pdata);
|
|
#endif
|
|
}
|
|
|
|
int cts_tcs_set_int_test(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_INT_TEST_EN_RW, &enable,
|
|
sizeof(enable));
|
|
}
|
|
|
|
int cts_tcs_set_int_pin(struct cts_device *cts_dev, u8 high)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_SET_INT_PIN_RW, &high,
|
|
sizeof(high));
|
|
}
|
|
|
|
int cts_tcs_get_module_id(struct cts_device *cts_dev, u32 *modId)
|
|
{
|
|
u8 buf[4] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_INFO_MODULE_ID_RO, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*modId = *(u32 *)buf;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
int cts_tcs_get_gestureinfo(struct cts_device *cts_dev,
|
|
struct cts_device_gesture_info *gesture_info)
|
|
{
|
|
size_t size = sizeof(*gesture_info) + TCS_TAIL_SIZE;
|
|
int ret;
|
|
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
ret = cts_tcs_i2c_read_touch(cts_dev, CMD_TP_DATA_COORDINATES_RO,
|
|
cts_dev->int_data, size);
|
|
#else
|
|
ret = cts_tcs_spi_read_1_cs(cts_dev, CMD_TP_DATA_COORDINATES_RO,
|
|
cts_dev->int_data, size);
|
|
#endif
|
|
if (cts_tcs_clr_gstr_ready_flag(cts_dev)) {
|
|
cts_err("Clear gesture ready flag failed");
|
|
}
|
|
if (ret < 0) {
|
|
cts_err("Get gesture info failed: ret=%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
memcpy(gesture_info, cts_dev->int_data, sizeof(*gesture_info));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_touchinfo(struct cts_device *cts_dev,
|
|
struct cts_device_touch_info *touch_info)
|
|
{
|
|
size_t size = cts_dev->fwdata.int_data_size;
|
|
int ret;
|
|
|
|
memset(touch_info, 0, sizeof(*touch_info));
|
|
|
|
#ifdef CONFIG_CTS_I2C_HOST
|
|
ret = cts_tcs_i2c_read_touch(cts_dev, CMD_TP_DATA_COORDINATES_RO,
|
|
cts_dev->int_data, size);
|
|
if (unlikely(ret != 0)) {
|
|
cts_err("cts_tcs_i2c_read_touch failed");
|
|
return ret;
|
|
}
|
|
#else
|
|
ret = cts_tcs_spi_read_1_cs(cts_dev, CMD_TP_DATA_COORDINATES_RO,
|
|
cts_dev->int_data, size);
|
|
if (unlikely(ret != 0)) {
|
|
cts_err("tcs_spi_read_1_cs failed");
|
|
return ret;
|
|
}
|
|
#endif
|
|
memcpy(touch_info, cts_dev->int_data, sizeof(*touch_info));
|
|
|
|
#ifdef CFG_CTS_HEARTBEAT_MECHANISM
|
|
if (unlikely((touch_info->debug_msg.reset_flag & 0xFFFFFF) != 0xFFFFFF
|
|
|| (touch_info->debug_msg.reset_flag & 0xFFFF) != 0xFFFF)) {
|
|
cts_err("reset flag:0x%08x error", touch_info->debug_msg.reset_flag);
|
|
cts_show_touch_debug_msg(&touch_info->debug_msg);
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_touch_status(struct cts_device *cts_dev)
|
|
{
|
|
return cts_tcs_read(cts_dev, CMD_TP_DATA_STATUS_RO,
|
|
cts_dev->int_data, TOUCH_INFO_SIZE);
|
|
}
|
|
|
|
int cts_tcs_get_workmode(struct cts_device *cts_dev, u8 *workmode)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_CURRENT_WORKMODE_RO,
|
|
&buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*workmode = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_workmode(struct cts_device *cts_dev, u8 workmode)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_WORK_MODE_RW,
|
|
&workmode, sizeof(workmode));
|
|
}
|
|
|
|
int cts_tcs_set_openshort_mode(struct cts_device *cts_dev, u8 mode)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_OPENSHORT_MODE_SEL_RW, &mode,
|
|
sizeof(mode));
|
|
}
|
|
|
|
int cts_tcs_get_curr_mode(struct cts_device *cts_dev, u8 *currmode)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_CURRENT_WORKMODE_RO,
|
|
&buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*currmode = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_krang_current_workmode(struct cts_device *cts_dev, u8 *workmode)
|
|
{
|
|
u8 buf = 0;
|
|
int ret = 0;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_KRANG_CURRENT_WORKMODE_RO,
|
|
&buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*workmode = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_krang_workmode(struct cts_device *cts_dev, u8 workmode)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_KRANG_WORK_MODE_RW, &workmode,
|
|
sizeof(workmode));
|
|
}
|
|
|
|
/*Tab A9 code for AX6739A-953 by suyurui at 20230609 end*/
|
|
int cts_tcs_set_tx_vol(struct cts_device *cts_dev, u8 txvol)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_VSTIM_LVL_RW, &txvol,
|
|
sizeof(txvol));
|
|
}
|
|
|
|
int cts_tcs_set_short_test_type(struct cts_device *cts_dev,
|
|
u8 short_type)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_OPENSHORT_SHORT_SEL_RW,
|
|
&short_type, sizeof(short_type));
|
|
}
|
|
|
|
int cts_tcs_is_openshort_enabled(struct cts_device *cts_dev, u8 *enabled)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_OPENSHORT_EN_RW, &buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*enabled = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_openshort_enable(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_OPENSHORT_EN_RW, &enable, sizeof(enable));
|
|
}
|
|
|
|
int cts_tcs_set_esd_enable(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_DDI_ESD_EN_RW, &enable, sizeof(enable));
|
|
}
|
|
|
|
int cts_tcs_is_cneg_enabled(struct cts_device *cts_dev, u8 *enabled)
|
|
{
|
|
return cts_tcs_read(cts_dev, CMD_CNEG_EN_RW, enabled, sizeof(*enabled));
|
|
}
|
|
|
|
int cts_tcs_is_mnt_enabled(struct cts_device *cts_dev, u8 *enabled)
|
|
{
|
|
return cts_tcs_read(cts_dev, CMD_MNT_EN_RW, enabled, sizeof(*enabled));
|
|
}
|
|
|
|
int cts_tcs_set_cneg_enable(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_CNEG_EN_RW, &enable, sizeof(enable));
|
|
}
|
|
|
|
int cts_tcs_set_mnt_enable(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_MNT_EN_RW, &enable, sizeof(enable));
|
|
}
|
|
|
|
int cts_tcs_is_display_on(struct cts_device *cts_dev, u8 *display_on)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_OPENSHORT_SHORT_DISP_ON_EN_RW,
|
|
&buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*display_on = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_pwr_mode(struct cts_device *cts_dev, u8 pwr_mode)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_PWR_STATE_RW,
|
|
&pwr_mode, sizeof(pwr_mode));
|
|
}
|
|
|
|
int cts_tcs_set_display_on(struct cts_device *cts_dev, u8 display_on)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_OPENSHORT_SHORT_DISP_ON_EN_RW,
|
|
&display_on, sizeof(display_on));
|
|
}
|
|
|
|
|
|
int cts_tcs_set_charger_plug(struct cts_device *cts_dev, u8 set)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set charger enable:%d", set);
|
|
status->charger = set;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_CHARGER_PLUGIN_RW, &set, 1);
|
|
if (ret < 0) {
|
|
cts_info("Set charger failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_charger_plug(struct cts_device *cts_dev, u8 *isset)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_CHARGER_PLUGIN_RW,&buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*isset = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_earjack_plug(struct cts_device *cts_dev, u8 set)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set earjack enable:%d", set);
|
|
|
|
status->earjack = set;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_EP_PLUGIN_RW, &set, 1);
|
|
if (ret) {
|
|
cts_info("Set earjack failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_earjack_plug(struct cts_device *cts_dev, u8 *isset)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_EP_PLUGIN_RW, &buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*isset = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_panel_direction(struct cts_device *cts_dev, u8 direction)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_PANEL_DIRECTION_RW,
|
|
&direction, sizeof(direction));
|
|
}
|
|
|
|
int cts_tcs_get_panel_direction(struct cts_device *cts_dev, u8 *direction)
|
|
{
|
|
u8 buf = 0;
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_PANEL_DIRECTION_RW,
|
|
&buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*direction = buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_game_mode(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set game enable:%d", enable);
|
|
|
|
status->game = enable;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_GAME_MODE_RW,
|
|
&enable, sizeof(enable));
|
|
if (ret) {
|
|
cts_err("Set game failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_game_mode(struct cts_device *cts_dev, u8 *enabled)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_GAME_MODE_RW, buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*enabled = buf[0];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_has_int_data(struct cts_device *cts_dev, bool *has)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_DATA_CAPTURE_SUPPORT_RO,
|
|
buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*has = !!buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_get_int_data_types(struct cts_device *cts_dev, u16 *type)
|
|
{
|
|
u8 buf[2] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_DATA_CAPTURE_FUNC_MAP_RW,
|
|
buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*type = buf[0] | (buf[1] << 8);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_int_data_types(struct cts_device *cts_dev, u16 type)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_DATA_CAPTURE_FUNC_MAP_RW,
|
|
(u8 *) &type, sizeof(type));
|
|
}
|
|
|
|
int cts_tcs_get_int_data_method(struct cts_device *cts_dev, u8 *method)
|
|
{
|
|
u8 buf[1] = { 0 };
|
|
int ret;
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_DATA_CAPTURE_EN_RW,
|
|
buf, sizeof(buf));
|
|
if (ret == 0) {
|
|
*method = buf[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_int_data_method(struct cts_device *cts_dev, u8 method)
|
|
{
|
|
return cts_tcs_write(cts_dev, CMD_SYS_STS_DATA_CAPTURE_EN_RW,
|
|
&method, sizeof(method));
|
|
}
|
|
|
|
int cts_tcs_set_proximity_mode(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set proximity enable:%d", enable);
|
|
status->proximity = enable;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_PARA_PROXI_EN_RW, &enable, 1);
|
|
if (ret != 0) {
|
|
cts_err("Set proximity failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_set_knuckle_mode(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set knuckle enable:%d", enable);
|
|
status->knuckle = enable;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_PARA_KUNCKLE_RW, &enable, 1);
|
|
if (ret != 0) {
|
|
cts_err("Set knuckle failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_set_glove_mode(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set glove enable:%d", enable);
|
|
status->glove = enable;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_HI_SENSE_EN_RW, &enable, 1);
|
|
if (ret != 0) {
|
|
cts_err("Set glove failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int cts_tcs_set_pocket_enable(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
int ret;
|
|
|
|
cts_info("Set pocket enable:%d", enable);
|
|
status->pocket = enable;
|
|
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_POCKET_MODE_EN_RW, &enable, 1);
|
|
if (ret != 0) {
|
|
cts_err("Set pocket failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void cts_tcs_reinit_fw_status(struct cts_device *cts_dev)
|
|
{
|
|
struct cts_firmware_status *status = (struct cts_firmware_status *)
|
|
&cts_dev->rtdata.firmware_status;
|
|
cts_tcs_set_charger_plug(cts_dev, status->charger);
|
|
cts_tcs_set_proximity_mode(cts_dev, status->proximity);
|
|
cts_tcs_set_earjack_plug(cts_dev, status->earjack);
|
|
cts_tcs_set_knuckle_mode(cts_dev, status->knuckle);
|
|
cts_tcs_set_glove_mode(cts_dev, status->glove);
|
|
cts_tcs_set_pocket_enable(cts_dev, status->pocket);
|
|
cts_tcs_set_game_mode(cts_dev, status->game);
|
|
}
|
|
|
|
|
|
int cts_tcs_set_product_en(struct cts_device *cts_dev, u8 enable)
|
|
{
|
|
int ret;
|
|
ret = cts_tcs_write(cts_dev, CMD_SYS_STS_PRODUCTION_TEST_EN_RW,
|
|
&enable, sizeof(enable));
|
|
if (ret) {
|
|
cts_err("Set product_en failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cts_tcs_wait_krang_stop(struct cts_device *cts_dev)
|
|
{
|
|
uint8_t status = 1;
|
|
int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
ret = cts_tcs_set_krang_stop(cts_dev);
|
|
if (ret < 0) {
|
|
cts_err("Set krang stop failed!");
|
|
mdelay(1);
|
|
continue;
|
|
}
|
|
|
|
ret = cts_tcs_read(cts_dev, CMD_SYS_STS_KRANG_WORK_STS_RO, &status, sizeof(status));
|
|
if (ret < 0) {
|
|
cts_err("Read krang stop status failed!");
|
|
mdelay(1);
|
|
continue;
|
|
}
|
|
|
|
if (0 == status) {
|
|
cts_info("krang flag was already stopped!");
|
|
return 0;
|
|
} else {
|
|
cts_err("Read krang stop status:%d != 0", status);
|
|
mdelay(1);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return -EBUSY;
|
|
}
|