blob: a6aaf5209e33010a9e2d82b06fa6132a71068600 [file] [log] [blame]
/* drivers/input/touchscreen/raydium_wt030/raydium_driver.c
*
* Raydium TouchScreen driver.
*
* Copyright (c) 2010 Raydium tech Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/unistd.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/regulator/consumer.h>
#include <linux/device.h>
#include <linux/kprobes.h>
#include <asm/traps.h>
#include <linux/firmware.h>
#include <linux/of_gpio.h>
#include "raydium_driver.h"
#if defined(CONFIG_FB)
#include <linux/notifier.h>
#include <linux/fb.h>
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif /*end of CONFIG_FB*/
struct raydium_slot_status {
unsigned char pt_id; /*Occupied point ID*/
unsigned char need_update; /*Mark as info need to be updated*/
unsigned char pt_report_offset; /*point info offset in report*/
};
/*The first 3 elements are currently occupied. therest is new coming points*/
struct raydium_slot_status gst_slot[MAX_TOUCH_NUM * 2];
struct raydium_slot_status gst_slot_init = {0xFF, 0, 0};
unsigned char g_u8_addr;
unsigned char g_u8_raydium_flag;
unsigned char g_u8_i2c_mode;
unsigned char g_u8_upgrade_type;
unsigned char g_u8_raw_data_type;
unsigned int g_u32_raw_data_len; /* 72 bytes*/
unsigned long g_u32_addr;
unsigned int g_u32_length;
unsigned int g_u32_driver_version;
unsigned char *g_rad_fw_image, *g_rad_init_image;
unsigned char *g_rad_boot_image, *g_rad_para_image;
unsigned char *g_rad_testfw_image, *g_rad_testpara_image;
unsigned char g_u8_table_setting, g_u8_table_init;
unsigned char g_u8_resetflag;
#ifdef ESD_SOLUTION_EN
unsigned char g_u8_checkflag;
#endif
#ifdef ENABLE_DUMP_DATA
unsigned char g_u8_dumpcount;
unsigned char g_u8_dump_flag;
unsigned char g_u8_palm_flag;
unsigned long timeout;
#endif
struct raydium_ts_data *g_raydium_ts;
/*****************************************************************************
* Name: raydium_variable_init
* Brief:
* Input:
* Output:
* Return:
*****************************************************************************/
static void raydium_variable_init(void)
{
g_u8_addr = RAYDIUM_PDA2_PDA_CFG_ADDR;
g_u8_raydium_flag = 0;
g_u8_i2c_mode = PDA2_MODE;
g_u8_upgrade_type = 0;
g_u8_raw_data_type = RAYDIUM_FT_UPDATE;
g_u32_raw_data_len = 36 * 2; /* 72 bytes*/
g_u32_addr = RAD_CHK_I2C_CMD;
g_u32_length = 1;
g_u8_table_setting = 0;
g_u8_table_init = 0;
g_rad_fw_image = NULL;
g_rad_init_image = NULL;
g_rad_boot_image = NULL;
g_rad_para_image = NULL;
g_rad_testfw_image = NULL;
g_rad_testpara_image = NULL;
g_u32_driver_version = ((RAD_MAIN_VERSION << 24) |
(RAD_MINOR_VERSION << 16) |
(RAD_CUSTOMER_VERSION));
g_u8_resetflag = false;
#ifdef ESD_SOLUTION_EN
g_u8_checkflag = false;
#endif
#ifdef ENABLE_DUMP_DATA
g_u8_dumpcount = 0;
g_u8_dump_flag = false;
g_u8_palm_flag = false;
#endif
}
/*****************************************************************************
* Name: raydium_gpio_configure
* Brief:
* Input:
* Output:
* Return:
*****************************************************************************/
static int raydium_gpio_configure(bool on)
{
int i32_err = 0;
if (on) {
if (gpio_is_valid(g_raydium_ts->irq_gpio)) {
i32_err = gpio_request(g_raydium_ts->irq_gpio,
"raydium_irq_gpio");
if (i32_err) {
dev_err(&g_raydium_ts->client->dev,
"[touch]irq gpio request failed");
goto err_irq_gpio_req;
}
i32_err = gpio_direction_input(g_raydium_ts->irq_gpio);
if (i32_err) {
dev_err(&g_raydium_ts->client->dev,
"[touch]set_direction for irq gpio failed\n");
goto err_irq_gpio_dir;
}
}
if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
i32_err = gpio_request(g_raydium_ts->rst_gpio,
"raydium_rst_gpio");
if (i32_err) {
dev_err(&g_raydium_ts->client->dev,
"[touch]rst gpio request failed");
goto err_irq_gpio_req;
}
i32_err = gpio_direction_output(g_raydium_ts->rst_gpio,
1);
if (i32_err) {
dev_err(&g_raydium_ts->client->dev,
"[touch]set_direction for irq gpio failed\n");
goto err_rst_gpio_dir;
}
}
} else {
if (gpio_is_valid(g_raydium_ts->irq_gpio))
gpio_free(g_raydium_ts->irq_gpio);
}
return 0;
err_rst_gpio_dir:
if (gpio_is_valid(g_raydium_ts->rst_gpio))
gpio_free(g_raydium_ts->rst_gpio);
return i32_err;
err_irq_gpio_dir:
if (gpio_is_valid(g_raydium_ts->irq_gpio))
gpio_free(g_raydium_ts->irq_gpio);
err_irq_gpio_req:
return i32_err;
}
/*****************************************************************************
* Name: raydium_ts_pinctrl_init
* Brief:
* Input:
* Output:
* Return:
*****************************************************************************/
#ifdef MSM_NEW_VER
static int raydium_ts_pinctrl_init(void)
{
int i32_ret;
/* Get pinctrl if target uses pinctrl */
g_raydium_ts->ts_pinctrl = devm_pinctrl_get(&(g_raydium_ts->client->dev));
if (IS_ERR_OR_NULL(g_raydium_ts->ts_pinctrl)) {
i32_ret = PTR_ERR(g_raydium_ts->ts_pinctrl);
pr_err("[touch]target does not use pinctrl %d\n", i32_ret);
goto err_pinctrl_get;
}
g_raydium_ts->pinctrl_state_active
= pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
PINCTRL_STATE_ACTIVE);
if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_active)) {
i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_active);
pr_err("[touch]Can not lookup %s pinstate %d\n",
PINCTRL_STATE_ACTIVE, i32_ret);
goto err_pinctrl_lookup;
}
g_raydium_ts->pinctrl_state_suspend
= pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
PINCTRL_STATE_SUSPEND);
if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_suspend)) {
i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_suspend);
pr_err("[touch]Can not lookup %s pinstate %d\n",
PINCTRL_STATE_SUSPEND, i32_ret);
goto err_pinctrl_lookup;
}
g_raydium_ts->pinctrl_state_release
= pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
PINCTRL_STATE_RELEASE);
if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_release)) {
i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_release);
pr_err("[touch]Can not lookup %s pinstate %d\n",
PINCTRL_STATE_RELEASE, i32_ret);
}
return 0;
err_pinctrl_lookup:
devm_pinctrl_put(g_raydium_ts->ts_pinctrl);
err_pinctrl_get:
g_raydium_ts->ts_pinctrl = NULL;
return i32_ret;
}
#endif/*end of MSM_NEW_VER*/
int wait_irq_state(struct i2c_client *client, unsigned int retry_time,
unsigned int u32_delay_us)
{
int i32_ret = SUCCESS;
unsigned int u32_retry;
unsigned int u32_irq_value;
unsigned int u32_min_delay_us = u32_delay_us - 500;
unsigned int u32_max_delay_us = u32_delay_us + 500;
u32_retry = retry_time;
u32_irq_value = 0;
while (u32_retry != 0 && u32_irq_value != 1) {
u32_irq_value = gpio_get_value(g_raydium_ts->irq_gpio);
usleep_range(u32_min_delay_us, u32_max_delay_us);
u32_retry--;
}
pr_debug("[touch]irq_value is %d\n", u32_irq_value);
if (u32_retry == 0) {
pr_err("[touch]%s, FW not ready, retry error!\n", __func__);
i32_ret = ERROR;
}
return i32_ret;
}
#ifdef ESD_SOLUTION_EN
static int raydium_hw_reset_fun(struct i2c_client *client)
{
int i32_ret = SUCCESS;
pr_debug("[touch]HW reset\n");
if ((g_u8_raydium_flag & ENG_MODE) == 0)
raydium_irq_control(DISABLE);
g_u8_resetflag = true;
/*HW reset*/
gpio_set_value(g_raydium_ts->rst_gpio, 1);
gpio_set_value(g_raydium_ts->rst_gpio, 0);
msleep(RAYDIUM_RESET_INTERVAL_MSEC);
gpio_set_value(g_raydium_ts->rst_gpio, 1);
g_u8_i2c_mode = PDA2_MODE;
i32_ret = wait_irq_state(client, 300, 2000);
if (i32_ret != ERROR)
msleep(25);
if ((g_u8_raydium_flag & ENG_MODE) == 0)
raydium_irq_control(ENABLE);
pr_debug("[touch]Raydium HW reset : %d\n", i32_ret);
return i32_ret;
}
#endif
int raydium_i2c_pda_set_address(unsigned int u32_address,
unsigned char u8_mode)
{
int i32_ret = 0;
unsigned char u8_retry;
unsigned char u8_buf[RAD_I2C_PDA_ADDRESS_LENGTH];
struct i2c_client *client = g_raydium_ts->client;
client->addr = RAYDIUM_I2C_EID;
u8_buf[0] = (u32_address & 0x0000FF00) >> 8;
u8_buf[1] = (u32_address & 0x00FF0000) >> 16;
u8_buf[2] = (u32_address & 0xFF000000) >> 24;
u8_buf[3] = u8_mode;
for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
i32_ret = i2c_master_send(client, u8_buf,
RAD_I2C_PDA_ADDRESS_LENGTH);
if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH) {
pr_err("[touch]%s: I2C retry %d\n",
__func__, u8_retry + 1);
usleep_range(500, 1500);
} else {
break;
}
}
return (i32_ret == RAD_I2C_PDA_ADDRESS_LENGTH) ? i32_ret : -EIO;
}
/*device attribute raydium_i2c_pda2_mode used*/
int raydium_i2c_pda_read(struct i2c_client *client,
unsigned int u32_addr, unsigned char *u8_r_data,
unsigned short u16_length)
{
int i32_ret;
unsigned char u8_retry;
unsigned char u8_mode = 0x00;
unsigned char u8_buf;
struct i2c_msg msg[] = {
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_WRITE,
.len = 1,
.buf = &u8_buf,
},
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_READ,
.len = u16_length,
.buf = u8_r_data,
},
};
if (u16_length == 4)
u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
RAD_I2C_PDA_2_MODE_DISABLE |
RAD_I2C_PDA_MODE_WORD_MODE;
else
u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
RAD_I2C_PDA_2_MODE_DISABLE;
u8_mode |= 0x03;
u8_buf = u32_addr & MASK_8BIT;
i32_ret = raydium_i2c_pda_set_address(u32_addr, u8_mode);
if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH)
goto exit;
usleep_range(50, 80);
for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
i32_ret = u16_length;
break;
}
pr_err("%s: I2C retry %d\n", __func__, u8_retry + 1);
usleep_range(500, 1500);
}
if (u8_retry == SYN_I2C_RETRY_TIMES) {
pr_err("%s: I2C read over retry limit\n", __func__);
i32_ret = -EIO;
}
exit:
return i32_ret;
}
int raydium_i2c_pda_write(struct i2c_client *client,
unsigned int u32_addr, unsigned char *u8_w_data,
unsigned short u16_length)
{
int i32_ret;
unsigned char u8_retry;
unsigned char u8_mode = 0x00;
unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 1];
struct i2c_msg msg[] = {
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_WRITE,
.len = u16_length + 1,
.buf = u8_buf,
},
};
if (u16_length > MAX_WRITE_PACKET_SIZE)
return -EINVAL;
if (u16_length == 4)
u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
RAD_I2C_PDA_2_MODE_DISABLE |
RAD_I2C_PDA_MODE_WORD_MODE;
else
u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
RAD_I2C_PDA_2_MODE_DISABLE;
u8_buf[0] = u32_addr & MASK_8BIT;
memcpy(&u8_buf[1], u8_w_data, u16_length);
i32_ret = raydium_i2c_pda_set_address(u32_addr, u8_mode);
if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH)
goto exit;
for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
if (i2c_transfer(client->adapter, msg, 1) == 1) {
i32_ret = u16_length;
break;
}
pr_err("[touch]%s: I2C retry %d\n", __func__, u8_retry + 1);
usleep_range(500, 1500);
}
if (u8_retry == SYN_I2C_RETRY_TIMES) {
pr_err("[touch]%s: I2C write over retry limit\n", __func__);
i32_ret = -EIO;
}
exit:
return i32_ret;
}
int raydium_i2c_pda2_set_page(struct i2c_client *client,
unsigned int is_suspend,
unsigned char u8_page)
{
int i32_ret = -1;
unsigned char u8_retry;
unsigned int u8_ret = (is_suspend) ? 10 : 2;
unsigned char u8_buf[RAYDIUM_I2C_PDA2_PAGE_LENGTH];
struct i2c_msg msg[] = {
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_WRITE,
.len = RAYDIUM_I2C_PDA2_PAGE_LENGTH,
.buf = u8_buf,
},
};
u8_buf[0] = RAYDIUM_PDA2_PAGE_ADDR;
u8_buf[1] = u8_page;
for (; u8_ret > 0; u8_ret--) {
for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
if (i2c_transfer(client->adapter, msg, 1) == 1) {
i32_ret = RAYDIUM_I2C_PDA2_PAGE_LENGTH;
break;
}
usleep_range(500, 1500);
}
if (i32_ret == RAYDIUM_I2C_PDA2_PAGE_LENGTH)
break;
usleep_range(2000, 5000);
}
if (u8_ret == 0) {
pr_err("[touch]%s: I2C write over retry limit\n", __func__);
i32_ret = -EIO;
}
return i32_ret;
}
int raydium_i2c_pda2_read(struct i2c_client *client,
unsigned char u8_addr,
unsigned char *u8_r_data,
unsigned short u16_length)
{
int i32_ret = -1;
unsigned char u8_retry;
struct i2c_msg msg[] = {
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_WRITE,
.len = 1,
.buf = &u8_addr,
},
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_READ,
.len = u16_length,
.buf = u8_r_data,
},
};
g_u8_i2c_mode = PDA2_MODE;
for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
i32_ret = u16_length;
break;
}
usleep_range(500, 1500);
}
if (u8_retry == SYN_I2C_RETRY_TIMES) {
pr_err("[touch]%s: I2C read over retry limit\n", __func__);
i32_ret = -EIO;
}
return i32_ret;
}
int raydium_i2c_pda2_write(struct i2c_client *client,
unsigned char u8_addr,
unsigned char *u8_w_data,
unsigned short u16_length)
{
int i32_ret = -1;
unsigned char u8_retry;
unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 1];
struct i2c_msg msg[] = {
{
.addr = RAYDIUM_I2C_NID,
.flags = RAYDIUM_I2C_WRITE,
.len = u16_length + 1,
.buf = u8_buf,
},
};
if (u16_length > MAX_WRITE_PACKET_SIZE)
return -EINVAL;
g_u8_i2c_mode = PDA2_MODE;
u8_buf[0] = u8_addr;
memcpy(&u8_buf[1], u8_w_data, u16_length);
for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
if (i2c_transfer(client->adapter, msg, 1) == 1) {
i32_ret = u16_length;
break;
}
usleep_range(500, 1500);
}
if (u8_retry == SYN_I2C_RETRY_TIMES) {
pr_err("[touch]%s: I2C write over retry limit\n", __func__);
i32_ret = -EIO;
}
return i32_ret;
}
void raydium_irq_control(bool enable)
{
if (enable) {
if (g_raydium_ts->irq_enabled) {
/*mutex_unlock(&ts->lock);*/
dev_info(&g_raydium_ts->client->dev,
"[touch]Already enable irq\n");
return;
}
/* Clear interrupts first */
if (g_raydium_ts->blank != FB_BLANK_POWERDOWN &&
g_u8_i2c_mode == PDA2_MODE) {
mutex_lock(&g_raydium_ts->lock);
if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0) < 0)
pr_err("[touch]set page fail%s\n",
__func__);
mutex_unlock(&g_raydium_ts->lock);
usleep_range(500, 1500);
}
while (g_raydium_ts->irq_desc->depth > 0) {
pr_debug("[touch]irq enable\n");
g_raydium_ts->irq_enabled = true;
enable_irq(g_raydium_ts->irq);
}
} else {
if (g_raydium_ts->irq_enabled &&
g_raydium_ts->irq_desc->depth == 0) {
disable_irq(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = false;
pr_debug("[touch]irq disable\n");
}
}
}
#ifdef CONFIG_RM_SYSFS_DEBUG
int raydium_i2c_mode_control(struct i2c_client *client,
unsigned char u8_mode)
{
unsigned char u8_buf[4];
switch (u8_mode) {
case 0: /* Disable INT flag */
pr_debug("[touch]RAD INT flag : %d\n",
g_raydium_ts->irq_enabled);
disable_irq(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = false;
pr_debug("[touch]RAD irq disable\n");
break;
case 1: /* Enable INT flag */
pr_debug("[touch]RAD INT flag : %d\n",
g_raydium_ts->irq_enabled);
enable_irq(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = true;
pr_debug("[touch]RAD irq enable\n");
break;
case 2: /* Disable INT by raydium_irq_control */
raydium_irq_control(DISABLE);
break;
case 3: /* Enable INT by raydium_irq_control */
raydium_irq_control(ENABLE);
break;
case 4: /* Show RAD INT depth */
pr_debug("[touch]RAD INT depth : %d\n",
g_raydium_ts->irq_desc->depth);
break;
case 7:
raydium_i2c_pda2_set_page(client,
g_raydium_ts->is_suspend, RAYDIUM_PDA2_2_PDA);
g_u8_i2c_mode = PDA_MODE;
pr_debug("[touch]Disable PDA2_MODE\n");
break;
case 8:
raydium_i2c_pda_read(client, RAD_PDA2_CTRL_CMD, u8_buf, 4);
u8_buf[0] |= RAD_ENABLE_PDA2 | RAD_ENABLE_SI2;
raydium_i2c_pda_write(client, RAD_PDA2_CTRL_CMD, u8_buf, 4);
raydium_i2c_pda_set_address(0x50000628, DISABLE);
g_u8_i2c_mode = PDA2_MODE;
pr_debug("[touch]Enable PDA2_MODE\n");
break;
}
return 0;
}
static const struct attribute_group raydium_attr_group = {
.attrs = raydium_attributes
};
/*create sysfs for debug update firmware*/
static int raydium_create_sysfs(struct i2c_client *client)
{
int ret = -1;
ret = sysfs_create_group(&(client->dev.kobj), &raydium_attr_group);
if (ret) {
pr_err("[touch]failed to register sysfs\n");
sysfs_remove_group(&client->dev.kobj, &raydium_attr_group);
ret = -EIO;
} else {
pr_debug("[touch]create raydium sysfs attr_group successful\n");
}
return ret;
}
static void raydium_release_sysfs(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &raydium_attr_group);
}
#endif /*end of CONFIG_RM_SYSFS_DEBUG*/
#ifdef ESD_SOLUTION_EN
int raydium_esd_check(void)
{
int i32_ret = 0;
unsigned char u8_esd_status[MAX_TCH_STATUS_PACKET_SIZE];
unsigned char u8_w_data[4];
mutex_lock(&g_raydium_ts->lock);
if (g_u8_i2c_mode == PDA2_MODE) {
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit;
/*read esd status*/
i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
u8_esd_status, MAX_TCH_STATUS_PACKET_SIZE);
if (i32_ret < 0) {
pr_err("[touch]%s: failed to read data: %d\n",
__func__, __LINE__);
goto exit;
}
if (u8_esd_status[POS_FW_STATE] != 0x1A &&
u8_esd_status[POS_FW_STATE] != 0xAA) {
if (g_u8_resetflag == true) {
pr_err("[touch]%s -> filter abnormal irq\n"
, __func__);
goto exit;
}
pr_err("[touch]%s -> abnormal irq, FW state = 0x%x\n",
__func__, u8_esd_status[POS_FW_STATE]);
g_u8_resetflag = false;
i32_ret = -1;
goto exit;
}
u8_w_data[POS_SEQ] = 0;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
u8_w_data, 1);
if (i32_ret < 0) {
pr_err("[touch]%s: failed to clear seq: %d\n",
__func__, __LINE__);
goto exit;
}
g_u8_resetflag = false;
}
exit:
mutex_unlock(&g_raydium_ts->lock);
pr_debug("[touch] raydium_esd_check\n");
return i32_ret;
}
#endif
#ifdef ENABLE_DUMP_DATA
int raydium_dump_data(unsigned char u8_frame, unsigned char u8_type)
{
unsigned char u8_rbuffer[MAX_READ_PACKET_SIZE*2];
short i16_data_buffer[MAX_READ_PACKET_SIZE*2];
unsigned char u8_w_data[RAYDIUM_FT_CMD_LENGTH];
unsigned int u32_target_addr;
unsigned int u32_offset;
unsigned short u16_read_length;
int i32_ret = -1;
int i32_retry = 0;
unsigned char u8_i, u8_j, u8_k;
char write_string[1000];
pr_debug("[touch] %s -> type:%d\n", __func__, u8_type);
for (u8_i = 0; u8_i < u8_frame; u8_i++) {
u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
u8_w_data[RAD_FT_CMD_POS] = u8_type;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_w_data, RAYDIUM_FT_CMD_LENGTH);
memset(u8_rbuffer, 0x00, MAX_READ_PACKET_SIZE*2);
/* make sure update flag was set*/
for (i32_retry = 0; i32_retry < 5; i32_retry++) {
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit_i2c_error;
i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_rbuffer,
RAYDIUM_FT_CMD_LENGTH);
if (i32_ret < 0)
goto exit_flag_error;
if ((u8_rbuffer[RAD_FT_CMD_POS] & RAYDIUM_FT_UPDATE) ==
RAYDIUM_FT_UPDATE)
break;
usleep_range(4500, 5500);
}
if (i32_retry == 5) {
i32_ret = -EAGAIN;
pr_err("[touch] %s -> flag timeout\n", __func__);
}
u32_offset = 0;
u16_read_length = 0;
#if DATA_MAP_5_5
g_u32_raw_data_len = 0x32;
#else
g_u32_raw_data_len = 0x48;
#endif
while (u32_offset < g_u32_raw_data_len) {
u16_read_length = g_u32_raw_data_len;
u32_target_addr = RAD_READ_FT_DATA_CMD + u32_offset;
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit_i2c_error;
*(unsigned int *)u8_rbuffer =
(RAD_I2C_PDA_MODE_ENABLE << 24)
| ((u32_target_addr & (~MASK_8BIT)) >> 8);
/*using byte mode to read 4 bytes*/
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_PDA_CFG_ADDR,
u8_rbuffer, 4);
if (i32_ret < 0)
goto exit_i2c_error;
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_ENABLE_PDA);
if (i32_ret < 0)
goto exit_i2c_error;
i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
(unsigned char)(u32_target_addr
& MASK_8BIT), u8_rbuffer,
u16_read_length);
if (i32_ret < 0)
goto exit_flag_error;
memcpy((i16_data_buffer + u32_offset),
u8_rbuffer,
u16_read_length);
u32_offset += u16_read_length;
}
pr_debug("[touch] frame%d\n", u8_i);
#if DATA_MAP_5_5
for (u8_j = 0; u8_j < 25; u8_j += 5) {
pr_debug("[touch] %4d, %4d, %4d, %4d, %4d\r\n",
i16_data_buffer[u8_j], i16_data_buffer[u8_j+1],
i16_data_buffer[u8_j+2], i16_data_buffer[u8_j+3],
i16_data_buffer[u8_j+4]);
}
#else
for (u8_j = 0; u8_j < 36; u8_j += 6) {
pr_debug("[touch] %4d, %4d, %4d, %4d, %4d, %4d\r\n",
i16_data_buffer[u8_j], i16_data_buffer[u8_j+1],
i16_data_buffer[u8_j+2], i16_data_buffer[u8_j+3],
i16_data_buffer[u8_j+4], i16_data_buffer[u8_j+5]);
}
#endif
/* clear update flag to get next one*/
u8_rbuffer[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
u8_rbuffer[RAD_FT_CMD_POS] = u8_type;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_rbuffer, RAYDIUM_FT_CMD_LENGTH);
if (i32_ret < 0)
goto exit_flag_error;
}
return 0;
exit_i2c_error:
pr_err("%s exit_i2c_error return %d\r\n", __func__, i32_ret);
exit_flag_error:
return i32_ret;
}
static void raydium_dump_data_work(struct work_struct *work)
{
int i32_ret = 0;
unsigned char u8_data_type;
unsigned char u8_w_data[RAYDIUM_FT_CMD_LENGTH];
/* set mode */
memset(u8_w_data, 0x00, RAYDIUM_FT_CMD_LENGTH);
pr_debug("[touch] raydium_dump_data_work\n");
disable_irq_nosync(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = false;
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit_error;
u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_FT_MODE;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_w_data, 1);
if (i32_ret < 0)
goto exit_error;
pr_debug("[touch] RAYDIUM_HOST_CMD_FT_MODE\n");
/*baseline*/
u8_data_type = 0x02;
raydium_dump_data(1, u8_data_type);
u8_data_type = 0x04;
raydium_dump_data(1, u8_data_type);
u8_data_type = 0x10;
raydium_dump_data(10, u8_data_type);
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit_error;
u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_TP_MODE;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_w_data, 1);
u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
u8_w_data[RAD_FT_CMD_POS] = 0;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_w_data, RAD_FT_CMD_LENGTH);
if (i32_ret < 0)
goto exit_error;
exit_error:
enable_irq(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = true;
}
#endif
#ifdef FILTER_POINTS
int raydium_pointer_filter(int i32_index,
unsigned short u16_diff_x,
unsigned short u16_diff_y)
{
if (abs(ts->x_pos[i32_index] - ts->last_x_pos[i32_index]) > u16_diff_x)
return 0;
if (abs(ts->y_pos[i32_index] - ts->last_y_pos[i32_index]) > u16_diff_y)
return 0;
return 1;
}
#endif
#ifdef HOST_NOTIFY_EN
int raydium_notify_function(unsigned short u16_display_mode)
{
int i32_ret = 0;
unsigned char u8_rbuffer[4];
mutex_lock(&g_raydium_ts->lock);
if (g_u8_i2c_mode == PDA2_MODE) {
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit;
memset(u8_rbuffer, 0, sizeof(u8_rbuffer));
u8_rbuffer[0] = RAYDIUM_HOST_CMD_DISPLAY_MODE;
u8_rbuffer[2] = (unsigned char) (u16_display_mode & 0x00ff);
u8_rbuffer[3] = (unsigned char) ((u16_display_mode & 0xff00) >> 8);
pr_debug("[touch] display mode %d %d %d\r\n", u16_display_mode,
u8_rbuffer[2], u8_rbuffer[3]);
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_rbuffer, 4);
}
exit:
mutex_unlock(&g_raydium_ts->lock);
pr_debug("[touch] raydium_notify_function\n");
return i32_ret;
}
#endif
static int raydium_touch_report(unsigned char *p_u8_buf,
unsigned char u8_points_amount)
{
unsigned char u8_i, u8_j, u8_offset = 0, u8_pt_id;
signed short i16_wx, i16_wy;
/* number of touch points */
unsigned char u8_touch_count = 0;
DECLARE_BITMAP(ids, g_raydium_ts->u8_max_touchs);
bitmap_zero(ids, g_raydium_ts->u8_max_touchs);
for (u8_i = 0; u8_i < (g_raydium_ts->u8_max_touchs * 2); u8_i++) {
gst_slot[u8_i].need_update = 0;
gst_slot[u8_i].pt_report_offset = 0;
}
/*Check incoming point info*/
for (u8_i = 0; u8_i < u8_points_amount; u8_i++) {
u8_pt_id = p_u8_buf[POS_PT_ID + u8_i * LEN_PT];
/* Current*/
for (u8_j = 0; u8_j < g_raydium_ts->u8_max_touchs; u8_j++) {
if (u8_pt_id == gst_slot[u8_j].pt_id) {
gst_slot[u8_j].need_update = 1;
gst_slot[u8_j].pt_report_offset = u8_i;
break;
}
}
/* New coming*/
if (u8_j == g_raydium_ts->u8_max_touchs) {
for (u8_j = g_raydium_ts->u8_max_touchs;
u8_j < (g_raydium_ts->u8_max_touchs * 2); u8_j++) {
if (!gst_slot[u8_j].need_update) {
gst_slot[u8_j].pt_id = u8_pt_id;
gst_slot[u8_j].need_update = 1;
gst_slot[u8_j].pt_report_offset = u8_i;
pr_debug("[touch]x:%d,y:%d\n",
p_u8_buf[POS_X_L + u8_offset] |
p_u8_buf[POS_X_H + u8_offset] << 8,
p_u8_buf[POS_Y_L + u8_offset] |
p_u8_buf[POS_Y_H + u8_offset] << 8);
break;
}
}
}
}
/*Release slot with non-occupied point*/
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
if (!gst_slot[u8_i].need_update) {
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, false);
gst_slot[u8_i].pt_id = 0xFF;
gst_slot[u8_i].pt_report_offset = 0;
gst_slot[u8_i].need_update = 0;
}
}
/*Assign new one to non-occupied slot*/
for (u8_i = g_raydium_ts->u8_max_touchs;
u8_i < (g_raydium_ts->u8_max_touchs * 2); u8_i++) {
if (gst_slot[u8_i].need_update) {
for (u8_j = 0; u8_j < g_raydium_ts->u8_max_touchs; u8_j++) {
if (!gst_slot[u8_j].need_update) {
gst_slot[u8_j] = gst_slot[u8_i];
gst_slot[u8_i] = gst_slot_init;
break;
}
}
} else {
break;
}
}
#ifdef FILTER_POINTS
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
if (gst_slot[u8_i].need_update) {
u8_offset = gst_slot[u8_i].pt_report_offset * LEN_PT;
g_raydium_ts->x_pos[i] = p_u8_buf[POS_X_L + u8_offset] |
p_u8_buf[POS_X_H + u8_offset] << BYTE_SHIFT;
g_raydium_ts->y_pos[i] = p_u8_buf[POS_Y_L + u8_offset] |
p_u8_buf[POS_Y_H + u8_offset] << BYTE_SHIFT;
g_raydium_ts->pressure = p_u8_buf[POS_PRESSURE_L + u8_offset] |
p_u8_buf[POS_PRESSURE_H + u8_offset] << BYTE_SHIFT;
i16_wx = p_u8_buf[POS_WX_L + u8_offset] |
p_u8_buf[POS_WX_H + u8_offset] << BYTE_SHIFT;
i16_wy = p_u8_buf[POS_WY_L + u8_offset] |
p_u8_buf[POS_WY_H + u8_offset] << BYTE_SHIFT;
if (!raydium_pointer_filter(g_raydium_ts, u8_i, DELTA_X, DELTA_Y)) {
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, true);
__set_bit(i, ids);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_X, g_raydium_ts->x_pos[u8_i]);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_Y, g_raydium_ts->y_pos[u8_i]);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_PRESSURE, g_raydium_ts->pressure);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_TOUCH_MAJOR, max(i16_wx, i16_wy));
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_TOUCH_MINOR, min(i16_wx, i16_wy));
input_report_key(g_raydium_ts->input_dev,
BTN_TOUCH, 1);
input_report_key(g_raydium_ts->input_dev,
BTN_TOOL_FINGER, 1);
input_sync(g_raydium_ts->input_dev);
g_raydium_ts->last_x_pos[u8_i] = g_raydium_ts->x_pos[u8_i];
g_raydium_ts->last_y_pos[u8_i] = g_raydium_ts->y_pos[u8_i];
} else {
g_raydium_ts->x_pos[u8_i] = g_raydium_ts->last_x_pos[u8_i];
g_raydium_ts->y_pos[u8_i] = g_raydium_ts->last_y_pos[u8_i];
}
}
}
if ((gst_slot[0].need_update == 0) &&
(gst_slot[1].need_update == 0)) {
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
if (test_bit(u8_i, ids))
continue;
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, false);
}
input_report_key(g_raydium_ts->input_dev, BTN_TOUCH, 0);
input_report_key(g_raydium_ts->input_dev, BTN_TOOL_FINGER, 0);
input_sync(g_raydium_ts->input_dev);
}
#else
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
if (gst_slot[u8_i].need_update) {
u8_offset = gst_slot[u8_i].pt_report_offset * LEN_PT;
g_raydium_ts->x_pos[u8_i] = p_u8_buf[POS_X_L + u8_offset] |
p_u8_buf[POS_X_H + u8_offset] << BYTE_SHIFT;
g_raydium_ts->y_pos[u8_i] = p_u8_buf[POS_Y_L + u8_offset] |
p_u8_buf[POS_Y_H + u8_offset] << BYTE_SHIFT;
g_raydium_ts->pressure = p_u8_buf[POS_PRESSURE_L + u8_offset] |
p_u8_buf[POS_PRESSURE_H + u8_offset] << BYTE_SHIFT;
i16_wx = p_u8_buf[POS_WX_L + u8_offset] |
p_u8_buf[POS_WX_H + u8_offset] << BYTE_SHIFT;
i16_wy = p_u8_buf[POS_WY_L + u8_offset] |
p_u8_buf[POS_WY_H + u8_offset] << BYTE_SHIFT;
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, true);
__set_bit(u8_i, ids);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_X, g_raydium_ts->x_pos[u8_i]);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_Y, g_raydium_ts->y_pos[u8_i]);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_PRESSURE, g_raydium_ts->pressure);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_TOUCH_MAJOR, max(i16_wx, i16_wy));
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_TOUCH_MINOR, min(i16_wx, i16_wy));
u8_touch_count++;
}
}
input_report_key(g_raydium_ts->input_dev,
BTN_TOUCH, u8_touch_count > 0);
input_report_key(g_raydium_ts->input_dev,
BTN_TOOL_FINGER, u8_touch_count > 0);
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
if (test_bit(u8_i, ids))
continue;
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, false);
}
input_sync(g_raydium_ts->input_dev);
#endif
return 0;
}
int raydium_read_touchdata(unsigned char *p_u8_tp_status,
unsigned char *p_u8_buf)
{
int i32_ret = 0;
unsigned char u8_points_amount;
static unsigned char u8_seq_no;
unsigned char u8_retry;
u8_retry = 3;
mutex_lock(&g_raydium_ts->lock);
while (u8_retry != 0) {
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0) {
msleep(250);
u8_retry--;
} else
break;
}
if (u8_retry == 0) {
pr_err("[touch]%s: failed to set page, hw reset\n", __func__);
goto reset_error;
}
memset(p_u8_buf, 0, MAX_REPORT_PACKET_SIZE);
memset(p_u8_tp_status, 0, MAX_TCH_STATUS_PACKET_SIZE);
/*read touch point information*/
i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
p_u8_tp_status, MAX_TCH_STATUS_PACKET_SIZE);
if (i32_ret < 0) {
pr_err("[touch]%s: failed to read data: %d\n",
__func__, __LINE__);
goto exit_error;
}
#ifdef ESD_SOLUTION_EN
if (p_u8_tp_status[POS_FW_STATE] != 0x1A &&
p_u8_tp_status[POS_FW_STATE] != 0xAA) {
if (g_u8_resetflag == true) {
pr_err("[touch]%s -> filter irq, FW state = 0x%x\n",
__func__, p_u8_tp_status[POS_FW_STATE]);
i32_ret = -1;
g_u8_resetflag = false;
goto exit_error;
}
pr_err("[touch]%s -> abnormal irq, FW state = 0x%x\n",
__func__, p_u8_tp_status[POS_FW_STATE]);
i32_ret = -1;
goto reset_error;
}
#endif
/* inform IC to prepare next report*/
if (u8_seq_no == p_u8_tp_status[POS_SEQ]) {
pr_err("%s -> report not updated.\n", __func__);
goto exit_error;
}
u8_points_amount = p_u8_tp_status[POS_PT_AMOUNT];
if (u8_points_amount > MAX_TOUCH_NUM)
goto exit_error;
/*read touch point report*/
/*PDA2 only support word mode*/
if (u8_points_amount != 0)
i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
RAYDIUM_PDA2_TCH_RPT_ADDR, p_u8_buf,
u8_points_amount * LEN_PT);
if (i32_ret < 0) {
pr_err("[touch]%s: failed to read data: %d\n",
__func__, __LINE__);
goto exit_error;
}
u8_seq_no = p_u8_tp_status[POS_SEQ];
p_u8_tp_status[POS_SEQ] = 0;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, p_u8_tp_status, 1);
if (i32_ret < 0) {
pr_err("[touch]%s: write data failed: %d\n", __func__, i32_ret);
goto exit_error;
}
raydium_touch_report(p_u8_buf, u8_points_amount);
exit_error:
mutex_unlock(&g_raydium_ts->lock);
return i32_ret;
reset_error:
mutex_unlock(&g_raydium_ts->lock);
#ifdef ESD_SOLUTION_EN
u8_retry = 3;
while (u8_retry != 0) {
i32_ret = raydium_hw_reset_fun(g_raydium_ts->client);
if (i32_ret < 0) {
msleep(100);
u8_retry--;
} else
break;
}
#endif
return i32_ret;
}
static void raydium_work_handler(struct work_struct *work)
{
int i32_ret = 0;
unsigned char u8_tp_status[MAX_TCH_STATUS_PACKET_SIZE];
unsigned char u8_buf[MAX_REPORT_PACKET_SIZE];
#ifdef GESTURE_EN
unsigned char u8_i;
if ((g_raydium_ts->blank == FB_BLANK_VSYNC_SUSPEND ||
g_raydium_ts->blank == FB_BLANK_POWERDOWN) &&
(g_u8_resetflag == false)) {
input_mt_slot(g_raydium_ts->input_dev, 0);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, 1);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_X, 100);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_Y, 100);
input_sync(g_raydium_ts->input_dev);
usleep_range(9500, 10500);
input_mt_slot(g_raydium_ts->input_dev, 0);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, 0);
input_mt_report_pointer_emulation(g_raydium_ts->input_dev,
false);
input_sync(g_raydium_ts->input_dev);
input_report_key(g_raydium_ts->input_dev, KEY_POWER, true);
usleep_range(9500, 10500);
input_sync(g_raydium_ts->input_dev);
input_report_key(g_raydium_ts->input_dev, KEY_POWER, false);
input_sync(g_raydium_ts->input_dev);
#ifdef ESD_SOLUTION_EN
g_u8_checkflag = true;
#endif
pr_debug("[touch]display wake up with g_u8_resetflag false\n");
} else {
if (g_u8_i2c_mode == PDA2_MODE) {
i32_ret = raydium_read_touchdata(u8_tp_status, u8_buf);
if (i32_ret < 0) {
pr_err("[touch]%s, read_touchdata error, ret:%d\n",
__func__, i32_ret);
return;
}
}
/*when display on can use palm to suspend*/
if (g_raydium_ts->blank == FB_BLANK_UNBLANK) {
if (u8_tp_status[POS_GES_STATUS] == RAD_PALM_ENABLE) {
if (g_raydium_ts->is_palm == 0) {
/* release all touches*/
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs;
u8_i++) {
input_mt_slot(g_raydium_ts->input_dev,
u8_i);
input_mt_report_slot_state(
g_raydium_ts->input_dev,
MT_TOOL_FINGER, false);
}
input_mt_report_pointer_emulation(
g_raydium_ts->input_dev,
false);
/*press sleep key*/
input_report_key(g_raydium_ts->input_dev,
KEY_SLEEP, true);
input_sync(g_raydium_ts->input_dev);
pr_debug("[touch]palm_status = %d.\n",
u8_tp_status[POS_GES_STATUS]);
g_raydium_ts->is_palm = 1;
/*goto exit;*/
}
} else if ((u8_tp_status[POS_GES_STATUS]
== RAD_PALM_DISABLE)
&& (g_raydium_ts->is_palm == 1)) {
pr_debug("[touch]leave palm mode.\n");
input_report_key(g_raydium_ts->input_dev,
KEY_SLEEP, false);
input_sync(g_raydium_ts->input_dev);
/*raydium_irq_control(raydium_ts, DISABLE);*/
g_raydium_ts->is_palm = 0;
/*goto exit;*/
}
} else if (g_raydium_ts->blank == FB_BLANK_VSYNC_SUSPEND ||
g_raydium_ts->blank == FB_BLANK_POWERDOWN) {
/*need check small area*/
if (u8_tp_status[POS_GES_STATUS] == RAD_WAKE_UP) {
input_mt_slot(g_raydium_ts->input_dev, 0);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, 1);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_X, 100);
input_report_abs(g_raydium_ts->input_dev,
ABS_MT_POSITION_Y, 100);
input_sync(g_raydium_ts->input_dev);
usleep_range(9500, 10500);
input_mt_slot(g_raydium_ts->input_dev, 0);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER, 0);
input_mt_report_pointer_emulation(
g_raydium_ts->input_dev,
false);
input_sync(g_raydium_ts->input_dev);
input_report_key(g_raydium_ts->input_dev, KEY_POWER, true);
usleep_range(9500, 10500);
input_sync(g_raydium_ts->input_dev);
input_report_key(g_raydium_ts->input_dev,
KEY_POWER, false);
input_sync(g_raydium_ts->input_dev);
pr_debug("[touch]display wake up with g_u8_resetflag true\n");
/*goto exit;*/
}
}
}
#else
if (g_u8_i2c_mode == PDA2_MODE) {
i32_ret = raydium_read_touchdata(u8_tp_status, u8_buf);
if (i32_ret < 0) {
pr_err("[touch]%s, read_touchdata error, ret:%d\n",
__func__, i32_ret);
}
}
#endif
}
/*The raydium device will signal the host about TRIGGER_FALLING.
*Processed when the interrupt is asserted.
*/
static irqreturn_t raydium_ts_interrupt(int irq, void *dev_id)
{
bool result = false;
/*For bootloader wrt/erase flash and software reset interrupt*/
if ((g_u8_raydium_flag & ENG_MODE) != 0) {
disable_irq_nosync(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = false;
pr_debug("[touch]RAD_ENG_MODE\n");
g_u8_raydium_flag |= INT_FLAG;
} else {
if (!work_pending(&g_raydium_ts->work)) {
/* Clear interrupts*/
result = queue_work(g_raydium_ts->workqueue,
&g_raydium_ts->work);
if (result == false) {
/*queue_work fail*/
pr_err("[touch]queue_work fail.\n");
}
} else {
/*work pending*/
mutex_lock(&g_raydium_ts->lock);
if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0) < 0) {
pr_err("[touch]%s: failed to set page in work_pending\n",
__func__);
}
mutex_unlock(&g_raydium_ts->lock);
pr_debug("[touch]work_pending\n");
}
}
return IRQ_HANDLED;
}
static int raydium_check_i2c_ready(unsigned short *u16_i2c_data)
{
unsigned char u8_buf[4];
int i32_ret = -1;
mutex_lock(&g_raydium_ts->lock);
if (g_u8_i2c_mode == PDA2_MODE) {
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit_error;
*(unsigned int *)u8_buf =
(RAD_I2C_PDA_MODE_ENABLE << 24) |
((RAD_CHK_I2C_CMD & (~MASK_8BIT)) >> 8);
/*using byte mode to read 4 bytes*/
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_PDA_CFG_ADDR,
u8_buf,
4);
if (i32_ret < 0)
goto exit_error;
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_ENABLE_PDA);
if (i32_ret < 0)
goto exit_error;
i32_ret = raydium_i2c_pda2_read(
g_raydium_ts->client,
(unsigned char)(RAD_CHK_I2C_CMD & MASK_8BIT),
u8_buf, 4);
if (i32_ret < 0)
goto exit_error;
if (u8_buf[3] != 0xF3) {
pr_err("[touch]PDA2 read i2c fail\n");
g_u8_i2c_mode = PDA_MODE;
i32_ret = raydium_i2c_pda_read(g_raydium_ts->client,
RAD_CHK_I2C_CMD, u8_buf,
4);
if (i32_ret < 0)
goto exit_error;
}
} else {
i32_ret = raydium_i2c_pda_read(g_raydium_ts->client,
RAD_CHK_I2C_CMD, u8_buf,
4);
if (i32_ret < 0)
goto exit_error;
}
*u16_i2c_data = u8_buf[3] << 8 | u8_buf[2];
pr_debug("[touch]RAD check I2C : 0x%02X%02X\n", u8_buf[3], u8_buf[2]);
exit_error:
mutex_unlock(&g_raydium_ts->lock);
return i32_ret;
}
#if defined(CONFIG_PM)
static void raydium_ts_do_suspend(void)
{
unsigned char u8_i = 0;
g_u8_resetflag = false;
if (g_raydium_ts->is_suspend == 1) {
pr_info("[touch]Already in suspend state\n");
return;
}
/*#ifndef GESTURE_EN*/
raydium_irq_control(DISABLE);
/*#endif*/
/*clear workqueue*/
if (!cancel_work_sync(&g_raydium_ts->work))
pr_info("[touch]workqueue is empty!\n");
pr_debug("[touch]%s.\n", __func__);
/* release all touches */
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER,
false);
}
input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
input_sync(g_raydium_ts->input_dev);
#ifdef ENABLE_DUMP_DATA
if (!g_u8_dumpcount)
timeout = jiffies + 2*HZ;
if (g_u8_dumpcount < 5)
g_u8_dumpcount++;
if (g_u8_palm_flag || (time_is_before_jiffies(timeout))) {
g_u8_dumpcount = 0;
g_u8_palm_flag = false;
}
if (g_u8_dumpcount == 5) {
g_u8_dump_flag = true;
g_u8_dumpcount = 0;
}
#endif
#ifdef GESTURE_EN
if (device_may_wakeup(&g_raydium_ts->client->dev)) {
pr_debug("[touch]Device may wakeup\n");
if (!enable_irq_wake(g_raydium_ts->irq))
g_raydium_ts->irq_wake = 1;
} else
pr_debug("[touch]Device not wakeup\n");
raydium_irq_control(ENABLE);
#endif
g_raydium_ts->is_suspend = 1;
}
static void raydium_ts_do_resume(void)
{
#ifdef ESD_SOLUTION_EN
int i32_ret = 0;
unsigned char u8_retry = 0;
#endif
unsigned char u8_w_data[4];
pr_debug("[touch]%s, %d.\n", __func__, g_raydium_ts->is_suspend);
if (g_raydium_ts->is_suspend == 0) {
pr_info("[touch]Already in resume state\n");
return;
}
/* clear interrupts*/
mutex_lock(&g_raydium_ts->lock);
if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0) < 0) {
pr_err("[ raydium ]%s: failed to set page\n", __func__);
mutex_unlock(&g_raydium_ts->lock);
return;
}
/* clear seq num*/
u8_w_data[POS_SEQ] = 0;
if (raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, u8_w_data, 1) < 0) {
pr_err("[ raydium ]%s: failed to clear seq\n", __func__);
mutex_unlock(&g_raydium_ts->lock);
return;
}
mutex_unlock(&g_raydium_ts->lock);
/* clear workqueue*/
if (!cancel_work_sync(&g_raydium_ts->work))
pr_info("[ raydium ]workqueue is empty!\n");
#ifdef ESD_SOLUTION_EN
if (g_u8_checkflag == true) {
i32_ret = raydium_esd_check();
if (i32_ret < 0) {
u8_retry = 3;
while (u8_retry != 0) {
i32_ret = raydium_hw_reset_fun(g_raydium_ts->client);
if (i32_ret < 0) {
msleep(100);
u8_retry--;
} else
break;
}
}
g_u8_checkflag = false;
}
#endif
raydium_irq_control(ENABLE);
#ifdef ENABLE_DUMP_DATA
if (g_u8_dump_flag) {
schedule_delayed_work(&g_raydium_ts->dump_work, HZ);
g_u8_dump_flag = false;
}
#endif
#ifdef GESTURE_EN
if (device_may_wakeup(&g_raydium_ts->client->dev)) {
pr_debug("[touch]Device may wakeup\n");
if (g_raydium_ts->irq_wake) {
disable_irq_wake(g_raydium_ts->irq);
g_raydium_ts->irq_wake = 0;
}
} else
pr_debug("[touch]Device not wakeup\n");
#endif
g_raydium_ts->is_suspend = 0;
}
static int raydium_ts_suspend(struct device *dev)
{
raydium_ts_do_suspend();
return 0;
}
static int raydium_ts_resume(struct device *dev)
{
raydium_ts_do_resume();
return 0;
}
static const struct dev_pm_ops raydium_ts_pm_ops = {
#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
.suspend = raydium_ts_suspend,
.resume = raydium_ts_resume,
#endif /*end of CONFIG_PM*/
};
/*used for touch lock feature*/
static int raydium_ts_open(struct input_dev *input_dev)
{
int i32_ret = 0;
pr_debug("[touch]%s()+\n", __func__);
pr_debug("[touch]ts->blank:%x\n", g_raydium_ts->blank);
if (g_raydium_ts->is_sleep == 1) {
mutex_lock(&g_raydium_ts->lock);
if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
g_u8_resetflag = true;
gpio_set_value(g_raydium_ts->rst_gpio, 1);
gpio_set_value(g_raydium_ts->rst_gpio, 0);
msleep(RAYDIUM_RESET_INTERVAL_MSEC);/*5ms*/
gpio_set_value(g_raydium_ts->rst_gpio, 1);
msleep(RAYDIUM_RESET_DELAY_MSEC);/*100ms*/
g_u8_i2c_mode = PDA2_MODE;
}
mutex_unlock(&g_raydium_ts->lock);
raydium_irq_control(ENABLE);
g_raydium_ts->is_sleep = 0;
pr_debug("[touch]disable touch lock.\n");
}
return i32_ret;
}
static void raydium_ts_close(struct input_dev *input_dev)
{
int i32_ret = 0;
unsigned char u8_i = 0;
unsigned char u8_wbuffer[1];
pr_debug("[touch]%s()+\n", __func__);
if (g_raydium_ts->is_sleep == 1) {
pr_debug("[touch]touch lock already enabled.\n");
return;
}
raydium_irq_control(DISABLE);
for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
input_mt_slot(g_raydium_ts->input_dev, u8_i);
input_mt_report_slot_state(g_raydium_ts->input_dev,
MT_TOOL_FINGER,
false);
}
input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
input_sync(g_raydium_ts->input_dev);
mutex_lock(&g_raydium_ts->lock);
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0) {
pr_err("[touch]ret:%d\n", i32_ret);
goto exit_i2c_error;
}
u8_wbuffer[0] = RAYDIUM_HOST_CMD_PWR_SLEEP;
i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
RAYDIUM_PDA2_HOST_CMD_ADDR,
u8_wbuffer,
1);
if (i32_ret < 0) {
pr_err("[touch]ret:%d\n", i32_ret);
goto exit_i2c_error;
}
mutex_unlock(&g_raydium_ts->lock);
g_raydium_ts->is_sleep = 1;
pr_debug("[touch]enable touch lock.\n");
return;
exit_i2c_error:
mutex_unlock(&g_raydium_ts->lock);
raydium_irq_control(ENABLE);
}
#else
static int raydium_ts_suspend(struct device *dev)
{
return 0;
}
static int raydium_ts_resume(struct device *dev)
{
return 0;
}
#endif /*end of CONFIG_FB*/
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event,
void *data)
{
struct fb_event *evdata = data;
int *blank;
if (evdata && evdata->data && event == FB_EVENT_BLANK &&
g_raydium_ts && g_raydium_ts->client) {
blank = evdata->data;
g_raydium_ts->blank = (*blank);
switch (*blank) {
/*screen on*/
case FB_BLANK_UNBLANK:
pr_debug("[touch]FB_BLANK_UNBLANK\n");
#ifdef GESTURE_EN
/* clear palm status */
g_raydium_ts->is_palm = 0;
#endif
#ifdef HOST_NOTIFY_EN
raydium_notify_function(ACTIVE_MODE);
#endif
raydium_ts_resume(&g_raydium_ts->client->dev);
break;
/*screen off*/
case FB_BLANK_POWERDOWN:
pr_debug("[touch]FB_BLANK_POWERDOWN\n");
#ifdef GESTURE_EN
/* clear palm status */
g_raydium_ts->is_palm = 0;
#endif
#ifdef HOST_NOTIFY_EN
raydium_notify_function(SLEEP_MODE);
#endif
raydium_ts_suspend(&g_raydium_ts->client->dev);
break;
/*ambient mode*/
case FB_BLANK_VSYNC_SUSPEND:
pr_debug("[touch]FB_BLANK_VSYNC_SUSPEND\n");
#ifdef GESTURE_EN
/* clear palm status */
g_raydium_ts->is_palm = 0;
#endif
#ifdef HOST_NOTIFY_EN
raydium_notify_function(AMBIENT_MODE);
#endif
raydium_ts_suspend(&g_raydium_ts->client->dev);
break;
default:
break;
}
}
return 0;
}
static void raydium_register_notifier(void)
{
memset(&g_raydium_ts->fb_notif, 0, sizeof(g_raydium_ts->fb_notif));
g_raydium_ts->fb_notif.notifier_call = fb_notifier_callback;
/* register on the fb notifier and work with fb*/
if (fb_register_client(&g_raydium_ts->fb_notif))
pr_err("[touch]register notifier failed\n");
}
static void raydium_unregister_notifier(void)
{
fb_unregister_client(&g_raydium_ts->fb_notif);
}
#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void raydium_ts_early_suspend(struct early_suspend *handler)
{
raydium_ts_do_suspend();
}
static void raydium_ts_late_resume(struct early_suspend *handler)
{
raydium_ts_do_resume();
}
#endif /*end of CONFIG_FB*/
#ifdef CONFIG_OF
static int raydium_get_dt_coords(struct device *dev, char *name,
struct raydium_ts_platform_data *pdata)
{
u32 coords[COORDS_ARR_SIZE];
struct property *prop;
struct device_node *np = dev->of_node;
int coords_size, rc;
prop = of_find_property(np, name, NULL);
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
coords_size = prop->length / sizeof(u32);
if (coords_size != COORDS_ARR_SIZE) {
pr_err("[touch]invalid %s\n", name);
return -EINVAL;
}
rc = of_property_read_u32_array(np, name, coords, coords_size);
if (rc && (rc != -EINVAL)) {
pr_err("[touch]unable to read %s\n", name);
return rc;
}
if (!strcmp(name, "raydium,display-coords")) {
pdata->x_min = coords[0];
pdata->y_min = coords[1];
pdata->x_max = coords[2];
pdata->y_max = coords[3];
} else {
pr_err("[touch]unsupported property %s\n", name);
return -EINVAL;
}
return 0;
}
static int raydium_parse_dt(struct device *dev,
struct raydium_ts_platform_data *pdata)
{
struct device_node *np = dev->of_node;
int rc = 0;
u32 temp_val = 0;
pdata->name = RAYDIUM_NAME;
rc = raydium_get_dt_coords(dev, "raydium,display-coords", pdata);
if (rc)
return rc;
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np,
"raydium,reset-gpio",
0,
&pdata->reset_gpio_flags);
if (pdata->reset_gpio < 0)
return pdata->reset_gpio;
pdata->irq_gpio = of_get_named_gpio_flags(np,
"raydium,irq-gpio",
0,
&pdata->irq_gpio_flags);
if (pdata->irq_gpio < 0)
return pdata->irq_gpio;
rc = of_property_read_u32(np,
"raydium,hard-reset-delay-ms", &temp_val);
if (!rc)
pdata->hard_rst_dly = temp_val;
else
return rc;
rc = of_property_read_u32(np,
"raydium,soft-reset-delay-ms", &temp_val);
if (!rc)
pdata->soft_rst_dly = temp_val;
else
return rc;
rc = of_property_read_u32(np, "raydium,num-max-touches", &temp_val);
if (!rc)
pdata->num_max_touches = temp_val;
else
return rc;
#ifdef FW_MAPPING_BYID_EN
rc = of_property_read_u32(np, "raydium,fw_id", &temp_val);
if (!rc)
pdata->fw_id = temp_val;
else
return rc;
#endif
return 0;
}
#else
static int raydium_parse_dt(struct device *dev,
struct raydium_ts_platform_data *pdata)
{
return -ENODEV;
}
#endif /*end of CONFIG_OF*/
static void raydium_input_set(struct input_dev *input_dev)
{
int ret = 0;
unsigned char i;
input_dev->name = "raydium_ts";/*name need same with .idc*/
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &g_raydium_ts->client->dev;
input_dev->open = raydium_ts_open;/*touch lock*/
input_dev->close = raydium_ts_close;
input_set_drvdata(input_dev, g_raydium_ts);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
pr_debug("[touch]set abs prarams x[%d], y[%d]\n",
g_raydium_ts->x_max, g_raydium_ts->y_max);
/* Multitouch input params setup */
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
g_raydium_ts->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
g_raydium_ts->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, PRESS_MAX, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR, 0, WIDTH_MAX, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MINOR, 0, WIDTH_MAX, 0, 0);
ret = input_mt_init_slots(input_dev, MAX_TOUCH_NUM,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (ret)
pr_err("[touch]failed to initialize MT slots: %d\n", ret);
for (i = 0; i < (MAX_TOUCH_NUM * 2); i++)
gst_slot[i] = gst_slot_init;
}
static int raydium_set_resolution(void)
{
unsigned char u8_buf[4];
int i32_ret = -1;
unsigned int u32_x, u32_y;
mutex_lock(&g_raydium_ts->lock);
i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
g_raydium_ts->is_suspend,
RAYDIUM_PDA2_PAGE_0);
if (i32_ret < 0)
goto exit_error;
i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
RAYDIUM_PDA2_DISPLAY_INFO_ADDR,
u8_buf, 4);
if (i32_ret < 0)
goto exit_error;
u32_x = u8_buf[3] << 8 | u8_buf[2];
u32_y = u8_buf[1] << 8 | u8_buf[0];
pr_debug("[touch]RAD display info x:%d, y:%d\n", u32_x, u32_y);
if (u32_x > 300 && u32_y > 300 &&
u32_x < 600 && u32_y < 600) {
g_raydium_ts->x_max = u32_x - 1;
g_raydium_ts->y_max = u32_y - 1;
}
exit_error:
mutex_unlock(&g_raydium_ts->lock);
return i32_ret;
}
static int raydium_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct raydium_ts_platform_data *pdata =
(struct raydium_ts_platform_data *)client->dev.platform_data;
struct input_dev *input_dev;
unsigned short u16_i2c_data;
int ret = 0;
pr_debug("[touch] probe\n");
if (client->dev.of_node) {
pdata = devm_kzalloc(&client->dev,
sizeof(struct raydium_ts_platform_data),
GFP_KERNEL);
if (!pdata) {
dev_err(&client->dev,
"[touch]failed to allocate memory\n");
return -ENOMEM;
}
ret = raydium_parse_dt(&client->dev, pdata);
if (ret) {
dev_err(&client->dev,
"[touch]device tree parsing failed\n");
goto parse_dt_failed;
}
} else
pdata = client->dev.platform_data;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
ret = -ENODEV;
goto exit_check_functionality_failed;
}
g_raydium_ts = devm_kzalloc(&client->dev,
sizeof(struct raydium_ts_data),
GFP_KERNEL);
if (!g_raydium_ts) {
pr_err("[touch]failed to allocate input driver data\n");
return -ENOMEM;
}
raydium_variable_init();
mutex_init(&g_raydium_ts->lock);
i2c_set_clientdata(client, g_raydium_ts);
g_raydium_ts->irq_enabled = false;
g_raydium_ts->irq_wake = false;
g_raydium_ts->irq_gpio = pdata->irq_gpio;
g_raydium_ts->rst_gpio = pdata->reset_gpio;
client->irq = g_raydium_ts->irq_gpio;
g_raydium_ts->u8_max_touchs = pdata->num_max_touches;
g_raydium_ts->client = client;
g_raydium_ts->x_max = pdata->x_max - 1;
g_raydium_ts->y_max = pdata->y_max - 1;
g_raydium_ts->is_suspend = 0;
g_raydium_ts->is_sleep = 0;
#ifdef GESTURE_EN
g_raydium_ts->is_palm = 0;
#endif
g_raydium_ts->fw_version = 0;
device_init_wakeup(&client->dev, 1);
#ifdef MSM_NEW_VER
ret = raydium_ts_pinctrl_init();
if (!ret && g_raydium_ts->ts_pinctrl) {
/*
* Pinctrl handle is optional. If pinctrl handle is found
* let pins to be configured in active state. If not
* found continue further without error.
*/
ret = pinctrl_select_state(g_raydium_ts->ts_pinctrl,
g_raydium_ts->pinctrl_state_active);
if (ret < 0)
pr_err("[touch]failed to set pin to active state\n");
}
#endif /*end of MSM_NEW_VER*/
ret = raydium_gpio_configure(true);
if (ret < 0) {
pr_err("[touch]failed to configure the gpios\n");
goto err_gpio_req;
}
/*modify dtsi to 360*/
msleep(pdata->soft_rst_dly);
/*print touch i2c ready*/
ret = raydium_check_i2c_ready(&u16_i2c_data);
if (ret < 0) {
pr_err("[touch]Check I2C failed\n");
ret = -ENODEV;
goto exit_check_i2c;
}
/*input device initialization*/
input_dev = input_allocate_device();
if (!input_dev) {
ret = -ENOMEM;
pr_err("[touch]failed to allocate input device\n");
goto exit_input_dev_alloc_failed;
}
raydium_set_resolution();
g_raydium_ts->input_dev = input_dev;
raydium_input_set(input_dev);
ret = input_register_device(input_dev);
if (ret) {
pr_err("[touch]failed to register input device: %s\n",
dev_name(&client->dev));
goto exit_input_register_device_failed;
}
#ifdef GESTURE_EN
input_set_capability(input_dev, EV_KEY, KEY_SLEEP);
input_set_capability(input_dev, EV_KEY, KEY_POWER);
#endif
/*suspend/resume routine*/
#if defined(CONFIG_FB)
raydium_register_notifier();
#elif defined(CONFIG_HAS_EARLYSUSPEND)
/*Early-suspend level*/
g_raydium_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
g_raydium_ts->early_suspend.suspend = raydium_ts_early_suspend;
g_raydium_ts->early_suspend.resume = raydium_ts_late_resume;
register_early_suspend(&g_raydium_ts->early_suspend);
#endif/*end of CONFIG_FB*/
#ifdef CONFIG_RM_SYSFS_DEBUG
raydium_create_sysfs(client);
#endif/*end of CONFIG_RM_SYSFS_DEBUG*/
INIT_WORK(&g_raydium_ts->work, raydium_work_handler);
g_raydium_ts->workqueue = create_singlethread_workqueue("raydium_ts");
#ifdef ENABLE_DUMP_DATA
INIT_DELAYED_WORK(&g_raydium_ts->dump_work, raydium_dump_data_work);
#endif
/*irq_gpio = 13 irqflags = 108*/
pr_debug("[touch]pdata irq : %d\n", g_raydium_ts->irq_gpio);
pr_debug("[touch]client irq : %d, pdata flags : %d\n",
client->irq, pdata->irqflags);
g_raydium_ts->irq = gpio_to_irq(pdata->irq_gpio);
ret = request_threaded_irq(g_raydium_ts->irq, NULL, raydium_ts_interrupt,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_NO_SUSPEND,
client->dev.driver->name, g_raydium_ts);
if (ret < 0) {
pr_err("[touch]raydium_probe: request irq failed\n");
goto exit_irq_request_failed;
}
g_raydium_ts->irq_desc = irq_to_desc(g_raydium_ts->irq);
g_raydium_ts->irq_enabled = true;
/*disable_irq then enable_irq for avoid Unbalanced enable for IRQ */
/*raydium_irq_control(ts, ENABLE);*/
pr_info("[touch]RAD Touch driver ver :0x%X\n", g_u32_driver_version);
#ifdef FW_UPDATE_EN
/*fw update check*/
ret = raydium_fw_update_check(u16_i2c_data);
if (ret < 0) {
pr_err("[touch]FW update check failed\n");
ret = -ENODEV;
goto exit_irq_request_failed;
}
#endif
return 0;
exit_irq_request_failed:
#if defined(CONFIG_FB)
raydium_unregister_notifier();
#endif/*end of CONFIG_FB*/
cancel_work_sync(&g_raydium_ts->work);
input_unregister_device(input_dev);
exit_input_register_device_failed:
input_free_device(input_dev);
exit_input_dev_alloc_failed:
exit_check_i2c:
if (gpio_is_valid(pdata->reset_gpio))
gpio_free(pdata->reset_gpio);
if (gpio_is_valid(pdata->irq_gpio))
gpio_free(pdata->irq_gpio);
err_gpio_req:
#ifdef MSM_NEW_VER
if (g_raydium_ts->ts_pinctrl) {
if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_release)) {
devm_pinctrl_put(g_raydium_ts->ts_pinctrl);
g_raydium_ts->ts_pinctrl = NULL;
} else {
ret = pinctrl_select_state(g_raydium_ts->ts_pinctrl,
g_raydium_ts->pinctrl_state_release);
if (ret)
pr_err("[touch]pinctrl_select_state failed\n");
}
}
#endif/*end of MSM_NEW_VER*/
parse_dt_failed:
exit_check_functionality_failed:
return ret;
}
static int raydium_ts_remove(struct i2c_client *client)
{
#if defined(CONFIG_FB)
raydium_unregister_notifier();
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&g_raydium_ts->early_suspend);
#endif/*end of CONFIG_FB*/
input_unregister_device(g_raydium_ts->input_dev);
input_free_device(g_raydium_ts->input_dev);
gpio_free(g_raydium_ts->rst_gpio);
#ifdef CONFIG_RM_SYSFS_DEBUG
raydium_release_sysfs(client);
#endif /*end of CONFIG_RM_SYSFS_DEBUG*/
free_irq(client->irq, g_raydium_ts);
if (gpio_is_valid(g_raydium_ts->rst_gpio))
gpio_free(g_raydium_ts->rst_gpio);
if (gpio_is_valid(g_raydium_ts->irq_gpio))
gpio_free(g_raydium_ts->irq_gpio);
cancel_work_sync(&g_raydium_ts->work);
destroy_workqueue(g_raydium_ts->workqueue);
kfree(g_raydium_ts);
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id raydium_ts_id[] = {
{RAYDIUM_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, raydium_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id raydium_match_table[] = {
{ .compatible = "raydium,raydium-ts",},
{ },
};
#else
#define raydium_match_table NULL
#endif/*end of CONFIG_OF*/
static struct i2c_driver raydium_ts_driver = {
.probe = raydium_ts_probe,
.remove = raydium_ts_remove,
.id_table = raydium_ts_id,
.driver = {
.name = RAYDIUM_NAME,
.owner = THIS_MODULE,
.of_match_table = raydium_match_table,
#if defined(CONFIG_PM)
.pm = &raydium_ts_pm_ops,
#endif/*end of CONFIG_PM*/
},
};
static int __init raydium_ts_init(void)
{
int ret;
ret = i2c_add_driver(&raydium_ts_driver);
return ret;
}
static void __exit raydium_ts_exit(void)
{
i2c_del_driver(&raydium_ts_driver);
}
module_init(raydium_ts_init);
module_exit(raydium_ts_exit);
MODULE_AUTHOR("Raydium");
MODULE_DESCRIPTION("Raydium TouchScreen driver");
MODULE_LICENSE("GPL");