1920 lines
56 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
#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_PLATFORM_MTK_TPD_SUPPORTED
int tpd_rst_gpio_index = 0;
int tpd_int_gpio_index = 1;
static int tpd_history_x, tpd_history_y;
#endif
#ifdef CFG_CTS_HAS_RESET_PIN
int cts_plat_set_reset(struct cts_platform_data *pdata, int val)
{
cts_info("Set Reset to %s", val ? "HIGH" : "LOW");
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
if (val)
tpd_gpio_output(tpd_rst_gpio_index, 1);
else
tpd_gpio_output(tpd_rst_gpio_index, 0);
#else
if (val)
gpio_set_value(pdata->rst_gpio, 1);
else
gpio_set_value(pdata->rst_gpio, 0);
#endif
return 0;
}
int cts_plat_reset_device(struct cts_platform_data *pdata)
{
/* !!!can not be modified */
/* !!!can not be modified */
/* !!!can not be modified */
cts_plat_set_reset(pdata, 1);
mdelay(1);
cts_plat_set_reset(pdata, 0);
mdelay(5);/* 1ms */
cts_plat_set_reset(pdata, 1);
/* under normal mode, delay over 50ms */
#ifdef CONFIG_CTS_I2C_HOST
mdelay(120);
#else
mdelay(70);
#endif
return 0;
}
#endif /* CFG_CTS_HAS_RESET_PIN */
#ifdef CFG_CTS_MANUAL_CS
int cts_plat_set_cs(struct cts_platform_data *pdata, int val)
{
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
if (val)
pinctrl_select_state(pdata->pinctrl1, pdata->spi_cs_high);
else
pinctrl_select_state(pdata->pinctrl1, pdata->spi_cs_low);
#else
if (val)
gpio_set_value(pdata->cs_gpio, 1);
else
gpio_set_value(pdata->cs_gpio, 0);
#endif
return 0;
}
#endif /* CFG_CTS_MANUAL_CS */
#ifdef CONFIG_CTS_I2C_HOST
size_t cts_plat_get_max_i2c_xfer_size(struct cts_platform_data *pdata)
{
#ifdef TPD_SUPPORT_I2C_DMA
if (pdata->i2c_dma_available) {
return CFG_CTS_MAX_I2C_XFER_SIZE;
} else {
return CFG_CTS_MAX_I2C_FIFO_XFER_SIZE;
}
#else
return CFG_CTS_MAX_I2C_XFER_SIZE;
#endif
}
u8 *cts_plat_get_i2c_xfer_buf(struct cts_platform_data *pdata, size_t xfer_size)
{
#ifdef TPD_SUPPORT_I2C_DMA
if (pdata->i2c_dma_available && xfer_size > CFG_CTS_MAX_I2C_FIFO_XFER_SIZE) {
return pdata->i2c_dma_buff_va;
} else
#endif /* TPD_SUPPORT_I2C_DMA */
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;
#ifdef TPD_SUPPORT_I2C_DMA
struct i2c_msg msg = {
.addr = i2c_addr,
.flags = !I2C_M_RD,
.len = len,
.timing = 300,
};
if (pdata->i2c_dma_available && len > CFG_CTS_MAX_I2C_FIFO_XFER_SIZE) {
msg.ext_flag = (pdata->i2c_client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
msg.buf = (u8 *)pdata->i2c_dma_buff_pa;
memcpy(pdata->i2c_dma_buff_va, src, len);
} else {
msg.buf = (u8 *)src;
}
msg.len = len;
#else /* TPD_SUPPORT_I2C_DMA */
struct i2c_msg msg = {
.flags = !I2C_M_RD,
.addr = i2c_addr,
.buf = (u8 *) src,
.len = len,
};
#endif /* TPD_SUPPORT_I2C_DMA */
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;
#ifdef TPD_SUPPORT_I2C_DMA
struct i2c_msg msgs[2] = {
{
.addr = i2c_addr,
.flags = !I2C_M_RD,
.len = wlen,
.buf = (u8 *)wbuf,
.timing = 300,
},
{
.addr = i2c_addr,
.flags = I2C_M_RD,
.len = rlen,
.timing = 300,
},
};
if (pdata->i2c_dma_available && rlen > CFG_CTS_MAX_I2C_FIFO_XFER_SIZE) {
msgs[1].ext_flag = (pdata->i2c_client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
msgs[1].buf = (u8 *)pdata->i2c_dma_buff_pa;
} else {
msgs[1].buf = (u8 *)rbuf;
}
#else /* TPD_SUPPORT_I2C_DMA */
struct i2c_msg msgs[2] = {
{
.addr = i2c_addr,
.flags = !I2C_M_RD,
.buf = (u8 *) wbuf,
.len = wlen },
{
.addr = i2c_addr,
.flags = I2C_M_RD,
.buf = (u8 *) rbuf,
.len = rlen }
};
#endif /* TPD_SUPPORT_I2C_DMA */
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 {
#ifdef TPD_SUPPORT_I2C_DMA
if (pdata->i2c_dma_available && rlen > CFG_CTS_MAX_I2C_FIFO_XFER_SIZE) {
memcpy(rbuf, pdata->i2c_dma_buff_va, rlen);
}
#endif /* TPD_SUPPORT_I2C_DMA */
return 0;
}
} while (++retries < retry);
return ret;
}
#else /*CONFIG_CTS_I2C_HOST*/
#ifdef CFG_MTK_LEGEND_PLATFORM
struct mt_chip_conf cts_spi_conf_mt65xx = {
.setuptime = 15,
.holdtime = 15,
.high_time = 21, //for mt6582, 104000khz/(4+4) = 130000khz
.low_time = 21,
.cs_idletime = 20,
.ulthgh_thrsh = 0,
.cpol = 0,
.cpha = 0,
.rx_mlsb = 1,
.tx_mlsb = 1,
.tx_endian = 0,
.rx_endian = 0,
.com_mod = FIFO_TRANSFER,
.pause = 1,
.finish_intr = 1,
.deassert = 0,
.ulthigh = 0,
.tckdly = 0,
};
typedef enum {
SPEED_500KHZ = 500,
SPEED_1MHZ = 1000,
SPEED_2MHZ = 2000,
SPEED_3MHZ = 3000,
SPEED_4MHZ = 4000,
SPEED_6MHZ = 6000,
SPEED_8MHZ = 8000,
SPEED_KEEP,
SPEED_UNSUPPORTED
} SPI_SPEED;
static int cts_plat_spi_set_mode(struct spi_device *spi, SPI_SPEED speed, int flag)
{
struct mt_chip_conf *mcc = &cts_spi_conf_mt65xx;
int ret;
if (flag == 0) {
mcc->com_mod = FIFO_TRANSFER;
} else {
mcc->com_mod = DMA_TRANSFER;
}
switch (speed) {
case SPEED_500KHZ:
mcc->high_time = 120;
mcc->low_time = 120;
break;
case SPEED_1MHZ:
mcc->high_time = 60;
mcc->low_time = 60;
break;
case SPEED_2MHZ:
mcc->high_time = 30;
mcc->low_time = 30;
break;
case SPEED_3MHZ:
mcc->high_time = 20;
mcc->low_time = 20;
break;
case SPEED_4MHZ:
mcc->high_time = 15;
mcc->low_time = 15;
break;
case SPEED_6MHZ:
mcc->high_time = 10;
mcc->low_time = 10;
break;
case SPEED_8MHZ:
mcc->high_time = 8;
mcc->low_time = 8;
break;
case SPEED_KEEP:
case SPEED_UNSUPPORTED:
break;
}
ret = spi_setup(spi);
if (ret) {
cts_err("Spi setup failed %d(%s)", ret, cts_strerror(ret));
}
return ret;
}
#endif /* CFG_MTK_LEGEND_PLATFORM */
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);
#ifdef CFG_MTK_LEGEND_PLATFORM
pdata->spi_client->controller_data = (void *)&cts_spi_conf_mt65xx;
ret = spi_setup(pdata->spi_client);
cts_plat_spi_set_mode(pdata->spi_client, pdata->spi_speed, 0);
#else /* CFG_MTK_LEGEND_PLATFORM */
ret = spi_setup(pdata->spi_client);
#endif /* CFG_MTK_LEGEND_PLATFORM */
if (ret) {
cts_err("spi_setup err!");
}
return ret;
}
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,
.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);
#ifdef CFG_CTS_MANUAL_CS
udelay(100);
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) {
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);
} 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) {
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);
} 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) {
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);
} 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 /*CONFIG_CTS_I2C_HOST*/
int cts_plat_is_normal_mode(struct cts_platform_data *pdata)
{
struct chipone_ts_data *cts_data;
u16 fwid;
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);
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 CFG_CTS_FORCE_UP
static void cts_plat_touch_timeout_work(struct work_struct *work)
{
struct cts_platform_data *pdata = container_of(work,
struct cts_platform_data, touch_timeout.work);
cts_warn("Touch event timeout work");
cts_plat_release_all_touch(pdata);
}
#endif
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
#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 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;
struct input_dev *pen_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;
pen_dev = input_allocate_device();
if (pen_dev == NULL) {
cts_err("Failed to allocate pen device.");
return -ENOMEM;
}
#ifdef CONFIG_CTS_I2C_HOST
pen_dev->id.bustype = BUS_I2C;
pen_dev->dev.parent = &pdata->i2c_client->dev;
#else
pen_dev->id.bustype = BUS_SPI;
pen_dev->dev.parent = &pdata->spi_client->dev;
#endif /* CONFIG_CTS_I2C_HOST */
pen_dev->name = "chipone-tddi,pen";
pen_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
__set_bit(ABS_X, pen_dev->absbit);
__set_bit(ABS_Y, pen_dev->absbit);
__set_bit(BTN_STYLUS, pen_dev->keybit);
__set_bit(BTN_STYLUS2, pen_dev->keybit);
__set_bit(BTN_TOUCH, pen_dev->keybit);
__set_bit(BTN_TOOL_PEN, pen_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, pen_dev->propbit);
input_set_abs_params(pen_dev, ABS_X, 0, pdata->res_x, 0, 0);
input_set_abs_params(pen_dev, ABS_Y, 0, pdata->res_y, 0, 0);
input_set_abs_params(pen_dev, ABS_PRESSURE, 0, 4096, 0, 0);
input_set_abs_params(pen_dev, ABS_TILT_X, -9000, 9000, 0, 0);
input_set_abs_params(pen_dev, ABS_TILT_Y, -9000, 9000, 0, 0);
input_set_abs_params(pen_dev, ABS_Z, 0, 36000, 0, 0);
ret = input_register_device(pen_dev);
if (ret) {
cts_err("Input pen device registration failed");
input_free_device(pen_dev);
pen_dev = NULL;
return ret;
}
pdata->pen_input_dev = pen_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_timeout, cts_plat_touch_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
}
#else /*CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED*/
#ifndef CONFIG_CTS_I2C_HOST
static int cts_plat_init_dts(struct cts_platform_data *pdata, struct device *device)
{
#ifdef CFG_CTS_MANUAL_CS
struct device_node *node;
pdata->pinctrl1 = devm_pinctrl_get(device);
node = device->of_node;
if (node) {
pdata->spi_cs_low = pinctrl_lookup_state(pdata->pinctrl1, "spi_cs_low");
if (IS_ERR(pdata->spi_cs_low)) {
cts_err("Cannot find pinctrl spi cs high!\n");
return -ENOENT;
}
pdata->spi_cs_high = pinctrl_lookup_state(pdata->pinctrl1, "spi_cs_high");
if (IS_ERR(pdata->spi_cs_high)) {
return -ENOENT;
}
return 0;
}
return -ENOENT;
#else
return 0;
#endif
}
#endif /* CONFIG_CTS_I2C_HOST */
#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 device_node *node = NULL;
u32 ints[2] = { 0, 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 */
}
#endif /* CONFIG_CTS_OF */
#ifdef CONFIG_CTS_I2C_HOST
pdata->i2c_client = i2c_client;
#else
pdata->spi_client = spi;
#endif /* CONFIG_CTS_I2C_HOST */
pdata->ts_input_dev = tpd->dev;
spin_lock_init(&pdata->irq_lock);
mutex_init(&pdata->dev_lock);
#if !defined(CONFIG_GENERIC_HARDIRQS)
INIT_WORK(&pdata->ts_irq_work, cts_plat_touch_dev_irq_work);
#endif /* CONFIG_GENERIC_HARDIRQS */
if ((node = of_find_matching_node(node, touch_of_match)) == NULL) {
cts_err("Find touch eint node failed");
return -ENODATA;
}
if (of_property_read_u32_array(node, "debounce", ints, ARRAY_SIZE(ints)) == 0) {
gpio_set_debounce(ints[0], ints[1]);
} else {
cts_info("Debounce time not found");
}
pdata->irq = irq_of_parse_and_map(node, 0);
if (pdata->irq == 0) {
cts_err("Parse irq in dts failed");
return -ENODEV;
}
#ifdef CONFIG_CTS_VIRTUALKEY
pdata->vkey_num = tpd_dts_data.tpd_keycnt;
#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 TPD_SUPPORT_I2C_DMA
tpd->dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
pdata->i2c_dma_buff_va = (u8 *)dma_alloc_coherent(&tpd->dev->dev,
CFG_CTS_MAX_I2C_XFER_SIZE, &pdata->i2c_dma_buff_pa, GFP_KERNEL);
if (pdata->i2c_dma_buff_va == NULL) {
cts_err("Allocate I2C DMA Buffer failed!");
//return -ENOMEM;
} else {
pdata->i2c_dma_available = true;
}
#endif /* TPD_SUPPORT_I2C_DMA */
#ifdef CFG_CTS_FORCE_UP
INIT_DELAYED_WORK(&pdata->touch_timeout, cts_plat_touch_timeout_work);
#endif
#ifndef CONFIG_CTS_I2C_HOST
cts_plat_init_dts(pdata, &spi->dev);
pdata->spi_speed = CFG_CTS_SPI_SPEED_KHZ;
cts_plat_spi_setup(pdata);
#endif
return 0;
}
int cts_plat_request_resource(struct cts_platform_data *pdata)
{
cts_info("Request resource");
tpd_gpio_as_int(tpd_int_gpio_index);
tpd_gpio_output(tpd_rst_gpio_index, 1);
return 0;
}
void cts_plat_free_resource(struct cts_platform_data *pdata)
{
cts_info("Free resource");
/**
* Note:
* If resource request without managed, should free all resource
* requested in cts_plat_request_resource().
*/
#ifdef TPD_SUPPORT_I2C_DMA
if (pdata->i2c_dma_buff_va) {
dma_free_coherent(&tpd->dev->dev, CFG_CTS_MAX_I2C_XFER_SIZE,
pdata->i2c_dma_buff_va, pdata->i2c_dma_buff_pa);
pdata->i2c_dma_buff_va = NULL;
pdata->i2c_dma_buff_pa = 0;
}
#endif /* TPD_SUPPORT_I2C_DMA */
}
#endif /*CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED*/
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;
}
int cts_plat_get_int_pin(struct cts_platform_data *pdata)
{
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
return gpio_get_value(pdata->int_gpio);
#else
cts_err("MTK platform can not get INT pin value");
return -ENOTSUPP;
#endif
}
int cts_plat_init_touch_device(struct cts_platform_data *pdata)
{
cts_info("Init touch device");
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
return input_mt_init_slots(pdata->ts_input_dev,
tpd_dts_data.touch_max_num, INPUT_MT_DIRECT);
#endif
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 = (msgs[i].xl) | (msgs[i].xh << 8);
y = (msgs[i].yl) | (msgs[i].yh << 8);
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:
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
TPD_DEBUG_SET_TIME;
TPD_EM_PRINT(x, y, x, y, msgs[i].id, 1);
tpd_history_x = x;
tpd_history_y = y;
#ifdef CONFIG_MTK_BOOT
if (tpd_dts_data.use_tpd_button) {
if (FACTORY_BOOT == get_boot_mode() ||
RECOVERY_BOOT == get_boot_mode())
tpd_button(x, y, 1);
}
#endif /* CONFIG_MTK_BOOT */
#endif /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
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:
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
TPD_DEBUG_SET_TIME;
TPD_EM_PRINT(tpd_history_x, tpd_history_y, tpd_history_x, tpd_history_y, msgs[i].id, 0);
tpd_history_x = 0;
tpd_history_y = 0;
#ifdef CONFIG_MTK_BOOT
if (tpd_dts_data.use_tpd_button) {
if (FACTORY_BOOT == get_boot_mode() ||
RECOVERY_BOOT == get_boot_mode())
tpd_button(0, 0, 0);
}
#endif /* CONFIG_MTK_BOOT */
//input_report_key(input_dev, BTN_TOUCH, 0);
//input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
#endif /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
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 /* CONFIG_CTS_SLOTPROTOCOL */
if (contact == 0) {
input_report_key(input_dev, BTN_TOUCH, 0);
input_mt_sync(input_dev);
}
#endif /* CONFIG_CTS_SLOTPROTOCOL */
input_sync(input_dev);
#ifdef CFG_CTS_FORCE_UP
if (contact) {
if (delayed_work_pending(&pdata->touch_timeout)) {
mod_delayed_work(cts_data->workqueue,
&pdata->touch_timeout, msecs_to_jiffies(100));
} else {
queue_delayed_work(cts_data->workqueue,
&pdata->touch_timeout, msecs_to_jiffies(100));
}
} else {
cancel_delayed_work_sync(&pdata->touch_timeout);
}
#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_process_stylus_msg(struct cts_platform_data *pdata,
struct cts_device_stylus_msg *msgs, int num)
{
struct chipone_ts_data *cts_data;
struct input_dev *pen_dev = pdata->pen_input_dev;
int i;
int contact = 0;
cts_dbg("Process stylus %d msgs", num);
cts_data = container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
if (num == 0 || num > CFG_CTS_MAX_STYLUS_NUM)
return 0;
for (i = 0; i < num; i++) {
u16 x, y, p;
x = (msgs[i].tip_xl) | (msgs[i].tip_xh << 8);
y = (msgs[i].tip_yl) | (msgs[i].tip_yh << 8);
p = msgs[i].pressure_l | (msgs[i].pressure_h << 8);
cts_dbg(" Process stylus msg[%d]: id[%u] ev=%u x=%u y=%u p=%u"
" tx=%d ty=%d btn0=%d btn1=%d btn2=%d",
i, msgs[i].id, msgs[i].event, x, y, p, msgs[i].tiltx, msgs[i].tilty,
msgs[i].btn0, msgs[i].btn1, msgs[i].btn2);
/* Report stylus button */
input_report_key(pen_dev, BTN_STYLUS, msgs[i].btn0);
input_report_key(pen_dev, BTN_STYLUS2, msgs[i].btn1);
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(pen_dev, ABS_X, x);
input_report_abs(pen_dev, ABS_Y, y);
input_report_abs(pen_dev, ABS_PRESSURE, p);
input_report_abs(pen_dev, ABS_TILT_X, msgs[i].tiltx);
input_report_abs(pen_dev, ABS_TILT_Y, msgs[i].tilty);
break;
case CTS_DEVICE_TOUCH_EVENT_UP:
break;
default:
cts_warn("Process stylus msg with unknwon event %u id %u",
msgs[i].event, msgs[i].id);
break;
}
}
input_report_key(pen_dev, BTN_TOUCH, contact > 0);
input_report_key(pen_dev, BTN_TOOL_PEN, contact > 0);
input_sync(pen_dev);
#ifdef CFG_CTS_FORCE_UP
if (contact) {
if (delayed_work_pending(&pdata->touch_timeout)) {
mod_delayed_work(cts_data->workqueue,
&pdata->touch_timeout, msecs_to_jiffies(100));
} else {
queue_delayed_work(cts_data->workqueue,
&pdata->touch_timeout, msecs_to_jiffies(100));
}
} else {
cancel_delayed_work_sync(&pdata->touch_timeout);
}
#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;
}
#ifdef CFG_CTS_FINGER_STYLUS_SUPPORTED
int cts_plat_process_touch_stylus(struct cts_platform_data *pdata,
struct cts_device_touch_info *touch_info)
{
struct chipone_ts_data *cts_data;
struct input_dev *input_dev = pdata->ts_input_dev;
struct input_dev *pen_dev = pdata->pen_input_dev;
struct cts_device_touch_msg *msgs = touch_info->msgs;
int touch_num = touch_info->num_msg;
struct cts_device_stylus_msg *smsgs = touch_info->smsgs;
int stylus_num = touch_info->stylus_num;
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, stylus %d msgs", touch_num, stylus_num);
cts_data = container_of(pdata->cts_dev, struct chipone_ts_data, cts_dev);
if (touch_num == 0 || touch_num > CFG_CTS_MAX_TOUCH_NUM) {
goto process_stylus;
}
for (i = 0; i < touch_num; i++) {
u16 x, y;
x = (msgs[i].xl) | (msgs[i].xh << 8);
y = (msgs[i].yl) | (msgs[i].yh << 8);
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:
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
TPD_DEBUG_SET_TIME;
TPD_EM_PRINT(x, y, x, y, msgs[i].id, 1);
tpd_history_x = x;
tpd_history_y = y;
#ifdef CONFIG_MTK_BOOT
if (tpd_dts_data.use_tpd_button) {
if (FACTORY_BOOT == get_boot_mode() ||
RECOVERY_BOOT == get_boot_mode())
tpd_button(x, y, 1);
}
#endif /* CONFIG_MTK_BOOT */
#endif /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
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:
#ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
TPD_DEBUG_SET_TIME;
TPD_EM_PRINT(tpd_history_x, tpd_history_y, tpd_history_x, tpd_history_y, msgs[i].id, 0);
tpd_history_x = 0;
tpd_history_y = 0;
#ifdef CONFIG_MTK_BOOT
if (tpd_dts_data.use_tpd_button) {
if (FACTORY_BOOT == get_boot_mode() ||
RECOVERY_BOOT == get_boot_mode())
tpd_button(0, 0, 0);
}
#endif /* CONFIG_MTK_BOOT */
#endif /* CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED */
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);
process_stylus:
if (stylus_num == 0 || stylus_num > CFG_CTS_MAX_STYLUS_NUM) {
return 0;
}
for (i = 0; i < stylus_num; i++) {
u16 x, y, p;
x = (smsgs[i].tip_xl) | (smsgs[i].tip_xh << 8);
y = (smsgs[i].tip_yl) | (smsgs[i].tip_yh << 8);
p = smsgs[i].pressure_l | (smsgs[i].pressure_h << 8);
cts_dbg(" Process stylus msg[%d]: id[%u] ev=%u x=%u y=%u p=%u"
" tx=%d ty=%d btn0=%d btn1=%d btn2=%d",
i, smsgs[i].id, smsgs[i].event, x, y, p, smsgs[i].tiltx, smsgs[i].tilty,
smsgs[i].btn0, smsgs[i].btn1, smsgs[i].btn2);
/* Report stylus button */
input_report_key(pen_dev, BTN_STYLUS, smsgs[i].btn0);
input_report_key(pen_dev, BTN_STYLUS2, smsgs[i].btn1);
switch (smsgs[i].event) {
case CTS_DEVICE_TOUCH_EVENT_DOWN:
case CTS_DEVICE_TOUCH_EVENT_MOVE:
case CTS_DEVICE_TOUCH_EVENT_STAY:
contact++;
input_report_abs(pen_dev, ABS_X, x);
input_report_abs(pen_dev, ABS_Y, y);
input_report_abs(pen_dev, ABS_PRESSURE, p);
input_report_abs(pen_dev, ABS_TILT_X, smsgs[i].tiltx);
input_report_abs(pen_dev, ABS_TILT_Y, smsgs[i].tilty);
break;
case CTS_DEVICE_TOUCH_EVENT_UP:
break;
default:
cts_warn("Process stylus msg with unknwon event %u id %u",
smsgs[i].event, smsgs[i].id);
break;
}
}
input_report_key(pen_dev, BTN_TOUCH, contact > 0);
input_report_key(pen_dev, BTN_TOOL_PEN, contact > 0);
input_sync(pen_dev);
#ifdef CFG_CTS_FORCE_UP
if (contact) {
if (delayed_work_pending(&pdata->touch_timeout)) {
mod_delayed_work(cts_data->workqueue,
&pdata->touch_timeout, msecs_to_jiffies(100));
} else {
queue_delayed_work(cts_data->workqueue,
&pdata->touch_timeout, msecs_to_jiffies(100));
}
} else {
cancel_delayed_work_sync(&pdata->touch_timeout);
}
#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;
}
#endif
int cts_plat_release_all_touch(struct cts_platform_data *pdata)
{
struct input_dev *input_dev = pdata->ts_input_dev;
struct input_dev *pen_dev = pdata->pen_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);
input_report_key(pen_dev, BTN_TOUCH, 0);
input_report_key(pen_dev, BTN_TOOL_PEN, 0);
input_sync(pen_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;
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
for (i = 0; i < pdata->vkey_num; i++) {
input_set_capability(pdata->ts_input_dev,
EV_KEY, pdata->vkey_keycodes[i]);
}
#else
if (tpd_dts_data.use_tpd_button) {
cts_info("Init vkey");
pdata->vkey_state = 0;
tpd_button_setting(tpd_dts_data.tpd_key_num, tpd_dts_data.tpd_key_local,
tpd_dts_data.tpd_key_dim_local);
}
#endif
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);
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
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);
}
#else
for (i = 0; i < pdata->vkey_num; i++) {
if (event & BIT(i)) {
tpd_button(x, y, vkey_state & BIT(i));
/* MTK fobidon more than one key pressed in the same time */
break;
}
}
#endif
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");
#ifndef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED
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);
}
}
#else
for (i = 0; i < pdata->vkey_num; i++) {
if (pdata->vkey_state & BIT(i)) {
tpd_button(x, y, 0);
}
}
#endif
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]) {
if (gesture_info->gesture_id == GESTURE_D_TAP) {
if (!pdata->cts_dev->rtdata.gesture_d_tap_enabled) {
cts_info("Ingore double tap");
return 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 */