kernel-brax3-ubuntu-touch/drivers/input/touchscreen/chipone-tddi/cts_platform.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

1307 lines
38 KiB
C
Executable file

#define LOG_TAG "Plat"
#include "cts_config.h"
#include "cts_platform.h"
#include "cts_core.h"
#include "cts_firmware.h"
#include "cts_sysfs.h"
#include "cts_tcs.h"
#ifdef CFG_CTS_FW_LOG_REDIRECT
size_t cts_plat_get_max_fw_log_size(struct cts_platform_data *pdata)
{
return CTS_FW_LOG_BUF_LEN;
}
u8 *cts_plat_get_fw_log_buf(struct cts_platform_data *pdata, size_t size)
{
return pdata->fw_log_buf;
}
#endif
size_t cts_plat_get_max_i2c_xfer_size(struct cts_platform_data *pdata)
{
return CFG_CTS_MAX_I2C_XFER_SIZE;
}
#ifdef CONFIG_CTS_I2C_HOST
u8 *cts_plat_get_i2c_xfer_buf(struct cts_platform_data *pdata, size_t xfer_size)
{
return pdata->i2c_fifo_buf;
}
int cts_plat_i2c_write(struct cts_platform_data *pdata, u8 i2c_addr,
const void *src, size_t len, int retry, int delay)
{
int ret = 0, retries = 0;
struct i2c_msg msg = {
.flags = 0,
.addr = i2c_addr,
.buf = (u8 *) src,
.len = len,
};
do {
ret = i2c_transfer(pdata->i2c_client->adapter, &msg, 1);
if (ret != 1) {
if (ret >= 0)
ret = -EIO;
if (delay)
mdelay(delay);
continue;
} else
return 0;
} while (++retries < retry);
return ret;
}
int cts_plat_i2c_read(struct cts_platform_data *pdata, u8 i2c_addr,
const u8 *wbuf, size_t wlen, void *rbuf, size_t rlen,
int retry, int delay)
{
int num_msg, ret = 0, retries = 0;
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
}
};
if (wbuf == NULL || wlen == 0)
num_msg = 1;
else
num_msg = 2;
do {
ret = i2c_transfer(pdata->i2c_client->adapter,
msgs + ARRAY_SIZE(msgs) - num_msg, num_msg);
if (ret != num_msg) {
if (ret >= 0)
ret = -EIO;
if (delay)
mdelay(delay);
continue;
} else
return 0;
} while (++retries < retry);
return ret;
}
#else
void dump_spi_common(const char *prefix, u8 *data, size_t datalen)
{
u8 str[1024];
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);
}
#ifdef CFG_CTS_MANUAL_CS
int cts_plat_set_cs(struct cts_platform_data *pdata, int val)
{
if (val)
gpio_set_value(pdata->cs_gpio, 1);
else
gpio_set_value(pdata->cs_gpio, 0);
return 0;
}
#endif
int cts_spi_send_recv(struct cts_platform_data *pdata, size_t len,
u8 *tx_buffer, u8 *rx_buffer)
{
struct chipone_ts_data *cts_data;
struct spi_message msg;
struct spi_transfer cmd = {
//.delay_usecs = 0, //drv deleted by chenjiaxi, there is no delay_usecs member in spi_transfer
.speed_hz = pdata->spi_speed * 1000u,
.tx_buf = tx_buffer,
.rx_buf = rx_buffer,
.len = len,
/* .tx_dma = 0, */
/* .rx_dma = 0, */
};
int ret = 0;
cts_data = container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
#ifdef CFG_CTS_MANUAL_CS
cts_plat_set_cs(pdata, 0);
#endif
spi_message_init(&msg);
spi_message_add_tail(&cmd, &msg);
ret = spi_sync(cts_data->spi_client, &msg);
if (ret)
cts_err("spi sync failed %d", ret);
udelay(100);
#ifdef CFG_CTS_MANUAL_CS
cts_plat_set_cs(pdata, 1);
#endif
return ret;
}
size_t cts_plat_get_max_spi_xfer_size(struct cts_platform_data *pdata)
{
return CFG_CTS_MAX_SPI_XFER_SIZE;
}
u8 *cts_plat_get_spi_xfer_buf(struct cts_platform_data *pdata, size_t xfer_size)
{
return pdata->spi_cache_buf;
}
int cts_plat_spi_write(struct cts_platform_data *pdata, u8 dev_addr,
const void *src, size_t len, int retry, int delay)
{
int ret = 0, retries = 0;
u16 crc16_calc;
size_t data_len;
if (len > CFG_CTS_MAX_SPI_XFER_SIZE) {
cts_err("write too much data:wlen=%zu", len);
return -EIO;
}
if (pdata->cts_dev->rtdata.program_mode) {
#ifdef CONFIG_CTS_ICTYPE_ICNL9922C
data_len = len - 3;
pdata->spi_tx_buf[0] = dev_addr;
memcpy(&pdata->spi_tx_buf[1], src, 3);
put_unaligned_be24(data_len, &pdata->spi_tx_buf[4]);
crc16_calc = (u16) cts_crc16(pdata->spi_tx_buf, 7);
put_unaligned_be16(~crc16_calc, &pdata->spi_tx_buf[7]);
memcpy(&pdata->spi_tx_buf[13], (char *)src + 3, data_len);
crc16_calc = (u16) cts_crc16((char *)src + 3, data_len);
put_unaligned_be16(~crc16_calc, &pdata->spi_tx_buf[len + 10]);
memset(pdata->spi_tx_buf + len + 12, 0, 3);
do {
ret = cts_spi_send_recv(pdata, len + 15, pdata->spi_tx_buf,
pdata->spi_rx_buf);
if (ret) {
cts_err("SPI write failed %d", ret);
if (delay)
mdelay(delay);
} else
return 0;
} while (++retries < retry);
#else
pdata->spi_tx_buf[0] = dev_addr;
memcpy(&pdata->spi_tx_buf[1], src, len);
do {
ret = cts_spi_send_recv(pdata, len + 1, pdata->spi_tx_buf,
pdata->spi_rx_buf);
if (ret) {
cts_err("SPI write failed %d", ret);
if (delay)
mdelay(delay);
} else
return 0;
} while (++retries < retry);
#endif
} else {
data_len = len - 2;
pdata->spi_tx_buf[0] = dev_addr;
pdata->spi_tx_buf[1] = *((u8 *) src + 1);
pdata->spi_tx_buf[2] = *((u8 *) src);
put_unaligned_le16(data_len, &pdata->spi_tx_buf[3]);
crc16_calc = (u16) cts_crc32(pdata->spi_tx_buf, 5);
put_unaligned_le16(crc16_calc, &pdata->spi_tx_buf[5]);
memcpy(&pdata->spi_tx_buf[7], (char *)src + 2, data_len);
crc16_calc = (u16) cts_crc32((char *)src + 2, data_len);
put_unaligned_le16(crc16_calc, &pdata->spi_tx_buf[7 + data_len]);
do {
ret = cts_spi_send_recv(pdata, len + 7, pdata->spi_tx_buf,
pdata->spi_rx_buf);
udelay(10 * data_len);
if (ret) {
cts_err("SPI write failed %d", ret);
if (delay)
mdelay(delay);
} else
return 0;
} while (++retries < retry);
}
return ret;
}
int cts_plat_spi_read(struct cts_platform_data *pdata, u8 dev_addr,
const u8 *wbuf, size_t wlen, void *rbuf, size_t rlen,
int retry, int delay)
{
int ret = 0, retries = 0;
u16 crc16_calc, crc16_recv;
if (wlen > CFG_CTS_MAX_SPI_XFER_SIZE
|| rlen > CFG_CTS_MAX_SPI_XFER_SIZE) {
cts_err("write/read too much data:wlen=%zd, rlen=%zd", wlen, rlen);
return -EIO;
}
if (pdata->cts_dev->rtdata.program_mode) {
#ifdef CONFIG_CTS_ICTYPE_ICNL9922C
memset(pdata->spi_tx_buf, 0, CFG_CTS_MAX_SPI_XFER_SIZE);
pdata->spi_tx_buf[0] = dev_addr | 0x01;
memcpy(&pdata->spi_tx_buf[1], wbuf, wlen);
put_unaligned_be24(rlen, &pdata->spi_tx_buf[4]);
crc16_calc = (u16) cts_crc16(pdata->spi_tx_buf, 7);
put_unaligned_be16(~crc16_calc, &pdata->spi_tx_buf[7]);
do {
ret = cts_spi_send_recv(pdata, wlen + rlen + 15,
pdata->spi_tx_buf, pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
memcpy(rbuf, pdata->spi_rx_buf + wlen + 10, rlen);
crc16_calc = (u16) cts_crc16(rbuf, rlen);
crc16_recv = get_unaligned_be16(&pdata->spi_rx_buf[wlen + rlen + 10]);
if (crc16_recv != (uint16_t)(~crc16_calc)) {
cts_err("SPI RX CRC error: rx_crc %04x != %04x",
crc16_recv, ~crc16_calc);
continue;
}
return 0;
} while (++retries < retry);
#else
pdata->spi_tx_buf[0] = dev_addr | 0x01;
memcpy(&pdata->spi_tx_buf[1], wbuf, wlen);
do {
ret = cts_spi_send_recv(pdata, rlen + 5, pdata->spi_tx_buf,
pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
memcpy(rbuf, pdata->spi_rx_buf + 5, rlen);
return 0;
} while (++retries < retry);
#endif
} else {
do {
if (wlen != 0) {
pdata->spi_tx_buf[0] = dev_addr | 0x01;
pdata->spi_tx_buf[1] = wbuf[1];
pdata->spi_tx_buf[2] = wbuf[0];
put_unaligned_le16(rlen, &pdata->spi_tx_buf[3]);
crc16_calc = (u16) cts_crc32(pdata->spi_tx_buf, 5);
put_unaligned_le16(crc16_calc, &pdata->spi_tx_buf[5]);
ret = cts_spi_send_recv(pdata, 7, pdata->spi_tx_buf,
pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
}
memset(pdata->spi_tx_buf, 0, 7);
pdata->spi_tx_buf[0] = dev_addr | 0x01;
udelay(100);
ret = cts_spi_send_recv(pdata, rlen + 2,
pdata->spi_tx_buf, pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
memcpy(rbuf, pdata->spi_rx_buf, rlen);
crc16_calc = (u16) cts_crc32(pdata->spi_rx_buf, rlen);
crc16_recv = get_unaligned_le16(&pdata->spi_rx_buf[rlen]);
if (crc16_recv != crc16_calc) {
cts_err("SPI RX CRC error: rx_crc %04x != %04x",
crc16_recv, crc16_calc);
continue;
}
return 0;
} while (++retries < retry);
}
if (retries >= retry)
cts_err("SPI read too much retry");
return -EIO;
}
int cts_plat_spi_read_delay_idle(struct cts_platform_data *pdata, u8 dev_addr,
const u8 *wbuf, size_t wlen, void *rbuf,
size_t rlen, int retry, int delay, int idle)
{
int ret = 0, retries = 0;
u16 crc;
if (wlen > CFG_CTS_MAX_SPI_XFER_SIZE
|| rlen > CFG_CTS_MAX_SPI_XFER_SIZE) {
cts_err("write/read too much data:wlen=%zu, rlen=%zu", wlen, rlen);
return -E2BIG;
}
if (pdata->cts_dev->rtdata.program_mode) {
#ifdef CONFIG_CTS_ICTYPE_ICNL9922C
pdata->spi_tx_buf[0] = dev_addr | 0x01;
memcpy(&pdata->spi_tx_buf[1], wbuf, wlen);
put_unaligned_be24(rlen, &pdata->spi_tx_buf[4]);
crc = (u16) cts_crc32(pdata->spi_tx_buf, 7);
put_unaligned_be16(crc, &pdata->spi_tx_buf[7]);
do {
ret = cts_spi_send_recv(pdata, wlen + rlen + 15,
pdata->spi_tx_buf, pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
memcpy(rbuf, pdata->spi_rx_buf + wlen + 10, rlen);
crc = (u16) cts_crc32(rbuf, rlen);
if (get_unaligned_le16(&pdata->spi_rx_buf[wlen + rlen + 10]) != crc) {
cts_err("SPI RX CRC error: rx_crc %04x != %04x",
get_unaligned_le16(&pdata->spi_rx_buf[wlen + rlen + 10]), crc);
continue;
}
return 0;
} while (++retries < retry);
#else
pdata->spi_tx_buf[0] = dev_addr | 0x01;
memcpy(&pdata->spi_tx_buf[1], wbuf, wlen);
do {
ret = cts_spi_send_recv(pdata, rlen + 5, pdata->spi_tx_buf,
pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
memcpy(rbuf, pdata->spi_rx_buf + 5, rlen);
return 0;
} while (++retries < retry);
#endif
} else {
do {
if (wlen != 0) {
pdata->spi_tx_buf[0] = dev_addr | 0x01;
pdata->spi_tx_buf[1] = wbuf[1];
pdata->spi_tx_buf[2] = wbuf[0];
put_unaligned_le16(rlen, &pdata->spi_tx_buf[3]);
crc = (u16) cts_crc32(pdata->spi_tx_buf, 5);
put_unaligned_le16(crc, &pdata->spi_tx_buf[5]);
ret = cts_spi_send_recv(pdata, 7, pdata->spi_tx_buf,
pdata->spi_rx_buf);
if (ret) {
cts_err("SPI read failed %d", ret);
if (delay)
mdelay(delay);
continue;
}
}
memset(pdata->spi_tx_buf, 0, 7);
pdata->spi_tx_buf[0] = dev_addr | 0x01;
udelay(idle);
ret = cts_spi_send_recv(pdata, rlen + 2,
pdata->spi_tx_buf, pdata->spi_rx_buf);
if (ret) {
if (delay)
mdelay(delay);
continue;
}
memcpy(rbuf, pdata->spi_rx_buf, rlen);
crc = (u16) cts_crc32(pdata->spi_rx_buf, rlen);
if (get_unaligned_le16(&pdata->spi_rx_buf[rlen]) != crc)
continue;
return 0;
} while (++retries < retry);
}
if (retries >= retry)
cts_err("cts_plat_spi_read error");
return -EIO;
}
#endif
int cts_plat_is_normal_mode(struct cts_platform_data *pdata)
{
struct chipone_ts_data *cts_data;
u16 fwid;
/*
u8 tx_buf[4] = { 0 };
u32 addr;
*/
int ret;
cts_set_normal_addr(pdata->cts_dev);
cts_data = container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
ret = cts_tcs_get_fw_id(pdata->cts_dev, &fwid);
/*
addr = CTS_DEVICE_FW_REG_CHIP_TYPE;
put_unaligned_be16(addr, tx_buf);
ret = cts_plat_spi_read(pdata, CTS_DEV_NORMAL_MODE_SPIADDR,
tx_buf, 2, &fwid, 2, 3, 10);
fwid = be16_to_cpu(fwid);
*/
if (ret || !cts_is_fwid_valid(fwid))
return false;
return true;
}
static void cts_plat_handle_irq(struct cts_platform_data *pdata)
{
int ret;
cts_dbg("Handle IRQ");
cts_lock_device(pdata->cts_dev);
ret = cts_irq_handler(pdata->cts_dev);
if (ret)
cts_err("Device handle IRQ failed %d", ret);
cts_unlock_device(pdata->cts_dev);
}
static irqreturn_t cts_plat_irq_handler(int irq, void *dev_id)
{
struct cts_platform_data *pdata;
#ifndef CONFIG_GENERIC_HARDIRQS
struct chipone_ts_data *cts_data;
#endif
cts_dbg("IRQ handler");
pdata = (struct cts_platform_data *)dev_id;
if (pdata == NULL) {
cts_err("IRQ handler with NULL dev_id");
return IRQ_NONE;
}
#ifdef CONFIG_GENERIC_HARDIRQS
cts_plat_handle_irq(pdata);
#else
cts_data = container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
if (queue_work(cts_data->workqueue, &pdata->ts_irq_work)) {
cts_dbg("IRQ queue work");
cts_plat_disable_irq(pdata);
} else
cts_warn("IRQ handler queue work failed as already on the queue");
#endif /* CONFIG_GENERIC_HARDIRQS */
return IRQ_HANDLED;
}
#ifndef CONFIG_GENERIC_HARDIRQS
static void cts_plat_touch_dev_irq_work(struct work_struct *work)
{
struct cts_platform_data *pdata =
container_of(work, struct cts_platform_data, ts_irq_work);
cts_dbg("IRQ work");
cts_plat_handle_irq(pdata);
cts_plat_enable_irq(pdata);
}
#endif /* CONFIG_GENERIC_HARDIRQS */
#ifdef CONFIG_CTS_OF
static int cts_plat_parse_dt(struct cts_platform_data *pdata,
struct device_node *dev_node)
{
int ret = 0;
cts_info("Parse device tree");
pdata->int_gpio = of_get_named_gpio(dev_node, CFG_CTS_OF_INT_GPIO_NAME, 0);
if (!gpio_is_valid(pdata->int_gpio)) {
cts_err("Parse INT GPIO from dt failed %d", pdata->int_gpio);
pdata->int_gpio = -1;
}
cts_info(" %-12s: %d", "int gpio", pdata->int_gpio);
pdata->irq = gpio_to_irq(pdata->int_gpio);
if (pdata->irq < 0) {
cts_err("Parse irq failed %d", ret);
return pdata->irq;
}
cts_info(" %-12s: %d", "irq num", pdata->irq);
#ifdef CFG_CTS_HAS_RESET_PIN
pdata->rst_gpio = of_get_named_gpio(dev_node, CFG_CTS_OF_RST_GPIO_NAME, 0);
if (!gpio_is_valid(pdata->rst_gpio)) {
cts_err("Parse RST GPIO from dt failed %d", pdata->rst_gpio);
pdata->rst_gpio = -1;
}
cts_info(" %-12s: %d", "rst gpio", pdata->rst_gpio);
#endif /* CFG_CTS_HAS_RESET_PIN */
#ifdef CFG_CTS_MANUAL_CS
pdata->cs_gpio = of_get_named_gpio(dev_node, CFG_CTS_OF_CS_GPIO_NAME, 0);
if (!gpio_is_valid(pdata->cs_gpio)) {
cts_err("Parse CS GPIO from dt failed %d", pdata->cs_gpio);
pdata->cs_gpio = -1;
}
cts_info(" %-12s: %d", "cs gpio", pdata->cs_gpio);
#endif
ret = of_property_read_u32(dev_node, CFG_CTS_OF_X_RESOLUTION_NAME,
&pdata->res_x);
if (ret)
cts_warn("Parse X resolution from dt failed %d", ret);
cts_info(" %-12s: %d", "X resolution", pdata->res_x);
ret = of_property_read_u32(dev_node, CFG_CTS_OF_Y_RESOLUTION_NAME,
&pdata->res_y);
if (ret)
cts_warn("Parse Y resolution from dt failed %d", ret);
cts_info(" %-12s: %d", "Y resolution", pdata->res_y);
if (of_property_read_u32(dev_node, "chipone,def-build-id", &pdata->build_id)) {
pdata->build_id = 0;
cts_info("chipone,build_id undefined.");
} else
cts_info("chipone,build_id=0x%04X", pdata->build_id);
if (of_property_read_u32(dev_node, "chipone,def-config-id", &pdata->config_id)) {
pdata->config_id = 0;
cts_info("chipone,config_id undefined.");
} else
cts_info("chipone,config_id=0x%04X", pdata->config_id);
#ifdef CFG_CTS_FW_UPDATE_SYS
ret = of_property_read_string(dev_node, CFG_CTS_OF_PANEL_SUPPLIER,
&pdata->panel_supplier);
if (ret) {
pdata->panel_supplier = NULL;
cts_warn("read panel supplier failed, ret=%d", ret);
} else
cts_info("panel supplier=%s", (char *)pdata->panel_supplier);
#endif
return 0;
}
#endif /* CONFIG_CTS_OF */
#ifdef CFG_CTS_FORCE_UP
static void cts_plat_touch_event_timeout_work(struct work_struct *work)
{
struct cts_platform_data *pdata = container_of(work,
struct cts_platform_data, touch_event_timeout_work.work);
cts_warn("Touch event timeout work");
cts_plat_release_all_touch(pdata);
}
#endif
#ifndef CONFIG_CTS_I2C_HOST
int cts_plat_spi_setup(struct cts_platform_data *pdata)
{
int ret;
pdata->spi_client->chip_select = 0;
pdata->spi_client->mode = SPI_MODE_0;
pdata->spi_client->bits_per_word = 8;
cts_info("chip_select :%d", pdata->spi_client->chip_select);
cts_info("spi_mode :%d", pdata->spi_client->mode);
cts_info("bits_per_word:%d", pdata->spi_client->bits_per_word);
ret = spi_setup(pdata->spi_client);
if (ret)
cts_err("spi_setup err!");
return 0;
}
#endif
#ifdef CONFIG_CTS_I2C_HOST
int cts_init_platform_data(struct cts_platform_data *pdata,
struct i2c_client *i2c_client)
#else
int cts_init_platform_data(struct cts_platform_data *pdata,
struct spi_device *spi)
#endif
{
struct input_dev *input_dev;
int ret = 0;
cts_info("cts_init_platform_data Init");
#ifdef CONFIG_CTS_OF
{
struct device *dev;
#ifdef CONFIG_CTS_I2C_HOST
dev = &i2c_client->dev;
#else
dev = &spi->dev;
#endif /* CONFIG_CTS_I2C_HOST */
ret = cts_plat_parse_dt(pdata, dev->of_node);
if (ret) {
cts_err("Parse dt failed %d", ret);
return ret;
}
}
#endif /* CONFIG_CTS_OF */
#ifdef CONFIG_CTS_I2C_HOST
pdata->i2c_client = i2c_client;
pdata->i2c_client->irq = pdata->irq;
#else
pdata->spi_client = spi;
pdata->spi_client->irq = pdata->irq;
#endif /* CONFIG_CTS_I2C_HOST */
mutex_init(&pdata->dev_lock);
spin_lock_init(&pdata->irq_lock);
input_dev = input_allocate_device();
if (input_dev == NULL) {
cts_err("Failed to allocate input device.");
return -ENOMEM;
}
/** - Init input device */
input_dev->name = CFG_CTS_DEVICE_NAME;
input_dev->name = CFG_CTS_DEVICE_NAME;
#ifdef CONFIG_CTS_I2C_HOST
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &pdata->i2c_client->dev;
#else
input_dev->id.bustype = BUS_SPI;
input_dev->dev.parent = &pdata->spi_client->dev;
#endif /* CONFIG_CTS_I2C_HOST */
input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
#ifdef CFG_CTS_PALM_DETECT
set_bit(CFG_CTS_PALM_EVENT, input_dev->keybit);
#endif
#ifdef CFG_CTS_SWAP_XY
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, pdata->res_y, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, pdata->res_x, 0, 0);
#else /* CFG_CTS_SWAP_XY */
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, pdata->res_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, pdata->res_y, 0, 0);
#endif /* CFG_CTS_SWAP_XY */
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
CFG_CTS_MAX_TOUCH_NUM * 2, 0, 0);
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
#ifdef CONFIG_CTS_SLOTPROTOCOL
input_mt_init_slots(input_dev, CFG_CTS_MAX_TOUCH_NUM, 0);
#endif /* CONFIG_CTS_SLOTPROTOCOL */
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
__set_bit(EV_ABS, input_dev->evbit);
input_set_drvdata(input_dev, pdata);
ret = input_register_device(input_dev);
if (ret) {
cts_err("Failed to register input device");
return ret;
}
pdata->ts_input_dev = input_dev;
#if !defined(CONFIG_GENERIC_HARDIRQS)
INIT_WORK(&pdata->ts_irq_work, cts_plat_touch_dev_irq_work);
#endif /* CONFIG_GENERIC_HARDIRQS */
#ifdef CONFIG_CTS_VIRTUALKEY
{
u8 vkey_keymap[CFG_CTS_NUM_VKEY] = CFG_CTS_VKEY_KEYCODES;
memcpy(pdata->vkey_keycodes, vkey_keymap, sizeof(vkey_keymap));
pdata->vkey_num = CFG_CTS_NUM_VKEY;
}
#endif /* CONFIG_CTS_VIRTUALKEY */
#ifdef CFG_CTS_GESTURE
{
u8 gesture_keymap[CFG_CTS_NUM_GESTURE][2] = CFG_CTS_GESTURE_KEYMAP;
memcpy(pdata->gesture_keymap, gesture_keymap, sizeof(gesture_keymap));
pdata->gesture_num = CFG_CTS_NUM_GESTURE;
}
#endif /* CFG_CTS_GESTURE */
#ifdef CFG_CTS_FORCE_UP
INIT_DELAYED_WORK(&pdata->touch_event_timeout_work,
cts_plat_touch_event_timeout_work);
#endif
#ifndef CONFIG_CTS_I2C_HOST
pdata->spi_speed = CFG_CTS_SPI_SPEED_KHZ;
cts_plat_spi_setup(pdata);
#endif
return 0;
}
int cts_deinit_platform_data(struct cts_platform_data *pdata)
{
cts_info("De-Init platform_data");
input_unregister_device(pdata->ts_input_dev);
return 0;
}
int cts_plat_request_resource(struct cts_platform_data *pdata)
{
int ret;
cts_info("Request resource");
ret = gpio_request_one(pdata->int_gpio, GPIOF_IN,
CFG_CTS_DEVICE_NAME "-int");
if (ret) {
cts_err("Request INT gpio (%d) failed %d", pdata->int_gpio, ret);
goto err_out;
}
#ifdef CFG_CTS_HAS_RESET_PIN
ret = gpio_request_one(pdata->rst_gpio, GPIOF_OUT_INIT_HIGH,
CFG_CTS_DEVICE_NAME "-rst");
if (ret) {
cts_err("Request RST gpio (%d) failed %d", pdata->rst_gpio, ret);
goto err_free_int;
}
#endif /* CFG_CTS_HAS_RESET_PIN */
#ifdef CFG_CTS_MANUAL_CS
ret = gpio_request_one(pdata->cs_gpio, GPIOF_OUT_INIT_HIGH,
CFG_CTS_DEVICE_NAME "-cs");
if (ret) {
cts_err("Request CS gpio (%d) failed %d", pdata->cs_gpio, ret);
goto err_request_cs_gpio;
}
#endif
return 0;
#ifdef CFG_CTS_MANUAL_CS
err_request_cs_gpio:
#endif
#ifdef CONFIG_CTS_REGULATOR
err_free_rst:
#endif /* CONFIG_CTS_REGULATOR */
#ifdef CFG_CTS_HAS_RESET_PIN
gpio_free(pdata->rst_gpio);
err_free_int:
#endif /* CFG_CTS_HAS_RESET_PIN */
gpio_free(pdata->int_gpio);
err_out:
return ret;
}
void cts_plat_free_resource(struct cts_platform_data *pdata)
{
cts_info("Free resource");
if (gpio_is_valid(pdata->int_gpio))
gpio_free(pdata->int_gpio);
#ifdef CFG_CTS_HAS_RESET_PIN
if (gpio_is_valid(pdata->rst_gpio))
gpio_free(pdata->rst_gpio);
#endif /* CFG_CTS_HAS_RESET_PIN */
#ifdef CFG_CTS_MANUAL_CS
if (gpio_is_valid(pdata->cs_gpio))
gpio_free(pdata->cs_gpio);
#endif
}
int cts_plat_request_irq(struct cts_platform_data *pdata)
{
int ret;
cts_info("Request IRQ");
#ifdef CONFIG_GENERIC_HARDIRQS
ret = request_threaded_irq(pdata->irq, NULL, cts_plat_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, CFG_CTS_DRIVER_NAME, pdata);
#else /* CONFIG_GENERIC_HARDIRQS */
ret = request_irq(pdata->irq, cts_plat_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, CFG_CTS_DRIVER_NAME, pdata);
#endif /* CONFIG_GENERIC_HARDIRQS */
if (ret) {
cts_err("Request IRQ failed %d", ret);
return ret;
}
cts_plat_disable_irq(pdata);
return 0;
}
void cts_plat_free_irq(struct cts_platform_data *pdata)
{
free_irq(pdata->irq, pdata);
}
int cts_plat_enable_irq(struct cts_platform_data *pdata)
{
unsigned long irqflags;
cts_dbg("Enable IRQ");
if (pdata->irq > 0) {
spin_lock_irqsave(&pdata->irq_lock, irqflags);
if (pdata->irq_is_disable) {/* && !cts_is_device_suspended(pdata->chip)) */
cts_dbg("Real enable IRQ");
enable_irq(pdata->irq);
pdata->irq_is_disable = false;
}
spin_unlock_irqrestore(&pdata->irq_lock, irqflags);
return 0;
}
return -ENODEV;
}
int cts_plat_disable_irq(struct cts_platform_data *pdata)
{
unsigned long irqflags;
cts_dbg("Disable IRQ");
if (pdata->irq > 0) {
spin_lock_irqsave(&pdata->irq_lock, irqflags);
if (!pdata->irq_is_disable) {
cts_dbg("Real disable IRQ");
disable_irq_nosync(pdata->irq);
pdata->irq_is_disable = true;
}
spin_unlock_irqrestore(&pdata->irq_lock, irqflags);
return 0;
}
return -ENODEV;
}
#ifdef CFG_CTS_HAS_RESET_PIN
int cts_plat_reset_device(struct cts_platform_data *pdata)
{
/* !!!can not be modified */
/* !!!can not be modified */
/* !!!can not be modified */
cts_info("Reset device");
gpio_set_value(pdata->rst_gpio, 1);
mdelay(1);
gpio_set_value(pdata->rst_gpio, 0);
mdelay(10);
gpio_set_value(pdata->rst_gpio, 1);
mdelay(40);
return 0;
}
int cts_plat_set_reset(struct cts_platform_data *pdata, int val)
{
cts_info("Set Reset to %s", val ? "HIGH" : "LOW");
if (val)
gpio_set_value(pdata->rst_gpio, 1);
else
gpio_set_value(pdata->rst_gpio, 0);
return 0;
}
#endif /* CFG_CTS_HAS_RESET_PIN */
int cts_plat_get_int_pin(struct cts_platform_data *pdata)
{
return gpio_get_value(pdata->int_gpio);
}
int cts_plat_power_up_device(struct cts_platform_data *pdata)
{
cts_info("Power up device");
return 0;
}
int cts_plat_power_down_device(struct cts_platform_data *pdata)
{
cts_info("Power down device");
return 0;
}
int cts_plat_init_touch_device(struct cts_platform_data *pdata)
{
cts_info("Init touch device");
return 0;
}
void cts_plat_deinit_touch_device(struct cts_platform_data *pdata)
{
cts_info("De-init touch device");
#ifndef CONFIG_GENERIC_HARDIRQS
if (work_pending(&pdata->ts_irq_work))
cancel_work_sync(&pdata->ts_irq_work);
#endif /* CONFIG_GENERIC_HARDIRQS */
}
#ifdef CFG_CTS_PALM_DETECT
void cts_report_palm_event(struct cts_platform_data *pdata)
{
input_report_key(pdata->ts_input_dev, CFG_CTS_PALM_EVENT, 1);
input_sync(pdata->ts_input_dev);
msleep(100);
input_report_key(pdata->ts_input_dev, CFG_CTS_PALM_EVENT, 0);
input_sync(pdata->ts_input_dev);
}
#endif
int cts_plat_process_touch_msg(struct cts_platform_data *pdata,
struct cts_device_touch_msg *msgs, int num)
{
struct chipone_ts_data *cts_data;
struct input_dev *input_dev = pdata->ts_input_dev;
int i;
int contact = 0;
#ifdef CONFIG_CTS_SLOTPROTOCOL
static unsigned char finger_last[CFG_CTS_MAX_TOUCH_NUM] = { 0 };
unsigned char finger_current[CFG_CTS_MAX_TOUCH_NUM] = { 0 };
#endif
cts_dbg("Process touch %d msgs", num);
cts_data = container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
if (num == 0 || num > CFG_CTS_MAX_TOUCH_NUM)
return 0;
for (i = 0; i < num; i++) {
u16 x, y;
x = le16_to_cpu(msgs[i].x);
y = le16_to_cpu(msgs[i].y);
#ifdef CFG_CTS_SWAP_XY
swap(x, y);
#endif /* CFG_CTS_SWAP_XY */
#ifdef CFG_CTS_WRAP_X
x = wrap(pdata->res_x, x);
#endif /* CFG_CTS_WRAP_X */
#ifdef CFG_CTS_WRAP_Y
y = wrap(pdata->res_y, y);
#endif /* CFG_CTS_WRAP_Y */
cts_dbg(" Process touch msg[%d]: id[%u] ev=%u x=%u y=%u p=%u",
i, msgs[i].id, msgs[i].event, x, y, msgs[i].pressure);
if (msgs[i].event == CTS_DEVICE_TOUCH_EVENT_DOWN
|| msgs[i].event == CTS_DEVICE_TOUCH_EVENT_MOVE
|| msgs[i].event == CTS_DEVICE_TOUCH_EVENT_STAY) {
if (msgs[i].id < CFG_CTS_MAX_TOUCH_NUM)
finger_current[msgs[i].id] = 1;
}
#ifdef CONFIG_CTS_SLOTPROTOCOL
/* input_mt_slot(input_dev, msgs[i].id); */
switch (msgs[i].event) {
case CTS_DEVICE_TOUCH_EVENT_DOWN:
case CTS_DEVICE_TOUCH_EVENT_MOVE:
case CTS_DEVICE_TOUCH_EVENT_STAY:
contact++;
input_mt_slot(input_dev, msgs[i].id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, msgs[i].pressure);
input_report_abs(input_dev, ABS_MT_PRESSURE, msgs[i].pressure);
break;
case CTS_DEVICE_TOUCH_EVENT_UP:
/* input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false); */
break;
default:
cts_warn("Process touch msg with unknwon event %u id %u",
msgs[i].event, msgs[i].id);
break;
}
#else /* CONFIG_CTS_SLOTPROTOCOL */
/**
* If the driver reports one of BTN_TOUCH or ABS_PRESSURE
* in addition to the ABS_MT events, the last SYN_MT_REPORT event
* may be omitted. Otherwise, the last SYN_REPORT will be dropped
* by the input core, resulting in no zero-contact event
* reaching userland.
*/
switch (msgs[i].event) {
case CTS_DEVICE_TOUCH_EVENT_DOWN:
case CTS_DEVICE_TOUCH_EVENT_MOVE:
case CTS_DEVICE_TOUCH_EVENT_STAY:
contact++;
input_report_abs(input_dev, ABS_MT_PRESSURE, msgs[i].pressure);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, msgs[i].pressure);
input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_mt_sync(input_dev);
break;
case CTS_DEVICE_TOUCH_EVENT_UP:
break;
default:
cts_warn("Process touch msg with unknwon event %u id %u",
msgs[i].event, msgs[i].id);
break;
}
#endif /* CONFIG_CTS_SLOTPROTOCOL */
}
#ifdef CONFIG_CTS_SLOTPROTOCOL
for (i = 0; i < CFG_CTS_MAX_TOUCH_NUM; i++) {
if (finger_last[i] != 0 && finger_current[i] == 0) {
input_mt_slot(input_dev, i);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
}
finger_last[i] = finger_current[i];
}
input_report_key(input_dev, BTN_TOUCH, contact > 0);
#else
if (contact == 0) {
input_report_key(input_dev, BTN_TOUCH, 0);
input_mt_sync(input_dev);
}
#endif
input_sync(input_dev);
#ifdef CFG_CTS_FORCE_UP
if (contact) {
if (delayed_work_pending(&pdata->touch_event_timeout_work)) {
mod_delayed_work(cts_data->workqueue,
&pdata->touch_event_timeout_work, msecs_to_jiffies(100));
} else {
queue_delayed_work(cts_data->workqueue,
&pdata->touch_event_timeout_work, msecs_to_jiffies(100));
}
} else {
cancel_delayed_work_sync(&pdata->touch_event_timeout_work);
}
#endif
#ifdef CFG_CTS_HEARTBEAT_MECHANISM
if (contact) {
if (delayed_work_pending(&cts_data->heart_work)) {
mod_delayed_work(cts_data->heart_workqueue,
&cts_data->heart_work, msecs_to_jiffies(2000));
} else {
queue_delayed_work(cts_data->heart_workqueue,
&cts_data->heart_work, msecs_to_jiffies(2000));
}
}
#endif
return 0;
}
int cts_plat_release_all_touch(struct cts_platform_data *pdata)
{
struct input_dev *input_dev = pdata->ts_input_dev;
#if defined(CONFIG_CTS_SLOTPROTOCOL)
int id;
#endif /* CONFIG_CTS_SLOTPROTOCOL */
cts_info("Release all touch");
#ifdef CONFIG_CTS_SLOTPROTOCOL
for (id = 0; id < CFG_CTS_MAX_TOUCH_NUM; id++) {
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
}
input_report_key(input_dev, BTN_TOUCH, 0);
#else
input_report_key(input_dev, BTN_TOUCH, 0);
input_mt_sync(input_dev);
#endif /* CONFIG_CTS_SLOTPROTOCOL */
input_sync(input_dev);
return 0;
}
#ifdef CONFIG_CTS_VIRTUALKEY
int cts_plat_init_vkey_device(struct cts_platform_data *pdata)
{
int i;
cts_info("Init VKey");
pdata->vkey_state = 0;
for (i = 0; i < pdata->vkey_num; i++) {
input_set_capability(pdata->ts_input_dev,
EV_KEY, pdata->vkey_keycodes[i]);
}
return 0;
}
void cts_plat_deinit_vkey_device(struct cts_platform_data *pdata)
{
cts_info("De-init VKey");
pdata->vkey_state = 0;
}
int cts_plat_process_vkey(struct cts_platform_data *pdata, u8 vkey_state)
{
u8 event;
int i;
event = pdata->vkey_state ^ vkey_state;
cts_dbg("Process vkey state=0x%02x, event=0x%02x", vkey_state, event);
for (i = 0; i < pdata->vkey_num; i++) {
input_report_key(pdata->ts_input_dev, pdata->vkey_keycodes[i],
vkey_state & BIT(i) ? 1 : 0);
}
pdata->vkey_state = vkey_state;
return 0;
}
int cts_plat_release_all_vkey(struct cts_platform_data *pdata)
{
int i;
cts_info("Release all vkeys");
for (i = 0; i < pdata->vkey_num; i++) {
if (pdata->vkey_state & BIT(i)) {
input_report_key(pdata->ts_input_dev, pdata->vkey_keycodes[i], 0);
}
}
pdata->vkey_state = 0;
return 0;
}
#endif /* CONFIG_CTS_VIRTUALKEY */
#ifdef CFG_CTS_GESTURE
int cts_plat_enable_irq_wake(struct cts_platform_data *pdata)
{
int ret;
cts_info("Enable IRQ wake");
if (pdata->irq > 0) {
ret = enable_irq_wake(pdata->irq);
if (ret < 0) {
cts_err("Enable irq wake failed");
return -EINVAL;
}
pdata->irq_wake_enabled = true;
return 0;
}
cts_warn("Enable irq wake while irq invalid %d", pdata->irq);
return -ENODEV;
}
int cts_plat_disable_irq_wake(struct cts_platform_data *pdata)
{
int ret;
cts_info("Disable IRQ wake");
if (pdata->irq > 0) {
ret = disable_irq_wake(pdata->irq);
if (ret < 0) {
cts_warn("Disable irq wake while already disabled");
return -EINVAL;
}
pdata->irq_wake_enabled = false;
return 0;
}
cts_warn("Disable irq wake while irq invalid %d", pdata->irq);
return -ENODEV;
}
int cts_plat_init_gesture(struct cts_platform_data *pdata)
{
int i;
cts_info("Init gesture");
/* TODO: If system will issure enable/disable command, comment following line. */
/* cts_enable_gesture_wakeup(pdata->cts_dev); */
for (i = 0; i < pdata->gesture_num; i++) {
input_set_capability(pdata->ts_input_dev, EV_KEY,
pdata->gesture_keymap[i][1]);
}
return 0;
}
void cts_plat_deinit_gesture(struct cts_platform_data *pdata)
{
cts_info("De-init gesture");
}
int cts_plat_process_gesture_info(struct cts_platform_data *pdata,
struct cts_device_gesture_info *gesture_info)
{
int i;
cts_info("Process gesture, id=0x%02x", gesture_info->gesture_id);
#if defined(CFG_CTS_GESTURE_REPORT_KEY)
for (i = 0; i < CFG_CTS_NUM_GESTURE; i++) {
if (gesture_info->gesture_id == pdata->gesture_keymap[i][0]) {
cts_info("Report key[%u]", pdata->gesture_keymap[i][1]);
input_report_key(pdata->ts_input_dev, pdata->gesture_keymap[i][1], 1);
input_sync(pdata->ts_input_dev);
input_report_key(pdata->ts_input_dev, pdata->gesture_keymap[i][1], 0);
input_sync(pdata->ts_input_dev);
return 0;
}
}
#endif /* CFG_CTS_GESTURE_REPORT_KEY */
cts_warn("Process unrecognized gesture id=%u", gesture_info->gesture_id);
return -EINVAL;
}
#endif /* CFG_CTS_GESTURE */