Loading drivers/input/touchscreen/gt9xx/goodix_tool.c +193 −192 Original line number Diff line number Diff line Loading @@ -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 flag0: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 */ Loading @@ -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; Loading @@ -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) { Loading Loading @@ -118,7 +113,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(>_client->dev, "I2C read retry limit over.\n"); ret = -EIO; } Loading @@ -143,7 +138,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(>_client->dev, "I2C write retry limit over.\n"); ret = -EIO; } Loading Loading @@ -178,10 +173,10 @@ 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!"); Loading @@ -199,54 +194,11 @@ static void unregister_i2c_func(void) pr_info("I2C function: unregister i2c transfer function!"); } 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."); 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!"); 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; } 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) Loading Loading @@ -302,15 +254,11 @@ 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!"); dev_err(>_client->dev, "Read flag data failed!"); return FAIL; } if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, Loading @@ -325,13 +273,34 @@ static u8 comfirm(void) } if (i >= cmd_head.times) { pr_err("Didn't get the flag to continue!"); dev_err(>_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. Loading @@ -340,72 +309,64 @@ nput: 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."); dev_err(>_client->dev, "copy_from_user failed."); ret = -EACCES; goto exit; } pr_debug("wr :0x%02x.", cmd_head.wr); pr_debug("flag:0x%02x.", cmd_head.flag); pr_debug("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); pr_debug("flag val:0x%02x.", cmd_head.flag_val); pr_debug("flag rel:0x%02x.", cmd_head.flag_relation); pr_debug("circle :%d.", (s32)cmd_head.circle); pr_debug("times :%d.", (s32)cmd_head.times); pr_debug("retry :%d.", (s32)cmd_head.retry); pr_debug("delay :%d.", (s32)cmd_head.delay); pr_debug("data len:%d.", (s32)cmd_head.data_len); pr_debug("addr len:%d.", (s32)cmd_head.addr_len); pr_debug("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); pr_debug("len:%d.", (s32)len); pr_debug("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]); if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) { pr_err("data len %d > data buff %d, rejected!\n", cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH)); dev_dbg(>_client->dev, "wr:0x%02x, flag:0x%02x, flag addr:0x%02x%02x, flag val:0x%02x, flag rel:0x%02x, circle:%d, times:%d, retry:%d, delay:%d, data len:%d, addr len:%d, addr:0x%02x%02x, write len: %d.", cmd_head.wr, cmd_head.flag, cmd_head.flag_addr[0], cmd_head.flag_addr[1], cmd_head.flag_val, cmd_head.flag_relation, (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)) { dev_err(>_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.addr_len > GTP_ADDR_LENGTH) { pr_err(" addr len %d > data buff %d, rejected!\n", dev_err(>_client->dev, "addr len %d > data buff %d, rejected!\n", cmd_head.addr_len, 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."); &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); if (ret) { dev_err(>_client->dev, "copy_from_user failed."); 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 (FAIL == comfirm()) { pr_err("[WRITE]Comfirm fail!"); if (cmd_head.flag == GTP_NEED_FLAG) { if (comfirm() == FAIL) { dev_err(>_client->dev, "Comfirm 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!"); dev_err(>_client->dev, "Write data failed!"); ret = -EIO; goto exit; } Loading @@ -415,32 +376,32 @@ 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."); if (ret) { dev_err(>_client->dev, "copy_from_user failed."); goto exit; } if (cmd_head.data_len > sizeof(IC_TYPE)) { pr_err("<<-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(>_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 Loading @@ -448,7 +409,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 Loading @@ -456,13 +417,15 @@ 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) &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); if (ret) { pr_debug("copy_from_user failed."); goto exit; } if (cmd_head.data[GTP_ADDR_LENGTH]) { pr_debug("gtp enter rawdiff."); ts->gtp_rawdiff_mode = true; Loading @@ -472,34 +435,34 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff, } ret = CMD_HEAD_LENGTH; goto exit; } #ifdef UPDATE_FUNCTIONS else if (cmd_head.wr == 11) { /* Enter update mode! */ if (FAIL == gup_enter_update_mode(gt_client)) { } 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_err("<<-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(>_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 (FAIL == gup_update_proc((void *)cmd_head.data)) { if (gup_update_proc((void *)cmd_head.data) == FAIL) { ret = -EBUSY; goto exit; } } #endif ret = CMD_HEAD_LENGTH; exit: Loading @@ -511,32 +474,33 @@ exit: Function: Goodix tool read function. Input: standard proc read function param. standard seq file 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"); if (cmd_head.wr & 0x1) { dev_err(>_client->dev, "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 (FAIL == comfirm()) { pr_err("[READ]Comfirm fail!"); } switch (cmd_head.wr) { case GTP_RW_READ: if (cmd_head.flag == GTP_NEED_FLAG) { if (comfirm() == FAIL) { dev_err(>_client->dev, "Comfirm fail!"); ret = -EINVAL; goto exit; } } else if (cmd_head.flag == 2) { } else if (cmd_head.flag == GTP_NEED_INTERRUPT) { /* Need interrupt! */ } Loading @@ -551,52 +515,89 @@ 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!"); if (data_len <= 0 || (data_len > data_length)) { dev_err(>_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.", page, (s32)cmd_head.data_len); ret = cmd_head.data_len; if (tool_i2c_read(cmd_head.data, data_len) <= 0) { dev_err(>_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 (6 == cmd_head.wr) { /* Read error code! */ } else if (8 == cmd_head.wr) { /*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); } else { dev_err(&client->dev, "Apply for memory failed."); return FAIL; } 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; } drivers/input/touchscreen/gt9xx/gt9xx.c +91 −47 Original line number Diff line number Diff line Loading @@ -47,17 +47,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 CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) #define GOODIX_VTG_MIN_UV 2600000 Loading @@ -84,7 +83,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); Loading @@ -93,6 +91,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); Loading @@ -103,7 +103,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 Loading @@ -118,6 +117,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: Loading Loading @@ -269,7 +272,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 Loading Loading @@ -598,26 +601,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. Loading Loading @@ -661,7 +644,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); Loading Loading @@ -1198,7 +1181,7 @@ Output: *******************************************************/ static int gtp_request_irq(struct goodix_ts_data *ts) { int ret; int ret = 0; const u8 irq_table[] = GTP_IRQ_TAB; ret = request_threaded_irq(ts->client->irq, NULL, Loading @@ -1206,21 +1189,12 @@ static int gtp_request_irq(struct goodix_ts_data *ts) 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; } gtp_irq_disable(ts); ts->use_irq = true; return 0; return ret; } /******************************************************* Loading Loading @@ -1567,6 +1541,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) { Loading Loading @@ -1798,7 +1822,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, Loading Loading @@ -1841,8 +1865,8 @@ 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"); Loading @@ -1858,7 +1882,7 @@ static int goodix_ts_probe(struct i2c_client *client, if (ts->use_irq) gtp_irq_enable(ts); #if GTP_CREATE_WR_NODE #ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG init_wr_node(client); #endif Loading @@ -1871,6 +1895,13 @@ static int goodix_ts_probe(struct i2c_client *client, goto exit_free_irq; } ret = gtp_debugfs_init(ts); if (ret != 0) { dev_err(&client->dev, "Failed to create debugfs entries, %d\n", ret); goto exit_remove_sysfs; } init_done = true; return 0; exit_free_irq: Loading @@ -1895,6 +1926,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, >p_attr_grp); exit_free_inputdev: kfree(ts->config_data); exit_power_off: Loading Loading @@ -1934,7 +1967,7 @@ static int goodix_ts_remove(struct i2c_client *client) #endif mutex_destroy(&ts->lock); #if GTP_CREATE_WR_NODE #ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG uninit_wr_node(); #endif Loading Loading @@ -1969,6 +2002,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; } Loading @@ -1987,9 +2021,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 Loading @@ -2015,6 +2053,7 @@ static int goodix_ts_suspend(struct device *dev) */ msleep(58); mutex_unlock(&ts->lock); ts->gtp_is_suspend = 1; return ret; } Loading @@ -2032,6 +2071,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); Loading @@ -2049,10 +2093,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; } Loading Loading
drivers/input/touchscreen/gt9xx/goodix_tool.c +193 −192 Original line number Diff line number Diff line Loading @@ -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 flag0: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 */ Loading @@ -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; Loading @@ -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) { Loading Loading @@ -118,7 +113,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(>_client->dev, "I2C read retry limit over.\n"); ret = -EIO; } Loading @@ -143,7 +138,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(>_client->dev, "I2C write retry limit over.\n"); ret = -EIO; } Loading Loading @@ -178,10 +173,10 @@ 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!"); Loading @@ -199,54 +194,11 @@ static void unregister_i2c_func(void) pr_info("I2C function: unregister i2c transfer function!"); } 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."); 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!"); 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; } 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) Loading Loading @@ -302,15 +254,11 @@ 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!"); dev_err(>_client->dev, "Read flag data failed!"); return FAIL; } if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, Loading @@ -325,13 +273,34 @@ static u8 comfirm(void) } if (i >= cmd_head.times) { pr_err("Didn't get the flag to continue!"); dev_err(>_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. Loading @@ -340,72 +309,64 @@ nput: 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."); dev_err(>_client->dev, "copy_from_user failed."); ret = -EACCES; goto exit; } pr_debug("wr :0x%02x.", cmd_head.wr); pr_debug("flag:0x%02x.", cmd_head.flag); pr_debug("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); pr_debug("flag val:0x%02x.", cmd_head.flag_val); pr_debug("flag rel:0x%02x.", cmd_head.flag_relation); pr_debug("circle :%d.", (s32)cmd_head.circle); pr_debug("times :%d.", (s32)cmd_head.times); pr_debug("retry :%d.", (s32)cmd_head.retry); pr_debug("delay :%d.", (s32)cmd_head.delay); pr_debug("data len:%d.", (s32)cmd_head.data_len); pr_debug("addr len:%d.", (s32)cmd_head.addr_len); pr_debug("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); pr_debug("len:%d.", (s32)len); pr_debug("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]); if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) { pr_err("data len %d > data buff %d, rejected!\n", cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH)); dev_dbg(>_client->dev, "wr:0x%02x, flag:0x%02x, flag addr:0x%02x%02x, flag val:0x%02x, flag rel:0x%02x, circle:%d, times:%d, retry:%d, delay:%d, data len:%d, addr len:%d, addr:0x%02x%02x, write len: %d.", cmd_head.wr, cmd_head.flag, cmd_head.flag_addr[0], cmd_head.flag_addr[1], cmd_head.flag_val, cmd_head.flag_relation, (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)) { dev_err(>_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.addr_len > GTP_ADDR_LENGTH) { pr_err(" addr len %d > data buff %d, rejected!\n", dev_err(>_client->dev, "addr len %d > data buff %d, rejected!\n", cmd_head.addr_len, 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."); &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); if (ret) { dev_err(>_client->dev, "copy_from_user failed."); 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 (FAIL == comfirm()) { pr_err("[WRITE]Comfirm fail!"); if (cmd_head.flag == GTP_NEED_FLAG) { if (comfirm() == FAIL) { dev_err(>_client->dev, "Comfirm 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!"); dev_err(>_client->dev, "Write data failed!"); ret = -EIO; goto exit; } Loading @@ -415,32 +376,32 @@ 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."); if (ret) { dev_err(>_client->dev, "copy_from_user failed."); goto exit; } if (cmd_head.data_len > sizeof(IC_TYPE)) { pr_err("<<-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(>_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 Loading @@ -448,7 +409,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 Loading @@ -456,13 +417,15 @@ 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) &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); if (ret) { pr_debug("copy_from_user failed."); goto exit; } if (cmd_head.data[GTP_ADDR_LENGTH]) { pr_debug("gtp enter rawdiff."); ts->gtp_rawdiff_mode = true; Loading @@ -472,34 +435,34 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff, } ret = CMD_HEAD_LENGTH; goto exit; } #ifdef UPDATE_FUNCTIONS else if (cmd_head.wr == 11) { /* Enter update mode! */ if (FAIL == gup_enter_update_mode(gt_client)) { } 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_err("<<-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(>_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 (FAIL == gup_update_proc((void *)cmd_head.data)) { if (gup_update_proc((void *)cmd_head.data) == FAIL) { ret = -EBUSY; goto exit; } } #endif ret = CMD_HEAD_LENGTH; exit: Loading @@ -511,32 +474,33 @@ exit: Function: Goodix tool read function. Input: standard proc read function param. standard seq file 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"); if (cmd_head.wr & 0x1) { dev_err(>_client->dev, "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 (FAIL == comfirm()) { pr_err("[READ]Comfirm fail!"); } switch (cmd_head.wr) { case GTP_RW_READ: if (cmd_head.flag == GTP_NEED_FLAG) { if (comfirm() == FAIL) { dev_err(>_client->dev, "Comfirm fail!"); ret = -EINVAL; goto exit; } } else if (cmd_head.flag == 2) { } else if (cmd_head.flag == GTP_NEED_INTERRUPT) { /* Need interrupt! */ } Loading @@ -551,52 +515,89 @@ 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!"); if (data_len <= 0 || (data_len > data_length)) { dev_err(>_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.", page, (s32)cmd_head.data_len); ret = cmd_head.data_len; if (tool_i2c_read(cmd_head.data, data_len) <= 0) { dev_err(>_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 (6 == cmd_head.wr) { /* Read error code! */ } else if (8 == cmd_head.wr) { /*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); } else { dev_err(&client->dev, "Apply for memory failed."); return FAIL; } 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; }
drivers/input/touchscreen/gt9xx/gt9xx.c +91 −47 Original line number Diff line number Diff line Loading @@ -47,17 +47,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 CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) #define GOODIX_VTG_MIN_UV 2600000 Loading @@ -84,7 +83,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); Loading @@ -93,6 +91,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); Loading @@ -103,7 +103,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 Loading @@ -118,6 +117,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: Loading Loading @@ -269,7 +272,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 Loading Loading @@ -598,26 +601,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. Loading Loading @@ -661,7 +644,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); Loading Loading @@ -1198,7 +1181,7 @@ Output: *******************************************************/ static int gtp_request_irq(struct goodix_ts_data *ts) { int ret; int ret = 0; const u8 irq_table[] = GTP_IRQ_TAB; ret = request_threaded_irq(ts->client->irq, NULL, Loading @@ -1206,21 +1189,12 @@ static int gtp_request_irq(struct goodix_ts_data *ts) 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; } gtp_irq_disable(ts); ts->use_irq = true; return 0; return ret; } /******************************************************* Loading Loading @@ -1567,6 +1541,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) { Loading Loading @@ -1798,7 +1822,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, Loading Loading @@ -1841,8 +1865,8 @@ 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"); Loading @@ -1858,7 +1882,7 @@ static int goodix_ts_probe(struct i2c_client *client, if (ts->use_irq) gtp_irq_enable(ts); #if GTP_CREATE_WR_NODE #ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG init_wr_node(client); #endif Loading @@ -1871,6 +1895,13 @@ static int goodix_ts_probe(struct i2c_client *client, goto exit_free_irq; } ret = gtp_debugfs_init(ts); if (ret != 0) { dev_err(&client->dev, "Failed to create debugfs entries, %d\n", ret); goto exit_remove_sysfs; } init_done = true; return 0; exit_free_irq: Loading @@ -1895,6 +1926,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, >p_attr_grp); exit_free_inputdev: kfree(ts->config_data); exit_power_off: Loading Loading @@ -1934,7 +1967,7 @@ static int goodix_ts_remove(struct i2c_client *client) #endif mutex_destroy(&ts->lock); #if GTP_CREATE_WR_NODE #ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG uninit_wr_node(); #endif Loading Loading @@ -1969,6 +2002,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; } Loading @@ -1987,9 +2021,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 Loading @@ -2015,6 +2053,7 @@ static int goodix_ts_suspend(struct device *dev) */ msleep(58); mutex_unlock(&ts->lock); ts->gtp_is_suspend = 1; return ret; } Loading @@ -2032,6 +2071,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); Loading @@ -2049,10 +2093,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; } Loading