/*++ 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: icn85xx.c Abstract: input driver. Author: Zhimin Tian Date : 08,14,2013 Version: 1.0 History : 2012,10,30, V0.1 first version --*/ #include "icn85xx.h" #include "icn85xx_fw.h" //#include "icn85xx_00_ht_0528.h" //#include "icn85xx_02_lh_0528.h" #if COMPILE_FW_WITH_DRIVER static char firmware[128] = "icn85xx_firmware"; #else #if SUPPORT_SENSOR_ID static char firmware[128] = {0}; #else //static char firmware[128] = {"/misc/modules/ICN8505.BIN"}; //static char firmware[128] = {"/system/etc/firmware/ICN8505.bin"}; static char firmware[128] = {"ICN8505.bin"}; #endif #endif #if SUPPORT_SENSOR_ID char cursensor_id,tarsensor_id,id_match; char invalid_id = 0; struct sensor_id { char value; const char bin_name[128]; unsigned char *fw_name; int size; }; static struct sensor_id sensor_id_table[] = { { 0x00, "/misc/modules/ICN8505_00_name1.BIN",fw_00_ht_0528,sizeof(fw_00_ht_0528)},//default bin or fw { 0x02, "/misc/modules/ICN8505_02_name3.BIN",fw_02_lh_0528,sizeof(fw_02_lh_0528)}, // if you want support other sensor id value ,please add here }; #endif struct i2c_client *this_client; short log_basedata[COL_NUM][ROW_NUM] = {{0,0}}; short log_rawdata[COL_NUM][ROW_NUM] = {{0,0}}; short log_diffdata[COL_NUM][ROW_NUM] = {{0,0}}; unsigned int log_on_off = 0; static struct touch_param g_param; static struct wake_lock downloadWakeLock; static struct task_struct *resume_download_task; static int bl_is_delay = 0; extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); //yank added void icn85xx_charge_mode(void) { printk("yank---%s\n",__func__); icn85xx_write_reg(ICN85xx_REG_PMODE, 0x55); } EXPORT_SYMBOL(icn85xx_charge_mode); void icn85xx_discharge_mode(void) { printk("yank---%s\n",__func__); icn85xx_write_reg(ICN85xx_REG_PMODE, 0x66); } EXPORT_SYMBOL(icn85xx_discharge_mode); static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer); #if SUPPORT_SYSFS static ssize_t icn85xx_show_update(struct device* cd,struct device_attribute *attr, char* buf); static ssize_t icn85xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len); static ssize_t icn85xx_show_process(struct device* cd,struct device_attribute *attr, char* buf); static ssize_t icn85xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn85xx_show_update, icn85xx_store_update); static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn85xx_show_process, icn85xx_store_process); static ssize_t icn85xx_show_process(struct device* cd,struct device_attribute *attr, char* buf) { ssize_t ret = 0; sprintf(buf, "icn85xx process\n"); ret = strlen(buf) + 1; return ret; } static ssize_t icn85xx_store_process(struct device* cd, struct device_attribute *attr, const char* buf, size_t len) { struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); unsigned long on_off = simple_strtoul(buf, NULL, 10); log_on_off = on_off; memset(&log_basedata[0][0], 0, COL_NUM*ROW_NUM*2); if(on_off == 0) { icn85xx_ts->work_mode = 0; } else if((on_off == 1) || (on_off == 2) || (on_off == 3)) { if((icn85xx_ts->work_mode == 0) && (icn85xx_ts->use_irq == 1)) { hrtimer_init(&icn85xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); icn85xx_ts->timer.function = chipone_timer_func; hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); } icn85xx_ts->work_mode = on_off; } else if(on_off == 10) { icn85xx_ts->work_mode = 4; mdelay(10); printk("update baseline\n"); icn85xx_write_reg(4, 0x30); icn85xx_ts->work_mode = 0; } else { icn85xx_ts->work_mode = 0; } return len; } static ssize_t icn85xx_show_update(struct device* cd, struct device_attribute *attr, char* buf) { ssize_t ret = 0; sprintf(buf, firmware); ret = strlen(buf) + 1; printk("firmware: %s, ret: %d\n", firmware, ret); return ret; } static ssize_t icn85xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len) { printk("len: %d, update: %s\n", len, buf); memset(firmware, 0, 128); memcpy(firmware, buf, len-1); if(R_OK == icn85xx_fw_update(firmware)) { printk("update ok\n"); } else { printk("update error\n"); } return len; } static int icn85xx_create_sysfs(struct i2c_client *client) { int err; struct device *dev = &(client->dev); icn85xx_trace("%s: \n",__func__); err = device_create_file(dev, &dev_attr_update); err = device_create_file(dev, &dev_attr_process); return err; } static void icn85xx_remove_sysfs(struct i2c_client *client) { struct device *dev = &(client->dev); icn85xx_trace("%s: \n",__func__); device_remove_file(dev, &dev_attr_update); device_remove_file(dev, &dev_attr_process); } #endif #if SUPPORT_PROC_FS pack_head cmd_head; static struct proc_dir_entry *icn85xx_proc_entry; int DATA_LENGTH = 0; STRUCT_PANEL_PARA_H g_structPanelPara; static int icn85xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data) { int ret = 0; int i; unsigned short addr; char retvalue; struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); proc_info("%s \n",__func__); if(down_interruptible(&icn85xx_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 para { 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; } //need copy to g_structPanelPara memcpy(&g_structPanelPara, &cmd_head.data[0], cmd_head.data_len); //write para to tp for(i=0; i cmd_head.data_len)?(cmd_head.data_len-i):64; ret = icn85xx_i2c_txdata(0x8000+i, &cmd_head.data[i], size); if (ret < 0) { proc_error("write para failed!\n"); goto write_out; } i = i + 64; } ret = cmd_head.data_len + CMD_HEAD_LENGTH; icn85xx_ts->work_mode = 5; //reinit printk("reinit tp\n"); icn85xx_write_reg(0, 1); mdelay(100); icn85xx_write_reg(0, 0); icn85xx_ts->work_mode = 0; goto write_out; } else if(3 == cmd_head.wr) //set update file { proc_info("cmd_head_.wr == 3 \n"); 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) //start update { proc_info("cmd_head_.wr == 5 \n"); icn85xx_update_status(1); ret = kernel_thread(icn85xx_fw_update,firmware,CLONE_KERNEL); icn85xx_trace("the kernel_thread result is:%d\n", ret); } else if(11 == cmd_head.wr) //write hostcomm { 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; } addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0]; icn85xx_write_reg(addr, cmd_head.data[0]); } else if(13 == cmd_head.wr) //adc enable { proc_info("cmd_head_.wr == 13 \n"); icn85xx_ts->work_mode = 4; mdelay(10); //set col icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8ColNum), 1); //u8RXOrder[0] = u8RXOrder[cmd_head.addr[0]]; icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8RXOrder[0]), g_structPanelPara.u8RXOrder[cmd_head.addr[0]]); //set row icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8RowNum), 1); //u8TXOrder[0] = u8TXOrder[cmd_head.addr[1]]; icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8TXOrder[0]), g_structPanelPara.u8TXOrder[cmd_head.addr[1]]); //scan mode icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8ScanMode), 0); //bit icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16BitFreq), 0xD0); icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16BitFreq)+1, 0x07); //freq icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16FreqCycleNum[0]), 0x64); icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16FreqCycleNum[0])+1, 0x00); //pga icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8PgaGain), 0x0); //config mode icn85xx_write_reg(0, 0x2); mdelay(1); icn85xx_read_reg(2, &retvalue); printk("retvalue0: %d\n", retvalue); while(retvalue != 1) { printk("retvalue: %d\n", retvalue); mdelay(1); icn85xx_read_reg(2, &retvalue); } if(icn85xx_goto_progmode() != 0) { printk("icn85xx_goto_progmode() != 0 error\n"); goto write_out; } icn85xx_prog_write_reg(0x040870, 1); } write_out: up(&icn85xx_ts->sem); proc_info("icn85xx_tool_write write_out \n"); return len; } static int icn85xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ) { int i, j; int ret = 0; char row, column, retvalue; unsigned short addr; struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); if(down_interruptible(&icn85xx_ts->sem)) { return -1; } proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count,(int)off,(int)cmd_head.data_len); if (cmd_head.wr % 2) { ret = 0; proc_info("cmd_head_.wr == 1111111 \n"); goto read_out; } else if (0 == cmd_head.wr) //read para { //read para proc_info("cmd_head_.wr == 0 \n"); ret = icn85xx_i2c_rxdata(0x8000, &page[0], cmd_head.data_len); if (ret < 0) { icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); } memcpy(&g_structPanelPara, &page[0], sizeof(g_structPanelPara)); goto read_out; } else if(2 == cmd_head.wr) //get update status { proc_info("cmd_head_.wr == 2 \n"); page[0] = icn85xx_get_status(); proc_info("status: %d\n", page[0]); } else if(4 == cmd_head.wr) //read rawdata { //icn85xx_read_reg(0x8004, &row); //icn85xx_read_reg(0x8005, &column); proc_info("cmd_head_.wr == 4 \n"); row = cmd_head.addr[1]; column = cmd_head.addr[0]; //scan tp rawdata icn85xx_write_reg(4, 0x20); mdelay(1); for(i=0; i<1000; i++) { mdelay(1); icn85xx_read_reg(2, &retvalue); if(retvalue == 1) break; } for(i=0; iictype == ICN85XX_WITHOUT_FLASH) { if(R_OK == icn85xx_fw_update(firmware)) { icn85xx_ts->code_loaded_flag = 1; icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code ok\n"); } else { icn85xx_ts->code_loaded_flag = 0; icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code error\n"); } } else { icn85xx_bootfrom_flash(); msleep(50); } icn85xx_ts->work_mode = 0; } } else if(12 == cmd_head.wr) //read hostcomm { proc_info("cmd_head_.wr == 12 \n"); addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0]; icn85xx_read_reg(addr, &retvalue); page[0] = retvalue; } else if(14 == cmd_head.wr) //read adc status { proc_info("cmd_head_.wr == 14 \n"); icn85xx_prog_read_reg(0x4085E, &retvalue); page[0] = retvalue; printk("0x4085E: 0x%x\n", retvalue); } read_out: up(&icn85xx_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; } void init_proc_node(void) { 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; icn85xx_trace("alloc memory size:%d.\n", DATA_LENGTH); } else { proc_error("alloc for memory failed.\n"); return ; } icn85xx_proc_entry = create_proc_entry(ICN85xx_ENTRY_NAME, 0666, NULL); if (icn85xx_proc_entry == NULL) { proc_error("Couldn't create proc entry!\n"); return ; } else { icn85xx_trace("Create proc entry success!\n"); icn85xx_proc_entry->write_proc = icn85xx_tool_write; icn85xx_proc_entry->read_proc = icn85xx_tool_read; } return ; } void uninit_proc_node(void) { kfree(cmd_head.data); cmd_head.data = NULL; remove_proc_entry(ICN85xx_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 icn85xx_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 : icn85xx_ts_wakeup Input : void Output : ret function : this function is used to wakeup tp ***********************************************************************************************/ void icn85xx_ts_wakeup(void) { } /*********************************************************************************************** Name : icn85xx_ts_reset Input : void Output : ret function : this function is used to reset tp, you should not delete it ***********************************************************************************************/ void icn85xx_ts_reset(void) { //set reset func int rst = g_param.rstgpio; gpio_direction_output(rst,0); msleep(50); icn85xx_info("[%s]:>>>>>>>>>>>>>>>>>CTP_RST_PORT = %d;msleep(50);\n",__func__,gpio_get_value(rst)); gpio_direction_output(rst,1); msleep(70); icn85xx_info("[%s]:>>>>>>>>>>>>>>>>>CTP_RST_PORT = %d;msleep(70);\n",__func__,gpio_get_value(rst)); } /*********************************************************************************************** Name : icn85xx_irq_disable Input : void Output : ret function : this function is used to disable irq ***********************************************************************************************/ void icn85xx_irq_disable(void) { unsigned long irqflags; struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); spin_lock_irqsave(&icn85xx_ts->irq_lock, irqflags); if (!icn85xx_ts->irq_is_disable) { icn85xx_ts->irq_is_disable = 1; wmt_gpio_mask_irq(g_param.irqgpio); //disable_irq_nosync(icn85xx_ts->irq); //disable_irq(icn85xx_ts->irq); } spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags); } /*********************************************************************************************** Name : icn85xx_irq_enable Input : void Output : ret function : this function is used to enable irq ***********************************************************************************************/ void icn85xx_irq_enable(void) { unsigned long irqflags = 0; struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); spin_lock_irqsave(&icn85xx_ts->irq_lock, irqflags); if (icn85xx_ts->irq_is_disable) { wmt_gpio_unmask_irq(g_param.irqgpio); //enable_irq(icn85xx_ts->irq); icn85xx_ts->irq_is_disable = 0; } spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags); } /*********************************************************************************************** Name : icn85xx_prog_i2c_rxdata Input : addr *rxdata length Output : ret function : read data from icn85xx, prog mode ***********************************************************************************************/ int icn85xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length) { int ret = -1; int retries = 0; #if 0 struct i2c_msg msgs[] = { { .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, .flags = I2C_M_RD, .len = length, .buf = rxdata, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, }; icn85xx_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) { icn85xx_error("%s i2c read error: %d\n", __func__, ret); // icn85xx_ts_reset(); } #else unsigned char tmp_buf[3]; struct i2c_msg msgs[] = { { .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, .flags = 0, .len = 3, .buf = tmp_buf, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, { .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, .flags = I2C_M_RD, .len = length, .buf = rxdata, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, }; tmp_buf[0] = (unsigned char)(addr>>16); tmp_buf[1] = (unsigned char)(addr>>8); tmp_buf[2] = (unsigned char)(addr); while(retries < IIC_RETRY_NUM) { ret = i2c_transfer(this_client->adapter, msgs, 2); if(ret == 2)break; retries++; } if (retries >= IIC_RETRY_NUM) { icn85xx_error("%s i2c read error: %d\n", __func__, ret); // icn85xx_ts_reset(); } #endif return ret; } /*********************************************************************************************** Name : icn85xx_prog_i2c_txdata Input : addr *rxdata length Output : ret function : send data to icn85xx , prog mode ***********************************************************************************************/ int icn85xx_prog_i2c_txdata(unsigned int addr, char *txdata, int length) { int ret = -1; char tmp_buf[128]; int retries = 0; struct i2c_msg msg[] = { { .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, .flags = 0, .len = length + 3, .buf = tmp_buf, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, }; if (length > 125) { icn85xx_error("%s too big datalen = %d!\n", __func__, length); return -1; } tmp_buf[0] = (unsigned char)(addr>>16); tmp_buf[1] = (unsigned char)(addr>>8); tmp_buf[2] = (unsigned char)(addr); if (length != 0 && txdata != NULL) { memcpy(&tmp_buf[3], 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) { icn85xx_error("%s i2c write error: %d\n", __func__, ret); // icn85xx_ts_reset(); } return ret; } /*********************************************************************************************** Name : icn85xx_prog_write_reg Input : addr -- address para -- parameter Output : function : write register of icn85xx, prog mode ***********************************************************************************************/ int icn85xx_prog_write_reg(unsigned int addr, char para) { char buf[3]; int ret = -1; buf[0] = para; ret = icn85xx_prog_i2c_txdata(addr, buf, 1); if (ret < 0) { icn85xx_error("%s write reg failed! %#x ret: %d\n", __func__, buf[0], ret); return -1; } return ret; } /*********************************************************************************************** Name : icn85xx_prog_read_reg Input : addr pdata Output : function : read register of icn85xx, prog mode ***********************************************************************************************/ int icn85xx_prog_read_reg(unsigned int addr, char *pdata) { int ret = -1; ret = icn85xx_prog_i2c_rxdata(addr, pdata, 1); return ret; } /*********************************************************************************************** Name : icn85xx_i2c_rxdata Input : addr *rxdata length Output : ret function : read data from icn85xx, normal mode ***********************************************************************************************/ int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length) { int ret = -1; int retries = 0; unsigned char tmp_buf[2]; #if 0 struct i2c_msg msgs[] = { { .addr = this_client->addr, .flags = 0, .len = 2, .buf = tmp_buf, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, { .addr = this_client->addr, .flags = I2C_M_RD, .len = length, .buf = rxdata, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, }; tmp_buf[0] = (unsigned char)(addr>>8); tmp_buf[1] = (unsigned char)(addr); while(retries < IIC_RETRY_NUM) { ret = i2c_transfer(this_client->adapter, msgs, 2); if(ret == 2)break; retries++; } if (retries >= IIC_RETRY_NUM) { icn85xx_error("%s i2c read error: %d\n", __func__, ret); // icn85xx_ts_reset(); } #else tmp_buf[0] = (unsigned char)(addr>>8); tmp_buf[1] = (unsigned char)(addr); while(retries < IIC_RETRY_NUM) { // ret = i2c_transfer(this_client->adapter, msgs, 2); ret = i2c_master_send(this_client, tmp_buf, 2); if (ret < 0) return ret; ret = i2c_master_recv(this_client, rxdata, length); if (ret < 0) return ret; if(ret == length)break; retries++; } if (retries >= IIC_RETRY_NUM) { icn85xx_error("%s i2c read error: %d\n", __func__, ret); // icn85xx_ts_reset(); } #endif return ret; } /*********************************************************************************************** Name : icn85xx_i2c_txdata Input : addr *rxdata length Output : ret function : send data to icn85xx , normal mode ***********************************************************************************************/ int icn85xx_i2c_txdata(unsigned short 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 + 2, .buf = tmp_buf, #if SUPPORT_ROCKCHIP .scl_rate = ICN85XX_I2C_SCL, #endif }, }; if (length > 125) { icn85xx_error("%s too big datalen = %d!\n", __func__, length); return -1; } tmp_buf[0] = (unsigned char)(addr>>8); tmp_buf[1] = (unsigned char)(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) { icn85xx_error("%s i2c write error: %d\n", __func__, ret); // icn85xx_ts_reset(); } return ret; } /*********************************************************************************************** Name : icn85xx_write_reg Input : addr -- address para -- parameter Output : function : write register of icn85xx, normal mode ***********************************************************************************************/ int icn85xx_write_reg(unsigned short addr, char para) { char buf[3]; int ret = -1; buf[0] = para; ret = icn85xx_i2c_txdata(addr, buf, 1); if (ret < 0) { icn85xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); return -1; } return ret; } /*********************************************************************************************** Name : icn85xx_read_reg Input : addr pdata Output : function : read register of icn85xx, normal mode ***********************************************************************************************/ int icn85xx_read_reg(unsigned short addr, char *pdata) { int ret = -1; ret = icn85xx_i2c_rxdata(addr, pdata, 1); if(ret < 0) { icn85xx_error("addr: 0x%x: 0x%x\n", addr, *pdata); } return ret; } /*********************************************************************************************** Name : icn85xx_log Input : 0: rawdata, 1: diff data Output : err type function : calibrate param ***********************************************************************************************/ static void icn85xx_log(char diff) { char row = 0; char column = 0; int i, j, ret; char retvalue = 0; icn85xx_read_reg(0x8004, &row); icn85xx_read_reg(0x8005, &column); //scan tp rawdata icn85xx_write_reg(4, 0x20); mdelay(1); for(i=0; i<1000; i++) { mdelay(1); icn85xx_read_reg(2, &retvalue); if(retvalue == 1) break; } if(diff == 0) { for(i=0; iictype = 0; icn85xx_trace("====%s begin=====. \n", __func__); while(retry++ < 3) { ret = icn85xx_read_reg(0xa, &value); if(ret > 0) { if(value == 0x85) { icn85xx_ts->ictype = ICN85XX_WITH_FLASH; return ret; } } icn85xx_info("iic test error! retry = %d\n", retry); msleep(3); } icn85xx_goto_progmode(); msleep(10); retry = 0; while(retry++ < 3) { ret = icn85xx_prog_i2c_rxdata(0x040002, &value, 1); icn85xx_info("icn85xx_check_progmod: 0x%x\n", value); if(ret > 0) { if(value == 0x85) { flashid = icn85xx_read_flashid(); if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid) ||(MD25D20_ID1 == flashid) || (MD25D20_ID1 == flashid) ||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)) { icn85xx_ts->ictype = ICN85XX_WITH_FLASH; } else { icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH; } return ret; } } icn85xx_error("iic2 test error! %d\n", retry); msleep(3); } return ret; } #if !CTP_REPORT_PROTOCOL /*********************************************************************************************** Name : icn85xx_ts_release Input : void Output : function : touch release ***********************************************************************************************/ static void icn85xx_ts_release(void) { struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); icn85xx_info("==icn85xx_ts_release ==\n"); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); input_sync(icn85xx_ts->input_dev); } /*********************************************************************************************** Name : icn85xx_report_value_A Input : void Output : function : reprot touch ponit ***********************************************************************************************/ static void icn85xx_report_value_A(void) { struct icn85xx_ts_data *icn85xx_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 icn85xx_info("==icn85xx_report_value_A ==\n"); ret = icn85xx_i2c_rxdata(0x1000, buf, POINT_NUM*POINT_SIZE+2); if (ret < 0) { icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); return ; } #if TOUCH_VIRTUAL_KEYS button = buf[0]; icn85xx_info("%s: button=%d\n",__func__, button); if((button_last != 0) && (button == 0)) { icn85xx_ts_release(); button_last = button; return ; } if(button != 0) { switch(button) { case ICN_VIRTUAL_BUTTON_HOME: icn85xx_info("ICN_VIRTUAL_BUTTON_HOME down\n"); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 280); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); input_mt_sync(icn85xx_ts->input_dev); input_sync(icn85xx_ts->input_dev); break; case ICN_VIRTUAL_BUTTON_BACK: icn85xx_info("ICN_VIRTUAL_BUTTON_BACK down\n"); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 470); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); input_mt_sync(icn85xx_ts->input_dev); input_sync(icn85xx_ts->input_dev); break; case ICN_VIRTUAL_BUTTON_MENU: icn85xx_info("ICN_VIRTUAL_BUTTON_MENU down\n"); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 100); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); input_mt_sync(icn85xx_ts->input_dev); input_sync(icn85xx_ts->input_dev); break; default: icn85xx_info("other gesture\n"); break; } button_last = button; return ; } #endif icn85xx_ts->point_num = buf[1]; if (icn85xx_ts->point_num == 0) { icn85xx_ts_release(); return ; } for(i=0;ipoint_num;i++){ if(buf[8 + POINT_SIZE*i] != 4) { break ; } else { } } if(i == icn85xx_ts->point_num) { icn85xx_ts_release(); return ; } for(i=0; ipoint_num; i++) { icn85xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i]; icn85xx_ts->point_info[i].u16PosX = (buf[4 + POINT_SIZE*i]<<8) + buf[3 + POINT_SIZE*i]; icn85xx_ts->point_info[i].u16PosY = (buf[6 + POINT_SIZE*i]<<8) + buf[5 + POINT_SIZE*i]; icn85xx_ts->point_info[i].u8Pressure = 20;//buf[7 + POINT_SIZE*i]; icn85xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i]; if(1 == icn85xx_ts->revert_x_flag) { icn85xx_ts->point_info[i].u16PosX = icn85xx_ts->screen_max_x- icn85xx_ts->point_info[i].u16PosX; } if(1 == icn85xx_ts->revert_y_flag) { icn85xx_ts->point_info[i].u16PosY = icn85xx_ts->screen_max_y- icn85xx_ts->point_info[i].u16PosY; } icn85xx_info("u8ID %d\n", icn85xx_ts->point_info[i].u8ID); icn85xx_info("u16PosX %d\n", icn85xx_ts->point_info[i].u16PosX); icn85xx_info("u16PosY %d\n", icn85xx_ts->point_info[i].u16PosY); icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[i].u8Pressure); icn85xx_info("u8EventId %d\n", icn85xx_ts->point_info[i].u8EventId); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, icn85xx_ts->point_info[i].u8ID); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn85xx_ts->point_info[i].u8Pressure); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, icn85xx_ts->point_info[i].u16PosX); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, icn85xx_ts->point_info[i].u16PosY); input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); input_mt_sync(icn85xx_ts->input_dev); icn85xx_point_info("point: %d ===x = %d,y = %d, press = %d ====\n",i, icn85xx_ts->point_info[i].u16PosX,icn85xx_ts->point_info[i].u16PosY, icn85xx_ts->point_info[i].u8Pressure); } input_sync(icn85xx_ts->input_dev); } #endif /*********************************************************************************************** Name : icn85xx_report_value_B Input : void Output : function : reprot touch ponit ***********************************************************************************************/ #if CTP_REPORT_PROTOCOL static void icn85xx_report_value_B(void) { struct icn85xx_ts_data *icn85xx_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; int x,y; icn85xx_info("==icn85xx_report_value_B ==\n"); ret = icn85xx_i2c_rxdata(0x1000, buf, POINT_NUM*POINT_SIZE+2); if (ret < 0) { icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); return ; } icn85xx_ts->point_num = buf[1]; if (icn85xx_ts->point_num > POINT_NUM) { return ; } if(icn85xx_ts->point_num > 0) { for(position = 0; positionpoint_num; position++) { temp = buf[2 + POINT_SIZE*position] + 1; finger_current[temp] = 1; icn85xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position]; icn85xx_ts->point_info[temp].u16PosX = (buf[4 + POINT_SIZE*position]<<8) + buf[3 + POINT_SIZE*position]; icn85xx_ts->point_info[temp].u16PosY = (buf[6 + POINT_SIZE*position]<<8) + buf[5 + POINT_SIZE*position]; icn85xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position]; icn85xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position]; if(icn85xx_ts->point_info[temp].u8EventId == 4) finger_current[temp] = 0; if(1 == icn85xx_ts->revert_x_flag) { icn85xx_ts->point_info[temp].u16PosX = icn85xx_ts->screen_max_x- icn85xx_ts->point_info[temp].u16PosX; } if(1 == icn85xx_ts->revert_y_flag) { icn85xx_ts->point_info[temp].u16PosY = icn85xx_ts->screen_max_y- icn85xx_ts->point_info[temp].u16PosY; } icn85xx_info("temp %d\n", temp); icn85xx_info("u8ID %d\n", icn85xx_ts->point_info[temp].u8ID); icn85xx_info("u16PosX %d\n", icn85xx_ts->point_info[temp].u16PosX); icn85xx_info("u16PosY %d\n", icn85xx_ts->point_info[temp].u16PosY); icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure); icn85xx_info("u8EventId %d\n", icn85xx_ts->point_info[temp].u8EventId); //icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure*16); } } else { for(position = 1; position < POINT_NUM+1; position++) { finger_current[position] = 0; } icn85xx_info("no touch\n"); } for(position = 1; position < POINT_NUM + 1; position++) { if((finger_current[position] == 0) && (finger_last[position] != 0)) { input_mt_slot(icn85xx_ts->input_dev, position-1); input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, false); icn85xx_point_info("one touch up: %d\n", position); } else if(finger_current[position]) { if (g_param.xyswap == 0) { x = icn85xx_ts->point_info[position].u16PosX; y = icn85xx_ts->point_info[position].u16PosY; } else { y = icn85xx_ts->point_info[position].u16PosX; x = icn85xx_ts->point_info[position].u16PosY; } if (g_param.xdir == -1) { x = g_param.panelres_x - x; } if (g_param.ydir == -1) { y = g_param.panelres_y - y; } if (g_param.lcd_exchg) { int tmp; tmp = x; x = y; y = g_param.panelres_x - tmp; } input_mt_slot(icn85xx_ts->input_dev, position-1); input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, true); input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); //input_report_abs(icn85xx_ts->input_dev, ABS_MT_PRESSURE, icn85xx_ts->point_info[position].u8Pressure); input_report_abs(icn85xx_ts->input_dev, ABS_MT_PRESSURE, 200); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, x); input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, y); //icn85xx_point_info("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn85xx_ts->point_info[position].u16PosX,icn85xx_ts->point_info[position].u16PosY, icn85xx_ts->point_info[position].u8Pressure); icn85xx_point_info("raw%d(%d,%d), rpt%d(%d,%d)\n", position, icn85xx_ts->point_info[position].u16PosX, icn85xx_ts->point_info[position].u16PosY, position, x, y); } } input_sync(icn85xx_ts->input_dev); for(position = 1; position < POINT_NUM + 1; position++) { finger_last[position] = finger_current[position]; } } #endif /*********************************************************************************************** Name : icn85xx_ts_pen_irq_work Input : void Output : function : work_struct ***********************************************************************************************/ static void icn85xx_ts_pen_irq_work(struct work_struct *work) { struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); #if SUPPORT_PROC_FS if(down_interruptible(&icn85xx_ts->sem)) { return ; } #endif if(icn85xx_ts->work_mode == 0) { #if CTP_REPORT_PROTOCOL icn85xx_report_value_B(); #else icn85xx_report_value_A(); #endif if(icn85xx_ts->use_irq) { icn85xx_irq_enable(); } if(log_on_off == 4) { printk("normal raw data\n"); icn85xx_log(0); //raw data } else if(log_on_off == 5) { printk("normal diff data\n"); icn85xx_log(1); //diff data } else if(log_on_off == 6) { printk("normal raw2diff\n"); icn85xx_log(2); //diff data } } else if(icn85xx_ts->work_mode == 1) { printk("raw data\n"); icn85xx_log(0); //raw data } else if(icn85xx_ts->work_mode == 2) { printk("diff data\n"); icn85xx_log(1); //diff data } else if(icn85xx_ts->work_mode == 3) { printk("raw2diff data\n"); icn85xx_log(2); //diff data } else if(icn85xx_ts->work_mode == 4) //idle { ; } else if(icn85xx_ts->work_mode == 5)//write para, reinit { printk("reinit tp\n"); icn85xx_write_reg(0, 1); mdelay(100); icn85xx_write_reg(0, 0); icn85xx_ts->work_mode = 0; } #if SUPPORT_PROC_FS up(&icn85xx_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 icn85xx_ts_data *icn85xx_ts = container_of(timer, struct icn85xx_ts_data, timer); queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); //icn85xx_info("chipone_timer_func\n"); if(icn85xx_ts->use_irq == 1) { if((icn85xx_ts->work_mode == 1) || (icn85xx_ts->work_mode == 2) || (icn85xx_ts->work_mode == 3)) { hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); } } else { hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); } return HRTIMER_NORESTART; } /*********************************************************************************************** Name : icn85xx_ts_interrupt Input : void Output : function : interrupt service routine ***********************************************************************************************/ static irqreturn_t icn85xx_ts_interrupt(int irq, void *dev_id) { struct icn85xx_ts_data *icn85xx_ts = dev_id; int irqindex = g_param.irqgpio; icn85xx_info("==========------icn85xx_ts TS Interrupt-----============\n"); if (gpio_irqstatus(irqindex)) { wmt_gpio_ack_irq(irqindex); if (is_gpio_irqenable(irqindex)) { icn85xx_irq_disable(); if(icn85xx_ts->work_mode != 0) { icn85xx_irq_enable(); return IRQ_HANDLED; } if (!work_pending(&icn85xx_ts->pen_event_work)) { icn85xx_info("Enter work\n"); queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); } } return IRQ_HANDLED; } return IRQ_NONE; /*if(icn85xx_ts->use_irq) icn85xx_irq_disable(); if (!work_pending(&icn85xx_ts->pen_event_work)) { queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); } return IRQ_HANDLED;*/ } /*********************************************************************************************** Name : icn85xx_ts_suspend Input : void Output : function : tp enter sleep mode ***********************************************************************************************/ static int icn85xx_ts_suspend(struct i2c_client *client, pm_message_t mesg) { struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); icn85xx_trace("icn85xx_ts_suspend\n"); if (icn85xx_ts->use_irq) { icn85xx_irq_disable(); } else { hrtimer_cancel(&icn85xx_ts->timer); } cancel_work_sync(&icn85xx_ts->pen_event_work); flush_workqueue(icn85xx_ts->ts_workqueue); //} //reset flag if ic is flashless when power off if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) { //icn85xx_ts->code_loaded_flag = 0; } #if SUSPEND_POWER_OFF #else icn85xx_write_reg(ICN85xx_REG_PMODE, PMODE_HIBERNATE); #endif return 0; } int resume_download_thread(void *arg) { int retry = 1; int need_update_fw = false; int ret = -1; unsigned char value; struct icn85xx_ts_data *icn85xx_ts = (struct icn85xx_ts_data*)arg; wake_lock(&downloadWakeLock); while (retry-- && !need_update_fw) { icn85xx_ts_reset(); icn85xx_bootfrom_sram(); msleep(50); ret = icn85xx_read_reg(0xa, &value); if (ret > 0) { need_update_fw = false; break; } } if (retry < 0) need_update_fw = true; if (need_update_fw) { if(R_OK == icn85xx_fw_update(firmware)) { icn85xx_ts->code_loaded_flag = 1; icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code ok\n"); } else { icn85xx_ts->code_loaded_flag = 0; icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code error\n"); } } if (icn85xx_ts->use_irq) { icn85xx_irq_enable(); } else { hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, \ (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); } wake_unlock(&downloadWakeLock); return 0; } /*********************************************************************************************** Name : icn85xx_ts_resume Input : void Output : function : wakeup tp or reset tp ***********************************************************************************************/ static int icn85xx_ts_resume(struct i2c_client *client) { struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); int i; icn85xx_trace("==icn85xx_ts_resume== \n"); //report touch release #if CTP_REPORT_PROTOCOL for(i = 0; i < POINT_NUM; i++) { input_mt_slot(icn85xx_ts->input_dev, i); input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, false); } #else icn85xx_ts_release(); #endif if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) { if (bl_is_delay) { resume_download_task = kthread_create(resume_download_thread, icn85xx_ts, "resume_download"); if(IS_ERR(resume_download_task)) { icn85xx_error("cread thread failed\n"); } wake_up_process(resume_download_task); } else resume_download_thread(icn85xx_ts); } else { icn85xx_write_reg(ICN85xx_REG_PMODE, 0xff); icn85xx_ts_reset(); if (icn85xx_ts->use_irq) { icn85xx_irq_enable(); } else { hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, \ (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); } } // icn85xx_write_reg(ICN85xx_REG_PMODE, 0x00); return 0; } /*********************************************************************************************** Name : icn85xx_request_io_port Input : void Output : function : 0 success, ***********************************************************************************************/ static int icn85xx_request_io_port(struct icn85xx_ts_data *icn85xx_ts) { #if SUPPORT_ROCKCHIP icn85xx_ts->screen_max_x = SCREEN_MAX_X; icn85xx_ts->screen_max_y = SCREEN_MAX_Y; icn85xx_ts->irq = CTP_IRQ_PORT; //maybe need changed #endif icn85xx_ts->irq = IRQ_GPIO; if (gpio_request(g_param.rstgpio, "ts_rst") < 0) { printk("gpio(%d) touchscreen reset request fail\n", g_param.rstgpio); return -EIO; } gpio_direction_output(g_param.rstgpio, 1); if (gpio_request(g_param.irqgpio, "ts_irq") < 0) { printk("gpio(%d) touchscreen interrupt request fail\n", g_param.irqgpio); gpio_free(g_param.rstgpio); return -EIO; } wmt_gpio_setpull(g_param.irqgpio, WMT_GPIO_PULL_UP); gpio_direction_input(g_param.irqgpio); return 0; } /*********************************************************************************************** Name : icn85xx_free_io_port Input : void Output : function : 0 success, ***********************************************************************************************/ static void icn85xx_free_io_port(void) { gpio_free(g_param.rstgpio); gpio_free(g_param.irqgpio); return; } /*********************************************************************************************** Name : icn85xx_request_irq Input : void Output : function : 0 success, ***********************************************************************************************/ static int icn85xx_request_irq(struct icn85xx_ts_data *icn85xx_ts) { int err = -1; wmt_gpio_set_irq_type(g_param.irqgpio, IRQ_TYPE_EDGE_FALLING); err = request_irq(icn85xx_ts->irq, icn85xx_ts_interrupt, IRQF_SHARED, "icn85xx_ts", icn85xx_ts); if (err < 0) { icn85xx_error("icn85xx_ts_probe: request irq failed\n"); return err; } else { icn85xx_irq_disable(); icn85xx_ts->use_irq = 1; } #if SUPPORT_ROCKCHIP err = gpio_request(icn85xx_ts->irq, "TS_INT"); //Request IO if (err < 0) { icn85xx_error("Failed to request GPIO:%d, ERRNO:%d\n", (int)icn85xx_ts->irq, err); return err; } gpio_direction_input(icn85xx_ts->irq); err = request_irq(icn85xx_ts->irq, icn85xx_ts_interrupt, IRQ_TYPE_EDGE_FALLING, "icn85xx_ts", icn85xx_ts); if (err < 0) { icn85xx_ts->use_irq = 0; icn85xx_error("icn85xx_ts_probe: request irq failed\n"); return err; } else { icn85xx_irq_disable(); icn85xx_ts->use_irq = 1; } #endif return 0; } /*********************************************************************************************** Name : icn85xx_free_irq Input : void Output : function : 0 success, ***********************************************************************************************/ static void icn85xx_free_irq(struct icn85xx_ts_data *icn85xx_ts) { if (icn85xx_ts) { if (icn85xx_ts->use_irq) { free_irq(icn85xx_ts->irq, icn85xx_ts); } else { hrtimer_cancel(&icn85xx_ts->timer); } } } /*********************************************************************************************** Name : icn85xx_request_input_dev Input : void Output : function : 0 success, ***********************************************************************************************/ static int icn85xx_request_input_dev(struct icn85xx_ts_data *icn85xx_ts) { int ret = -1; struct input_dev *input_dev; input_dev = input_allocate_device(); if (!input_dev) { icn85xx_error("failed to allocate input device\n"); return -ENOMEM; } icn85xx_ts->input_dev = input_dev; icn85xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; #if CTP_REPORT_PROTOCOL __set_bit(INPUT_PROP_DIRECT, icn85xx_ts->input_dev->propbit); input_mt_init_slots(icn85xx_ts->input_dev, POINT_NUM*2); #else set_bit(ABS_MT_TOUCH_MAJOR, icn85xx_ts->input_dev->absbit); set_bit(ABS_MT_POSITION_X, icn85xx_ts->input_dev->absbit); set_bit(ABS_MT_POSITION_Y, icn85xx_ts->input_dev->absbit); set_bit(ABS_MT_WIDTH_MAJOR, icn85xx_ts->input_dev->absbit); #endif if (g_param.lcd_exchg) { input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_y, 0, 0); input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_x, 0, 0); } else { input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_x, 0, 0); input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_y, 0, 0); } input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, POINT_NUM*2, 0, 0); __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) { icn85xx_error("Register %s input device failed\n", input_dev->name); input_free_device(input_dev); return -ENODEV; } #ifdef CONFIG_HAS_EARLYSUSPEND icn85xx_trace("==register_early_suspend =\n"); icn85xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; icn85xx_ts->early_suspend.suspend = icn85xx_ts_suspend; icn85xx_ts->early_suspend.resume = icn85xx_ts_resume; register_early_suspend(&icn85xx_ts->early_suspend); #endif return 0; } #if SUPPORT_SENSOR_ID static void read_sensor_id(void) { int i,ret; //icn85xx_trace("scan sensor id value begin sensor_id_num = %d\n",(sizeof(sensor_id_table)/sizeof(sensor_id_table[0]))); ret = icn85xx_read_reg(0x10, &cursensor_id); if(ret > 0) { icn85xx_trace("cursensor_id= 0x%x\n", cursensor_id); } else { icn85xx_error("icn85xx read cursensor_id failed.\n"); cursensor_id = -1; } ret = icn85xx_read_reg(0x1e, &tarsensor_id); if(ret > 0) { icn85xx_trace("tarsensor_id= 0x%x\n", tarsensor_id); tarsensor_id = -1; } else { icn85xx_error("icn85xx read tarsensor_id failed.\n"); } ret = icn85xx_read_reg(0x1f, &id_match); if(ret > 0) { icn85xx_trace("match_flag= 0x%x\n", id_match); // 1: match; 0:not match } else { icn85xx_error("icn85xx read id_match failed.\n"); id_match = -1; } // scan sensor id value icn85xx_trace("begin to scan id table,find correct fw or bin. sensor_id_num = %d\n",(sizeof(sensor_id_table)/sizeof(sensor_id_table[0]))); for(i = 0;i < (sizeof(sensor_id_table)/sizeof(sensor_id_table[0])); i++) // not change tp { if (cursensor_id == sensor_id_table[i].value) { #if COMPILE_FW_WITH_DRIVER icn85xx_set_fw(sensor_id_table[i].size, sensor_id_table[i].fw_name); #else strcpy(firmware,sensor_id_table[i].bin_name); icn85xx_trace("icn85xx matched firmware = %s\n", firmware); #endif icn85xx_trace("icn85xx matched id = 0x%x\n", sensor_id_table[i].value); invalid_id = 1; break; } else { invalid_id = 0; icn85xx_trace("icn85xx not matched id%d= 0x%x\n", i,sensor_id_table[i].value); //icn85xx_trace("not match sensor_id_table[%d].value= 0x%x,bin_name = %s\n",i,sensor_id_table[i].value,sensor_id_table[i].bin_name); } } } static void compare_sensor_id(void) { int retry = 5; read_sensor_id(); // select sensor id if(0 == invalid_id) //not compare sensor id,update default fw or bin { icn85xx_trace("not compare sensor id table,update default: invalid_id= %d, cursensor_id= %d\n", invalid_id,cursensor_id); #if COMPILE_FW_WITH_DRIVER icn85xx_set_fw(sensor_id_table[0].size, sensor_id_table[0].fw_name); #else strcpy(firmware,sensor_id_table[0].bin_name); icn85xx_trace("match default firmware = %s\n", firmware); #endif while(retry > 0) { if(R_OK == icn85xx_fw_update(firmware)) { icn85xx_trace("icn85xx upgrade default firmware ok\n"); break; } retry--; icn85xx_error("icn85xx_fw_update default firmware failed.\n"); } } if ((1 == invalid_id)&&(0 == id_match)) // tp is changed,update current fw or bin { icn85xx_trace("icn85xx detect tp is changed!!! invalid_id= %d,id_match= %d,\n", invalid_id,id_match); while(retry > 0) { if(R_OK == icn85xx_fw_update(firmware)) { icn85xx_trace("icn85xx upgrade cursensor id firmware ok\n"); break; } retry--; icn85xx_error("icn85xx_fw_update current id firmware failed.\n"); } } } #endif static void icn85xx_update(struct icn85xx_ts_data *icn85xx_ts) { short fwVersion = 0; short curVersion = 0; int retry = 0; if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) { #if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID) icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]); #endif #if SUPPORT_SENSOR_ID while(0 == invalid_id ) //reselect sensor id { compare_sensor_id(); // select sensor id icn85xx_trace("invalid_id= %d\n", invalid_id); } #else if(R_OK == icn85xx_fw_update(firmware)) { icn85xx_ts->code_loaded_flag = 1; icn85xx_trace("ICN85XX_WITHOUT_FLASH, update default fw ok\n"); } else { icn85xx_ts->code_loaded_flag = 0; icn85xx_trace("ICN85XX_WITHOUT_FLASH, update error\n"); } #endif } else if(icn85xx_ts->ictype == ICN85XX_WITH_FLASH) { #if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID) icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]); #endif #if SUPPORT_SENSOR_ID while(0 == invalid_id ) //reselect sensor id { compare_sensor_id(); // select sensor id if( 1 == invalid_id) { icn85xx_trace("select sensor id ok. begin compare fwVersion with curversion\n"); } } #endif fwVersion = icn85xx_read_fw_Ver(firmware); curVersion = icn85xx_readVersion(); icn85xx_trace("fwVersion : 0x%x\n", fwVersion); icn85xx_trace("current version: 0x%x\n", curVersion); #if FORCE_UPDATA_FW retry = 5; while(retry > 0) { if(icn85xx_goto_progmode() != 0) { printk("icn85xx_goto_progmode() != 0 error\n"); return -1; } icn85xx_read_flashid(); if(R_OK == icn85xx_fw_update(firmware)) { break; } retry--; icn85xx_error("icn85xx_fw_update failed.\n"); } #else if(fwVersion > curVersion) { retry = 5; while(retry > 0) { if(R_OK == icn85xx_fw_update(firmware)) { break; } retry--; icn85xx_error("icn85xx_fw_update failed.\n"); } } #endif } } static int icn85xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct icn85xx_ts_data *icn85xx_ts; int err = 0; icn85xx_trace("====%s begin=====. \n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { icn85xx_error("I2C check functionality failed.\n"); return -ENODEV; } icn85xx_ts = kzalloc(sizeof(*icn85xx_ts), GFP_KERNEL); if (!icn85xx_ts) { icn85xx_error("Alloc icn85xx_ts memory failed.\n"); return -ENOMEM; } memset(icn85xx_ts, 0, sizeof(*icn85xx_ts)); this_client = client; this_client->addr = client->addr; i2c_set_clientdata(client, icn85xx_ts); icn85xx_ts->work_mode = 0; spin_lock_init(&icn85xx_ts->irq_lock); // icn85xx_ts->irq_lock = SPIN_LOCK_UNLOCKED; icn85xx_request_io_port(icn85xx_ts); if (err != 0) { icn85xx_error("icn85xx_request_io_port failed.\n"); goto fail1; } memset(firmware, 0, 128); sprintf(firmware,"%s.bin",g_param.fw_name); icn85xx_ts_reset(); err = icn85xx_iic_test(); if (err <= 0) { icn85xx_error("icn85xx_iic_test failed.\n"); goto fail2; } else { icn85xx_trace("iic communication ok: 0x%x\n", icn85xx_ts->ictype); } icn85xx_update(icn85xx_ts); err= icn85xx_request_input_dev(icn85xx_ts); if (err < 0) { icn85xx_error("request input dev failed\n"); goto fail3; } #if TOUCH_VIRTUAL_KEYS icn85xx_ts_virtual_keys_init(); #endif err = icn85xx_request_irq(icn85xx_ts); if (err != 0) { icn85xx_error("request irq error, use timer\n"); icn85xx_ts->use_irq = 0; hrtimer_init(&icn85xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); icn85xx_ts->timer.function = chipone_timer_func; hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); } #if SUPPORT_SYSFS icn85xx_create_sysfs(client); #endif #if SUPPORT_PROC_FS sema_init(&icn85xx_ts->sem, 1); init_proc_node(); #endif INIT_WORK(&icn85xx_ts->pen_event_work, icn85xx_ts_pen_irq_work); icn85xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev)); if (!icn85xx_ts->ts_workqueue) { icn85xx_error("create_singlethread_workqueue failed.\n"); err = -ESRCH; goto fail4; } if(icn85xx_ts->use_irq) icn85xx_irq_enable(); icn85xx_trace("==%s over =\n", __func__); return 0; fail4: cancel_work_sync(&icn85xx_ts->pen_event_work); fail3: input_unregister_device(icn85xx_ts->input_dev); input_free_device(icn85xx_ts->input_dev); fail2: icn85xx_free_io_port(); fail1: kfree(icn85xx_ts); icn85xx_free_fw(); return err; } static int __devexit icn85xx_ts_remove(struct i2c_client *client) { struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); icn85xx_trace("==icn85xx_ts_remove=\n"); if(icn85xx_ts->use_irq) icn85xx_irq_disable(); #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&icn85xx_ts->early_suspend); #endif #if SUPPORT_PROC_FS uninit_proc_node(); #endif #if SUPPORT_SYSFS icn85xx_remove_sysfs(client); #endif input_unregister_device(icn85xx_ts->input_dev); input_free_device(icn85xx_ts->input_dev); cancel_work_sync(&icn85xx_ts->pen_event_work); destroy_workqueue(icn85xx_ts->ts_workqueue); icn85xx_free_irq(icn85xx_ts); icn85xx_free_io_port(); icn85xx_free_fw(); kfree(icn85xx_ts); i2c_set_clientdata(client, NULL); return 0; } static int wmt_check_touch_env(void) { int ret = 0; int len = 96; char retval[200] = {0},*p=NULL,*s=NULL; int Enable=0; ret = wmt_getsyspara("wmt.io.touch", retval, &len); if(ret){ printk("Read wmt.io.touch Failed.\n"); return -EIO; } //paste: p = retval; Enable = (p[0] - '0' == 1) ? 1 : 0; if(Enable == 0){ printk("Touch Screen Is Disabled.\n"); return -ENODEV; } p = strchr(p,':');p++; s = strchr(p,':'); strncpy(g_param.fw_name,p, (s-p)); printk("ts_name=%s\n", g_param.fw_name); if (strncmp(g_param.fw_name, "ICN85", 5)) { printk("Wrong firmware name.\n"); return -ENODEV; } p = s+1; ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d", &(g_param.irqgpio),&(g_param.panelres_x),&(g_param.panelres_y),&(g_param.rstgpio), &(g_param.xyswap),&(g_param.xdir),&(g_param.ydir)); if (ret < 7) { printk("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); return -ENODEV; } printk("p.x = %d, p.y = %d, irqgpio=%d, rstgpio=%d,xyswap=%d,xdir=%d,ydir=%d\n", g_param.panelres_x,g_param.panelres_y,g_param.irqgpio,g_param.rstgpio, g_param.xyswap,g_param.xdir,g_param.ydir); /*memset(retval,0,sizeof(retval)); ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); if(!ret) g_param.earlysus_en = (retval[0] - '0' == 1) ? 1 : 0;*/ memset(retval,0,sizeof(retval)); ret = wmt_getsyspara("wmt.display.fb0", retval, &len); if (!ret) { int tmp[6]; p = retval; sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); if (tmp[4] > tmp[5]) g_param.lcd_exchg = 1; } ret = wmt_getsyspara("wmt.backlight.delay", retval, &len); if(ret) { bl_is_delay = 0; } else bl_is_delay = 1; return 0; } static const struct i2c_device_id icn85xx_ts_id[] = { { CTP_NAME, 0 }, {} }; MODULE_DEVICE_TABLE(i2c, icn85xx_ts_id); static struct i2c_driver icn85xx_ts_driver = { .probe = icn85xx_ts_probe, .remove = __devexit_p(icn85xx_ts_remove), #ifndef CONFIG_HAS_EARLYSUSPEND .suspend = icn85xx_ts_suspend, .resume = icn85xx_ts_resume, #endif .id_table = icn85xx_ts_id, .driver = { .name = CTP_NAME, .owner = THIS_MODULE, }, }; static struct i2c_board_info i2c_board_info = { I2C_BOARD_INFO(CTP_NAME, ICN85XX_IIC_ADDR), }; static int __init icn85xx_ts_init(void) { struct i2c_client *client; struct i2c_adapter *adap; icn85xx_trace("===========================%s=====================\n", __func__); if(wmt_check_touch_env()) return -ENODEV; {//register i2c device adap = i2c_get_adapter(1); //i2c Bus 1 if (!adap) return -ENODEV; client = i2c_new_device(adap, &i2c_board_info); i2c_put_adapter(adap); if (!client) { printk("i2c_new_device error\n"); return -ENODEV; } } return i2c_add_driver(&icn85xx_ts_driver); } static void __exit icn85xx_ts_exit(void) { icn85xx_trace("==icn85xx_ts_exit==\n"); i2c_unregister_device(this_client); i2c_del_driver(&icn85xx_ts_driver); } late_initcall(icn85xx_ts_init); //module_init(icn85xx_ts_init); module_exit(icn85xx_ts_exit); MODULE_AUTHOR(""); MODULE_DESCRIPTION("Chipone icn85xx TouchScreen driver"); MODULE_LICENSE("GPL");