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