diff options
Diffstat (limited to 'drivers/input/touchscreen/gt1151/gt1x_tools.c')
| -rw-r--r-- | drivers/input/touchscreen/gt1151/gt1x_tools.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/gt1151/gt1x_tools.c b/drivers/input/touchscreen/gt1151/gt1x_tools.c new file mode 100644 index 000000000000..765707e11c53 --- /dev/null +++ b/drivers/input/touchscreen/gt1151/gt1x_tools.c @@ -0,0 +1,441 @@ +/* drivers/input/touchscreen/goodix_tool.c +* +* 2010 - 2014 Goodix Technology. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be a reference +* to you, when you are integrating the GOODiX's CTP IC into your system, +* 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. +* +* Version: 1.4 +* Release Date: 2015/07/10 +*/ + +#include <linux/delay.h> +#include <asm/uaccess.h> +#include <linux/proc_fs.h> +#include <generated/utsrelease.h> +#include "gt1x_generic.h" + +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos); +static ssize_t gt1x_tool_write(struct file *filp, const char *buffer, size_t count, loff_t * ppos); + + +static int gt1x_tool_release(struct inode *inode, struct file *filp); +static int gt1x_tool_open(struct inode *inode,struct file *file); + +#pragma pack(1) +typedef struct { + 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 + u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:< + u16 circle; //polling cycle + u8 times; //plling times + u8 retry; //I2C retry times + u16 delay; //delay befor read or after write + u16 data_len; //data length + u8 addr_len; //address length + u8 addr[2]; //address + u8 res[3]; //reserved + u8 *data; //data pointer +} st_cmd_head; +#pragma pack() +st_cmd_head cmd_head; + +s32 DATA_LENGTH = 0; +s8 IC_TYPE[16] = "GT1X"; + +#define UPDATE_FUNCTIONS +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*)) + +static char procname[20] = { 0 }; + +static struct proc_dir_entry *gt1x_tool_proc_entry; +static struct file_operations gt1x_tool_fops = { + .read = gt1x_tool_read, + .write = gt1x_tool_write, +.open = gt1x_tool_open, +.release = gt1x_tool_release, +.owner = THIS_MODULE, +}; + +static void set_tool_node_name(char *procname) +{ + + int v0 = 0, v1 = 0, v2 = 0; + + sscanf(UTS_RELEASE, "%d.%d.%d", &v0, &v1, &v2); + sprintf(procname, "gmnode%02d%02d%02d", v0, v1, v2); +} + +int gt1x_init_tool_node(void) +{ + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.wr = 1; //if the first operation is read, will return fail. + cmd_head.data = kzalloc(DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL == cmd_head.data) { + GTP_ERROR("Apply for memory failed."); + return -1; + } + GTP_INFO("Alloc memory size:%d.", DATA_LENGTH_UINT); + DATA_LENGTH = DATA_LENGTH_UINT - GTP_ADDR_LENGTH; + + set_tool_node_name(procname); + + gt1x_tool_proc_entry = proc_create(procname, 0666, NULL, >1x_tool_fops); + if (gt1x_tool_proc_entry == NULL) { + GTP_ERROR("CAN't create proc entry /proc/%s.", procname); + return -1; + } else { + GTP_INFO("Created proc entry /proc/%s.", procname); + } + return 0; +} + +void gt1x_deinit_tool_node(void) +{ + remove_proc_entry(procname, NULL); + kfree(cmd_head.data); + cmd_head.data = NULL; +} + +static s32 tool_i2c_read(u8 * buf, u16 len) +{ + u16 addr = (buf[0] << 8) + buf[1]; + if (!gt1x_i2c_read(addr, &buf[2], len)) { + return 1; + } + return -1; +} + +static s32 tool_i2c_write(u8 * buf, u16 len) +{ + u16 addr = (buf[0] << 8) + buf[1]; + if (!gt1x_i2c_write(addr, &buf[2], len - 2)) { + return 1; + } + return -1; +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32) ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* +Function: + Comfirm function. +Input: +None. +Output: + Return write length. +********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + 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) { + GTP_ERROR("Read flag data failed!"); + return -1; + } + + if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation)) { + GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]); + GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + GTP_ERROR("Didn't get the flag to continue!"); + return -1; + } + + return 0; +} + +/******************************************************* +Function: + Goodix tool write function. +Input: +standard proc write function param. +Output: + Return write length. +********************************************************/ +static ssize_t gt1x_tool_write(struct file *filp, const char __user * buff, size_t len, loff_t * data) +{ + u64 ret = 0; + GTP_DEBUG_FUNC(); + GTP_DEBUG_ARRAY((u8 *) buff, len); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + GTP_ERROR("copy_from_user failed."); + } + + GTP_DEBUG("wr :0x%02x.", cmd_head.wr); + /* + GTP_DEBUG("flag:0x%02x.", cmd_head.flag); + GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); + GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val); + GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation); + GTP_DEBUG("circle :%d.", (s32)cmd_head.circle); + GTP_DEBUG("times :%d.", (s32)cmd_head.times); + GTP_DEBUG("retry :%d.", (s32)cmd_head.retry); + GTP_DEBUG("delay :%d.", (s32)cmd_head.delay); + GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len); + GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len); + GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); + GTP_DEBUG("len:%d.", (s32)len); + GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]); + */ + + if (1 == cmd_head.wr) { + u16 addr, data_len, pos; + + if (1 == cmd_head.flag) { + if (comfirm()) { + GTP_ERROR("[WRITE]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head.flag) { + //Need interrupt! + } + + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + data_len = cmd_head.data_len; + pos = 0; + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH + pos], len); + if (ret) { + GTP_ERROR("[WRITE]copy_from_user failed."); + return -1; + } + cmd_head.data[0] = ((addr >> 8) & 0xFF); + cmd_head.data[1] = (addr & 0xFF); + + GTP_DEBUG_ARRAY(cmd_head.data, len + GTP_ADDR_LENGTH); + + if (tool_i2c_write(cmd_head.data, len + GTP_ADDR_LENGTH) <= 0) { + GTP_ERROR("[WRITE]Write data failed!"); + return -1; + } + addr += len; + pos += len; + data_len -= len; + } + + if (cmd_head.delay) { + msleep(cmd_head.delay); + } + + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (3 == cmd_head.wr) { //gt1x unused + + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (5 == cmd_head.wr) { //? + + //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (7 == cmd_head.wr) { //disable irq! + gt1x_irq_disable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + return CMD_HEAD_LENGTH; + } else if (9 == cmd_head.wr) { //enable irq! + gt1x_irq_enable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + return CMD_HEAD_LENGTH; + } else if (17 == cmd_head.wr) { + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if (ret) { + GTP_ERROR("copy_from_user failed."); + return -1; + } + + if (cmd_head.data[GTP_ADDR_LENGTH]) { + GTP_DEBUG("gtp enter rawdiff."); + gt1x_rawdiff_mode = true; + } else { + gt1x_rawdiff_mode = false; + GTP_DEBUG("gtp leave rawdiff."); + } + + return CMD_HEAD_LENGTH; +#if GTP_AUTO_UPDATE + } else if (11 == cmd_head.wr) { + gt1x_enter_update_mode(); + } else if (13 == cmd_head.wr) { + gt1x_leave_update_mode(); + } else if (15 == cmd_head.wr) { + struct task_struct *thrd = NULL; + memset(cmd_head.data, 0, cmd_head.data_len + 1); + memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + GTP_DEBUG("update firmware, filename: %s", cmd_head.data); + thrd = kthread_run(gt1x_update_firmware, (void *)cmd_head.data, "GT1x FW Update"); + if (IS_ERR(thrd)) { + return PTR_ERR(thrd); + } +#endif + } + return CMD_HEAD_LENGTH; +} + +static u8 devicecount = 0; +static int gt1x_tool_open(struct inode *inode,struct file *file) +{ + if (devicecount > 0) { + return -ERESTARTSYS; + GTP_ERROR("tools open failed!"); + } + + devicecount++; + return 0; +} + +static int gt1x_tool_release(struct inode *inode, struct file *filp) +{ + devicecount--; + return 0; +} +/******************************************************* +Function: + Goodix tool read function. +Input: +standard proc read function param. +Output: + Return read length. +********************************************************/ +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) +{ + GTP_DEBUG_FUNC(); + if(*ppos) { + GTP_DEBUG("[PARAM]size: %zd, *ppos: %d", count, (int)*ppos); + *ppos = 0; + return 0; + } + + if (cmd_head.wr % 2) { + GTP_ERROR("[READ] invaild operator fail!"); + return -1; + } else if (!cmd_head.wr) { + /* general i2c read */ + u16 addr, data_len, len, loc; + + if (1 == cmd_head.flag) { + if (comfirm()) { + GTP_ERROR("[READ]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head.flag) { + //Need interrupt! + } + + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + data_len = cmd_head.data_len; + loc = 0; + + GTP_DEBUG("[READ] ADDR:0x%04X.", addr); + GTP_DEBUG("[READ] Length: %d", data_len); + + if (cmd_head.delay) { + msleep(cmd_head.delay); + } + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head.data[0] = (addr >> 8) & 0xFF; + cmd_head.data[1] = (addr & 0xFF); + if (tool_i2c_read(cmd_head.data, len) <= 0) { + GTP_ERROR("[READ]Read data failed!"); + return -1; + } + memcpy(&buffer[loc], &cmd_head.data[GTP_ADDR_LENGTH], len); + data_len -= len; + addr += len; + loc += len; + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len); + } + *ppos += cmd_head.data_len; + return cmd_head.data_len; + } else if (2 == cmd_head.wr) { + GTP_DEBUG("Return ic type:%s len:%d.", buffer, (s32) cmd_head.data_len); + return -1; +#if GTP_AUTO_UPDATE + } else if (4 == cmd_head.wr) { + /* read fw update progress */ + buffer[0] = update_info.progress >> 8; + buffer[1] = update_info.progress & 0xff; + buffer[2] = update_info.max_progress >> 8; + buffer[3] = update_info.max_progress & 0xff; + *ppos += 4; + return 4; +#endif + } else if (6 == cmd_head.wr) { + //Read error code! + return -1; + } else if (8 == cmd_head.wr) { + /* Read driver version */ + s32 tmp_len; + tmp_len = strlen(GTP_DRIVER_VERSION); + memcpy(buffer, GTP_DRIVER_VERSION, tmp_len); + buffer[tmp_len] = 0; + *ppos += tmp_len + 1; + return (tmp_len + 1); + } + *ppos += cmd_head.data_len; + return cmd_head.data_len; +} |
