342 lines
9.5 KiB
C
Executable File
342 lines
9.5 KiB
C
Executable File
/**
|
|
*Name : hynitron_esd_check.c
|
|
*Author : steven
|
|
*Version : V2.0
|
|
*Create : 2018-1-23
|
|
*Copyright : zxzz
|
|
*/
|
|
|
|
|
|
#include "hynitron_core.h"
|
|
|
|
/*****************************************************************************/
|
|
#if HYN_ESDCHECK_EN
|
|
|
|
#define SWITCH_ESD_OFF 0
|
|
#define SWITCH_ESD_ON 1
|
|
|
|
|
|
extern int hyn_reset_proc(int hdelayms);
|
|
|
|
/************************************************************************
|
|
* Name: hyn_esd_show
|
|
* Brief: no
|
|
* Input: device, device attribute, char buf
|
|
* Output: no
|
|
* Return:
|
|
***********************************************************************/
|
|
static ssize_t hyn_esd_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count;
|
|
|
|
//struct i2c_client *client = container_of(dev, struct i2c_client, dev);
|
|
HYN_FUNC_ENTER();
|
|
mutex_lock(&hyn_ts_data->hyn_esd_lock);
|
|
count = sprintf(buf,"ESD Mode: %d,ESD running = %d\n", hyn_ts_data->hyn_esd_mode,hyn_ts_data->hyn_esd_running);
|
|
mutex_unlock(&hyn_ts_data->hyn_esd_lock);
|
|
HYN_FUNC_EXIT();
|
|
return count;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Name: hyn_esd_store
|
|
* Brief: no
|
|
* Input: device, device attribute, char buf, char count
|
|
* Output: no
|
|
* Return:
|
|
***********************************************************************/
|
|
static ssize_t hyn_esd_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
mutex_lock(&hyn_ts_data->hyn_esd_lock);
|
|
|
|
if (buf[0]==1)
|
|
{
|
|
HYN_INFO("[ESD]enable ESD");
|
|
hyn_ts_data->hyn_esd_mode = ENABLE;
|
|
}
|
|
else if (buf[0]==0)
|
|
{
|
|
HYN_INFO("[ESD]disable ESD");
|
|
hyn_ts_data->hyn_esd_mode = DISABLE;
|
|
}
|
|
|
|
mutex_unlock(&hyn_ts_data->hyn_esd_lock);
|
|
|
|
HYN_FUNC_EXIT();
|
|
return count;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Name: hyn_esd_buf_show
|
|
* Brief: no
|
|
* Input: device, device attribute, char buf
|
|
* Output: no
|
|
* Return:
|
|
***********************************************************************/
|
|
static ssize_t hyn_esd_buf_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
int count;
|
|
HYN_FUNC_ENTER();
|
|
|
|
mutex_lock(&hyn_ts_data->hyn_esd_lock);
|
|
count = snprintf(buf, PAGE_SIZE, "ESD running: 0x%x\n", hyn_ts_data->hyn_esd_running);
|
|
count += snprintf(buf + count, PAGE_SIZE, "ESD pre_counter:0x%x\n", hyn_ts_data->hyn_esd_pre_counter);
|
|
count += snprintf(buf + count, PAGE_SIZE, "ESD cur_counter:0x%x\n", hyn_ts_data->hyn_esd_cur_counter);
|
|
count += snprintf(buf + count, PAGE_SIZE, "ESD work_cycle:0x%x\n", hyn_ts_data->hyn_esd_work_cycle);
|
|
mutex_unlock(&hyn_ts_data->hyn_esd_lock);
|
|
|
|
HYN_FUNC_EXIT();
|
|
return count;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Name: hyn_esd_buf_store
|
|
* Brief: no
|
|
* Input: device, device attribute, char buf, char count
|
|
* Output: no
|
|
* Return:
|
|
***********************************************************************/
|
|
static ssize_t hyn_esd_buf_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
/* place holder for future use */
|
|
return -EPERM;
|
|
}
|
|
|
|
static DEVICE_ATTR (hyn_esd_mode, S_IRUGO|S_IWUSR, hyn_esd_show, hyn_esd_store);
|
|
/*
|
|
* read example: cat hyn_esd_buf ---read esd buf
|
|
*/
|
|
static DEVICE_ATTR (hyn_esd_buf, S_IRUGO|S_IWUSR, hyn_esd_buf_show, hyn_esd_buf_store);
|
|
static struct attribute *hyn_esd_mode_attrs[] =
|
|
{
|
|
|
|
&dev_attr_hyn_esd_mode.attr,
|
|
&dev_attr_hyn_esd_buf.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group hyn_esd_group =
|
|
{
|
|
.attrs = hyn_esd_mode_attrs,
|
|
};
|
|
void hyn_create_esd_sysfs(struct i2c_client *client)
|
|
{
|
|
int ret = 0;
|
|
HYN_FUNC_ENTER();
|
|
|
|
//if(hyn_ts_data->k_obj==NULL)
|
|
if(!hyn_ts_data->k_obj)
|
|
return;
|
|
|
|
ret = sysfs_create_group(hyn_ts_data->k_obj, &hyn_esd_group);
|
|
if ( ret != 0)
|
|
{
|
|
HYN_ERROR( "[GESTURE]hyn_gesture_mode_group(sysfs) create failed!");
|
|
sysfs_remove_group(hyn_ts_data->k_obj, &hyn_esd_group);
|
|
return;
|
|
}
|
|
HYN_FUNC_EXIT();
|
|
return;
|
|
}
|
|
|
|
static void hyn_esd_poweron_ic(unsigned int ms)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
hyn_reset_proc(10);
|
|
HYN_FUNC_EXIT();
|
|
|
|
}
|
|
void hyn_esd_suspend(void)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
if(hyn_ts_data->hyn_esd_mode)
|
|
hyn_esd_switch(SWITCH_ESD_OFF);
|
|
HYN_FUNC_EXIT();
|
|
|
|
}
|
|
void hyn_esd_resume(void)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
if(hyn_ts_data->hyn_esd_mode)
|
|
hyn_esd_switch(SWITCH_ESD_ON);
|
|
HYN_FUNC_EXIT();
|
|
|
|
}
|
|
|
|
void hyn_esd_switch(s32 on)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
if(!hyn_ts_data->hyn_esd_mode)
|
|
return;
|
|
|
|
mutex_lock(&hyn_ts_data->hyn_esd_lock);
|
|
if (SWITCH_ESD_ON == on) { /* switch on esd check */
|
|
if (!hyn_ts_data->hyn_esd_running) {
|
|
hyn_ts_data->hyn_esd_running = 1;
|
|
hyn_ts_data->hyn_esd_pre_counter = 0;
|
|
hyn_ts_data->hyn_esd_cur_counter = 0;
|
|
HYN_DEBUG(" Esd protector started!");
|
|
queue_delayed_work(hyn_ts_data->hyn_esd_workqueue, &hyn_ts_data->hyn_esd_check_work, hyn_ts_data->hyn_esd_work_cycle);
|
|
}
|
|
} else { /* switch off esd check */
|
|
if (hyn_ts_data->hyn_esd_running) {
|
|
hyn_ts_data->hyn_esd_running = 0;
|
|
hyn_ts_data->hyn_esd_pre_counter = 0;
|
|
hyn_ts_data->hyn_esd_cur_counter = 0;
|
|
HYN_DEBUG(" Esd protector stopped!");
|
|
cancel_delayed_work(&hyn_ts_data->hyn_esd_check_work);
|
|
}
|
|
}
|
|
mutex_unlock(&hyn_ts_data->hyn_esd_lock);
|
|
HYN_FUNC_EXIT();
|
|
|
|
}
|
|
|
|
static void hyn_esd_check_func(struct work_struct *work)
|
|
{
|
|
int retry = 0;
|
|
int ret;
|
|
int check_sum;
|
|
unsigned char buf[8];
|
|
|
|
HYN_FUNC_ENTER();
|
|
|
|
if(!hyn_ts_data->hyn_esd_mode){
|
|
HYN_DEBUG("Esd protector hyn_esd_mode is disable !");
|
|
return;
|
|
}
|
|
if(hyn_ts_data->work_mode!=0){
|
|
HYN_DEBUG("Esd protector work_mode is false !");
|
|
return;
|
|
}
|
|
if (!hyn_ts_data->hyn_esd_running) {
|
|
HYN_DEBUG("Esd protector hyn_esd_running is not running!");
|
|
return;
|
|
}
|
|
|
|
if((hyn_ts_data->hyn_esd_i2c_lock_flag != 0)||(hyn_ts_data->apk_rdwr_flag!=0)||(hyn_ts_data->fw_updating!=0))
|
|
goto END;
|
|
else hyn_ts_data->hyn_esd_i2c_lock_flag = 1;
|
|
|
|
if(hyn_ts_data->config_chip_product_line==HYN_CHIP_PRODUCT_LINE_MUT_CAP){
|
|
|
|
while(retry++ < 5) {
|
|
buf[0] = HYN_REG_MUT_ESD_VALUE>>8;
|
|
buf[1] = HYN_REG_MUT_ESD_VALUE&0xff;
|
|
ret = cst3xx_i2c_read_register(hyn_ts_data->client, buf, 6);
|
|
if (ret > 0){
|
|
check_sum = buf[0]+buf[1]+buf[2]+buf[3]+0xA5;
|
|
if(check_sum != ( (buf[4]<<8)+ buf[5])){
|
|
HYN_ERROR("hyn_esd_check_func iic read check_sum error.\n");
|
|
}else{
|
|
break;
|
|
}
|
|
}else{
|
|
HYN_ERROR("hyn_esd_check_func iic error" );
|
|
goto hyn_esd_check_init;
|
|
}
|
|
mdelay(2);
|
|
}
|
|
|
|
}else if(hyn_ts_data->config_chip_product_line==HYN_CHIP_PRODUCT_LINE_SEL_CAP){
|
|
|
|
}
|
|
|
|
if((retry==6)||(retry==0)|| (ret<0)){
|
|
HYN_ERROR("hyn_esd_check_func iic read esd data error,please check firmware,driver and hardware.\n");
|
|
goto END;
|
|
}
|
|
hyn_ts_data->hyn_esd_cur_counter = buf[3]+(buf[2]<<8)+(buf[1]<<16)+(buf[0]<<24);
|
|
if(((hyn_ts_data->hyn_esd_cur_counter-hyn_ts_data->hyn_esd_pre_counter)<20)
|
|
&&(hyn_ts_data->hyn_esd_pre_counter>100))
|
|
{
|
|
HYN_ERROR("hyn_esd_check_func hyn_esd_cur_counter is :0x%x. hyn_esd_pre_counter is:0x%x.------\n",hyn_ts_data->hyn_esd_cur_counter,hyn_ts_data->hyn_esd_pre_counter);
|
|
goto hyn_esd_check_init;
|
|
}
|
|
goto END;
|
|
|
|
hyn_esd_check_init:
|
|
HYN_ERROR("hyn_esd_check_func reset.\n");
|
|
hyn_esd_poweron_ic(10);
|
|
mdelay(100);
|
|
hyn_ts_data->hyn_esd_cur_counter=0;
|
|
|
|
|
|
END:
|
|
hyn_ts_data->hyn_esd_i2c_lock_flag = 0;
|
|
hyn_ts_data->hyn_esd_pre_counter=hyn_ts_data->hyn_esd_cur_counter;
|
|
mutex_lock(&hyn_ts_data->hyn_esd_lock);
|
|
if (hyn_ts_data->hyn_esd_running)
|
|
queue_delayed_work(hyn_ts_data->hyn_esd_workqueue, &hyn_ts_data->hyn_esd_check_work, hyn_ts_data->hyn_esd_work_cycle);
|
|
else
|
|
HYN_DEBUG(" Esd protector suspended!");
|
|
mutex_unlock(&hyn_ts_data->hyn_esd_lock);
|
|
|
|
HYN_FUNC_EXIT();
|
|
}
|
|
int hyn_esd_get_status(void)
|
|
{
|
|
u8 buf[7];
|
|
int ret=-1;
|
|
u16 check_sum=0;
|
|
HYN_FUNC_ENTER();
|
|
|
|
buf[0] = HYN_REG_MUT_ESD_VALUE>>8;
|
|
buf[1] = HYN_REG_MUT_ESD_VALUE&0xff;
|
|
ret = cst3xx_i2c_read_register(hyn_ts_data->client, buf, 6);
|
|
check_sum = buf[0]+buf[1]+buf[2]+buf[3]+0xA5;
|
|
if(check_sum != ( (buf[4]<<8)+ buf[5])){
|
|
HYN_ERROR(" esd check sum error.\n ");
|
|
return -1;
|
|
}
|
|
|
|
HYN_FUNC_EXIT();
|
|
return 1;
|
|
}
|
|
|
|
void hyn_esd_init(void)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
|
|
if(hyn_esd_get_status() < 0) {
|
|
HYN_ERROR(" hyn_esd_get_status failed!");
|
|
return;
|
|
}
|
|
hyn_ts_data->hyn_esd_workqueue = create_singlethread_workqueue("hyn_esd_workqueue");
|
|
if(!hyn_ts_data->hyn_esd_workqueue)
|
|
HYN_ERROR(" hyn_esd_workqueue failed!");
|
|
else{
|
|
hyn_init_esd_protect();
|
|
hyn_esd_switch(SWITCH_ESD_ON);
|
|
hyn_ts_data->hyn_esd_running=ENABLE;
|
|
}
|
|
hyn_create_esd_sysfs(hyn_ts_data->client);
|
|
HYN_FUNC_EXIT();
|
|
}
|
|
void hyn_init_esd_protect(void)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
hyn_ts_data->hyn_esd_work_cycle=1000;
|
|
hyn_ts_data->hyn_esd_mode=ENABLE;
|
|
HYN_DEBUG(" Clock ticks for an esd cycle: %d", hyn_ts_data->hyn_esd_work_cycle);
|
|
INIT_DELAYED_WORK(&hyn_ts_data->hyn_esd_check_work, hyn_esd_check_func);
|
|
mutex_init(&hyn_ts_data->hyn_esd_lock);
|
|
HYN_FUNC_EXIT();
|
|
}
|
|
|
|
void hyn_esd_exit(void)
|
|
{
|
|
HYN_FUNC_ENTER();
|
|
if (hyn_ts_data->hyn_esd_workqueue){
|
|
destroy_workqueue(hyn_ts_data->hyn_esd_workqueue);
|
|
hyn_ts_data->hyn_esd_workqueue = NULL;
|
|
}
|
|
mutex_destroy(&hyn_ts_data->hyn_esd_lock);
|
|
HYN_FUNC_EXIT();
|
|
}
|
|
|
|
#endif
|
|
|
|
|