OSHW-DEIMOS/SOFTWARE/A64-TERES/linux-a64/drivers/input/touchscreen/icn83xx/icn83xx.c
Dimitar Gamishev f9b0e7a283 linux
2017-10-13 14:07:04 +03:00

1514 lines
56 KiB
C
Executable File

/*
Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved.
This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd.
and may contains trade secrets and/or other confidential information of ChipOne
Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party,
in whole or in part, without prior written consent of ChipOne.
THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS,
WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR
IMPLIED WARRANTIES.
File Name: icn83xx.c
Abstract:
input driver.
Author: Zhimin Tian
Date : 01,17,2013
Version: 1.0
History :
2012,10,30, V0.1 first version
*/
#include "icn83xx.h"
static struct i2c_client *this_client;
short log_rawdata[28][16] = {{0},};
short log_diffdata[28][16] = {{0},};
#define CTP_IRQ_NUMBER (config_info.int_number)
#define CTP_IRQ_MODE (IRQF_TRIGGER_FALLING)
#define SCREEN_MAX_X (screen_max_x)
#define SCREEN_MAX_Y (screen_max_y)
#define PRESS_MAX (255)
static int screen_max_x = 0;
static int screen_max_y = 0;
static int revert_x_flag = 0;
static int revert_y_flag = 0;
static int exchange_x_y_flag = 0;
static u32 int_handle = 0;
static __u32 twi_id = 0;
struct ctp_config_info config_info = {
.input_type = CTP_TYPE,
.name = NULL,
};
static u32 debug_mask = 0;
enum{
DEBUG_INIT = 1U << 0,
DEBUG_SUSPEND = 1U << 1,
DEBUG_INT_INFO = 1U << 2,
DEBUG_X_Y_INFO = 1U << 3,
DEBUG_KEY_INFO = 1U << 4,
DEBUG_WAKEUP_INFO = 1U << 5,
DEBUG_OTHERS_INFO = 1U << 6,
};
#define dprintk(level_mask,fmt,arg...) if(unlikely(debug_mask & level_mask)) \
printk("[CTP]:"fmt, ## arg)
module_param_named(debug_mask,debug_mask,int,S_IRUGO | S_IWUSR | S_IWGRP);
static const unsigned short normal_i2c[2] = {0x40,I2C_CLIENT_END};
#if SUPPORT_FW_UPDATE
static char firmware[128] = {"/system/vendor/modules/fw.bin"};
#endif
#if SUPPORT_SYSFS
static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer);
static ssize_t icn83xx_show_update(struct device* cd,struct device_attribute *attr, char* buf);
static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len);
static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf);
static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len);
static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn83xx_show_update, icn83xx_store_update);
static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn83xx_show_process, icn83xx_store_process);
static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf)
{
ssize_t ret = 0;
sprintf(buf, "icn83xx process\n");
ret = strlen(buf) + 1;
return ret;
}
static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr,
const char* buf, size_t len)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
unsigned long on_off = simple_strtoul(buf, NULL, 10);
if(on_off == 0) {
icn83xx_ts->work_mode = on_off;
} else if((on_off == 1) || (on_off == 2)){
if((icn83xx_ts->work_mode == 0) && (icn83xx_ts->use_irq == 1)) {
hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
icn83xx_ts->timer.function = chipone_timer_func;
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}
icn83xx_ts->work_mode = on_off;
}
return len;
}
static ssize_t icn83xx_show_update(struct device* cd,
struct device_attribute *attr, char* buf)
{
ssize_t ret = 0;
sprintf(buf, "icn83xx firmware\n");
ret = strlen(buf) + 1;
return ret;
}
static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len)
{
int err=0;
unsigned long on_off = simple_strtoul(buf, NULL, 10);
return len;
}
static int icn83xx_create_sysfs(struct i2c_client *client)
{
int err;
struct device *dev = &(client->dev);
printk("%s: \n",__func__);
err = device_create_file(dev, &dev_attr_update);
err = device_create_file(dev, &dev_attr_process);
return err;
}
#endif
#if SUPPORT_PROC_FS
pack_head cmd_head;
static struct proc_dir_entry *icn83xx_proc_entry;
int DATA_LENGTH = 0;
static int icn83xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
{
int ret = 0;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
proc_info("%s \n",__func__);
if(down_interruptible(&icn83xx_ts->sem)) {
return -1;
}
ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
if(ret) {
proc_error("copy_from_user failed.\n");
goto write_out;
} else {
ret = CMD_HEAD_LENGTH;
}
proc_info("wr :0x%02x.\n", cmd_head.wr);
proc_info("flag:0x%02x.\n", cmd_head.flag);
proc_info("circle :%d.\n", (int)cmd_head.circle);
proc_info("times :%d.\n", (int)cmd_head.times);
proc_info("retry :%d.\n", (int)cmd_head.retry);
proc_info("data len:%d.\n", (int)cmd_head.data_len);
proc_info("addr len:%d.\n", (int)cmd_head.addr_len);
proc_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]);
proc_info("len:%d.\n", (int)len);
proc_info("data:0x%02x%02x.\n", buff[CMD_HEAD_LENGTH], buff[CMD_HEAD_LENGTH+1]);
if (1 == cmd_head.wr) {
if(1 == cmd_head.addr_len) {
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret) {
proc_error("copy_from_user failed.\n");
goto write_out;
}
ret = icn83xx_i2c_txdata(cmd_head.addr[0], &cmd_head.data[0], cmd_head.data_len);
if (ret < 0) {
proc_error("write iic failed! ret: %d\n", ret);
goto write_out;
}
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto write_out;
}
} else if(3 == cmd_head.wr) {
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret) {
proc_error("copy_from_user failed.\n");
goto write_out;
}
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
memset(firmware, 0, 128);
memcpy(firmware, &cmd_head.data[0], cmd_head.data_len);
proc_info("firmware : %s\n", firmware);
} else if(5 == cmd_head.wr) {
icn83xx_update_status(1);
ret = kernel_thread(icn83xx_fw_update,firmware,CLONE_KERNEL);
icn83xx_trace("the kernel_thread result is:%d\n", ret);
} else if(7 == cmd_head.wr) {
if(2 == cmd_head.addr_len) {
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret) {
proc_error("copy_from_user failed.\n");
goto write_out;
}
ret = icn83xx_writeReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], cmd_head.data[0]);
if (ret < 0) {
proc_error("write reg failed! ret: %d\n", ret);
goto write_out;
}
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto write_out;
}
}
write_out:
up(&icn83xx_ts->sem);
return len;
}
static int icn83xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )
{
int i;
int ret = 0;
int data_len = 0;
int len = 0;
int loc = 0;
char retvalue;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
if(down_interruptible(&icn83xx_ts->sem))
return -1;
proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count, off, cmd_head.data_len);
if (cmd_head.wr % 2) {
ret = 0;
goto read_out;
} else if (0 == cmd_head.wr) {
if(1 == cmd_head.addr_len) {
data_len = cmd_head.data_len;
if(cmd_head.addr[0] == 0xff) {
page[0] = 83;
proc_info("read ic type: %d\n", page[0]);
} else {
while(data_len>0) {
if (data_len > DATA_LENGTH)
len = DATA_LENGTH;
else
len = data_len;
data_len -= len;
memset(&cmd_head.data[0], 0, len+1);
ret = icn83xx_i2c_rxdata(cmd_head.addr[0]+loc, &cmd_head.data[0], len);
if(ret < 0) {
icn83xx_error("read iic failed: %d\n", ret);
goto read_out;
} else
memcpy(&page[loc], &cmd_head.data[0], len);
loc += len;
}
proc_info("page[0]: 0x%02x\n", page[0]);
proc_info("page[1]: 0x%02x\n", page[1]);
}
}
} else if(2 == cmd_head.wr) {
//scan tp rawdata
icn83xx_write_reg(4, 0x20);
mdelay(cmd_head.times);
icn83xx_read_reg(2, &retvalue);
while(retvalue != 1) {
mdelay(cmd_head.times);
icn83xx_read_reg(2, &retvalue);
}
if(2 == cmd_head.addr_len) {
for(i=0; i<cmd_head.addr[1]; i++) {
icn83xx_write_reg(3, i);
mdelay(cmd_head.times);
ret = icn83xx_i2c_rxdata(128, &cmd_head.data[0], cmd_head.addr[0]*2);
if (ret < 0) {
icn83xx_error("read rawdata failed: %d\n", ret);
goto read_out;
} else {
//proc_info("read rawdata out %d bytes, loc: %d\n", cmd_head.addr[0]*2, loc);
memcpy(&page[loc], &cmd_head.data[0], cmd_head.addr[0]*2);
}
loc += cmd_head.addr[0]*2;
}
for(i=0; i<cmd_head.data_len; i=i+2)
swap_ab(page[i], page[i+1]);
//icn83xx_rawdatadump(&page[0], cmd_head.data_len/2, cmd_head.addr[0]);
}
//finish scan tp rawdata
icn83xx_write_reg(2, 0x0);
}else if(4 == cmd_head.wr) //get update status
page[0] = icn83xx_get_status();
else if(6 == cmd_head.wr) {
if(2 == cmd_head.addr_len) {
ret = icn83xx_readReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], &cmd_head.data[0]);
if (ret < 0) {
proc_error("reg reg failed! ret: %d\n", ret);
goto read_out;
}
page[0] = cmd_head.data[0];
goto read_out;
}
}
read_out:
up(&icn83xx_ts->sem);
proc_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len);
return cmd_head.data_len;
}
int init_proc_node()
{
int i;
memset(&cmd_head, 0, sizeof(cmd_head));
cmd_head.data = NULL;
i = 5;
while ((!((int)cmd_head.data) )&& i){
cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
if (NULL != cmd_head.data)
break;
i--;
}
if (i) {
//DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
DATA_LENGTH = i * DATA_LENGTH_UINT;
proc_info("alloc memory size:%d.\n", DATA_LENGTH);
} else {
printk("alloc for memory failed.\n");
return 0;
}
icn83xx_proc_entry = create_proc_entry(ICN83XX_ENTRY_NAME, 0666, NULL);
if (icn83xx_proc_entry == NULL) {
printk("Couldn't create proc entry!\n");
return 0;
} else {
proc_info("Create proc entry success!\n");
icn83xx_proc_entry->write_proc = icn83xx_tool_write;
icn83xx_proc_entry->read_proc = icn83xx_tool_read;
}
return 1;
}
void uninit_proc_node(void)
{
kfree(cmd_head.data);
cmd_head.data = NULL;
remove_proc_entry(ICN83XX_ENTRY_NAME, NULL);
}
#endif
#if TOUCH_VIRTUAL_KEYS
static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf,
__stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:1030:50:60"
":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":280:1030:50:60"
":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":470:1030:50:60"
":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":900:1030:50:60"
"\n");
}
static struct kobj_attribute virtual_keys_attr = {
.attr = {
.name = "virtualkeys.chipone-ts",
.mode = S_IRUGO,
},
.show = &virtual_keys_show,
};
static struct attribute *properties_attrs[] = {
&virtual_keys_attr.attr,
NULL
};
static struct attribute_group properties_attr_group = {
.attrs = properties_attrs,
};
static void icn83xx_ts_virtual_keys_init(void)
{
int ret;
struct kobject *properties_kobj;
properties_kobj = kobject_create_and_add("board_properties", NULL);
if (properties_kobj)
ret = sysfs_create_group(properties_kobj,
&properties_attr_group);
if (!properties_kobj || ret)
pr_err("failed to create board_properties\n");
}
#endif
/**
* ctp_print_info - sysconfig print function
* return value:
*
*/
void ctp_print_info(struct ctp_config_info info,int debug_level)
{
if(debug_level == DEBUG_INIT)
{
printk("info.ctp_used:%d\n",info.ctp_used);
printk("info.twi_id:%d\n",info.twi_id);
printk("info.screen_max_x:%d\n",info.screen_max_x);
printk("info.screen_max_y:%d\n",info.screen_max_y);
printk("info.revert_x_flag:%d\n",info.revert_x_flag);
printk("info.revert_y_flag:%d\n",info.revert_y_flag);
printk("info.exchange_x_y_flag:%d\n",info.exchange_x_y_flag);
printk("info.irq_gpio_number:%d\n",info.irq_gpio.gpio);
printk("info.wakeup_gpio_number:%d\n",info.wakeup_gpio.gpio);
}
}
/**
* ctp_wakeup - function
*
*/
int ctp_wakeup(int status,int ms)
{
dprintk(DEBUG_INIT,"***CTP*** %s:status:%d,ms = %d\n",__func__,status,ms);
if (status == 0) {
if(ms == 0) {
__gpio_set_value(config_info.wakeup_gpio.gpio, 0);
}else {
__gpio_set_value(config_info.wakeup_gpio.gpio, 0);
msleep(ms);
__gpio_set_value(config_info.wakeup_gpio.gpio, 1);
}
}
if (status == 1) {
if(ms == 0) {
__gpio_set_value(config_info.wakeup_gpio.gpio, 1);
}else {
__gpio_set_value(config_info.wakeup_gpio.gpio, 1);
msleep(ms);
__gpio_set_value(config_info.wakeup_gpio.gpio, 0);
}
}
msleep(5);
return 0;
}
/**
* ctp_detect - Device detection callback for automatic device creation
* return value:
* = 0; success;
* < 0; err
*/
int ctp_detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
if(twi_id == adapter->nr)
{
dprintk(DEBUG_INIT,"\n##############%s: Detected chip %s at adapter %d, address 0x%02x ##############\n",
__func__, CTP_NAME, i2c_adapter_id(adapter), client->addr);
strlcpy(info->type, CTP_NAME, I2C_NAME_SIZE);
return 0;
}else{
return -ENODEV;
}
}
/***********************************************************************************************
Name : icn83xx_prog_i2c_rxdata
Input : addr
*rxdata
length
Output : ret
function : read data from icn83xx, prog mode
***********************************************************************************************/
int icn83xx_prog_i2c_rxdata(unsigned short addr, char *rxdata, int length)
{
int ret = -1;
int retries = 0;
unsigned char tmp_buf[2];
struct i2c_msg msgs[] = {
{
.addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
.flags = 0,
.len = 2,
.buf = tmp_buf,
},{
.addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
tmp_buf[0] = U16HIBYTE(addr);
tmp_buf[1] = U16LOBYTE(addr);
while(retries < IIC_RETRY_NUM) {
ret = i2c_transfer(this_client->adapter, msgs, 2);
if(ret == 2)break;
retries++;
}
if (retries >= IIC_RETRY_NUM) {
printk("%s i2c read error: %d\n", __func__, ret);
//icn83xx_ts_reset();
}
return ret;
}
/***********************************************************************************************
Name : icn83xx_prog_i2c_txdata
Input : addr
*rxdata
length
Output : ret
function : send data to icn83xx , prog mode
***********************************************************************************************/
int icn83xx_prog_i2c_txdata(unsigned short addr, char *txdata, int length)
{
int ret = -1;
char tmp_buf[128];
int retries = 0;
struct i2c_msg msg[] = {
{
.addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
.flags = 0,
.len = length + 2,
.buf = tmp_buf,
},
};
if (length > 125) {
printk("%s too big datalen = %d!\n", __func__, length);
return -1;
}
tmp_buf[0] = U16HIBYTE(addr);
tmp_buf[1] = U16LOBYTE(addr);
if (length != 0 && txdata != NULL)
memcpy(&tmp_buf[2], txdata, length);
while(retries < IIC_RETRY_NUM) {
ret = i2c_transfer(this_client->adapter, msg, 1);
if(ret == 1)break;
retries++;
}
if (retries >= IIC_RETRY_NUM) {
printk("%s i2c write error: %d\n", __func__, ret);
//icn83xx_ts_reset();
}
return ret;
}
/***********************************************************************************************
Name : icn83xx_prog_write_reg
Input : addr -- address
para -- parameter
Output :
function : write register of icn83xx, prog mode
***********************************************************************************************/
int icn83xx_prog_write_reg(unsigned short addr, char para)
{
char buf[3];
int ret = -1;
buf[0] = para;
ret = icn83xx_prog_i2c_txdata(addr, buf, 1);
if (ret < 0) {
printk("write reg failed! %#x ret: %d\n", buf[0], ret);
return -1;
}
return ret;
}
/***********************************************************************************************
Name : icn83xx_prog_read_reg
Input : addr
pdata
Output :
function : read register of icn83xx, prog mode
***********************************************************************************************/
int icn83xx_prog_read_reg(unsigned short addr, char *pdata)
{
int ret = -1;
ret = icn83xx_prog_i2c_rxdata(addr, pdata, 1);
return ret;
}
/***********************************************************************************************
Name : icn83xx_i2c_rxdata
Input : addr
*rxdata
length
Output : ret
function : read data from icn83xx, normal mode
***********************************************************************************************/
int icn83xx_i2c_rxdata(unsigned char addr, char *rxdata, int length)
{
int ret = -1;
int retries = 0;
unsigned char tmp_buf[1];
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = 1,
.buf = tmp_buf,
}, {
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
tmp_buf[0] = addr;
while(retries < IIC_RETRY_NUM) {
ret = i2c_transfer(this_client->adapter, msgs, 2);
if(ret == 2)break;
retries++;
}
if (retries >= IIC_RETRY_NUM)
printk("%s i2c read error: %d\n", __func__, ret);
return ret;
}
/***********************************************************************************************
Name : icn83xx_i2c_txdata
Input : addr
*rxdata
length
Output : ret
function : send data to icn83xx , normal mode
***********************************************************************************************/
int icn83xx_i2c_txdata(unsigned char addr, char *txdata, int length)
{
int ret = -1;
unsigned char tmp_buf[128];
int retries = 0;
struct i2c_msg msg[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = length + 1,
.buf = tmp_buf,
},
};
if (length > 125) {
printk("%s too big datalen = %d!\n", __func__, length);
return -1;
}
tmp_buf[0] = addr;
if (length != 0 && txdata != NULL) {
memcpy(&tmp_buf[1], txdata, length);
}
while(retries < IIC_RETRY_NUM) {
ret = i2c_transfer(this_client->adapter, msg, 1);
if(ret == 1)break;
retries++;
}
if (retries >= IIC_RETRY_NUM)
printk("%s i2c write error: %d\n", __func__, ret);
return ret;
}
/***********************************************************************************************
Name : icn83xx_write_reg
Input : addr -- address
para -- parameter
Output :
function : write register of icn83xx, normal mode
***********************************************************************************************/
int icn83xx_write_reg(unsigned char addr, char para)
{
char buf[3];
int ret = -1;
buf[0] = para;
ret = icn83xx_i2c_txdata(addr, buf, 1);
if (ret < 0) {
printk("write reg failed! %#x ret: %d\n", buf[0], ret);
return -1;
}
return ret;
}
/***********************************************************************************************
Name : icn83xx_read_reg
Input : addr
pdata
Output :
function : read register of icn83xx, normal mode
***********************************************************************************************/
int icn83xx_read_reg(unsigned char addr, char *pdata)
{
int ret = -1;
ret = icn83xx_i2c_rxdata(addr, pdata, 1);
return ret;
}
#if SUPPORT_FW_UPDATE
/***********************************************************************************************
Name : icn83xx_log
Input : 0: rawdata, 1: diff data
Output : err type
function : calibrate param
***********************************************************************************************/
int icn83xx_log(char diff)
{
char row = 0;
char column = 0;
int i, j;
icn83xx_read_reg(160, &row);
icn83xx_read_reg(161, &column);
if(diff == 1) {
icn83xx_readTP(row, column, (char *)&log_diffdata[0][0]);
for(i=0; i<row; i++) {
for(j=0; j<column; j++) {
log_diffdata[i][j] = log_diffdata[i][j] - log_rawdata[i][j];
}
}
icn83xx_rawdatadump(&log_diffdata[0][0], row*16, 16);
} else {
icn83xx_readTP(row, column, (char *)&log_rawdata[0][0]);
icn83xx_rawdatadump(&log_rawdata[0][0], row*16, 16);
}
return 0;
}
#endif
/***********************************************************************************************
Name : icn83xx_iic_test
Input : void
Output :
function : 0 success,
***********************************************************************************************/
static int icn83xx_iic_test(void)
{
int ret = -1;
char value = 0;
int retry = 0;
while(retry++ < 3) {
ret = icn83xx_read_reg(0, &value);
if(ret > 0)
return ret;
printk("iic test error! %d\n", retry);
msleep(3);
}
return ret;
}
/***********************************************************************************************
Name : icn83xx_ts_release
Input : void
Output :
function : touch release
***********************************************************************************************/
static void icn83xx_ts_release(void)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
dprintk(DEBUG_X_Y_INFO,"==icn83xx_ts_release ==\n");
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_sync(icn83xx_ts->input_dev);
}
/***********************************************************************************************
Name : icn83xx_report_value_A
Input : void
Output :
function : reprot touch ponit
***********************************************************************************************/
static void icn83xx_report_value_A(void)
{
char buf[POINT_NUM*POINT_SIZE+3]={0};
int ret = -1;
int i;
#if TOUCH_VIRTUAL_KEYS
unsigned char button;
static unsigned char button_last;
#endif
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
dprintk(DEBUG_OTHERS_INFO,"==icn83xx_report_value_A ==\n");
ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2);
if (ret < 0) {
printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return;
}
#if TOUCH_VIRTUAL_KEYS
button = buf[0];
dprintk(DEBUG_OTHERS_INFO,"%s: button=%d\n",__func__, button);
if((button_last != 0) && (button == 0)) {
icn83xx_ts_release();
button_last = button;
return 1;
}
if(button != 0) {
switch(button) {
case ICN_VIRTUAL_BUTTON_HOME:
dprintk(DEBUG_X_Y_INFO,"ICN_VIRTUAL_BUTTON_HOME down\n");
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 280);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
break;
case ICN_VIRTUAL_BUTTON_BACK:
dprintk(DEBUG_X_Y_INFO,"ICN_VIRTUAL_BUTTON_BACK down\n");
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 470);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
break;
case ICN_VIRTUAL_BUTTON_MENU:
dprintk(DEBUG_X_Y_INFO,"ICN_VIRTUAL_BUTTON_MENU down\n");
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 100);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
break;
default:
dprintk(DEBUG_X_Y_INFO,"other gesture\n");
break;
}
button_last = button;
return;
}
#endif
icn83xx_ts->point_num = buf[1];
dprintk(DEBUG_OTHERS_INFO,"point_num is :%d\n",icn83xx_ts->point_num);
if (icn83xx_ts->point_num == 0) {
icn83xx_ts_release();
return;
}
for(i=0;i<icn83xx_ts->point_num;i++)
if(buf[8 + POINT_SIZE*i] != 4) break ;
if(i == icn83xx_ts->point_num) {
icn83xx_ts_release();
return;
}
for(i=0; i<icn83xx_ts->point_num; i++) {
icn83xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i];
icn83xx_ts->point_info[i].u16PosX = (buf[3 + POINT_SIZE*i]<<8) + buf[4 + POINT_SIZE*i];
icn83xx_ts->point_info[i].u16PosY = (buf[5 + POINT_SIZE*i]<<8) + buf[6 + POINT_SIZE*i];
icn83xx_ts->point_info[i].u8Pressure = 30;//buf[7 + POINT_SIZE*i];
icn83xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i];
dprintk(DEBUG_X_Y_INFO,"source point: %d ===x = %d,y = %d, press = %d ====\n",
i, icn83xx_ts->point_info[i].u16PosX,icn83xx_ts->point_info[i].u16PosY, icn83xx_ts->point_info[i].u8Pressure);
if((0 == icn83xx_ts->point_info[i].u16PosX) && (0 == icn83xx_ts->point_info[i].u16PosY))
return;
if(1 == exchange_x_y_flag) {
unsigned short x = 0;
x = icn83xx_ts->point_info[i].u16PosX;
icn83xx_ts->point_info[i].u16PosX = icn83xx_ts->point_info[i].u16PosY;
icn83xx_ts->point_info[i].u16PosY = x;
}
if(1 == revert_x_flag)
icn83xx_ts->point_info[i].u16PosX = SCREEN_MAX_X- icn83xx_ts->point_info[i].u16PosX;
if(1 == revert_y_flag)
icn83xx_ts->point_info[i].u16PosY = SCREEN_MAX_Y- icn83xx_ts->point_info[i].u16PosY;
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, icn83xx_ts->point_info[i].u8ID);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn83xx_ts->point_info[i].u8Pressure);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, icn83xx_ts->point_info[i].u16PosX);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, icn83xx_ts->point_info[i].u16PosY);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(icn83xx_ts->input_dev);
dprintk(DEBUG_X_Y_INFO,"report point: %d ===x = %d,y = %d, press = %d ====\n",
i, icn83xx_ts->point_info[i].u16PosX,icn83xx_ts->point_info[i].u16PosY, icn83xx_ts->point_info[i].u8Pressure);
}
input_sync(icn83xx_ts->input_dev);
}
/***********************************************************************************************
Name : icn83xx_report_value_B
Input : void
Output :
function : reprot touch ponit
***********************************************************************************************/
#if CTP_REPORT_PROTOCOL
static void icn83xx_report_value_B(void)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
char buf[POINT_NUM*POINT_SIZE+3]={0};
static unsigned char finger_last[POINT_NUM + 1]={0};
unsigned char finger_current[POINT_NUM + 1] = {0};
unsigned int position = 0;
int temp = 0;
int ret = -1;
dprintk(DEBUG_OTHERS_INFO,"==icn83xx_report_value_B ==\n");
ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2);
if (ret < 0) {
printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ret;
}
icn83xx_ts->point_num = buf[1];
if(icn83xx_ts->point_num > 0) {
for(position = 0; position<icn83xx_ts->point_num; position++) {
temp = buf[2 + POINT_SIZE*position] + 1;
finger_current[temp] = 1;
icn83xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position];
icn83xx_ts->point_info[temp].u16PosX = (buf[3 + POINT_SIZE*position]<<8) + buf[4 + POINT_SIZE*position];
icn83xx_ts->point_info[temp].u16PosY = (buf[5 + POINT_SIZE*position]<<8) + buf[6 + POINT_SIZE*position];
icn83xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position];
icn83xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position];
if(icn83xx_ts->point_info[temp].u8EventId == 4)
finger_current[temp] = 0;
if(1 == revert_x_flag)
icn83xx_ts->point_info[temp].u16PosX = screen_max_x- icn83xx_ts->point_info[temp].u16PosX;
if(1 == revert_y_flag)
icn83xx_ts->point_info[temp].u16PosY = screen_max_y- icn83xx_ts->point_info[temp].u16PosY;
icn83xx_info("temp %d\n", temp);
icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[temp].u8ID);
icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[temp].u16PosX);
icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[temp].u16PosY);
icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure);
icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[temp].u8EventId);
//icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure*16);
}
} else {
for(position = 1; position < POINT_NUM+1; position++)
finger_current[position] = 0;
dprintk(DEBUG_OTHERS_INFO,"no touch\n");
}
for(position = 1; position < POINT_NUM + 1; position++) {
if((finger_current[position] == 0) && (finger_last[position] != 0)) {
input_mt_slot(icn83xx_ts->input_dev, position-1);
input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false);
dprintk(DEBUG_X_Y_INFO,"one touch up: %d\n", position);
}
else if(finger_current[position]) {
input_mt_slot(icn83xx_ts->input_dev, position-1);
input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, true);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1);
//input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, icn83xx_ts->point_info[position].u8Pressure);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, 200);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, icn83xx_ts->point_info[position].u16PosX);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, icn83xx_ts->point_info[position].u16PosY);
dprintk(DEBUG_X_Y_INFO,"===position: %d, x = %d,y = %d, press = %d ====\n",
position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure);
}
}
input_sync(icn83xx_ts->input_dev);
for(position = 1; position < POINT_NUM + 1; position++)
finger_last[position] = finger_current[position];
}
#endif
/***********************************************************************************************
Name : icn83xx_ts_pen_irq_work
Input : void
Output :
function : work_struct
***********************************************************************************************/
static void icn83xx_ts_pen_irq_work(struct work_struct *work)
{
int ret = -1;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
#if SUPPORT_PROC_FS
if(down_interruptible(&icn83xx_ts->sem))
return -1;
#endif
if(icn83xx_ts->work_mode == 0) {
#if CTP_REPORT_PROTOCOL
icn83xx_report_value_B();
#else
icn83xx_report_value_A();
#endif
ret = input_set_int_enable(&(config_info.input_type), 1);
if (ret < 0)
printk("%s irq ensable failed\n", ICN83XX_NAME);
}
#if SUPPORT_FW_UPDATE
else if(icn83xx_ts->work_mode == 1){
printk("log raw data\n");
icn83xx_log(0); //raw data
} else if(icn83xx_ts->work_mode == 2){
printk("log diff data\n");
icn83xx_log(1); //diff data
}
#endif
#if SUPPORT_PROC_FS
up(&icn83xx_ts->sem);
#endif
dprintk(DEBUG_INT_INFO,"%s:ret:\n",__func__);
}
/***********************************************************************************************
Name : chipone_timer_func
Input : void
Output :
function : Timer interrupt service routine.
***********************************************************************************************/
static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer)
{
struct icn83xx_ts_data *icn83xx_ts = container_of(timer, struct icn83xx_ts_data, timer);
queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work);
if(icn83xx_ts->use_irq == 1){
if((icn83xx_ts->work_mode == 1) || (icn83xx_ts->work_mode == 2)) {
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}
} else {
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}
return HRTIMER_NORESTART;
}
/***********************************************************************************************
Name : icn83xx_ts_interrupt
Input : void
Output :
function : interrupt service routine
*
**********************************************************************************************/
irqreturn_t icn83xx_ts_interrupt(int irq, void *dev_id)
{
int ret = -1;
struct icn83xx_ts_data *icn83xx_ts = (struct icn83xx_ts_data *)dev_id;
ret = input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
printk("%s irq dissable failed\n", ICN83XX_NAME);
dprintk(DEBUG_INT_INFO,"==========icn83xx TS Interrupt============\n");
queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
/***********************************************************************************************
Name : icn83xx_ts_suspend
Input : void
Output :
function : tp enter sleep mode
***********************************************************************************************/
static void icn83xx_ts_suspend(struct early_suspend *handler)
{
int ret = -1;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
dprintk(DEBUG_SUSPEND,"\n#######################icn83xx_ts_suspend: write ICN83XX_REG_PMODE .#######################\n");
if (icn83xx_ts->use_irq){
ret = input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
printk("%s irq dissable failed\n", ICN83XX_NAME);
} else {
hrtimer_cancel(&icn83xx_ts->timer);
}
cancel_work_sync(&icn83xx_ts->pen_event_work);
flush_workqueue(icn83xx_ts->ts_workqueue);
icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE);
dprintk(DEBUG_SUSPEND,"\n####################### icn83xx_ts_suspend OVER .#######################\n");
}
/***********************************************************************************************
Name : icn83xx_ts_resume
Input : void
Output :
function : wakeup tp or reset tp
***********************************************************************************************/
static void icn83xx_ts_resume(struct early_suspend *handler)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
int ret = -1;
dprintk(DEBUG_SUSPEND,"==icn83xx_ts_resume== \n");
#if CTP_REPORT_PROTOCOL
int i;
for(i = 0; i < POINT_NUM; i++){
input_mt_slot(icn83xx_ts->input_dev, i);
input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false);
}
#else
icn83xx_ts_release();
#endif
ctp_wakeup(0, CTP_WAKEUP_LOW_PERIOD);
msleep(CTP_WAKEUP_HIGH_PERIOD);
if (icn83xx_ts->use_irq) {
ret = input_set_int_enable(&(config_info.input_type), 1);
if (ret < 0)
dprintk(DEBUG_SUSPEND,"%s irq ensable failed\n", ICN83XX_NAME);
} else {
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}
}
#else
/***********************************************************************************************
Name : icn83xx_ts_suspend
Input : void
Output :
function : tp enter sleep mode
***********************************************************************************************/
static int ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
int ret = -1;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
dprintk(DEBUG_SUSPEND,"\n#######################icn83xx_ts_suspend: write ICN83XX_REG_PMODE .#######################\n");
if (icn83xx_ts->use_irq){
ret = input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
printk("%s irq dissable failed\n", ICN83XX_NAME);
} else {
hrtimer_cancel(&icn83xx_ts->timer);
}
cancel_work_sync(&icn83xx_ts->pen_event_work);
flush_workqueue(icn83xx_ts->ts_workqueue);
icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE);
dprintk(DEBUG_SUSPEND,"\n####################### icn83xx_ts_suspend OVER .#######################\n");
return 0;
}
/***********************************************************************************************
Name : icn83xx_ts_resume
Input : void
Output :
function : wakeup tp or reset tp
***********************************************************************************************/
static int ts_resume(struct i2c_client *client)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
int ret = -1;
dprintk(DEBUG_SUSPEND,"==icn83xx_ts_resume== \n");
#if CTP_REPORT_PROTOCOL
int i;
for(i = 0; i < POINT_NUM; i++){
input_mt_slot(icn83xx_ts->input_dev, i);
input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false);
}
#else
icn83xx_ts_release();
#endif
ctp_wakeup(0, CTP_WAKEUP_LOW_PERIOD);
msleep(CTP_WAKEUP_HIGH_PERIOD);
if (icn83xx_ts->use_irq) {
ret = input_set_int_enable(&(config_info.input_type), 1);
if (ret < 0)
dprintk(DEBUG_SUSPEND,"%s irq ensable failed\n", ICN83XX_NAME);
} else {
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}
return 0;
}
#endif
/***********************************************************************************************
Name : icn83xx_request_input_dev
Input : void
Output :
function : 0 success,
***********************************************************************************************/
static int icn83xx_request_input_dev(struct icn83xx_ts_data *icn83xx_ts)
{
int ret = -1;
struct input_dev *input_dev;
input_dev = input_allocate_device();
if (!input_dev) {
printk("failed to allocate input device\n");
return -ENOMEM;
}
icn83xx_ts->input_dev = input_dev;
icn83xx_ts->input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;//BIT_MASK(EV_SYN) |
#if CTP_REPORT_PROTOCOL
__set_bit(INPUT_PROP_DIRECT, icn83xx_ts->input_dev->propbit);
input_mt_init_slots(icn83xx_ts->input_dev, 255);
#else
set_bit(ABS_MT_TOUCH_MAJOR, icn83xx_ts->input_dev->absbit);
set_bit(ABS_MT_POSITION_X, icn83xx_ts->input_dev->absbit);
set_bit(ABS_MT_POSITION_Y, icn83xx_ts->input_dev->absbit);
set_bit(ABS_MT_WIDTH_MAJOR, icn83xx_ts->input_dev->absbit);
#endif
input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);
set_bit(INPUT_PROP_DIRECT, icn83xx_ts->input_dev->propbit);
__set_bit(KEY_MENU, input_dev->keybit);
__set_bit(KEY_BACK, input_dev->keybit);
__set_bit(KEY_HOME, input_dev->keybit);
__set_bit(KEY_SEARCH, input_dev->keybit);
input_dev->name = CTP_NAME;
ret = input_register_device(input_dev);
if (ret) {
printk("Register %s input device failed\n", input_dev->name);
input_free_device(input_dev);
return -ENODEV;
}
return 0;
}
char FbCap[4][16]={
{0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14},
{0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12},
{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
{0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08},
};
static int icn83xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct icn83xx_ts_data *icn83xx_ts;
int err = 0;
#if SUPPORT_FW_UPDATE
short fwVersion = 0;
short curVersion = 0;
int retry;
#endif
dprintk(DEBUG_INIT,"\n %s begin: addr = 0x%02x . \n", __func__, client->addr);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
printk("\n %s I2C check functionality failed. \n",__func__);
return -ENODEV;
}
icn83xx_ts = kzalloc(sizeof(*icn83xx_ts), GFP_KERNEL);
if (!icn83xx_ts) {
printk("Alloc icn83xx_ts memory failed.\n");
return -ENOMEM;
}
memset(icn83xx_ts, 0, sizeof(*icn83xx_ts));
this_client = client;
this_client->addr = client->addr;
i2c_set_clientdata(client, icn83xx_ts);
icn83xx_ts->work_mode = 0;
dprintk(DEBUG_INIT,"work_mode:%d\n",icn83xx_ts->work_mode);
INIT_WORK(&icn83xx_ts->pen_event_work, icn83xx_ts_pen_irq_work);
icn83xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
if (!icn83xx_ts->ts_workqueue) {
printk("create_singlethread_workqueue failed.\n");
kfree(icn83xx_ts);
return -ESRCH;
}
err = icn83xx_iic_test();
if (err < 0) {
printk("icn83xx_iic_test failed.\n");
#if SUPPORT_FW_UPDATE
#if COMPILE_FW_WITH_DRIVER
icn83xx_set_fw(sizeof(icn83xx_fw), &icn83xx_fw[0]);
#endif
if(icn83xx_check_progmod() == 0) {
retry = 5;
dprintk(DEBUG_INIT,"in prog mode\n");
while(retry > 0) {
if(R_OK == icn83xx_fw_update(firmware)) {
break;
}
retry--;
printk("icn83xx_fw_update failed.\n");
}
} else {
printk("I2C communication failed.\n");
kfree(icn83xx_ts);
return -1;
}
#endif
} else {
dprintk(DEBUG_INIT,"iic communication ok\n");
}
#if SUPPORT_FW_UPDATE
fwVersion = icn83xx_read_fw_Ver(firmware);
curVersion = icn83xx_readVersion();
dprintk(DEBUG_INIT,"fwVersion : 0x%x\n", fwVersion);
dprintk(DEBUG_INIT,"current version: 0x%x\n", curVersion);
#if FORCE_UPDATA_FW
retry = 5;
while(retry > 0){
if(R_OK == icn83xx_fw_update(firmware)){
break;
}
retry--;
printk("icn83xx_fw_update failed.\n");
}
#else
if(fwVersion > curVersion) {
retry = 5;
while(retry > 0) {
if(R_OK == icn83xx_fw_update(firmware)) {
break;
}
retry--;
printk("icn83xx_fw_update failed.\n");
}
}
#endif
#endif
#if SUPPORT_FW_CALIB
err = icn83xx_read_reg(0, &value);
if(err > 0) {
//auto calib fw
average = icn83xx_calib(0, NULL);
//fix FbCap
//average = icn83xx_calib(0, FbCap[1]);
dprintk(DEBUG_INIT,"average : %d\n", average);
icn83xx_setPeakGroup(250, 150);
icn83xx_setDownUp(400, 300);
}
#endif
err= icn83xx_request_input_dev(icn83xx_ts);
if (err < 0) {
printk("request input dev failed\n");
kfree(icn83xx_ts);
return err;
}
#if TOUCH_VIRTUAL_KEYS
icn83xx_ts_virtual_keys_init();
#endif
config_info.dev = &(icn83xx_ts->input_dev->dev);
int_handle = input_request_int(&(config_info.input_type), icn83xx_ts_interrupt,CTP_IRQ_MODE, icn83xx_ts);
if (int_handle) {
printk("icn83xx_ts_probe: request irq failed\n");
input_free_int(&(config_info.input_type), icn83xx_ts);
icn83xx_ts->use_irq = 0;
hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
icn83xx_ts->timer.function = chipone_timer_func;
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}else {
icn83xx_ts->use_irq = 1;
printk("icn83xx_ts_probe: request irq sucesse\n");
}
#if SUPPORT_SYSFS
icn83xx_create_sysfs(client);
#endif
#if SUPPORT_PROC_FS
sema_init(&icn83xx_ts->sem, 1);
init_proc_node();
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
printk("==register_early_suspend =\n");
icn83xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
icn83xx_ts->early_suspend.suspend = icn83xx_ts_suspend;
icn83xx_ts->early_suspend.resume = icn83xx_ts_resume;
register_early_suspend(&icn83xx_ts->early_suspend);
#endif
printk("==%s over =\n", __func__);
return 0;
}
static int __devexit icn83xx_ts_remove(struct i2c_client *client)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(client);
printk("==icn83xx_ts_remove==\n");
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&icn83xx_ts->early_suspend);
#endif
#if SUPPORT_PROC_FS
uninit_proc_node();
#endif
if(1 == icn83xx_ts->use_irq)
input_free_int(&(config_info.input_type), icn83xx_ts);
input_unregister_device(icn83xx_ts->input_dev);
cancel_work_sync(&icn83xx_ts->pen_event_work);
destroy_workqueue(icn83xx_ts->ts_workqueue);
kfree(icn83xx_ts);
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id icn83xx_ts_id[] = {
{ CTP_NAME, 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, icn83xx_ts_id);
static struct i2c_driver icn83xx_ts_driver = {
.class = I2C_CLASS_HWMON,
.probe = icn83xx_ts_probe,
.remove = __devexit_p(icn83xx_ts_remove),
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = ts_suspend,
.resume = ts_resume,
#endif
.id_table = icn83xx_ts_id,
.driver = {
.name = CTP_NAME,
.owner = THIS_MODULE,
},
.address_list = normal_i2c,
};
static int ctp_get_system_config(void)
{
ctp_print_info(config_info,DEBUG_INIT);
screen_max_x = config_info.screen_max_x;
screen_max_y = config_info.screen_max_y;
revert_x_flag = config_info.revert_x_flag;
revert_y_flag = config_info.revert_y_flag;
exchange_x_y_flag = config_info.exchange_x_y_flag;
if((screen_max_x == 0) || (screen_max_y == 0)){
printk("%s:read config error!\n",__func__);
return 0;
}
return 1;
}
static int __init icn83xx_ts_init(void)
{
int ret = -1;
dprintk(DEBUG_INIT,"***************************init begin*************************************\n");
if (input_fetch_sysconfig_para(&(config_info.input_type))) {
printk("%s: ctp_fetch_sysconfig_para err.\n", __func__);
return 0;
} else {
ret = input_init_platform_resource(&(config_info.input_type));
if (0 != ret) {
printk("%s:init_platform_resource err. \n", __func__);
}
}
if(config_info.ctp_used == 0){
printk("*** ctp_used set to 0 !\n");
printk("*** if use ctp,please put the sys_config.fex ctp_used set to 1. \n");
return 0;
}
if(!ctp_get_system_config()){
printk("%s:read config fail!\n",__func__);
return ret;
}
ctp_wakeup(0, CTP_WAKEUP_LOW_PERIOD);
icn83xx_ts_driver.detect = ctp_detect;
ret = i2c_add_driver(&icn83xx_ts_driver);
return ret;
}
static void __exit icn83xx_ts_exit(void)
{
printk("==icn83xx_ts_exit==\n");
i2c_del_driver(&icn83xx_ts_driver);
input_free_platform_resource(&(config_info.input_type));
}
module_init(icn83xx_ts_init);
module_exit(icn83xx_ts_exit);
MODULE_AUTHOR("<zmtian@chiponeic.com>");
MODULE_DESCRIPTION("Chipone icn83xx TouchScreen driver");
MODULE_LICENSE("GPL");