blob: ab754344f2dc9e3fea571bb51024d7044a7fded6 [file] [log] [blame]
/*++
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 <linux/i2c/icn83xx.h>
#include <linux/notifier.h>
#if COMPILE_FW_WITH_DRIVER
#include "icn83xx_fw.h"
#endif
//static struct regulator *tp_regulator = NULL;
static struct i2c_client *this_client;
short log_rawdata[28][16] = {0,};
short log_diffdata[28][16] = {0,};
static char firmware[128] = {"/system/vendor/firmware/icn83xx.bin"};
//extern void atc260x_set_adjust_tp_para(void *ptr);
//extern int atc260x_get_charge_status();
static BLOCKING_NOTIFIER_HEAD(touch_key_notifier);
int register_touch_key_notifier(struct notifier_block *n)
{
return blocking_notifier_chain_register(&touch_key_notifier, n);
}
int unregister_touch_key_notifier(struct notifier_block *n)
{
return blocking_notifier_chain_unregister(&touch_key_notifier, n);
}
#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;
icn83xx_fw_update(firmware);
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);
icn83xx_trace("%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) // write iic
{
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) //write reg
{
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) //read iic
{
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);
//proc_info("cmd_head.data[0]: 0x%02x\n", cmd_head.data[0]);
//proc_info("cmd_head.data[1]: 0x%02x\n", cmd_head.data[1]);
if(ret < 0)
{
icn83xx_error("read iic failed: %d\n", ret);
goto read_out;
}
else
{
//proc_info("iic read out %d bytes, loc: %d\n", len, loc);
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) //read rawdata
{
//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) //read reg
{
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 ((!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;
icn83xx_trace("alloc memory size:%d.\n", DATA_LENGTH);
}
else
{
proc_error("alloc for memory failed.\n");
return 0;
}
icn83xx_proc_entry = create_proc_entry(ICN83XX_ENTRY_NAME, 0666, NULL);
if (icn83xx_proc_entry == NULL)
{
proc_error("Couldn't create proc entry!\n");
return 0;
}
else
{
icn83xx_trace("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
/* ---------------------------------------------------------------------
*
* Chipone panel related driver
*
*
----------------------------------------------------------------------*/
/***********************************************************************************************
Name : icn83xx_ts_wakeup
Input : void
Output : ret
function : this function is used to wakeup tp
***********************************************************************************************/
void icn83xx_ts_wakeup(void)
{
}
/***********************************************************************************************
Name : icn83xx_ts_reset
Input : void
Output : ret
function : this function is used to reset tp, you should not delete it
***********************************************************************************************/
void icn83xx_ts_reset(void)
{
//set reset func
gpio_set_value_cansleep(CTP_RST_PORT, 0);
msleep(20);
gpio_set_value_cansleep(CTP_RST_PORT, 1);
msleep(200);
}
/***********************************************************************************************
Name : icn83xx_irq_disable
Input : void
Output : ret
function : this function is used to disable irq
***********************************************************************************************/
void icn83xx_irq_disable(void)
{
unsigned long irqflags;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags);
if (!icn83xx_ts->irq_is_disable)
{
icn83xx_ts->irq_is_disable = 1;
disable_irq_nosync(icn83xx_ts->irq);
//disable_irq(icn83xx_ts->irq);
}
spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags);
}
/***********************************************************************************************
Name : icn83xx_irq_enable
Input : void
Output : ret
function : this function is used to enable irq
***********************************************************************************************/
void icn83xx_irq_enable(void)
{
unsigned long irqflags = 0;
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags);
if (icn83xx_ts->irq_is_disable)
{
enable_irq(icn83xx_ts->irq);
icn83xx_ts->irq_is_disable = 0;
}
spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags);
}
/***********************************************************************************************
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;
#if 0
struct i2c_msg msgs[] = {
{
.addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
#if SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
};
icn83xx_prog_i2c_txdata(addr, NULL, 0);
while(retries < IIC_RETRY_NUM)
{
ret = i2c_transfer(this_client->adapter, msgs, 1);
if(ret == 1)break;
retries++;
}
if (retries >= IIC_RETRY_NUM)
{
icn83xx_error("%s i2c read error: %d\n", __func__, ret);
// icn83xx_ts_reset();
}
#else
unsigned char tmp_buf[2];
struct i2c_msg msgs[] = {
{
.addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
.flags = 0,
.len = 2,
.buf = tmp_buf,
#if SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
{
.addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
#if SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
};
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++;
//printk("icn83xx_prog_i2c_rxdata: %d, ret: %d\n", retries, ret);
}
if (retries >= IIC_RETRY_NUM)
{
icn83xx_error("%s i2c read error: %d\n", __func__, ret);
// icn83xx_ts_reset();
}
#endif
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 SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
};
if (length > 125)
{
icn83xx_error("%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 > 0)break;
retries++;
//printk("icn83xx_prog_i2c_txdata: %d, ret: %d\n", retries, ret);
}
if (retries >= IIC_RETRY_NUM)
{
icn83xx_error("%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) {
icn83xx_error("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;
#if 0
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
#if SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
};
icn83xx_i2c_txdata(addr, NULL, 0);
while(retries < IIC_RETRY_NUM)
{
ret = i2c_transfer(this_client->adapter, msgs, 1);
if(ret == 1)break;
retries++;
}
if (retries >= IIC_RETRY_NUM)
{
icn83xx_error("%s i2c read error: %d\n", __func__, ret);
// icn83xx_ts_reset();
}
#else
unsigned char tmp_buf[1];
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = 1,
.buf = tmp_buf,
#if SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
#if SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
};
tmp_buf[0] = addr;
while(retries < IIC_RETRY_NUM)
{
ret = i2c_transfer(this_client->adapter, msgs, 2);
if(ret == 2)break;
retries++;
//printk("icn83xx_i2c_rxdata: %d, ret: %d\n", retries, ret);
}
if (retries >= IIC_RETRY_NUM)
{
icn83xx_error("%s i2c read error: %d\n", __func__, ret);
// icn83xx_ts_reset();
}
#endif
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 SUPPORT_ROCKCHIP
.scl_rate = ICN83XX_I2C_SCL,
#endif
},
};
if (length > 125)
{
icn83xx_error("%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++;
//printk("icn83xx_i2c_txdata: %d, ret: %d\n", retries, ret);
}
if (retries >= IIC_RETRY_NUM)
{
icn83xx_error("%s i2c write error: %d\n", __func__, ret);
// icn83xx_ts_reset();
}
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) {
icn83xx_error("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, &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, &log_rawdata[0][0]);
icn83xx_rawdatadump(&log_rawdata[0][0], row*16, 16);
}
}
#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;
}
icn83xx_error("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);
icn83xx_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)
{
icn83xx_info("==icn83xx_report_value_A ==\n");
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
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
ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2);
if (ret < 0) {
icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ret;
}
#if TOUCH_VIRTUAL_KEYS
button = buf[0];
icn83xx_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:
icn83xx_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);
blocking_notifier_call_chain(
&touch_key_notifier, 0, NULL);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
break;
case ICN_VIRTUAL_BUTTON_BACK:
icn83xx_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);
blocking_notifier_call_chain(
&touch_key_notifier, 0, NULL);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
break;
case ICN_VIRTUAL_BUTTON_MENU:
icn83xx_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);
blocking_notifier_call_chain(
&touch_key_notifier, 0, NULL);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
break;
default:
icn83xx_info("other gesture\n");
break;
}
button_last = button;
return 1;
}
#endif
icn83xx_ts->point_num = buf[1];
if (icn83xx_ts->point_num == 0) {
icn83xx_ts_release();
return 1;
}
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 1;
}
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 = 200;//buf[7 + POINT_SIZE*i];
icn83xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i];
if(1 == icn83xx_ts->revert_x_flag)
{
icn83xx_ts->point_info[i].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[i].u16PosX;
}
if(1 == icn83xx_ts->revert_y_flag)
{
icn83xx_ts->point_info[i].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[i].u16PosY;
}
icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[i].u8ID);
icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[i].u16PosX);
icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[i].u16PosY);
icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[i].u8Pressure);
icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[i].u8EventId);
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);
icn83xx_point_info("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 reported = 0;
int temp = 0;
int ret = -1;
ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2);
if (ret < 0) {
icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ret;
}
icn83xx_ts->point_num = buf[1];
icn83xx_info("==icn83xx_report_value_B icn83xx_ts->point_num = %d ==\n", icn83xx_ts->point_num);
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 == icn83xx_ts->revert_x_flag)
{
icn83xx_ts->point_info[temp].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[temp].u16PosX;
}
if(1 == icn83xx_ts->revert_y_flag)
{
icn83xx_ts->point_info[temp].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[temp].u16PosY;
}
icn83xx_info("temp %d\n", temp);
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*16);
}
}
else
{
for(position = 1; position < POINT_NUM+1; position++)
{
finger_current[position] = 0;
}
input_report_key(icn83xx_ts->input_dev, BTN_TOUCH, 0);
input_mt_sync(icn83xx_ts->input_dev);
reported = 1;
icn83xx_info("input_report up----\n");
}
for(position = 1; position < POINT_NUM + 1; position++)
{
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_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);
input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 8);
input_report_key(icn83xx_ts->input_dev, BTN_TOUCH, 1);
input_mt_sync(icn83xx_ts->input_dev);
reported = 1;
icn83xx_point_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);
}
}
if (reported) {
input_sync(icn83xx_ts->input_dev);
} else {
input_report_key(icn83xx_ts->input_dev, BTN_TOUCH, 0);
input_mt_sync(icn83xx_ts->input_dev);
input_sync(icn83xx_ts->input_dev);
}
for(position = 1; position < POINT_NUM + 1; position++)
{
finger_last[position] = finger_current[position];
}
icn83xx_point_info("===reported: %d ====\n", reported);
}
#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
#if (SUPPORT_ALLWINNER_A13 == 0)
if(icn83xx_ts->use_irq)
{
icn83xx_irq_enable();
}
#endif
}
#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
}
/***********************************************************************************************
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
***********************************************************************************************/
static irqreturn_t icn83xx_ts_interrupt(int irq, void *dev_id)
{
struct icn83xx_ts_data *icn83xx_ts = dev_id;
icn83xx_info("==========------icn83xx_ts TS Interrupt-----============\n");
if(icn83xx_ts->work_mode != 0)
{
return IRQ_HANDLED;
}
#if SUPPORT_ALLWINNER_A13
// irq share, can not disable irq?
if(!ctp_ops.judge_int_occur()){
icn83xx_info("==IRQ_EINT21=\n");
ctp_ops.clear_penirq();
if (!work_pending(&icn83xx_ts->pen_event_work))
{
icn83xx_info("Enter work\n");
queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work);
}
}else{
icn83xx_info("Other Interrupt\n");
return IRQ_NONE;
}
#else
icn83xx_irq_disable();
if (!work_pending(&icn83xx_ts->pen_event_work))
{
icn83xx_info("Enter work\n");
queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work);
}
#endif
return IRQ_HANDLED;
}
#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)
{
struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n");
if (icn83xx_ts->use_irq)
{
icn83xx_irq_disable();
}
else
{
hrtimer_cancel(&icn83xx_ts->timer);
}
icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE);
}
/***********************************************************************************************
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 i;
icn83xx_trace("==icn83xx_ts_resume== \n");
icn83xx_ts_wakeup();
icn83xx_ts_reset();
if (icn83xx_ts->use_irq)
{
icn83xx_irq_enable();
}
else
{
hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
}
}
#endif
/***********************************************************************************************
Name : icn83xx_request_io_port
Input : void
Output :
function : 0 success,
***********************************************************************************************/
static int icn83xx_request_io_port(struct icn83xx_ts_data *icn83xx_ts)
{
int err = 0;
icn83xx_ts->screen_max_x = SCREEN_MAX_X;
icn83xx_ts->screen_max_y = SCREEN_MAX_Y;
icn83xx_ts->irq = CTP_IRQ_PORT;
return err;
}
/***********************************************************************************************
Name : icn83xx_free_io_port
Input : void
Output :
function : 0 success,
***********************************************************************************************/
static int icn83xx_free_io_port(struct icn83xx_ts_data *icn83xx_ts)
{
#if SUPPORT_ALLWINNER_A13
ctp_ops.free_platform_resource();
#endif
#if SUPPORT_ROCKCHIP
#endif
#if SUPPORT_SPREADTRUM
#endif
}
/***********************************************************************************************
Name : icn83xx_request_irq
Input : void
Output :
function : 0 success,
***********************************************************************************************/
static int icn83xx_request_irq(struct icn83xx_ts_data *icn83xx_ts)
{
int err = -1;
//icn83xx_ts->irq = IRQ_SIRQ0;
err = gpio_request(icn83xx_ts->irq , "icn83xx_irq");
gpio_direction_input(icn83xx_ts->irq);
err = request_irq(gpio_to_irq(icn83xx_ts->irq), icn83xx_ts_interrupt, IRQ_TYPE_EDGE_RISING, "icn83xx_ts", icn83xx_ts);
if (err < 0)
{
icn83xx_error("icn83xx_ts_probe: request irq failed\n");
return err;
}
else
{
icn83xx_irq_disable();
icn83xx_ts->use_irq = 1;
}
return 0;
}
/***********************************************************************************************
Name : icn83xx_free_irq
Input : void
Output :
function : 0 success,
***********************************************************************************************/
static int icn83xx_free_irq(struct icn83xx_ts_data *icn83xx_ts)
{
if (icn83xx_ts)
{
if (icn83xx_ts->use_irq)
{
free_irq(icn83xx_ts->irq, icn83xx_ts);
}
else
{
hrtimer_cancel(&icn83xx_ts->timer);
}
}
}
/***********************************************************************************************
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) {
icn83xx_error("failed to allocate input device\n");
return -ENOMEM;
}
icn83xx_ts->input_dev = input_dev;
icn83xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
__set_bit(INPUT_PROP_DIRECT, icn83xx_ts->input_dev->propbit);
set_bit(EV_ABS, icn83xx_ts->input_dev->evbit);
set_bit(EV_SYN, icn83xx_ts->input_dev->evbit);
set_bit(BTN_TOUCH, icn83xx_ts->input_dev->keybit);
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_TOUCH_MAJOR, 0, 8, 0, 0);
input_dev->name = CTP_NAME;
ret = input_register_device(input_dev);
if (ret) {
icn83xx_error("Register %s input device failed\n", input_dev->name);
input_free_device(input_dev);
return -ENODEV;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
icn83xx_trace("==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
return 0;
}
void inc83xx_ts_charger_mode()
{
icn83xx_write_reg(ICN83XX_REG_PMODE, 0x55);
}
EXPORT_SYMBOL_GPL(inc83xx_ts_charger_mode);
void inc83xx_ts_charger_mode_disable()
{
icn83xx_write_reg(ICN83XX_REG_PMODE, 0x66);
}
EXPORT_SYMBOL_GPL(inc83xx_ts_charger_mode_disable);
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;
short fwVersion = 0;
short curVersion = 0;
int average;
int err = 0;
char value;
int retry;
icn83xx_trace("====%s begin=====. \n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
icn83xx_error("I2C check functionality failed.\n");
return -ENODEV;
}
icn83xx_ts = kzalloc(sizeof(*icn83xx_ts), GFP_KERNEL);
if (!icn83xx_ts)
{
icn83xx_error("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;
spin_lock_init(&icn83xx_ts->irq_lock);
// icn83xx_ts->irq_lock = SPIN_LOCK_UNLOCKED;
icn83xx_ts_reset();
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) {
icn83xx_error("create_singlethread_workqueue failed.\n");
kfree(icn83xx_ts);
return -ESRCH;
}
err= icn83xx_request_input_dev(icn83xx_ts);
if (err < 0)
{
icn83xx_error("request input dev failed\n");
kfree(icn83xx_ts);
return err;
}
err = icn83xx_request_io_port(icn83xx_ts);
if (err != 0)
{
icn83xx_error("icn83xx_request_io_port failed.\n");
kfree(icn83xx_ts);
return err;
}
err = icn83xx_iic_test();
if (err < 0)
{
icn83xx_error("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;
icn83xx_trace("in prog mode\n");
while(retry > 0)
{
if(R_OK == icn83xx_fw_update(firmware))
{
break;
}
retry--;
icn83xx_error("icn83xx_fw_update failed.\n");
}
}
else //
{
icn83xx_error("I2C communication failed.\n");
kfree(icn83xx_ts);
return -1;
}
#endif
}
else
{
icn83xx_trace("iic communication ok\n");
}
#if SUPPORT_FW_UPDATE
fwVersion = icn83xx_read_fw_Ver(firmware);
curVersion = icn83xx_readVersion();
icn83xx_trace("fwVersion : 0x%x\n", fwVersion);
icn83xx_trace("current version: 0x%x\n", curVersion);
#if FORCE_UPDATA_FW
retry = 5;
while(retry > 0)
{
if(R_OK == icn83xx_fw_update(firmware))
{
break;
}
retry--;
icn83xx_error("icn83xx_fw_update failed.\n");
}
#else
if(fwVersion > curVersion)
{
retry = 5;
while(retry > 0)
{
if(R_OK == icn83xx_fw_update(firmware))
{
break;
}
retry--;
icn83xx_error("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]);
icn83xx_trace("average : %d\n", average);
icn83xx_setPeakGroup(250, 150);
icn83xx_setDownUp(400, 300);
}
#endif
#if TOUCH_VIRTUAL_KEYS
icn83xx_ts_virtual_keys_init();
#endif
err = icn83xx_request_irq(icn83xx_ts);
if (err != 0)
{
icn83xx_error("request irq error, use timer\n");
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);
}
#if SUPPORT_SYSFS
icn83xx_create_sysfs(client);
#endif
#if SUPPORT_PROC_FS
sema_init(&icn83xx_ts->sem, 1);
init_proc_node();
#endif
icn83xx_irq_enable();
/*
if(atc260x_get_charge_status() == 1)
{
printk("atc260x_get_charge_status====1\n");
inc83xx_ts_charger_mode();
}
else
{
inc83xx_ts_charger_mode_disable();
}
void callback(int status)
{
printk("CALLBACK TP %d !!!!!!!!!\n",status);
if(status ==1)
{
inc83xx_ts_charger_mode();
}
else
{
inc83xx_ts_charger_mode_disable();
}
}
atc260x_set_adjust_tp_para(callback);
*/
icn83xx_trace("==%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);
icn83xx_trace("==icn83xx_ts_remove=\n");
icn83xx_irq_disable();
gpio_direction_input(CTP_RST_PORT);
gpio_free(CTP_RST_PORT);
//free_irq(client->irq, icn83xx_ts);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&icn83xx_ts->early_suspend);
#endif
#if SUPPORT_PROC_FS
uninit_proc_node();
#endif
input_unregister_device(icn83xx_ts->input_dev);
input_free_device(icn83xx_ts->input_dev);
cancel_work_sync(&icn83xx_ts->pen_event_work);
destroy_workqueue(icn83xx_ts->ts_workqueue);
icn83xx_free_irq(icn83xx_ts);
icn83xx_free_io_port(icn83xx_ts);
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 = icn83xx_ts_suspend,
.resume = icn83xx_ts_resume,
#endif
.id_table = icn83xx_ts_id,
.driver = {
.name = CTP_NAME,
.owner = THIS_MODULE,
},
};
static struct i2c_board_info tp_info = {
.type = CTP_NAME,
.addr = 0x40,
};
////POWER
/*
static struct regulator *regulator_init(const char *name, int minvol, int maxvol)
{
struct regulator *power;
power = regulator_get(NULL,"sensor28");// name);
if (IS_ERR(power)) {
printk("Nova err,regulator_get fail\n!!!");
return NULL;
}
if (regulator_set_voltage(power, minvol, maxvol)) {
printk("Nova err,cannot set voltage\n!!!");
regulator_put(power);
return NULL;
}
regulator_enable(power);
return (power);
}
*/
static int icn83xx_hw_init(void)
{
int err = 0;
err = gpio_request(CTP_RST_PORT, "icn83xx_rest");
if ( err ) {
err = -EINVAL;
return err;
}
err = gpio_direction_output(CTP_RST_PORT, 1);
if ( err ) {
err = -EINVAL;
return err;
}
/*
tp_regulator = regulator_init(CTP_POWER_ID,
CTP_POWER_MIN_VOL, CTP_POWER_MAX_VOL);
if ( !tp_regulator ) {
printk(KERN_ERR "icn83xx tp init power failed");
err = -EINVAL;
return err;
}
*/
msleep(50);
gpio_set_value_cansleep(CTP_RST_PORT, 0);
msleep(100);
gpio_set_value_cansleep(CTP_RST_PORT, 1);
msleep(300);
return err;
}
static int __init icn83xx_ts_init(void)
{
int ret = -1;
icn83xx_trace("===========================%s=====================\n", __func__);
icn83xx_hw_init();
/*
struct i2c_adapter *adap = i2c_get_adapter(3);
printk(KERN_ERR "==icn83xx_init %d!!!!!!!!\n",__LINE__);
i2c_new_device(adap, &tp_info);
*/
ret = i2c_add_driver(&icn83xx_ts_driver);
return ret;
}
static void __exit icn83xx_ts_exit(void)
{
icn83xx_trace("==icn83xx_ts_exit==\n");
i2c_del_driver(&icn83xx_ts_driver);
}
module_init(icn83xx_ts_init);
module_exit(icn83xx_ts_exit);
MODULE_AUTHOR("<zmtian@chiponeic.com>");
MODULE_DESCRIPTION("Chipone icn83xx TouchScreen driver");
MODULE_LICENSE("GPL");