blob: 1c33be6ecde36b9fc954e858321bb6ef1d6d4df8 [file] [log] [blame]
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: Focaltech_ex_fun.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-08
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
/*****************************************************************************
* 1.Included header files
*****************************************************************************/
#include "focaltech_core.h"
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
/*create apk debug channel*/
#define PROC_UPGRADE 0
#define PROC_READ_REGISTER 1
#define PROC_WRITE_REGISTER 2
#define PROC_AUTOCLB 4
#define PROC_UPGRADE_INFO 5
#define PROC_WRITE_DATA 6
#define PROC_READ_DATA 7
#define PROC_SET_TEST_FLAG 8
#define PROC_SET_SLAVE_ADDR 10
#define PROC_HW_RESET 11
#define PROC_NAME "ftxxxx-debug"
#define WRITE_BUF_SIZE 512
#define READ_BUF_SIZE 512
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
/*****************************************************************************
* Static variables
*****************************************************************************/
static unsigned char proc_operate_mode = PROC_UPGRADE;
static struct proc_dir_entry *fts_proc_entry;
static struct
{
int op; // 0: read, 1: write
int reg; // register
int value; // read: return value, write: op return
int result; // 0: success, otherwise: fail
} g_rwreg_result;
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
#if FTS_ESDCHECK_EN
static void esd_process(u8 *writebuf, int buflen, bool flag)
{
if (flag)
{
if ( (writebuf[1] == 0xFC) && (writebuf[2] == 0x55) && (buflen == 0x03) )
{
/* Upgrade command */
FTS_DEBUG("[ESD]: Upgrade command(%x %x %x)!!", writebuf[0], writebuf[1], writebuf[2]);
fts_esdcheck_switch(DISABLE);
}
else if ( (writebuf[1] == 0x00) && (writebuf[2] == 0x40) && (buflen == 0x03) )
{
/* factory mode bit 4 5 6 */
FTS_DEBUG("[ESD]: Entry factory mode(%x %x %x)!!", writebuf[0], writebuf[1], writebuf[2]);
fts_esdcheck_switch(DISABLE);
}
else if ( (writebuf[1] == 0x00) && (writebuf[2] == 0x00) && (buflen == 0x03) )
{
/* normal mode bit 4 5 6 */
FTS_DEBUG("[ESD]: Exit factory mode(%x %x %x)!!", writebuf[0], writebuf[1], writebuf[2]);
fts_esdcheck_switch(ENABLE);
}
else
{
fts_esdcheck_proc_busy(1);
}
}
else
{
if ( (writebuf[1] == 0x07) && (buflen == 0x02) )
{
FTS_DEBUG("[ESD]: Upgrade finish-trigger reset(07)(%x %x)!!", writebuf[0], writebuf[1]);
fts_esdcheck_switch(ENABLE);
}
else
{
fts_esdcheck_proc_busy(0);
}
}
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
/*interface of write proc*/
/************************************************************************
* Name: fts_debug_write
* Brief:interface of write proc
* Input: file point, data buf, data len, no use
* Output: no
* Return: data len
***********************************************************************/
static ssize_t fts_debug_write(struct file *filp, const char __user *buff, size_t count, loff_t *ppos)
{
unsigned char writebuf[WRITE_BUF_SIZE];
int buflen = 0;
int writelen = 0;
int ret = 0;
char tmp[25];
buflen = count < WRITE_BUF_SIZE ? count : WRITE_BUF_SIZE - 1;
if (copy_from_user(&writebuf, buff, buflen))
{
FTS_DEBUG("[APK]: copy from user error!!");
return -EFAULT;
}
writebuf[buflen] = '\0';
#if FTS_ESDCHECK_EN
esd_process(writebuf, buflen, 1);
#endif
proc_operate_mode = writebuf[0];
switch (proc_operate_mode)
{
case PROC_UPGRADE:
{
char upgrade_file_path[FILE_NAME_LENGTH];
memset(upgrade_file_path, 0, sizeof(upgrade_file_path));
sprintf(upgrade_file_path, "%s", writebuf + 1);
buflen = count < FILE_NAME_LENGTH ? count : FILE_NAME_LENGTH - 1;
upgrade_file_path[buflen-1] = '\0';
FTS_DEBUG("%s\n", upgrade_file_path);
fts_irq_disable();
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(DISABLE);
#endif
if (fts_updatefun_curr.upgrade_with_app_bin_file)
ret = fts_updatefun_curr.upgrade_with_app_bin_file(fts_i2c_client, upgrade_file_path);
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(ENABLE);
#endif
fts_irq_enable();
if (ret < 0)
{
FTS_ERROR("[APK]: upgrade failed!!");
}
}
break;
case PROC_SET_TEST_FLAG:
FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x!!", writebuf[1]);
#if FTS_ESDCHECK_EN
if (writebuf[1] == 0)
{
fts_esdcheck_switch(DISABLE);
}
else
{
fts_esdcheck_switch(ENABLE);
}
#endif
break;
case PROC_READ_REGISTER:
writelen = 1;
ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen);
if (ret < 0)
{
FTS_ERROR("[APK]: write iic error!!");
}
break;
case PROC_WRITE_REGISTER:
writelen = 2;
ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen);
if (ret < 0)
{
FTS_ERROR("[APK]: write iic error!!");
}
break;
case PROC_SET_SLAVE_ADDR:
ret = fts_i2c_client->addr;
FTS_DEBUG("Original i2c addr 0x%x ", ret<<1 );
if (writebuf[1] != fts_i2c_client->addr)
{
fts_i2c_client->addr = writebuf[1];
FTS_DEBUG("Change i2c addr 0x%x to 0x%x", ret<<1, writebuf[1]<<1);
}
break;
case PROC_HW_RESET:
sprintf(tmp, "%s", writebuf + 1);
buflen = count < 25 ? count : 25 - 1;
tmp[buflen - 1] = '\0';
if (strncmp(tmp,"focal_driver",12)==0)
{
FTS_DEBUG("Begin HW Reset");
fts_reset_proc(1);
}
break;
case PROC_AUTOCLB:
FTS_DEBUG("[APK]: autoclb!!");
fts_ctpm_auto_clb(fts_i2c_client);
break;
case PROC_READ_DATA:
case PROC_WRITE_DATA:
writelen = count - 1;
if (writelen>0)
{
ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen);
if (ret < 0)
{
FTS_ERROR("[APK]: write iic error!!");
}
}
break;
default:
break;
}
#if FTS_ESDCHECK_EN
esd_process(writebuf, buflen, 0);
#endif
if (ret < 0)
{
return ret;
}
else
{
return count;
}
}
/* interface of read proc */
/************************************************************************
* Name: fts_debug_read
* Brief:interface of read proc
* Input: point to the data, no use, no use, read len, no use, no use
* Output: page point to data
* Return: read char number
***********************************************************************/
static ssize_t fts_debug_read(struct file *filp, char __user *buff, size_t count, loff_t *ppos)
{
int ret = 0;
int num_read_chars = 0;
int readlen = 0;
u8 regvalue = 0x00, regaddr = 0x00;
unsigned char buf[READ_BUF_SIZE];
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(1);
#endif
switch (proc_operate_mode)
{
case PROC_UPGRADE:
// after calling fts_debug_write to upgrade
regaddr = FTS_REG_FW_VER;
ret = fts_i2c_read_reg(fts_i2c_client, regaddr, &regvalue);
if (ret < 0)
num_read_chars = sprintf(buf, "%s", "get fw version failed.\n");
else
num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue);
break;
case PROC_READ_REGISTER:
readlen = 1;
ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen);
if (ret < 0)
{
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
FTS_ERROR("[APK]: read iic error!!");
return ret;
}
num_read_chars = 1;
break;
case PROC_READ_DATA:
readlen = count;
ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen);
if (ret < 0)
{
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
FTS_ERROR("[APK]: read iic error!!");
return ret;
}
num_read_chars = readlen;
break;
case PROC_WRITE_DATA:
break;
default:
break;
}
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
if (copy_to_user(buff, buf, num_read_chars))
{
FTS_ERROR("[APK]: copy to user error!!");
return -EFAULT;
}
return num_read_chars;
}
static const struct file_operations fts_proc_fops =
{
.owner = THIS_MODULE,
.read = fts_debug_read,
.write = fts_debug_write,
};
#else
/* interface of write proc */
/************************************************************************
* Name: fts_debug_write
* Brief:interface of write proc
* Input: file point, data buf, data len, no use
* Output: no
* Return: data len
***********************************************************************/
static int fts_debug_write(struct file *filp,
const char __user *buff, unsigned long len, void *data)
{
unsigned char writebuf[WRITE_BUF_SIZE];
int buflen = len;
int writelen = 0;
int ret = 0;
char tmp[25];
if (copy_from_user(&writebuf, buff, buflen))
{
FTS_ERROR("[APK]: copy from user error!!");
return -EFAULT;
}
#if FTS_ESDCHECK_EN
esd_process(writebuf, buflen, 1);
#endif
proc_operate_mode = writebuf[0];
switch (proc_operate_mode)
{
case PROC_UPGRADE:
{
char upgrade_file_path[FILE_NAME_LENGTH];
memset(upgrade_file_path, 0, sizeof(upgrade_file_path));
sprintf(upgrade_file_path, "%s", writebuf + 1);
upgrade_file_path[buflen-1] = '\0';
FTS_DEBUG("%s\n", upgrade_file_path);
fts_irq_disable();
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(DISABLE);
#endif
if (fts_updatefun_curr.upgrade_with_app_bin_file)
ret = fts_updatefun_curr.upgrade_with_app_bin_file(fts_i2c_client, upgrade_file_path);
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(ENABLE);
#endif
fts_irq_enable();
if (ret < 0)
{
FTS_ERROR("[APK]: upgrade failed!!");
}
}
break;
case PROC_SET_TEST_FLAG:
FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x!!", writebuf[1]);
#if FTS_ESDCHECK_EN
if (writebuf[1] == 0)
{
fts_esdcheck_switch(DISABLE);
}
else
{
fts_esdcheck_switch(ENABLE);
}
#endif
break;
case PROC_READ_REGISTER:
writelen = 1;
ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen);
if (ret < 0)
{
FTS_ERROR("[APK]: write iic error!!n");
}
break;
case PROC_WRITE_REGISTER:
writelen = 2;
ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen);
if (ret < 0)
{
FTS_ERROR("[APK]: write iic error!!");
}
break;
case PROC_SET_SLAVE_ADDR:
ret = fts_i2c_client->addr;
FTS_DEBUG("Original i2c addr 0x%x ", ret<<1 );
if (writebuf[1] != fts_i2c_client->addr)
{
fts_i2c_client->addr = writebuf[1];
FTS_DEBUG("Change i2c addr 0x%x to 0x%x", ret<<1, writebuf[1]<<1);
}
break;
case PROC_HW_RESET:
sprintf(tmp, "%s", writebuf + 1);
tmp[buflen - 1] = '\0';
if (strncmp(tmp,"focal_driver",12)==0)
{
FTS_DEBUG("Begin HW Reset");
fts_reset_proc(1);
}
break;
case PROC_AUTOCLB:
FTS_DEBUG("[APK]: autoclb!!");
fts_ctpm_auto_clb(fts_i2c_client);
break;
case PROC_READ_DATA:
case PROC_WRITE_DATA:
writelen = len - 1;
if (writelen>0)
{
ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen);
if (ret < 0)
{
FTS_ERROR("[APK]: write iic error!!");
}
}
break;
default:
break;
}
#if FTS_ESDCHECK_EN
esd_process(writebuf, buflen, 0);
#endif
if (ret < 0)
{
return ret;
}
else
{
return len;
}
}
/* interface of read proc */
/************************************************************************
* Name: fts_debug_read
* Brief:interface of read proc
* Input: point to the data, no use, no use, read len, no use, no use
* Output: page point to data
* Return: read char number
***********************************************************************/
static int fts_debug_read( char *page, char **start,
off_t off, int count, int *eof, void *data )
{
int ret = 0;
unsigned char buf[READ_BUF_SIZE];
int num_read_chars = 0;
int readlen = 0;
u8 regvalue = 0x00, regaddr = 0x00;
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(1);
#endif
switch (proc_operate_mode)
{
case PROC_UPGRADE:
// after calling fts_debug_write to upgrade
regaddr = FTS_REG_FW_VER;
ret = fts_i2c_read_reg(fts_i2c_client, regaddr, &regvalue);
if (ret < 0)
num_read_chars = sprintf(buf, "%s", "get fw version failed.\n");
else
num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue);
break;
case PROC_READ_REGISTER:
readlen = 1;
ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen);
if (ret < 0)
{
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
FTS_ERROR("[APK]: read iic error!!");
return ret;
}
num_read_chars = 1;
break;
case PROC_READ_DATA:
readlen = count;
ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen);
if (ret < 0)
{
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
FTS_ERROR("[APK]: read iic error!!");
return ret;
}
num_read_chars = readlen;
break;
case PROC_WRITE_DATA:
break;
default:
break;
}
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
memcpy(page, buf, num_read_chars);
return num_read_chars;
}
#endif
/************************************************************************
* Name: fts_create_apk_debug_channel
* Brief: create apk debug channel
* Input: i2c info
* Output: no
* Return: success =0
***********************************************************************/
int fts_create_apk_debug_channel(struct i2c_client * client)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
fts_proc_entry = proc_create(PROC_NAME, 0777, NULL, &fts_proc_fops);
#else
fts_proc_entry = create_proc_entry(PROC_NAME, 0777, NULL);
#endif
if (NULL == fts_proc_entry)
{
FTS_ERROR("Couldn't create proc entry!");
return -ENOMEM;
}
else
{
FTS_INFO("Create proc entry success!");
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
fts_proc_entry->write_proc = fts_debug_write;
fts_proc_entry->read_proc = fts_debug_read;
#endif
}
return 0;
}
/************************************************************************
* Name: fts_release_apk_debug_channel
* Brief: release apk debug channel
* Input: no
* Output: no
* Return: no
***********************************************************************/
void fts_release_apk_debug_channel(void)
{
if (fts_proc_entry)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
proc_remove(fts_proc_entry);
#else
remove_proc_entry(PROC_NAME, NULL);
#endif
}
/*
* fts_hw_reset interface
*/
static ssize_t fts_hw_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
return -EPERM;
}
static ssize_t fts_hw_reset_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t count = 0;
fts_reset_proc(200);
count = snprintf(buf, PAGE_SIZE, "hw reset executed\n");
return count;
}
/*
* fts_toggle_hw_reset interface
* This grants userspace access to toggle reset pin so caller can manage timing
*/
static ssize_t fts_toggle_reset_pin_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
if (FTS_SYSFS_ECHO_ON(buf)){
gpio_direction_output(fts_wq_data->pdata->reset_gpio, 1);
}
else if (FTS_SYSFS_ECHO_OFF(buf)) {
gpio_direction_output(fts_wq_data->pdata->reset_gpio, 0);
}
msleep(20);
return count;
}
static ssize_t fts_toggle_reset_pin_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return -EPERM;
}
/*
* fts_irq interface
*/
static ssize_t fts_irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
if (FTS_SYSFS_ECHO_ON(buf))
{
FTS_INFO("[EX-FUN]enable irq");
fts_irq_enable();
}
else if (FTS_SYSFS_ECHO_OFF(buf))
{
FTS_INFO("[EX-FUN]disable irq");
fts_irq_disable();
}
return count;
}
static ssize_t fts_irq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return -EPERM;
}
/************************************************************************
* Name: fts_tpfwver_show
* Brief: show tp fw vwersion
* Input: device, device attribute, char buf
* Output: no
* Return: char number
***********************************************************************/
static ssize_t fts_tpfwver_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t num_read_chars = 0;
u8 fwver = 0;
mutex_lock(&fts_input_dev->mutex);
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(1);
#endif
if (fts_i2c_read_reg(fts_i2c_client, FTS_REG_FW_VER, &fwver) < 0)
{
num_read_chars = snprintf(buf, PAGE_SIZE,"I2c transfer error!\n");
}
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
if (fwver == 255)
num_read_chars = snprintf(buf, PAGE_SIZE,"get tp fw version fail!\n");
else
{
num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver);
}
mutex_unlock(&fts_input_dev->mutex);
return num_read_chars;
}
/************************************************************************
* Name: fts_tpfwver_store
* Brief: no
* Input: device, device attribute, char buf, char count
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_tpfwver_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
/* place holder for future use */
return -EPERM;
}
static int fts_is_hex_char(const char ch)
{
int result = 0;
if (ch >= '0' && ch <= '9')
{
result = 1;//(int)(ch - '0');
}
else if (ch >= 'a' && ch <= 'f')
{
result = 1;//(int)(ch - 'a') + 10;
}
else if (ch >= 'A' && ch <= 'F')
{
result = 1;//(int)(ch - 'A') + 10;
}
else
{
result = 0;
}
return result;
}
static int fts_hex_char_to_int(const char ch)
{
int result = 0;
if (ch >= '0' && ch <= '9')
{
result = (int)(ch - '0');
}
else if (ch >= 'a' && ch <= 'f')
{
result = (int)(ch - 'a') + 10;
}
else if (ch >= 'A' && ch <= 'F')
{
result = (int)(ch - 'A') + 10;
}
else
{
result = -1;
}
return result;
}
static int fts_hex_to_str(char *hex, int iHexLen, char *ch, int *iChLen)
{
int high=0;
int low=0;
int tmp = 0;
int i = 0;
int iCharLen = 0;
if (hex == NULL || ch == NULL)
{
return -1;
}
FTS_DEBUG("iHexLen: %d in function:%s!!\n\n", iHexLen, __func__);
if (iHexLen %2 == 1)
{
return -2;
}
for (i=0; i<iHexLen; i+=2)
{
high = fts_hex_char_to_int(hex[i]);
if (high < 0)
{
ch[iCharLen] = '\0';
return -3;
}
low = fts_hex_char_to_int(hex[i+1]);
if (low < 0)
{
ch[iCharLen] = '\0';
return -3;
}
tmp = (high << 4) + low;
ch[iCharLen++] = (char)tmp;
}
ch[iCharLen] = '\0';
*iChLen = iCharLen;
FTS_DEBUG("iCharLen: %d, iChLen: %d in function:%s!!\n\n", iCharLen, *iChLen, __func__);
return 0;
}
static void fts_str_to_bytes(char * bufStr, int iLen, char* uBytes, int *iBytesLen)
{
int i=0;
int iNumChLen=0;
*iBytesLen=0;
for (i=0; i<iLen; i++)
{
if (fts_is_hex_char(bufStr[i])) //filter illegal chars
{
bufStr[iNumChLen++] = bufStr[i];
}
}
bufStr[iNumChLen] = '\0';
fts_hex_to_str(bufStr, iNumChLen, uBytes, iBytesLen);
}
/************************************************************************
* Name: fts_tprwreg_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_tprwreg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int count;
mutex_lock(&fts_input_dev->mutex);
if (!g_rwreg_result.op)
{
if (g_rwreg_result.result == 0)
{
count = sprintf(buf, "Read %02X: %02X\n", g_rwreg_result.reg, g_rwreg_result.value);
}
else
{
count = sprintf(buf, "Read %02X failed, ret: %d\n",g_rwreg_result.reg, g_rwreg_result.result);
}
}
else
{
if (g_rwreg_result.result == 0)
{
count = sprintf(buf, "Write %02X, %02X success\n",g_rwreg_result.reg, g_rwreg_result.value);
}
else
{
count = sprintf(buf, "Write %02X failed, ret: %d\n",g_rwreg_result.reg, g_rwreg_result.result);
}
}
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_tprwreg_store
* Brief: read/write register
* Input: device, device attribute, char buf, char count
* Output: print register value
* Return: char count
***********************************************************************/
static ssize_t fts_tprwreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
ssize_t num_read_chars = 0;
int retval;
long unsigned int wmreg=0;
u8 regaddr=0xff,regvalue=0xff;
u8 valbuf[5]= {0};
memset(valbuf, 0, sizeof(valbuf));
mutex_lock(&fts_input_dev->mutex);
num_read_chars = count - 1;
if (num_read_chars != 2)
{
if (num_read_chars != 4)
{
FTS_ERROR("please input 2 or 4 character");
goto error_return;
}
}
memcpy(valbuf, buf, num_read_chars);
retval = kstrtoul(valbuf, 16, &wmreg);
fts_str_to_bytes((char*)buf, num_read_chars, valbuf, &retval);
if (1==retval)
{
regaddr = valbuf[0];
retval = 0;
}
else if (2==retval)
{
regaddr = valbuf[0];
regvalue = valbuf[1];
retval = 0;
}
else
retval =-1;
if (0 != retval)
{
FTS_ERROR("%s() - ERROR: Could not convert the given input to a number. The given input was: \"%s\"", __FUNCTION__, buf);
goto error_return;
}
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(1);
#endif
if (2 == num_read_chars)
{
g_rwreg_result.op = 0;
g_rwreg_result.reg = regaddr;
/*read register*/
regaddr = wmreg;
g_rwreg_result.result = fts_i2c_read_reg(client, regaddr, &regvalue);
if (g_rwreg_result.result < 0)
{
FTS_ERROR("Could not read the register(0x%02x)", regaddr);
}
else
{
FTS_INFO("the register(0x%02x) is 0x%02x", regaddr, regvalue);
g_rwreg_result.value = regvalue;
g_rwreg_result.result = 0;
}
}
else
{
regaddr = wmreg>>8;
regvalue = wmreg;
g_rwreg_result.op = 1;
g_rwreg_result.reg = regaddr;
g_rwreg_result.value = regvalue;
g_rwreg_result.result = fts_i2c_write_reg(client, regaddr, regvalue);
if (g_rwreg_result.result < 0)
{
FTS_ERROR("Could not write the register(0x%02x)", regaddr);
}
else
{
FTS_INFO("Write 0x%02x into register(0x%02x) successful", regvalue, regaddr);
g_rwreg_result.result = 0;
}
}
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
error_return:
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_fwupdate_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_fwupdate_show(struct device *dev, struct device_attribute *attr, char *buf)
{
/* place holder for future use */
return -EPERM;
}
/************************************************************************
* Name: fts_fwupdate_store
* Brief: upgrade from *.i
* Input: device, device attribute, char buf, char count
* Output: no
* Return: char count
***********************************************************************/
static ssize_t fts_fwupdate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
mutex_lock(&fts_input_dev->mutex);
fts_irq_disable();
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(DISABLE);
#endif
if (fts_updatefun_curr.upgrade_with_app_i_file)
fts_updatefun_curr.upgrade_with_app_i_file(client);
#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN
if (fts_updatefun_curr.upgrade_with_lcd_cfg_i_file)
fts_updatefun_curr.upgrade_with_lcd_cfg_i_file(client);
#endif
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(ENABLE);
#endif
fts_irq_enable();
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_fwupgradeapp_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_fwupgradeapp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
/* place holder for future use */
return -EPERM;
}
/************************************************************************
* Name: fts_fwupgradeapp_store
* Brief: upgrade from app.bin
* Input: device, device attribute, char buf, char count
* Output: no
* Return: char count
***********************************************************************/
static ssize_t fts_fwupgradeapp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
char fwname[FILE_NAME_LENGTH];
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
memset(fwname, 0, sizeof(fwname));
sprintf(fwname, "%s", buf);
fwname[count-1] = '\0';
mutex_lock(&fts_input_dev->mutex);
fts_irq_disable();
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(DISABLE);
#endif
if (fts_updatefun_curr.upgrade_with_app_bin_file)
fts_updatefun_curr.upgrade_with_app_bin_file(client, fwname);
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(ENABLE);
#endif
fts_irq_enable();
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_driverversion_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_driverversion_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int count;
mutex_lock(&fts_input_dev->mutex);
count = sprintf(buf, FTS_DRIVER_VERSION "\n");
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_driverversion_store
* Brief: no
* Input: device, device attribute, char buf, char count
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_driverversion_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
/* place holder for future use */
return -EPERM;
}
#if FTS_ESDCHECK_EN
/************************************************************************
* Name: fts_esdcheck_store
* Brief: no
* Input: device, device attribute, char buf, char count
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_esdcheck_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
mutex_lock(&fts_input_dev->mutex);
if (FTS_SYSFS_ECHO_ON(buf))
{
FTS_DEBUG("enable esdcheck");
fts_esdcheck_switch(ENABLE);
}
else if (FTS_SYSFS_ECHO_OFF(buf))
{
FTS_DEBUG("disable esdcheck");
fts_esdcheck_switch(DISABLE);
}
mutex_unlock(&fts_input_dev->mutex);
return -EPERM;
}
/************************************************************************
* Name: fts_esdcheck_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_esdcheck_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int count;
mutex_lock(&fts_input_dev->mutex);
count = sprintf(buf, "Esd check: %s\n", fts_esdcheck_get_status() ? "On" : "Off");
mutex_unlock(&fts_input_dev->mutex);
return count;
}
#endif
/************************************************************************
* Name: fts_module_config_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_module_config_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
mutex_lock(&fts_input_dev->mutex);
count += sprintf(buf, "FTS_CHIP_TYPE: \t\t\t%04X\n", FTS_CHIP_TYPE);
count += sprintf(buf+count, "FTS_DEBUG_EN: \t\t\t%s\n", FTS_DEBUG_EN ? "ON" : "OFF");
#if defined(FTS_MT_PROTOCOL_B_EN)
count += sprintf(buf+count, "TS_MT_PROTOCOL_B_EN: \t\t%s\n", FTS_MT_PROTOCOL_B_EN ? "ON" : "OFF");
#endif
count += sprintf(buf+count, "FTS_GESTURE_EN: \t\t%s\n", FTS_GESTURE_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_ESDCHECK_EN: \t\t%s\n", FTS_ESDCHECK_EN ? "ON" : "OFF");
#if defined(FTS_PSENSOR_EN)
count += sprintf(buf+count, "FTS_PSENSOR_EN: \t\t%s\n", FTS_PSENSOR_EN ? "ON" : "OFF");
#endif
count += sprintf(buf+count, "FTS_GLOVE_EN: \t\t\t%s\n", FTS_GLOVE_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_COVER_EN: \t\t%s\n", FTS_COVER_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_CHARGER_EN: \t\t\t%s\n", FTS_CHARGER_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_REPORT_PRESSURE_EN: \t\t%s\n", FTS_REPORT_PRESSURE_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_APK_NODE_EN: \t\t%s\n", FTS_APK_NODE_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_POWER_SOURCE_CUST_EN: \t%s\n", FTS_POWER_SOURCE_CUST_EN ? "ON" : "OFF");
count += sprintf(buf+count, "FTS_AUTO_UPGRADE_EN: \t\t%s\n", FTS_AUTO_UPGRADE_EN ? "ON" : "OFF");
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_module_config_store
* Brief: no
* Input: device, device attribute, char buf, char count
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_module_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
/* place holder for future use */
return -EPERM;
}
/************************************************************************
* Name: fts_show_log_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_show_log_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int count;
mutex_lock(&fts_input_dev->mutex);
count = sprintf(buf, "Log: %s\n", g_show_log ? "On" : "Off");
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_show_log_store
* Brief: no
* Input: device, device attribute, char buf, char count
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_show_log_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
/* place holder for future use */
mutex_lock(&fts_input_dev->mutex);
if (FTS_SYSFS_ECHO_ON(buf))
{
FTS_DEBUG("enable show log info/error");
g_show_log = 1;
}
else if (FTS_SYSFS_ECHO_OFF(buf))
{
FTS_DEBUG("disable show log info/error");
g_show_log = 0;
}
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/************************************************************************
* Name: fts_dumpreg_store
* Brief: no
* Input: device, device attribute, char buf, char count
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_dumpreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
/* place holder for future use */
return -EPERM;
}
/************************************************************************
* Name: fts_dumpreg_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_dumpreg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
char tmp[256];
int count = 0;
u8 regvalue = 0;
struct i2c_client *client;
mutex_lock(&fts_input_dev->mutex);
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(1);
#endif
client = container_of(dev, struct i2c_client, dev);
fts_i2c_read_reg(client, FTS_REG_POWER_MODE, &regvalue); //power mode 0:active 1:monitor 3:sleep
count += sprintf(tmp + count, "Power Mode:0x%02x\n", regvalue);
fts_i2c_read_reg(client, FTS_REG_FW_VER, &regvalue); //FWver
count += sprintf(tmp + count, "FW Ver:0x%02x\n",regvalue);
fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &regvalue); //Vendor ID
count += sprintf(tmp + count, "Vendor ID:0x%02x\n", regvalue);
fts_i2c_read_reg(client, FTS_REG_LCD_BUSY_NUM, &regvalue); //LCD Busy number
count += sprintf(tmp + count, "LCD Busy Number:0x%02x\n", regvalue);
fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &regvalue); // 1 Gesture mode,0 Normal mode
count += sprintf(tmp + count, "Gesture Mode:0x%02x\n", regvalue);
fts_i2c_read_reg(client, FTS_REG_CHARGER_MODE_EN, &regvalue); // 3 charge in
count += sprintf(tmp + count, "charge stat:0x%02x\n", regvalue);
fts_i2c_read_reg(client, FTS_REG_INT_CNT, &regvalue); //Interrupt counter
count += sprintf(tmp + count, "INT count:0x%02x\n", regvalue);
fts_i2c_read_reg(client, FTS_REG_FLOW_WORK_CNT, &regvalue); //Flow work counter
count += sprintf(tmp + count, "ESD count:0x%02x\n", regvalue);
#if FTS_ESDCHECK_EN
fts_esdcheck_proc_busy(0);
#endif
memcpy(buf, tmp, count);
mutex_unlock(&fts_input_dev->mutex);
return count;
}
/****************************************/
/* sysfs */
/* get the fw version
* example:cat fw_version
*/
static DEVICE_ATTR(fts_fw_version, S_IRUGO|S_IWUSR, fts_tpfwver_show, fts_tpfwver_store);
/* upgrade from *.i
* example: echo 1 > fw_update
*/
static DEVICE_ATTR(fts_fw_update, S_IRUGO|S_IWUSR, fts_fwupdate_show, fts_fwupdate_store);
/* read and write register
* read example: echo 88 > rw_reg ---read register 0x88
* write example:echo 8807 > rw_reg ---write 0x07 into register 0x88
*
* note:the number of input must be 2 or 4.if it not enough,please fill in the 0.
*/
static DEVICE_ATTR(fts_rw_reg, S_IRUGO|S_IWUSR, fts_tprwreg_show, fts_tprwreg_store);
/* upgrade from app.bin
* example:echo "*_app.bin" > upgrade_app
*/
static DEVICE_ATTR(fts_upgrade_app, S_IRUGO|S_IWUSR, fts_fwupgradeapp_show, fts_fwupgradeapp_store);
static DEVICE_ATTR(fts_driver_version, S_IRUGO|S_IWUSR, fts_driverversion_show, fts_driverversion_store);
static DEVICE_ATTR(fts_dump_reg, S_IRUGO|S_IWUSR, fts_dumpreg_show, fts_dumpreg_store);
static DEVICE_ATTR(fts_show_log, S_IRUGO|S_IWUSR, fts_show_log_show, fts_show_log_store);
static DEVICE_ATTR(fts_module_config, S_IRUGO|S_IWUSR, fts_module_config_show, fts_module_config_store);
static DEVICE_ATTR(fts_hw_reset, S_IRUGO|S_IWUSR, fts_hw_reset_show, fts_hw_reset_store);
static DEVICE_ATTR(fts_toggle_reset_pin, S_IRUGO|S_IWUSR, fts_toggle_reset_pin_show, fts_toggle_reset_pin_store);
static DEVICE_ATTR(fts_irq, S_IRUGO|S_IWUSR, fts_irq_show, fts_irq_store);
#if FTS_ESDCHECK_EN
static DEVICE_ATTR(fts_esd_check, S_IRUGO|S_IWUSR, fts_esdcheck_show, fts_esdcheck_store);
#endif
/* add your attr in here*/
static struct attribute *fts_attributes[] =
{
&dev_attr_fts_fw_version.attr,
&dev_attr_fts_fw_update.attr,
&dev_attr_fts_rw_reg.attr,
&dev_attr_fts_dump_reg.attr,
&dev_attr_fts_upgrade_app.attr,
&dev_attr_fts_driver_version.attr,
&dev_attr_fts_show_log.attr,
&dev_attr_fts_module_config.attr,
&dev_attr_fts_hw_reset.attr,
&dev_attr_fts_toggle_reset_pin.attr,
&dev_attr_fts_irq.attr,
#if FTS_ESDCHECK_EN
&dev_attr_fts_esd_check.attr,
#endif
NULL
};
static struct attribute_group fts_attribute_group =
{
.attrs = fts_attributes
};
/************************************************************************
* Name: fts_create_sysfs
* Brief: create sysfs for debug
* Input: i2c info
* Output: no
* Return: success =0
***********************************************************************/
int fts_create_sysfs(struct i2c_client * client)
{
int err;
err = sysfs_create_group(&client->dev.kobj, &fts_attribute_group);
if (0 != err)
{
FTS_ERROR("[EX]: sysfs_create_group() failed!!");
sysfs_remove_group(&client->dev.kobj, &fts_attribute_group);
return -EIO;
}
else
{
FTS_INFO("[EX]: sysfs_create_group() succeeded!!");
}
return err;
}
/************************************************************************
* Name: fts_remove_sysfs
* Brief: remove sys
* Input: i2c info
* Output: no
* Return: no
***********************************************************************/
int fts_remove_sysfs(struct i2c_client * client)
{
sysfs_remove_group(&client->dev.kobj, &fts_attribute_group);
return 0;
}