Merge "input: touchscreen: Change dev_pm_ops for Goodix driver"

This commit is contained in:
Linux Build Service Account 2016-09-29 11:20:33 -07:00 committed by Gerrit - the friendly Code Review server
commit 612fafbe3e
5 changed files with 719 additions and 895 deletions

View file

@ -23,16 +23,15 @@
#include "gt9xx.h"
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/debugfs.h>
#define DATA_LENGTH_UINT 512
#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *))
static char procname[20] = {0};
#define UPDATE_FUNCTIONS
#pragma pack(1)
struct {
u8 wr; /* write read flag£¬0:R 1:W 2:PID 3: */
struct st_cmd_head {
u8 wr; /* write read flag 0:R 1:W 2:PID 3: */
u8 flag; /* 0:no need flag/int 1: need flag 2:need int */
u8 flag_addr[2];/* flag address */
u8 flag_val; /* flag val */
@ -46,9 +45,9 @@ struct {
u8 addr[2]; /* address */
u8 res[3]; /* reserved */
u8 *data; /* data pointer */
} st_cmd_head;
#pragma pack()
st_cmd_head cmd_head;
} __packed;
static struct st_cmd_head cmd_head;
static struct i2c_client *gt_client;
@ -56,15 +55,11 @@ static struct proc_dir_entry *goodix_proc_entry;
static struct mutex lock;
static s32 goodix_tool_write(struct file *filp, const char __user *buff,
unsigned long len, void *data);
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
static s32 (*tool_i2c_read)(u8 *, u16);
static s32 (*tool_i2c_write)(u8 *, u16);
s32 DATA_LENGTH;
s8 IC_TYPE[16] = {0};
s32 data_length;
s8 ic_type[16] = {0};
static void tool_set_proc_name(char *procname)
{
@ -113,7 +108,7 @@ static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
}
if (i == cmd_head.retry) {
dev_err(&client->dev, "I2C read retry limit over.\n");
dev_err(&gt_client->dev, "I2C read retry limit over\n");
ret = -EIO;
}
@ -138,7 +133,7 @@ static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
}
if (i == cmd_head.retry) {
dev_err(&client->dev, "I2C write retry limit over.\n");
dev_err(&gt_client->dev, "I2C write retry limit over\n");
ret = -EIO;
}
@ -173,17 +168,17 @@ static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
static void register_i2c_func(void)
{
if (strcmp(IC_TYPE, "GT8110") && strcmp(IC_TYPE, "GT8105")
&& strcmp(IC_TYPE, "GT801") && strcmp(IC_TYPE, "GT800")
&& strcmp(IC_TYPE, "GT801PLUS") && strcmp(IC_TYPE, "GT811")
&& strcmp(IC_TYPE, "GTxxx")) {
if (strcmp(ic_type, "GT8110") && strcmp(ic_type, "GT8105")
&& strcmp(ic_type, "GT801") && strcmp(ic_type, "GT800")
&& strcmp(ic_type, "GT801PLUS") && strcmp(ic_type, "GT811")
&& strcmp(ic_type, "GTxxx")) {
tool_i2c_read = tool_i2c_read_with_extra;
tool_i2c_write = tool_i2c_write_with_extra;
pr_debug("I2C function: with pre and end cmd!\n");
pr_debug("I2C function: with pre and end cmd\n");
} else {
tool_i2c_read = tool_i2c_read_no_extra;
tool_i2c_write = tool_i2c_write_no_extra;
pr_info("I2C function: without pre and end cmd!\n");
pr_info("I2C function: without pre and end cmd\n");
}
}
@ -191,57 +186,14 @@ static void unregister_i2c_func(void)
{
tool_i2c_read = NULL;
tool_i2c_write = NULL;
pr_info("I2C function: unregister i2c transfer function!\n");
}
s32 init_wr_node(struct i2c_client *client)
{
u8 i;
gt_client = client;
memset(&cmd_head, 0, sizeof(cmd_head));
cmd_head.data = NULL;
i = 5;
while ((!cmd_head.data) && i) {
cmd_head.data = devm_kzalloc(&client->dev,
i * DATA_LENGTH_UINT, GFP_KERNEL);
if (cmd_head.data)
break;
i--;
}
if (i) {
DATA_LENGTH = i * DATA_LENGTH_UINT;
dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
} else {
pr_err("Apply for memory failed.\n");
return FAIL;
}
cmd_head.addr_len = 2;
cmd_head.retry = 5;
register_i2c_func();
mutex_init(&lock);
tool_set_proc_name(procname);
goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
if (goodix_proc_entry == NULL) {
pr_err("Couldn't create proc entry!\n");
return FAIL;
}
GTP_INFO("Create proc entry success!");
goodix_proc_entry->write_proc = goodix_tool_write;
dix_proc_entry->read_proc = goodix_tool_read;
return SUCCESS;
pr_info("I2C function: unregister i2c transfer function\n");
}
void uninit_wr_node(void)
{
cmd_head.data = NULL;
unregister_i2c_func();
remove_proc_entry(procname, NULL);
proc_remove(goodix_proc_entry);
}
static u8 relation(u8 src, u8 dst, u8 rlt)
@ -256,7 +208,7 @@ static u8 relation(u8 src, u8 dst, u8 rlt)
case 1:
ret = (src == dst) ? true : false;
pr_debug("equal:src:0x%02x dst:0x%02x ret:%d.\n",
pr_debug("equal:src:0x%02x dst:0x%02x ret:%d\n",
src, dst, (s32)ret);
break;
@ -298,23 +250,18 @@ static u8 comfirm(void)
s32 i = 0;
u8 buf[32];
/* memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len],
* &cmd_head.flag_addr, cmd_head.addr_len);
* memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);
* //Modified by Scott, 2012-02-17
*/
memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
for (i = 0; i < cmd_head.times; i++) {
if (tool_i2c_read(buf, 1) <= 0) {
pr_err("Read flag data failed!\n");
dev_err(&gt_client->dev, "Read flag data failed");
return FAIL;
}
if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val,
cmd_head.flag_relation)) {
pr_debug("value at flag addr:0x%02x.\n",
pr_debug("value at flag addr:0x%02x\n",
buf[GTP_ADDR_LENGTH]);
pr_debug("flag value:0x%02x.\n", cmd_head.flag_val);
pr_debug("flag value:0x%02x\n", cmd_head.flag_val);
break;
}
@ -322,89 +269,99 @@ static u8 comfirm(void)
}
if (i >= cmd_head.times) {
pr_debug("Didn't get the flag to continue!\n");
dev_err(&gt_client->dev, "Didn't get the flag to continue");
return FAIL;
}
return SUCCESS;
}
/********************************************************
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
static s32 fill_update_info(char __user *user_buf,
size_t count, loff_t *ppos)
{
u8 buf[4];
buf[0] = show_len >> 8;
buf[1] = show_len & 0xff;
buf[2] = total_len >> 8;
buf[3] = total_len & 0xff;
return simple_read_from_buffer(user_buf, count, ppos,
buf, sizeof(buf));
}
#else
static s32 fill_update_info(char __user *user_buf,
size_t count, loff_t *ppos)
{
return -ENODEV;
}
#endif
/*
* Function:
* Goodix tool write function.
* Input:
* standard proc write function param.
* Output:
* Return write length.
*******************************************************
*/
static s32 goodix_tool_write(struct file *filp, const char __user *buff,
unsigned long len, void *data)
static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
size_t count, loff_t *ppos)
{
s32 ret = 0;
mutex_lock(&lock);
ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH);
if (ret) {
pr_err("copy_from_user failed.\n");
ret = -EACCES;
dev_err(&gt_client->dev, "copy_from_user failed");
ret = -EFAULT;
goto exit;
}
pr_debug("wr :0x%02x.\n", cmd_head.wr);
pr_debug("flag:0x%02x.\n", cmd_head.flag);
pr_debug("flag addr:0x%02x%02x.\n", cmd_head.flag_addr[0],
cmd_head.flag_addr[1]);
pr_debug("flag val:0x%02x.\n", cmd_head.flag_val);
pr_debug("flag rel:0x%02x.\n", cmd_head.flag_relation);
pr_debug("circle :%d.\n", (s32)cmd_head.circle);
pr_debug("times :%d.\n", (s32)cmd_head.times);
pr_debug("retry :%d.\n", (s32)cmd_head.retry);
pr_debug("delay :%d.\n", (s32)cmd_head.delay);
pr_debug("data len:%d.\n", (s32)cmd_head.data_len);
pr_debug("addr len:%d.\n", (s32)cmd_head.addr_len);
pr_debug("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]);
pr_debug("len:%d.\n", (s32)len);
pr_debug("buf[20]:0x%02x.\n", buff[CMD_HEAD_LENGTH]);
dev_dbg(&gt_client->dev, "wr:0x%02x, flag:0x%02x, flag addr:0x%02x%02x,
flag val:0x%02x, flag rel:0x%02x,", cmd_headd.wr,
cmd_head.flag, cmd_head.flag_addr[0],
cmd_head.flag_addr[1], cmd_head.flag_val,
cmd_head.flag_relation);
dev_dbg(&gt_client->dev, "circle:%d, times:%d, retry:%d, delay:%d,
data len:%d, addr len:%d, addr:0x%02x%02x, write len: %d",
(s32)cmd_head.circle, (s32)cmd_head.times, (s32)cmd_head.retry,
(s32)cmd_head.delay, (s32)cmd_head.data_len,
(s32)cmd_head.addr_len, cmd_head.addr[0], cmd_head.addr[1],
(s32)count);
if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
pr_debug("data len %d > data buff %d, rejected!\n",
cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
ret = -EINVAL;
goto exit;
}
if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
pr_debug(" addr len %d > data buff %d, rejected!\n",
cmd_head.addr_len, GTP_ADDR_LENGTH);
if (cmd_head.data_len > (data_length - GTP_ADDR_LENGTH)) {
dev_err(&gt_client->dev, "data len %d > data buff %d, rejected\n",
cmd_head.data_len, (data_length - GTP_ADDR_LENGTH));
ret = -EINVAL;
goto exit;
}
if (cmd_head.wr == 1) {
/* copy_from_user(&cmd_head.data[cmd_head.addr_len],
* &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
*/
if (cmd_head.wr == GTP_RW_WRITE) {
ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
if (ret)
pr_err("copy_from_user failed.\n");
&userbuf[CMD_HEAD_LENGTH], cmd_head.data_len);
if (ret) {
dev_err(&gt_client->dev, "copy_from_user failed");
ret = -EFAULT;
goto exit;
}
memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
cmd_head.addr, cmd_head.addr_len);
if (cmd_head.flag == 1) {
if (cmd_head.flag == GTP_NEED_FLAG) {
if (comfirm() == FAIL) {
pr_err("[WRITE]Comfirm fail!\n");
dev_err(&gt_client->dev, "Confirm fail");
ret = -EINVAL;
goto exit;
}
} else if (cmd_head.flag == 2) {
} else if (cmd_head.flag == GTP_NEED_INTERRUPT) {
/* Need interrupt! */
}
if (tool_i2c_write(
&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
cmd_head.data_len + cmd_head.addr_len) <= 0) {
pr_err("[WRITE]Write data failed!\n");
dev_err(&gt_client->dev, "Write data failed");
ret = -EIO;
goto exit;
}
@ -414,32 +371,33 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 3) { /* Write ic type */
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
} else if (cmd_head.wr == GTP_RW_WRITE_IC_TYPE) { /* Write ic type */
ret = copy_from_user(&cmd_head.data[0],
&userbuf[CMD_HEAD_LENGTH],
cmd_head.data_len);
if (ret)
pr_err("copy_from_user failed.\n");
if (ret) {
dev_err(&gt_client->dev, "copy_from_user failed");
ret = -EFAULT;
goto exit;
}
if (cmd_head.data_len > sizeof(IC_TYPE)) {
pr_debug("<<-GTP->> data len %d > data buff %d, rejected!\n",
cmd_head.data_len, sizeof(IC_TYPE));
if (cmd_head.data_len > sizeof(ic_type)) {
dev_err(&gt_client->dev,
"data len %d > data buff %d, rejected\n",
cmd_head.data_len, sizeof(ic_type));
ret = -EINVAL;
goto exit;
}
memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
memcpy(ic_type, cmd_head.data, cmd_head.data_len);
register_i2c_func();
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 5) {
/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
} else if (cmd_head.wr == GTP_RW_NO_WRITE) {
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 7) { /* disable irq! */
} else if (cmd_head.wr == GTP_RW_DISABLE_IRQ) { /* disable irq! */
gtp_irq_disable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
@ -447,7 +405,7 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
#endif
ret = CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 9) { /* enable irq! */
} else if (cmd_head.wr == GTP_RW_ENABLE_IRQ) { /* enable irq! */
gtp_irq_enable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
@ -455,41 +413,45 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
#endif
ret = CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 17) {
} else if (cmd_head.wr == GTP_RW_CHECK_RAWDIFF_MODE) {
struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
if (ret)
pr_debug("copy_from_user failed.\n");
&userbuf[CMD_HEAD_LENGTH], cmd_head.data_len);
if (ret) {
dev_err(&gt_client->dev, "copy_from_user failed");
goto exit;
}
if (cmd_head.data[GTP_ADDR_LENGTH]) {
pr_debug("gtp enter rawdiff.\n");
pr_debug("gtp enter rawdiff\n");
ts->gtp_rawdiff_mode = true;
} else {
ts->gtp_rawdiff_mode = false;
pr_debug("gtp leave rawdiff.\n");
pr_debug("gtp leave rawdiff\n");
}
ret = CMD_HEAD_LENGTH;
goto exit;
}
#ifdef UPDATE_FUNCTIONS
else if (cmd_head.wr == 11) { /* Enter update mode! */
if (gup_enter_update_mode(gt_client) == FAIL)
} else if (cmd_head.wr == GTP_RW_ENTER_UPDATE_MODE) {
/* Enter update mode! */
if (gup_enter_update_mode(gt_client) == FAIL) {
ret = -EBUSY;
goto exit;
} else if (cmd_head.wr == 13) { /* Leave update mode! */
gup_leave_update_mode();
} else if (cmd_head.wr == 15) { /* Update firmware! */
}
} else if (cmd_head.wr == GTP_RW_LEAVE_UPDATE_MODE) {
/* Leave update mode! */
gup_leave_update_mode(gt_client);
} else if (cmd_head.wr == GTP_RW_UPDATE_FW) {
/* Update firmware! */
show_len = 0;
total_len = 0;
if (cmd_head.data_len + 1 > DATA_LENGTH) {
pr_debug("<<-GTP->> data len %d > data buff %d, rejected!\n",
cmd_head.data_len + 1, DATA_LENGTH);
if (cmd_head.data_len + 1 > data_length) {
dev_err(&gt_client->dev, "data len %d > data buff %d, rejected\n",
cmd_head.data_len + 1, data_length);
ret = -EINVAL;
goto exit;
}
memset(cmd_head.data, 0, cmd_head.data_len + 1);
memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
memcpy(cmd_head.data, &userbuf[CMD_HEAD_LENGTH],
cmd_head.data_len);
if (gup_update_proc((void *)cmd_head.data) == FAIL) {
@ -497,7 +459,6 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
goto exit;
}
}
#endif
ret = CMD_HEAD_LENGTH;
exit:
@ -505,37 +466,37 @@ exit:
return ret;
}
/*******************************************************
/*
* Function:
* Goodix tool read function.
* Input:
* standard proc read function param.
* Output:
* Return read length.
*******************************************************
*/
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
*/
static s32 goodix_tool_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
u16 data_len = 0;
s32 ret;
u8 buf[32];
mutex_lock(&lock);
if (cmd_head.wr % 2) {
pr_err("<< [READ]command head wrong\n");
ret = -EINVAL;
goto exit;
} else if (!cmd_head.wr) {
u16 len = 0;
s16 data_len = 0;
u16 loc = 0;
if (cmd_head.flag == 1) {
if (comfirm() == FAIL) {
pr_err("[READ]Comfirm fail!\n");
if (cmd_head.wr & 0x1) {
dev_err(&gt_client->dev, "command head wrong\n");
ret = -EINVAL;
goto exit;
}
} else if (cmd_head.flag == 2) {
switch (cmd_head.wr) {
case GTP_RW_READ:
if (cmd_head.flag == GTP_NEED_FLAG) {
if (comfirm() == FAIL) {
dev_err(&gt_client->dev, "Confirm fail");
ret = -EINVAL;
goto exit;
}
} else if (cmd_head.flag == GTP_NEED_INTERRUPT) {
/* Need interrupt! */
}
@ -550,54 +511,86 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
msleep(cmd_head.delay);
data_len = cmd_head.data_len;
while (data_len > 0) {
if (data_len > DATA_LENGTH)
len = DATA_LENGTH;
else
len = data_len;
data_len -= len;
if (tool_i2c_read(cmd_head.data, len) <= 0) {
pr_err("[READ]Read data failed!\n");
if (data_len <= 0 || (data_len > data_length)) {
dev_err(&gt_client->dev, "Invalid data length %d\n",
data_len);
ret = -EINVAL;
goto exit;
}
memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
len);
loc += len;
}
} else if (cmd_head.wr == 2) {
/* memcpy(page, "gt8", cmd_head.data_len);
* memcpy(page, "GT818", 5);
* page[5] = 0;
*/
if (data_len > count)
data_len = count;
pr_debug("Return ic type:%s len:%d.\n", page,
(s32)cmd_head.data_len);
ret = cmd_head.data_len;
if (tool_i2c_read(cmd_head.data, data_len) <= 0) {
dev_err(&gt_client->dev, "Read data failed\n");
ret = -EIO;
goto exit;
/* return sizeof(IC_TYPE_NAME); */
} else if (cmd_head.wr == 4) {
page[0] = show_len >> 8;
page[1] = show_len & 0xff;
page[2] = total_len >> 8;
page[3] = total_len & 0xff;
} else if (cmd_head.wr == 6) {
/* Read error code! */
} else if (cmd_head.wr == 8) { /*Read driver version */
/* memcpy(page, GTP_DRIVER_VERSION,
* strlen(GTP_DRIVER_VERSION));
*/
s32 tmp_len;
tmp_len = strlen(GTP_DRIVER_VERSION);
memcpy(page, GTP_DRIVER_VERSION, tmp_len);
page[tmp_len] = 0;
}
ret = cmd_head.data_len;
ret = simple_read_from_buffer(user_buf, count, ppos,
&cmd_head.data[GTP_ADDR_LENGTH], data_len);
break;
case GTP_RW_FILL_INFO:
ret = fill_update_info(user_buf, count, ppos);
break;
case GTP_RW_READ_VERSION:
/* Read driver version */
data_len = scnprintf(buf, sizeof(buf), "%s\n",
GTP_DRIVER_VERSION);
ret = simple_read_from_buffer(user_buf, count, ppos,
buf, data_len);
break;
default:
ret = -EINVAL;
break;
}
exit:
mutex_unlock(&lock);
return ret;
}
static const struct file_operations goodix_proc_fops = {
.write = goodix_tool_write,
.read = goodix_tool_read,
.open = simple_open,
.owner = THIS_MODULE,
};
s32 init_wr_node(struct i2c_client *client)
{
u8 i;
gt_client = client;
memset(&cmd_head, 0, sizeof(cmd_head));
cmd_head.data = NULL;
i = GTP_I2C_RETRY_5;
while ((!cmd_head.data) && i) {
cmd_head.data = devm_kzalloc(&client->dev,
i * DATA_LENGTH_UINT, GFP_KERNEL);
if (cmd_head.data)
break;
i--;
}
if (i) {
data_length = i * DATA_LENGTH_UINT;
dev_dbg(&client->dev, "Applied memory size:%d", data_length);
}
cmd_head.addr_len = 2;
cmd_head.retry = GTP_I2C_RETRY_5;
register_i2c_func();
mutex_init(&lock);
tool_set_proc_name(procname);
goodix_proc_entry = proc_create(procname,
S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP,
goodix_proc_entry,
&goodix_proc_fops);
if (goodix_proc_entry == NULL) {
dev_err(&client->dev, "Couldn't create proc entry");
return FAIL;
}
return SUCCESS;
}

View file

@ -44,18 +44,16 @@
#include "gt9xx.h"
#include <linux/of_gpio.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/input/mt.h>
#include <linux/debugfs.h>
#define GOODIX_DEV_NAME "Goodix-CTP"
#define CFG_MAX_TOUCH_POINTS 5
#define GOODIX_COORDS_ARR_SIZE 4
#define MAX_BUTTONS 4
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
#define GTP_I2C_ADDRESS_HIGH 0x14
#define GTP_I2C_ADDRESS_LOW 0x5D
#define GOODIX_VTG_MIN_UV 2600000
#define GOODIX_VTG_MAX_UV 3300000
#define GOODIX_I2C_VTG_MIN_UV 1800000
@ -79,7 +77,6 @@ static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
#endif
static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
static int gtp_i2c_test(struct i2c_client *client);
static int goodix_power_off(struct goodix_ts_data *ts);
@ -88,6 +85,8 @@ static int goodix_power_on(struct goodix_ts_data *ts);
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data);
static int goodix_ts_suspend(struct device *dev);
static int goodix_ts_resume(struct device *dev);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
@ -98,7 +97,6 @@ static struct delayed_work gtp_esd_check_work;
static struct workqueue_struct *gtp_esd_check_workqueue;
static void gtp_esd_check_func(struct work_struct *work);
static int gtp_init_ext_watchdog(struct i2c_client *client);
struct i2c_client *i2c_connect_client;
#endif
#if GTP_SLIDE_WAKEUP
@ -113,6 +111,10 @@ static s8 gtp_enter_doze(struct goodix_ts_data *ts);
bool init_done;
static u8 chip_gt9xxs; /* true if ic is gt9xxs, like gt915s */
u8 grp_cfg_version;
struct i2c_client *i2c_connect_client;
#define GTP_DEBUGFS_DIR "ts_debug"
#define GTP_DEBUGFS_FILE_SUSPEND "suspend"
/*******************************************************
Function:
@ -264,7 +266,7 @@ Output:
result of i2c write operation.
> 0: succeed, otherwise: failed
*********************************************************/
static int gtp_send_cfg(struct goodix_ts_data *ts)
int gtp_send_cfg(struct goodix_ts_data *ts)
{
int ret;
#if GTP_DRIVER_SEND_CFG
@ -593,26 +595,6 @@ exit_work_func:
return;
}
/*******************************************************
Function:
Timer interrupt service routine for polling mode.
Input:
timer: timer struct pointer
Output:
Timer work mode.
HRTIMER_NORESTART: no restart mode
*********************************************************/
static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
{
struct goodix_ts_data
*ts = container_of(timer, struct goodix_ts_data, timer);
queue_work(ts->goodix_wq, &ts->work);
hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
/*******************************************************
Function:
External interrupt service routine for interrupt mode.
@ -656,7 +638,7 @@ Input:
Output:
None.
*******************************************************/
static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
{
/* This reset sequence will selcet I2C slave address */
gpio_direction_output(ts->pdata->reset_gpio, 0);
@ -730,16 +712,13 @@ static s8 gtp_enter_doze(struct goodix_ts_data *ts)
return ret;
}
#else
/*******************************************************
Function:
Enter sleep mode.
Input:
ts: private data.
Output:
Executive outcomes.
>0: succeed, otherwise failed.
*******************************************************/
static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
/**
* gtp_enter_sleep - Enter sleep mode
* @ts: driver private data
*
* Returns zero on success, else an error.
*/
static u8 gtp_enter_sleep(struct goodix_ts_data *ts)
{
int ret = -1;
s8 retry = 0;
@ -761,16 +740,16 @@ static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
ret = goodix_power_off(ts);
if (ret) {
dev_err(&ts->client->dev, "GTP power off failed.\n");
return 0;
return ret;
}
return 1;
return 0;
}
usleep(5000);
while (retry++ < GTP_I2C_RETRY_5) {
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret == 1) {
dev_dbg(&ts->client->dev, "GTP enter sleep!");
return ret;
return 0;
}
msleep(20);
}
@ -1196,19 +1175,14 @@ static int gtp_request_irq(struct goodix_ts_data *ts)
int ret;
const u8 irq_table[] = GTP_IRQ_TAB;
ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
GTP_DEBUG("INT trigger type:%x, irq=%d", ts->int_trigger_type,
ts->client->irq);
ret = request_threaded_irq(ts->client->irq, NULL,
goodix_ts_irq_handler,
irq_table[ts->int_trigger_type],
ts->client->name, ts);
if (ret) {
dev_err(&ts->client->dev, "Request IRQ failed!ERRNO:%d.\n",
ret);
gpio_direction_input(ts->pdata->irq_gpio);
hrtimer_init(&ts->timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
ts->timer.function = goodix_ts_timer_handler;
hrtimer_start(&ts->timer, ktime_set(1, 0),
HRTIMER_MODE_REL);
ts->use_irq = false;
return ret;
}
@ -1560,6 +1534,56 @@ static const struct attribute_group gtp_attr_grp = {
.attrs = gtp_attrs,
};
static int gtp_debug_suspend_set(void *_data, u64 val)
{
struct goodix_ts_data *ts = _data;
mutex_lock(&ts->input_dev->mutex);
if (val)
goodix_ts_suspend(&ts->client->dev);
else
goodix_ts_resume(&ts->client->dev);
mutex_unlock(&ts->input_dev->mutex);
return 0;
}
static int gtp_debug_suspend_get(void *_data, u64 *val)
{
struct goodix_ts_data *ts = _data;
mutex_lock(&ts->input_dev->mutex);
*val = ts->gtp_is_suspend;
mutex_unlock(&ts->input_dev->mutex);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, gtp_debug_suspend_get,
gtp_debug_suspend_set, "%lld\n");
static int gtp_debugfs_init(struct goodix_ts_data *data)
{
data->debug_base = debugfs_create_dir(GTP_DEBUGFS_DIR, NULL);
if (IS_ERR_OR_NULL(data->debug_base)) {
pr_err("Failed to create debugfs dir\n");
return -EINVAL;
}
if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_SUSPEND,
S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP,
data->debug_base,
data,
&debug_suspend_fops)))) {
pr_err("Failed to create suspend file\n");
debugfs_remove_recursive(data->debug_base);
return -EINVAL;
}
return 0;
}
static int goodix_ts_get_dt_coords(struct device *dev, char *name,
struct goodix_ts_platform_data *pdata)
{
@ -1694,7 +1718,7 @@ static int goodix_parse_dt(struct device *dev,
prop->value, pdata->config_data_len[i]);
read_cfg_num++;
}
dev_dbg(dev, "%d config data read from device tree.\n", read_cfg_num);
dev_dbg(dev, "%d config data read from device tree\n", read_cfg_num);
return 0;
}
@ -1783,7 +1807,7 @@ static int goodix_ts_probe(struct i2c_client *client,
ret = gtp_i2c_test(client);
if (ret != 2) {
dev_err(&client->dev, "I2C communication ERROR!\n");
dev_err(&client->dev, "I2C communication ERROR\n");
goto exit_power_off;
}
@ -1791,7 +1815,7 @@ static int goodix_ts_probe(struct i2c_client *client,
strlcpy(ts->fw_name, pdata->fw_name,
strlen(pdata->fw_name) + 1);
#if GTP_AUTO_UPDATE
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
ret = gup_init_update_proc(ts);
if (ret < 0) {
dev_err(&client->dev,
@ -1834,24 +1858,24 @@ static int goodix_ts_probe(struct i2c_client *client,
INIT_WORK(&ts->work, goodix_ts_work_func);
ret = gtp_request_irq(ts);
if (ret < 0)
dev_info(&client->dev, "GTP works in polling mode.\n");
if (ret)
dev_info(&client->dev, "GTP request irq failed %d\n", ret);
else
dev_info(&client->dev, "GTP works in interrupt mode.\n");
dev_info(&client->dev, "GTP works in interrupt mode\n");
ret = gtp_read_fw_version(client, &version_info);
if (ret != 2)
dev_err(&client->dev, "GTP firmware version read failed.\n");
dev_err(&client->dev, "GTP firmware version read failed\n");
ret = gtp_check_product_id(client);
if (ret != 0) {
dev_err(&client->dev, "GTP Product id doesn't match.\n");
dev_err(&client->dev, "GTP Product id doesn't match\n");
goto exit_free_irq;
}
if (ts->use_irq)
gtp_irq_enable(ts);
#if GTP_CREATE_WR_NODE
#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG
init_wr_node(client);
#endif
@ -1860,10 +1884,14 @@ static int goodix_ts_probe(struct i2c_client *client,
#endif
ret = sysfs_create_group(&client->dev.kobj, &gtp_attr_grp);
if (ret < 0) {
dev_err(&client->dev, "sys file creation failed.\n");
dev_err(&client->dev, "sys file creation failed\n");
goto exit_free_irq;
}
ret = gtp_debugfs_init(ts);
if (ret != 0)
goto exit_remove_sysfs;
init_done = true;
return 0;
exit_free_irq:
@ -1871,7 +1899,7 @@ exit_free_irq:
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts->fb_notif))
dev_err(&client->dev,
"Error occurred while unregistering fb_notifier.\n");
"Error occurred while unregistering fb_notifier\n");
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts->early_suspend);
#endif
@ -1888,6 +1916,8 @@ exit_free_irq:
input_free_device(ts->input_dev);
ts->input_dev = NULL;
}
exit_remove_sysfs:
sysfs_remove_group(&ts->input_dev->dev.kobj, &gtp_attr_grp);
exit_free_inputdev:
kfree(ts->config_data);
exit_power_off:
@ -1921,13 +1951,13 @@ static int goodix_ts_remove(struct i2c_client *client)
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts->fb_notif))
dev_err(&client->dev,
"Error occurred while unregistering fb_notifier.\n");
"Error occurred while unregistering fb_notifier\n");
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts->early_suspend);
#endif
mutex_destroy(&ts->lock);
#if GTP_CREATE_WR_NODE
#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG
uninit_wr_node();
#endif
@ -1962,6 +1992,7 @@ static int goodix_ts_remove(struct i2c_client *client)
goodix_power_deinit(ts);
i2c_set_clientdata(client, NULL);
}
debugfs_remove_recursive(ts->debug_base);
return 0;
}
@ -1980,9 +2011,13 @@ static int goodix_ts_suspend(struct device *dev)
struct goodix_ts_data *ts = dev_get_drvdata(dev);
int ret = 0, i;
if (ts->gtp_is_suspend) {
dev_dbg(&ts->client->dev, "Already in suspend state\n");
return 0;
}
mutex_lock(&ts->lock);
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 1;
gtp_esd_switch(ts->client, SWITCH_OFF);
#endif
@ -2001,13 +2036,14 @@ static int goodix_ts_suspend(struct device *dev)
ret = gtp_enter_sleep(ts);
#endif
if (ret <= 0)
dev_err(&ts->client->dev, "GTP early suspend failed.\n");
if (ret < 0)
dev_err(&ts->client->dev, "GTP early suspend failed\n");
/* to avoid waking up while not sleeping,
* delay 48 + 10ms to ensure reliability
*/
msleep(58);
mutex_unlock(&ts->lock);
ts->gtp_is_suspend = 1;
return ret;
}
@ -2025,6 +2061,11 @@ static int goodix_ts_resume(struct device *dev)
struct goodix_ts_data *ts = dev_get_drvdata(dev);
int ret = 0;
if (!ts->gtp_is_suspend) {
dev_dbg(&ts->client->dev, "Already in awake state\n");
return 0;
}
mutex_lock(&ts->lock);
ret = gtp_wakeup_sleep(ts);
@ -2033,7 +2074,7 @@ static int goodix_ts_resume(struct device *dev)
#endif
if (ret <= 0)
dev_err(&ts->client->dev, "GTP resume failed.\n");
dev_err(&ts->client->dev, "GTP resume failed\n");
if (ts->use_irq)
gtp_irq_enable(ts);
@ -2042,10 +2083,10 @@ static int goodix_ts_resume(struct device *dev)
ktime_set(1, 0), HRTIMER_MODE_REL);
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 0;
gtp_esd_switch(ts->client, SWITCH_ON);
#endif
mutex_unlock(&ts->lock);
ts->gtp_is_suspend = 0;
return ret;
}
@ -2236,8 +2277,15 @@ static void gtp_esd_check_func(struct work_struct *work)
}
#endif
static SIMPLE_DEV_PM_OPS(goodix_ts_dev_pm_ops, goodix_ts_suspend,
goodix_ts_resume);
#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
.suspend = goodix_ts_suspend,
.resume = goodix_ts_resume,
};
#else
static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
};
#endif
static const struct i2c_device_id goodix_ts_id[] = {
{ GTP_I2C_NAME, 0 },

View file

@ -22,18 +22,9 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
#include <linux/debugfs.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
@ -105,6 +96,7 @@ struct goodix_ts_data {
#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
struct dentry *debug_base;
};
extern u16 show_len;
@ -116,14 +108,6 @@ extern u16 total_len;
#define GTP_DRIVER_SEND_CFG 1
#define GTP_HAVE_TOUCH_KEY 1
/* auto updated by .bin file as default */
#define GTP_AUTO_UPDATE 0
/* auto updated by head_fw_array in gt9xx_firmware.h,
* function together with GTP_AUTO_UPDATE
*/
#define GTP_HEADER_FW_UPDATE 0
#define GTP_CREATE_WR_NODE 0
#define GTP_ESD_PROTECT 0
#define GTP_WITH_PEN 0
@ -132,18 +116,6 @@ extern u16 total_len;
/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
#define GTP_DBL_CLK_WAKEUP 0
/*************************** PART2:TODO define *******************************/
/* STEP_1(REQUIRED): Define Configuration Information Group(s) */
/* Sensor_ID Map: */
/* sensor_opt1 sensor_opt2 Sensor_ID
* GND GND 0
* VDDIO GND 1
* NC GND 2
* GND NC/300K 3
* VDDIO NC/300K 4
* NC NC/300K 5
*/
#define GTP_IRQ_TAB {\
IRQ_TYPE_EDGE_RISING,\
IRQ_TYPE_EDGE_FALLING,\
@ -151,7 +123,7 @@ extern u16 total_len;
IRQ_TYPE_LEVEL_HIGH\
}
/* STEP_3(optional): Specify your special config info if needed */
#define GTP_IRQ_TAB_RISING 0
#define GTP_IRQ_TAB_FALLING 1
#if GTP_CUSTOM_CFG
@ -197,16 +169,52 @@ extern u16 total_len;
#define RESOLUTION_LOC 3
#define TRIGGER_LOC 8
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
#define GTP_I2C_ADDRESS_HIGH 0x14
#define GTP_I2C_ADDRESS_LOW 0x5D
/* GTP CM_HEAD RW flags */
#define GTP_RW_READ 0
#define GTP_RW_WRITE 1
#define GTP_RW_READ_IC_TYPE 2
#define GTP_RW_WRITE_IC_TYPE 3
#define GTP_RW_FILL_INFO 4
#define GTP_RW_NO_WRITE 5
#define GTP_RW_READ_ERROR 6
#define GTP_RW_DISABLE_IRQ 7
#define GTP_RW_READ_VERSION 8
#define GTP_RW_ENABLE_IRQ 9
#define GTP_RW_ENTER_UPDATE_MODE 11
#define GTP_RW_LEAVE_UPDATE_MODE 13
#define GTP_RW_UPDATE_FW 15
#define GTP_RW_CHECK_RAWDIFF_MODE 17
/* GTP need flag or interrupt */
#define GTP_NO_NEED 0
#define GTP_NEED_FLAG 1
#define GTP_NEED_INTERRUPT 2
/*****************************End of Part III********************************/
void gtp_esd_switch(struct i2c_client *client, int on);
#if GTP_CREATE_WR_NODE
extern s32 init_wr_node(struct i2c_client *client);
extern void uninit_wr_node(void);
int gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr,
u8 *rxbuf, int len);
int gtp_send_cfg(struct goodix_ts_data *ts);
void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
void gtp_irq_disable(struct goodix_ts_data *ts);
void gtp_irq_enable(struct goodix_ts_data *ts);
#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG
s32 init_wr_node(struct i2c_client *client);
void uninit_wr_node(void);
#endif
#if GTP_AUTO_UPDATE
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
s32 gup_enter_update_mode(struct i2c_client *client);
void gup_leave_update_mode(struct i2c_client *client);
s32 gup_update_proc(void *dir);
extern struct i2c_client *i2c_connect_client;
#endif
#endif /* _GOODIX_GT9XX_H_ */

View file

@ -1,6 +0,0 @@
/*
* make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
* define your own firmware array here
*/
const unsigned char header_fw_array[] = {
};

File diff suppressed because it is too large Load diff