Files

4208 lines
116 KiB
C
Executable File

/*
* drivers/input/touchscreen/ak37d_icn85xx.c
*
* Copyright (c) 2019 Zhipeng Zhang <zhangzhipeng@anyka.com>
* Copyright (c) 2019 Anyka Technology (Guangzhou) Co., Ltd.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/hrtimer.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/kthread.h>
#include "ts_icn85xx.h"
#define DRIVER_VERSION "1.0.0"
static struct file *fp;
static int g_status = R_OK;
static char fw_mode = 0;
static int fw_size = 0;
static unsigned char *fw_buf;
static char boot_mode = ICN85XX_WITHOUT_FLASH_87;
unsigned short icnt87_sram_crc = 0;
unsigned short icnt87_sram_length = 0;
void setbootmode(char bmode)
{
boot_mode= bmode;
}
unsigned short const Crc16Table[]= {
0x0000,0x8005,0x800F,0x000A,0x801B,0x001E,0x0014,0x8011,0x8033,0x0036,0x003C,0x8039,0x0028,0x802D,0x8027,0x0022,
0x8063,0x0066,0x006C,0x8069,0x0078,0x807D,0x8077,0x0072,0x0050,0x8055,0x805F,0x005A,0x804B,0x004E,0x0044,0x8041,
0x80C3,0x00C6,0x00CC,0x80C9,0x00D8,0x80DD,0x80D7,0x00D2,0x00F0,0x80F5,0x80FF,0x00FA,0x80EB,0x00EE,0x00E4,0x80E1,
0x00A0,0x80A5,0x80AF,0x00AA,0x80BB,0x00BE,0x00B4,0x80B1,0x8093,0x0096,0x009C,0x8099,0x0088,0x808D,0x8087,0x0082,
0x8183,0x0186,0x018C,0x8189,0x0198,0x819D,0x8197,0x0192,0x01B0,0x81B5,0x81BF,0x01BA,0x81AB,0x01AE,0x01A4,0x81A1,
0x01E0,0x81E5,0x81EF,0x01EA,0x81FB,0x01FE,0x01F4,0x81F1,0x81D3,0x01D6,0x01DC,0x81D9,0x01C8,0x81CD,0x81C7,0x01C2,
0x0140,0x8145,0x814F,0x014A,0x815B,0x015E,0x0154,0x8151,0x8173,0x0176,0x017C,0x8179,0x0168,0x816D,0x8167,0x0162,
0x8123,0x0126,0x012C,0x8129,0x0138,0x813D,0x8137,0x0132,0x0110,0x8115,0x811F,0x011A,0x810B,0x010E,0x0104,0x8101,
0x8303,0x0306,0x030C,0x8309,0x0318,0x831D,0x8317,0x0312,0x0330,0x8335,0x833F,0x033A,0x832B,0x032E,0x0324,0x8321,
0x0360,0x8365,0x836F,0x036A,0x837B,0x037E,0x0374,0x8371,0x8353,0x0356,0x035C,0x8359,0x0348,0x834D,0x8347,0x0342,
0x03C0,0x83C5,0x83CF,0x03CA,0x83DB,0x03DE,0x03D4,0x83D1,0x83F3,0x03F6,0x03FC,0x83F9,0x03E8,0x83ED,0x83E7,0x03E2,
0x83A3,0x03A6,0x03AC,0x83A9,0x03B8,0x83BD,0x83B7,0x03B2,0x0390,0x8395,0x839F,0x039A,0x838B,0x038E,0x0384,0x8381,
0x0280,0x8285,0x828F,0x028A,0x829B,0x029E,0x0294,0x8291,0x82B3,0x02B6,0x02BC,0x82B9,0x02A8,0x82AD,0x82A7,0x02A2,
0x82E3,0x02E6,0x02EC,0x82E9,0x02F8,0x82FD,0x82F7,0x02F2,0x02D0,0x82D5,0x82DF,0x02DA,0x82CB,0x02CE,0x02C4,0x82C1,
0x8243,0x0246,0x024C,0x8249,0x0258,0x825D,0x8257,0x0252,0x0270,0x8275,0x827F,0x027A,0x826B,0x026E,0x0264,0x8261,
0x0220,0x8225,0x822F,0x022A,0x823B,0x023E,0x0234,0x8231,0x8213,0x0216,0x021C,0x8219,0x0208,0x820D,0x8207,0x0202,
};
void icn85xx_rawdatadump(short *mem, int size, char br)
{
int i;
for(i=0;i<size; i++)
{
if((i!=0)&&(i%br == 0))
printk("\n");
printk(" %5d", mem[i]);
}
printk("\n");
}
void icn85xx_memdump(char *mem, int size)
{
int i;
for(i=0;i<size; i++)
{
if(i%16 == 0)
printk("\n");
printk(" 0x%2x", mem[i]);
}
printk("\n");
}
int icn85xx_checksum(int sum, char *buf, unsigned int size)
{
int i;
for(i=0; i<size; i++)
{
sum = sum + buf[i];
}
return sum;
}
int icn85xx_update_status(int status)
{
g_status = status;
return 0;
}
int icn85xx_get_status(void)
{
return g_status;
}
void icn85xx_set_fw(int size, unsigned char *buf)
{
fw_size = size;
fw_buf = buf;
}
int icn85xx_open_fw( char *fw)
{
int file_size;
mm_segment_t fs;
struct inode *inode = NULL;
if(strcmp(fw, "icn85xx_firmware") == 0)
{
fw_mode = 1; //use inner array
return fw_size;
}
else
{
fw_mode = 0; //use file in file system
}
fp = filp_open(fw, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("read fw file error\n");
return -1;
}
else
pr_info("open fw file ok\n");
//inode = fp->f_dentry->d_inode;
inode = file_inode(fp);
file_size = inode->i_size;
fs = get_fs();
set_fs(KERNEL_DS);
return file_size;
}
int icn85xx_read_fw(int offset, int length, char *buf)
{
loff_t pos = offset;
if(fw_mode == 1)
{
memcpy(buf, fw_buf+offset, length);
}
else
{
vfs_read(fp, buf, length, &pos);
}
return 0;
}
int icn85xx_close_fw(void)
{
if(fw_mode == 0)
{
filp_close(fp, NULL);
}
return 0;
}
int icn85xx_readVersion(void)
{
int err = 0;
char tmp[2];
short CurVersion;
err = icn85xx_i2c_rxdata(0x000c, tmp, 2);
if (err < 0) {
pr_err("%s failed: %d\n", __func__, err);
return 0;
}
CurVersion = (tmp[0]<<8) | tmp[1];
return CurVersion;
}
int icn85xx_goto_progmode(void)
{
int ret = -1;
int retry = 3;
unsigned char ucTemp;
while(retry > 0)
{
icn85xx_set_prog_addr();
ucTemp = 0x5a;
ret = icn85xx_prog_i2c_txdata(0xcc3355, &ucTemp,1);
if( ret < 0)
{
retry -- ;
mdelay(2);
}
else
break;
}
pr_info("icn85xx_goto_progmode over, ret: %d\n", ret);
if(retry == 0)
return -1;
return 0;
}
int icn85xx_check_progmod(void)
{
int ret;
unsigned char ucTemp = 0x0;
ret = icn85xx_prog_i2c_rxdata(0x040002, &ucTemp, 1);
if(ret < 0)
{
pr_err("icn85xx_check_progmod error, ret: %d\n", ret);
return ret;
}
if(ucTemp == 0x85)
return 0;
else
return -1;
}
unsigned char FlashState(unsigned char State_Index)
{
unsigned char ucTemp[4] = {0,0,0,0};
ucTemp[2]=0x08;
ucTemp[1]=0x10;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3);
if(State_Index==0)
{
ucTemp[0]=0x05;
}
else if(State_Index==1)
{
ucTemp[0]=0x35;
}
icn85xx_prog_i2c_txdata(0x40630,ucTemp,1);
ucTemp[1]=0x00;
ucTemp[0]=0x01;
icn85xx_prog_i2c_txdata(0x40640,ucTemp,2);
ucTemp[0]=1;
icn85xx_prog_i2c_txdata(0x40644,ucTemp,1);
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
icn85xx_prog_i2c_rxdata(0x40648,ucTemp,1);
return (unsigned char)(ucTemp[0]);
}
int icn85xx_read_flashid(void)
{
unsigned char ucTemp[4] = {0,0,0,0};
int flashid=0;
ucTemp[2]=0x08;
ucTemp[1]=0x10;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3);
ucTemp[0]=0x9f;
icn85xx_prog_i2c_txdata(0x40630,ucTemp,1);
ucTemp[1] = 0x00;
ucTemp[0] = 0x03;
icn85xx_prog_i2c_txdata(0x40640,ucTemp,2);
ucTemp[0]=1;
icn85xx_prog_i2c_txdata(0x40644,ucTemp,1);
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
icn85xx_prog_i2c_rxdata(0x40648,(char *)&flashid,4);
flashid=flashid&0x00ffffff;
pr_info("flashid: 0x%x\n", flashid);
return flashid;
}
int icn87xx_boot_sram(void)
{
int ret = -1;
unsigned char ucTemp = 0x03;
ret = icn87xx_prog_i2c_txdata(0xf400,&ucTemp,1);
return ret;
}
int icn87xx_boot_flash(void)
{
int ret = -1;
unsigned char ucTemp = 0x7f;
ret = icn87xx_prog_i2c_txdata(0xf008,&ucTemp,1);//chip rest
return ret;
}
int icn87xx_read_flashstate(void)
{
int ret = -1;
unsigned char ucTemp[2] = {0 , 0};
ucTemp[0] = 1;
while(ucTemp[0])
{
ret = icn87xx_prog_i2c_rxdata(SF_BUSY_87,&ucTemp[0],1);
if(ret < 0)
{
return ret;
}
}
ucTemp[0] = FLASH_CMD_READ_STATUS;
ret = icn87xx_prog_i2c_txdata(CMD_SEL_87, &ucTemp[0],1);
if(ret < 0)
{
return ret;
}
ucTemp[1] = (unsigned char)(SRAM_EXCHANGE_ADDR>>8);
ucTemp[0] = (unsigned char)(SRAM_EXCHANGE_ADDR);
ret = icn87xx_prog_i2c_txdata(SRAM_ADDR_87, &ucTemp[0],2);
if(ret < 0)
{
return ret;
}
ucTemp[0] = 1;
ret = icn87xx_prog_i2c_txdata(START_DEXC_87, &ucTemp[0],1);
if(ret < 0)
{
return ret;
}
while(ucTemp[0])
{
ret = icn87xx_prog_i2c_rxdata(SF_BUSY_87,&ucTemp[0],1);
if(ret < 0)
{
return ret;
}
}
ret = icn87xx_prog_i2c_rxdata(SRAM_EXCHANGE_ADDR,&ucTemp[0],1);
if(ret < 0)
{
return ret;
}
return ucTemp[0];
}
int icn87xx_read_flashid(void)
{
int ret = -1;
int flash_id;
unsigned char ucTemp[4];
ucTemp[0] = FLASH_CMD_READ_IDENTIFICATION;
ret = icn87xx_prog_i2c_txdata(CMD_SEL_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
ucTemp[1] = (unsigned char)(SRAM_EXCHANGE_ADDR1 >> 8);
ucTemp[0] = (unsigned char)SRAM_EXCHANGE_ADDR1;
ret = icn87xx_prog_i2c_txdata(SRAM_ADDR_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
ucTemp[0] = 1;
ret = icn87xx_prog_i2c_txdata(START_DEXC_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
while(ucTemp[0])
{
ret = icn87xx_prog_i2c_rxdata(SF_BUSY_87,&ucTemp[0],1);
if(ret < 0)
{
return ret;
}
}
ret = icn87xx_prog_i2c_rxdata(SRAM_EXCHANGE_ADDR1, ucTemp,4);
if(ret < 0)
{
return ret;
}
flash_id = (((ucTemp[0])<<16) + ((ucTemp[1])<<8) + ucTemp[2]);
return flash_id;
}
int icn87xx_calculate_crc(unsigned short len)
{
unsigned char ucTemp[4];
int ret = -1;
int crc = 0;
//2.1 set address
ucTemp[0] = 0x00;
ucTemp[1] = 0x00;
ret = icn87xx_prog_i2c_txdata(SRAM_ADDR_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
ucTemp[0] = len & 0xff;
ucTemp[1] = (len >> 8 )& 0xff;
ret = icn87xx_prog_i2c_txdata(DATA_LENGTH_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
ucTemp[0] = 0x01;
ret = icn87xx_prog_i2c_txdata(SW_CRC_START_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
//2.4 poll status
while(ucTemp[0])
{
ret = icn87xx_prog_i2c_rxdata(SF_BUSY_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
}
ret = icn87xx_prog_i2c_rxdata(CRC_RESULT_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
crc = (((ucTemp[1])<<8) + (ucTemp[0]))&0x0000ffff;
return crc;
}
unsigned short icn87xx_fw_Crc(unsigned short crc,unsigned char *buf ,unsigned short size)
{
unsigned short u16CrcValue = crc;
unsigned short u16Length = size;
unsigned char u8CheckData = 0;
while(u16Length)
{
u8CheckData = *buf++;
u16CrcValue = (u16CrcValue << 8)^Crc16Table[(u16CrcValue >> 8)^((u8CheckData)&0xff)];
u16Length--;
}
return u16CrcValue;
}
int icn87xx_erase_flash(U8 u8EraseMode, U32 u32FlashAddr)
{
U8 ucTemp[4];
int ret = -1;
if(FLASH_EARSE_4K == u8EraseMode)
{
ucTemp[0] = FLASH_CMD_ERASE_SECTOR;
}
else if(FLASH_EARSE_32K == u8EraseMode)
{
ucTemp[0] = FLASH_CMD_ERASE_BLOCK;
}
ret = icn87xx_prog_i2c_txdata(CMD_SEL_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
ucTemp[2] =(U8)(u32FlashAddr >> 16);
ucTemp[1] =(U8)(u32FlashAddr >> 8);
ucTemp[0] =(U8)(u32FlashAddr );
ret = icn87xx_prog_i2c_txdata(FLASH_ADDR_87, ucTemp,3);
if(ret < 0)
{
return ret;
}
ucTemp[0] = 1;
ret = icn87xx_prog_i2c_txdata(START_DEXC_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
while(ucTemp[0])
{
ret = icn87xx_read_flashstate();
if(ret < 0)
{
return ret;
}
ucTemp[0] = (unsigned char)(ret&0x01);
}
return 1;
}
int icn87xx_erase_chip(void)
{
int ret = -1;
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0xe000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_32K, 0);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0x8000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0x9000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0xa000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0xb000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0xc000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_4K, 0xd000);
if(ret < 0)
{
return ret;
}
ret = icn87xx_erase_flash(FLASH_EARSE_32K, 0x10000);
if(ret < 0)
{
return ret;
}
return ret;
}
int icn87xx_flash_write( U32 u32FlashAddr, U32 u32SramAddr, U32 u32Length)
{
U8 ucTemp[3] = {0, 0, 0};
int ret = -1;
U32 u32FlashTempAddr = u32FlashAddr;
U32 u32SramTempAddr = u32SramAddr;
U16 u16NotAlignLength;
U16 i = 0;
for(i = 0; i < u32Length;) //should not i++
{
ucTemp[0] = 1; //confirm the flash whether in busy state
while(ucTemp[0])
{
ret = icn87xx_read_flashstate();
if(ret < 0)
{
return ret;
}
ucTemp[0] = (unsigned char)(ret&0x01);
}
ucTemp[2] = (U8)(u32FlashTempAddr >> 16);
ucTemp[1] = (U8)(u32FlashTempAddr >> 8);
ucTemp[0] = (U8)(u32FlashTempAddr );
ret = icn87xx_prog_i2c_txdata(FLASH_ADDR_87, ucTemp,3);
if(ret < 0)
{
return ret;
}
ucTemp[2] = (U8)(u32SramTempAddr >> 16);
ucTemp[1] = (U8)(u32SramTempAddr >> 8);
ucTemp[0] = (U8)(u32SramTempAddr );
ret = icn87xx_prog_i2c_txdata(SRAM_ADDR_87, ucTemp,3);
if(ret < 0)
{
return ret;
}
if(u32FlashTempAddr % 0x100) // not aglin
{
u16NotAlignLength = 0x100 - (u32FlashTempAddr % 0x100);
if(u32Length <= u16NotAlignLength)
{
ucTemp[1] = (U8)(u32Length >> 8);
ucTemp[0] = (U8)(u32Length );
ret = icn87xx_prog_i2c_txdata(DATA_LENGTH_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
}
else
{
ucTemp[1] = (U8)(u16NotAlignLength >> 8);
ucTemp[0] = (U8)(u16NotAlignLength );
ret = icn87xx_prog_i2c_txdata(DATA_LENGTH_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
}
u32FlashTempAddr += u16NotAlignLength; //change the flash and sram address
u32SramTempAddr += u16NotAlignLength;
i += u16NotAlignLength;
}
else
{
if(i+256<=u32Length)
{
ucTemp[1] = (U8)(0x01);
ucTemp[0] = (U8)(0x00 );
ret = icn87xx_prog_i2c_txdata(DATA_LENGTH_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
}
else
{
ucTemp[1] = (U8)((u32Length-i) >> 8);
ucTemp[0] = (U8)(u32Length-i );
ret = icn87xx_prog_i2c_txdata(DATA_LENGTH_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
}
u32FlashTempAddr += 256; //change the flash and sram address
u32SramTempAddr += 256;
i += 256;
}
ucTemp[0] = FLASH_CMD_PAGE_PROGRAM;
ret = icn87xx_prog_i2c_txdata(CMD_SEL_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
ucTemp[0] = 1;
ret = icn87xx_prog_i2c_txdata(START_DEXC_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
}
ucTemp[0] = 1;
while(ucTemp[0]) //confirm whether the last pageprogram whether complete
{
ret = icn87xx_read_flashstate();
if(ret < 0)
{
return ret;
}
ucTemp[0] = (unsigned char)(ret&0x01);
}
return ret;
}
int icn87xx_flash_read(U32 u32SramAddr, U32 u32FlashAddr, U16 u16Length)
{
U8 ucTemp[4] = {0, 0, 0, 0};
int ret = -1;
ucTemp[0] = FLASH_CMD_FAST_READ;
ret = icn87xx_prog_i2c_txdata(CMD_SEL_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
ucTemp[3] = (U8)(u32FlashAddr >> 24);
ucTemp[2] = (U8)(u32FlashAddr >> 16);
ucTemp[1] = (U8)(u32FlashAddr >> 8);
ucTemp[0] = (U8)(u32FlashAddr);
ret = icn87xx_prog_i2c_txdata(FLASH_ADDR_87, ucTemp,3);
if(ret < 0)
{
return ret;
}
ucTemp[3] = (U8)(u32SramAddr >> 24);
ucTemp[2] = (U8)(u32SramAddr >> 16);
ucTemp[1] = (U8)(u32SramAddr >> 8);
ucTemp[0] = (U8)(u32SramAddr);
ret = icn87xx_prog_i2c_txdata(SRAM_ADDR_87, ucTemp,3);
if(ret < 0)
{
return ret;
}
ucTemp[1] = (U8)(u16Length >> 8);
ucTemp[0] = (U8)(u16Length);
ret = icn87xx_prog_i2c_txdata(DATA_LENGTH_87, ucTemp,2);
if(ret < 0)
{
return ret;
}
ucTemp[0] = 1;
ret = icn87xx_prog_i2c_txdata(START_DEXC_87, ucTemp,1);
if(ret < 0)
{
return ret;
}
while(ucTemp[0])
{
ret = icn87xx_read_flashstate();
if(ret < 0)
{
return ret;
}
ucTemp[0] = (unsigned char)(ret&0x01);
}
return ret;
}
int icn87xx_write_pr_info(U32 u32FlashAddr, U32 u32SramAddr, U8 *buf, U16 u16Length)
{
int ret = -1;
ret = icn87xx_prog_i2c_txdata(u32SramAddr, buf, u16Length);
if(ret < 0)
{
return ret;
}
ret = icn87xx_flash_write(u32FlashAddr, u32SramAddr, u16Length);
return ret;
}
void FlashWriteEnable(void)
{
unsigned char ucTemp[4] = {0,0,0,0};
ucTemp[2]=0x00;
ucTemp[1]=0x10;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3);
ucTemp[0]=0x06;
icn85xx_prog_i2c_txdata(0x40630,ucTemp,1);
ucTemp[0]=0x00;
ucTemp[1]=0x00;
icn85xx_prog_i2c_txdata(0x40640,ucTemp,2);
ucTemp[0]=1;
icn85xx_prog_i2c_txdata(0x40644,ucTemp,1);
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
ucTemp[0]=FlashState(0);
while( (ucTemp[0]&0x02)!=0x02)
{
ucTemp[0]=FlashState(0);
}
}
#ifndef QUAD_OUTPUT_ENABLE
void ClearFlashState(void)
{
unsigned char ucTemp[4] = {0,0,0,0};
icn85xx_prog_i2c_rxdata(0x40603,ucTemp,1);
ucTemp[0]=(ucTemp[0]|0x20);
icn85xx_prog_i2c_txdata(0x40603, ucTemp, 1 );
FlashWriteEnable();
ucTemp[2]=0x00;
ucTemp[1]=0x10;
ucTemp[0]=0x10;
icn85xx_prog_i2c_txdata(0x4062c,ucTemp,3);
ucTemp[0]=0x01;
icn85xx_prog_i2c_txdata(0x40630,ucTemp,1);
ucTemp[0]=0x00;
ucTemp[1]=0x00;
icn85xx_prog_i2c_txdata(0x40640,ucTemp,2);
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x40638,ucTemp,1);
ucTemp[0]=1;
icn85xx_prog_i2c_txdata(0x40644,ucTemp,1);
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
while(FlashState(0)&0x01);
}
#else
void ClearFlashState(void)
{
}
#endif
void EarseFlash(unsigned char erase_index,ulong flash_addr)
{
unsigned char ucTemp[4] = {0,0,0,0};
FlashWriteEnable();
if(erase_index==0) //erase the chip
{
ucTemp[0]=0xc7;
icn85xx_prog_i2c_txdata(0x40630, ucTemp, 1 );
ucTemp[2]=0x00;
ucTemp[1]=0x10;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3 );
}
else if(erase_index==1) //erase 32k space of the flash
{
ucTemp[0]=0x52;
icn85xx_prog_i2c_txdata(0x40630, ucTemp, 1);
ucTemp[2]=0x00;
ucTemp[1]=0x13;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3);
}
else if(erase_index==2) //erase 64k space of the flash
{
ucTemp[0]=0xd8;
icn85xx_prog_i2c_txdata(0x40630, ucTemp,1);
ucTemp[2]=0x00;
ucTemp[1]=0x13;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3);
}
else if(erase_index==3)
{
ucTemp[0]=0x20;
icn85xx_prog_i2c_txdata(0x40630, ucTemp, 1);
ucTemp[2]=0x00;
ucTemp[1]=0x13;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3);
}
ucTemp[2]=(unsigned char)(flash_addr>>16);
ucTemp[1]=(unsigned char)(flash_addr>>8);
ucTemp[0]=(unsigned char)(flash_addr);
icn85xx_prog_i2c_txdata(0x40634, ucTemp, 3);
ucTemp[1]=0x00;
ucTemp[0]=0x00;
icn85xx_prog_i2c_txdata(0x40640, ucTemp, 2 );
ucTemp[0]=1;
icn85xx_prog_i2c_txdata(0x40644, ucTemp, 1);
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
}
int icn85xx_erase_flash(void)
{
int i;
ClearFlashState();
while(FlashState(0)&0x01);
FlashWriteEnable();
EarseFlash(1,0);
while((FlashState(0)&0x01));
for(i=0; i<7; i++)
{
FlashWriteEnable();
EarseFlash(3,0x8000+i*0x1000);
while((FlashState(0)&0x01));
}
for(i=0; i<4; i++)
{
FlashWriteEnable();
EarseFlash(3,0x10000+i*0x1000);
while((FlashState(0)&0x01));
}
return 0;
}
int icn85xx_prog_buffer(unsigned int flash_addr,unsigned int sram_addr,unsigned int copy_length,unsigned char program_type)
{
unsigned char ucTemp[4] = {0,0,0,0};
unsigned char prog_state=0;
unsigned int i=0;
unsigned char program_commond=0;
if(program_type == 0)
{
program_commond = 0x02;
}
else if(program_type == 1)
{
program_commond = 0xf2;
}
else
{
program_commond = 0x02;
}
for(i=0; i<copy_length; )
{
prog_state=(FlashState(0)&0x01);
while(prog_state)
{
prog_state=(FlashState(0)&0x01);
}
FlashWriteEnable();
ucTemp[2]=0;
ucTemp[1]=0x13;
ucTemp[0]=0;
icn85xx_prog_i2c_txdata(0x4062c, ucTemp, 3);
ucTemp[2]=(unsigned char)(flash_addr>>16);
ucTemp[1]=(unsigned char)(flash_addr>>8);
ucTemp[0]=(unsigned char)(flash_addr);
icn85xx_prog_i2c_txdata(0x40634, ucTemp, 3);
ucTemp[2]=(unsigned char)(sram_addr>>16);
ucTemp[1]=(unsigned char)(sram_addr>>8);
ucTemp[0]=(unsigned char)(sram_addr);
icn85xx_prog_i2c_txdata(0x4063c, ucTemp, 3);
if(i+256<=copy_length)
{
ucTemp[1]=0x01;
ucTemp[0]=0x00;
}
else
{
ucTemp[1]=(unsigned char)((copy_length-i)>>8);
ucTemp[0]=(unsigned char)(copy_length-i);
}
icn85xx_prog_i2c_txdata(0x40640, ucTemp,2);
ucTemp[0]=program_commond;
icn85xx_prog_i2c_txdata(0x40630, ucTemp,1);
ucTemp[0]=0x01;
icn85xx_prog_i2c_txdata(0x40644, ucTemp,1);
flash_addr+=256;
sram_addr+=256;
i+=256;
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
}
prog_state=(FlashState(0)&0x01);
while(prog_state)
{
prog_state=(FlashState(0)&0x01);
}
return 0;
}
int icn85xx_prog_data(unsigned int flash_addr, unsigned int data)
{
unsigned char ucTemp[4] = {0,0,0,0};
ucTemp[3]=(unsigned char)(data>>24);
ucTemp[2]=(unsigned char)(data>>16);
ucTemp[1]=(unsigned char)(data>>8);
ucTemp[0]=(unsigned char)(data);
icn85xx_prog_i2c_txdata(0x2a000, ucTemp,4);
icn85xx_prog_buffer(flash_addr , 0x2a000, 0x04, 0);
return 0;
}
void icn85xx_read_flash(unsigned int sram_address,unsigned int flash_address,unsigned long copy_length,unsigned char i2c_wire_num)
{
unsigned char ucTemp[4] = {0,0,0,0};
if(i2c_wire_num==1)
{
ucTemp[2]=0x18;
ucTemp[1]=0x13;
ucTemp[0]=0x00;
}
else if(i2c_wire_num==2)
{
ucTemp[2]=0x1a;
ucTemp[1]=0x13;
ucTemp[0]=0x01;
}
else if(i2c_wire_num==4)
{
ucTemp[2]=0x19;
ucTemp[1]=0x13;
ucTemp[0]=0x01;
}
else
{
ucTemp[2]=0x18;
ucTemp[1]=0x13;
ucTemp[0]=0x01;
}
icn85xx_prog_i2c_txdata(0x4062c, ucTemp,3);
if(i2c_wire_num==1)
{
ucTemp[0]=0x03;
}
else if(i2c_wire_num==2)
{
ucTemp[0]=0x3b;
}
else if(i2c_wire_num==4)
{
ucTemp[0]=0x6b;
}
else
{
ucTemp[0]=0x0b;
}
icn85xx_prog_i2c_txdata(0x40630, ucTemp,1);
ucTemp[2]=(unsigned char)(flash_address>>16);
ucTemp[1]=(unsigned char)(flash_address>>8);
ucTemp[0]=(unsigned char)(flash_address);
icn85xx_prog_i2c_txdata(0x40634, ucTemp,3);
ucTemp[2]=(unsigned char)(sram_address>>16);
ucTemp[1]=(unsigned char)(sram_address>>8);
ucTemp[0]=(unsigned char)(sram_address);
icn85xx_prog_i2c_txdata(0x4063c, ucTemp,3);
ucTemp[1]=(unsigned char)(copy_length>>8);
ucTemp[0]=(unsigned char)(copy_length);
icn85xx_prog_i2c_txdata(0x40640, ucTemp,2);
ucTemp[0]=0x01;
icn85xx_prog_i2c_txdata(0x40644, ucTemp,1);
while(ucTemp[0])
{
icn85xx_prog_i2c_rxdata(0x40644,ucTemp,1);
}
}
short icn85xx_read_fw_Ver(char *fw)
{
short FWversion;
char tmp[2];
int file_size;
file_size = icn85xx_open_fw(fw);
if(file_size < 0)
{
return -1;
}
icn85xx_read_fw(0x100, 2, &tmp[0]);
icn85xx_close_fw();
FWversion = (tmp[1]<<8)|tmp[0];
return FWversion;
}
int icn87xx_read_fw_info(char *fw, unsigned char *buffer, unsigned short u16Addr, unsigned char u8Length)
{
int file_size;
file_size = icn85xx_open_fw(fw);
if(file_size < 0)
{
return -1;
}
icn85xx_read_fw(u16Addr, u8Length, buffer);
icn85xx_close_fw();
return 1;
}
#define ENABLE_BYTE_CHECK 0
int icn85xx_fw_download(unsigned int offset, unsigned char * buffer, unsigned int size)
{
int i;
#ifdef ENABLE_BYTE_CHECK
char testb[B_SIZE];
#endif
icn85xx_prog_i2c_txdata(offset,buffer,size);
#ifdef ENABLE_BYTE_CHECK
icn85xx_prog_i2c_rxdata(offset,testb,size);
for(i = 0; i < size; i++)
{
if(buffer[i] != testb[i])
{
pr_err("buffer[%d]:%x testb[%d]:%x\n",i,buffer[i],i,testb[i]);
return -1;
}
}
#endif
return 0;
}
int icn87xx_fw_download(unsigned int offset, unsigned char * buffer, unsigned int size)
{
int i;
#ifdef ENABLE_BYTE_CHECK
unsigned char testb[B_SIZE];
#endif
icn87xx_prog_i2c_txdata(offset,buffer,size);
#ifdef ENABLE_BYTE_CHECK
icn87xx_prog_i2c_rxdata(offset,testb,size);
for(i = 0; i < size; i++)
{
//pr_err("buffer[%d]:%x testb[%d]:%x\n",i,buffer[i],i,testb[i]);
if(buffer[i] != testb[i])
{
pr_err("buffer[%d]:%x testb[%d]:%x\n",i,buffer[i],i,testb[i]);
return -1;
}
}
#endif
return 0;
}
int icn85xx_bootfrom_flash(int ictype)
{
int ret = -1;
unsigned char ucTemp;
if(ictype == ICN85XX_WITH_FLASH_85)
{
ucTemp=0x7f;
ret = icn85xx_prog_i2c_txdata(0x40004, &ucTemp, 1 ); //ICN85XX chip reset
if (ret < 0) {
pr_err("1 %s failed: %d\n", __func__, ret);
return ret;
}
}
else if(ictype == ICN85XX_WITH_FLASH_86)
{
ucTemp=0x7f;
ret = icn85xx_prog_i2c_txdata(0x4046c, &ucTemp, 1 ); //ICN85EX chip reset
if (ret < 0) {
pr_err("2 %s failed: %d\n", __func__, ret);
return ret;
}
}
return ret;
}
int icn85xx_bootfrom_sram(void)
{
int ret = -1;
unsigned char ucTemp = 0x03;
unsigned long addr = 0x40400;
pr_info("icn85xx_bootfrom_sram\n");
ret = icn85xx_prog_i2c_txdata(addr, &ucTemp, 1 ); //change bootmode from sram
return ret;
}
/*
This polynomial (0x04c11db7) is used at: AUTODIN II, Ethernet, & FDDI
*/
static unsigned int crc32table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
unsigned int icn85xx_crc_calc(unsigned crc_in, char *buf, int len)
{
int i;
unsigned int crc = crc_in;
for(i = 0; i < len; i++)
crc = (crc << 8) ^ crc32table[((crc >> 24) ^ *buf++) & 0xFF];
return crc;
}
int icn85xx_crc_enable(unsigned char enable)
{
unsigned char ucTemp;
int ret = 0;
if(enable==1)
{
ucTemp = 1;
ret = icn85xx_prog_i2c_txdata(0x40028, &ucTemp, 1 );
}
else if(enable==0)
{
ucTemp = 0;
ret = icn85xx_prog_i2c_txdata(0x40028, &ucTemp, 1 );
}
return ret;
}
int icn85xx_crc_check(unsigned int crc, unsigned int len)
{
int ret;
unsigned int crc_len;
unsigned int crc_result;
unsigned char ucTemp[4] = {0,0,0,0};
ret= icn85xx_prog_i2c_rxdata(0x4002c, ucTemp, 4 );
crc_result = ucTemp[3]<<24 | ucTemp[2]<<16 | ucTemp[1] << 8 | ucTemp[0];
ret = icn85xx_prog_i2c_rxdata(0x40034, ucTemp, 2);
crc_len = ucTemp[1] << 8 | ucTemp[0];
if((crc_result == crc) && (crc_len == len))
return 0;
else
{
pr_info("crc_fw: 0x%x\n", crc);
pr_info("crc_result: 0x%x\n", crc_result);
pr_info("crc_len: %d\n", crc_len);
return -1;
}
}
int icn85xx_fw_update(void *fw)
{
int file_size, last_length;
int j, num;
char temp_buf[B_SIZE];
unsigned int crc_fw;
file_size = icn85xx_open_fw(fw);
if(file_size < 0)
{
icn85xx_update_status(R_FILE_ERR);
return R_FILE_ERR;
}
if(icn85xx_goto_progmode() != 0)
{
icn85xx_update_status(R_PROGRAM_ERR);
pr_err("icn85xx_goto_progmode() != 0 error\n");
return R_STATE_ERR;
}
msleep(1);
icn85xx_crc_enable(1);
num = file_size/B_SIZE;
crc_fw = 0;
for(j=0; j < num; j++)
{
icn85xx_read_fw(j*B_SIZE, B_SIZE, temp_buf);
crc_fw = icn85xx_crc_calc(crc_fw, temp_buf, B_SIZE);
if(icn85xx_fw_download(j*B_SIZE, temp_buf, B_SIZE) != 0)
{
pr_err("error j:%d\n",j);
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
icn85xx_update_status(5+(int)(60*j/num));
}
last_length = file_size - B_SIZE*j;
if(last_length > 0)
{
icn85xx_read_fw(j*B_SIZE, last_length, temp_buf);
crc_fw = icn85xx_crc_calc(crc_fw, temp_buf, last_length);
if(icn85xx_fw_download(j*B_SIZE, temp_buf, last_length) != 0)
{
pr_err("error last length\n");
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
}
icn85xx_close_fw();
icn85xx_update_status(65);
icn85xx_crc_enable(0);
if(icn85xx_crc_check(crc_fw, file_size) != 0)
{
icn85xx_update_status(R_VERIFY_ERR);
pr_info("down fw error, crc error\n");
return R_PROGRAM_ERR;
}
else
{
//pr_info("downoad fw ok, crc ok\n");
}
icn85xx_update_status(70);
if((ICN85XX_WITH_FLASH_85 == boot_mode) || (ICN85XX_WITH_FLASH_86 == boot_mode))
{
icn85xx_erase_flash();
icn85xx_update_status(75);
FlashWriteEnable();
icn85xx_prog_buffer( 0, 0, file_size,0);
icn85xx_update_status(85);
while((FlashState(0)&0x01));
FlashWriteEnable();
icn85xx_prog_data(FLASH_CRC_ADDR, crc_fw);
icn85xx_prog_data(FLASH_CRC_ADDR+4, file_size);
icn85xx_update_status(90);
icn85xx_crc_enable(1);
icn85xx_read_flash( 0, 0, file_size, 2);
icn85xx_crc_enable(0);
if(icn85xx_crc_check(crc_fw, file_size) != 0)
{
pr_info("read flash data error, crc error\n");
return R_PROGRAM_ERR;
}
else
{
pr_info("read flash data ok, crc ok\n");
}
while((FlashState(0)&0x01));
icn85xx_update_status(95);
if(icn85xx_bootfrom_sram() == 0) //code already in ram
{
pr_err("icn85xx_bootfrom_flash error\n");
icn85xx_update_status(R_STATE_ERR);
return R_STATE_ERR;
}
}
else if((ICN85XX_WITHOUT_FLASH_85 == boot_mode) || (ICN85XX_WITHOUT_FLASH_86 == boot_mode))
{
if(icn85xx_bootfrom_sram() == 0)
{
pr_err("icn85xx_bootfrom_sram error\n");
icn85xx_update_status(R_STATE_ERR);
return R_STATE_ERR;
}
}
msleep(50);
icn85xx_update_status(R_OK);
pr_info("icn85xx upgrade ok\n");
return R_OK;
}
int icn87xx_fw_update(void *fw)
{
int file_size, last_length;
int ret = -1;
int j, num;
unsigned char temp_buf[B_SIZE];
unsigned char buf[20];
unsigned char version = 0;
unsigned short crc_fw = 0;
unsigned short sram_len = 0;
unsigned short sram_crc = 0;
unsigned short temp_crc = 0;
unsigned short fw_version = 0;
ret = icn87xx_read_fw_info(fw, buf, FIRMWARA_INFO_AT_BIN_ADDR,16); //contain sram lenth ,fwversion
sram_len = (((buf[9])<<8) + buf[8]) + (((buf[6])<<16) + ((buf[5])<<8) + buf[4]) - (((buf[2])<<16) + ((buf[1])<<8) + buf[0]);
fw_version = (((buf[13])<<8)+ buf[12]);
file_size = icn85xx_open_fw(fw);
pr_info("file_size:%d \n",file_size);
pr_info("boot mode:0x%x\n",boot_mode);
if(file_size <= 0)
{
icn85xx_update_status(R_FILE_ERR);
return R_FILE_ERR;
}
if(icn85xx_goto_progmode() < 0)
{
icn85xx_update_status(R_PROGRAM_ERR);
pr_err("icn85xx_goto_progmode() error\n");
return R_STATE_ERR;
}
pr_info("sram_len:%d \n",sram_len);
msleep(1);
if(ICN85XX_WITH_FLASH_87 == boot_mode)
{
ret = icn87xx_erase_chip();
if(ret < 0)
{
pr_err("earse error\n");
return ret;
}
}
if(sram_len == file_size)
{
num = file_size/B_SIZE;
crc_fw = 0;
for(j=0; j < num; j++)
{
icn85xx_read_fw(j*B_SIZE, B_SIZE, temp_buf);
crc_fw = icn87xx_fw_Crc(crc_fw, temp_buf, B_SIZE);
if(icn87xx_fw_download(j*B_SIZE, temp_buf, B_SIZE) != 0)
{
pr_err("error j:%d\n",j);
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
icn85xx_update_status(5+(int)(60*j/num));
}
last_length = file_size - B_SIZE*num;
if(last_length > 0)
{
icn85xx_read_fw(j*B_SIZE, last_length, temp_buf);
crc_fw = icn87xx_fw_Crc(crc_fw, temp_buf, last_length);
if(icn87xx_fw_download(j*B_SIZE, temp_buf, last_length) != 0)
{
pr_err("error last length\n");
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
}
if( icn87xx_calculate_crc(sram_len) != crc_fw)
{
pr_err("crc error\n");
return -1;
}
else
{
sram_crc = crc_fw;
}
if(ICN85XX_WITH_FLASH_87 == boot_mode)
{
ret = icn87xx_flash_write(0, 0, file_size);
if(ret < 0)
{
return ret;
}
}
}
else if(file_size > sram_len)
{
if(ICN85XX_WITHOUT_FLASH_87 == boot_mode)
{
pr_err("error!! file_size > sram_len\n");
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
num = sram_len/B_SIZE;
crc_fw = 0;
for(j = 0; j < num; j++)
{
icn85xx_read_fw(j*B_SIZE, B_SIZE, temp_buf);
crc_fw = icn87xx_fw_Crc(crc_fw, temp_buf, B_SIZE);
if(icn87xx_fw_download(j*B_SIZE, temp_buf, B_SIZE) != 0)
{
pr_err("error j:%d\n",j);
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
icn85xx_update_status(5+(int)(60*j/num));
}
last_length = sram_len - B_SIZE*num;
if(last_length > 0)
{
icn85xx_read_fw(j*B_SIZE, last_length, temp_buf);
crc_fw = icn87xx_fw_Crc(crc_fw, temp_buf, last_length);
if(icn87xx_fw_download(j*B_SIZE, temp_buf, last_length) != 0)
{
pr_err("error last length\n");
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
}
if(icn87xx_calculate_crc(sram_len) != crc_fw)
{
pr_err("crc error0\n");
return -1;
}
else
{
sram_crc = crc_fw;
}
ret = icn87xx_flash_write(0, 0, sram_len);
if(ret < 0)
{
return ret;
}
num = (file_size - sram_len)/B_SIZE;
temp_crc = 0;
for(j=0; j < num; j++)
{
icn85xx_read_fw(sram_len + j*B_SIZE, B_SIZE, temp_buf);
crc_fw = icn87xx_fw_Crc(crc_fw, temp_buf, B_SIZE);
temp_crc = icn87xx_fw_Crc(temp_crc, temp_buf, B_SIZE);
if(icn87xx_fw_download(j*B_SIZE, temp_buf, B_SIZE) != 0)
{
pr_err("error j:%d\n",j);
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
icn85xx_update_status(5+(int)(60*j/num));
}
last_length = (file_size - sram_len) - B_SIZE*num;
if(last_length > 0)
{
icn85xx_read_fw( sram_len + j*B_SIZE, last_length, temp_buf);
crc_fw = icn87xx_fw_Crc(crc_fw, temp_buf, last_length);
temp_crc = icn87xx_fw_Crc(temp_crc, temp_buf, last_length);
if(icn87xx_fw_download(j*B_SIZE, temp_buf, last_length) != 0)
{
pr_err("error last length\n");
icn85xx_update_status(R_PROGRAM_ERR);
icn85xx_close_fw();
return R_PROGRAM_ERR;
}
}
if(icn87xx_calculate_crc(file_size - sram_len) != temp_crc)
{
pr_err("crc error1\n");
return -1;
}
ret = icn87xx_flash_write(sram_len, 0, file_size - sram_len);
if(ret < 0)
{
return ret;
}
}
if(ICN85XX_WITH_FLASH_87 == boot_mode)
{
pr_info("write flashinfo \n");
icn85xx_update_status(85);
buf[0] = (unsigned char)(crc_fw);
buf[1] = (unsigned char)(crc_fw>>8);
buf[2] = 0;
buf[3] = 0;
buf[4] = (unsigned char)(file_size);
buf[5] = (unsigned char)(file_size>>8);
buf[6] = 0;
buf[7] = 0;
buf[8] = 0x5a;
buf[9] = 0xc4;
buf[10] = 0;
buf[11] = 0;
buf[12] = (unsigned char)(sram_crc);
buf[13] = (unsigned char)(sram_crc>>8);
buf[14] = 0;
buf[15] = 0;
buf[16] = (unsigned char)(sram_len);
buf[17] = (unsigned char)(sram_len>>8);
buf[18] = 0;
buf[19] = 0;
for(j=0;j<5;j++){
ret = icn87xx_write_pr_info(FLASH_STOR_INFO_ADDR+j*4,SRAM_EXCHANGE_ADDR1+j*4,buf+j*4,4);
}
icn85xx_update_status(95);
msleep(5);
while(version != 0x81)
{
if(icn87xx_boot_flash() < 0) //code already in ram
{
pr_err("icn85xx_bootfrom_flash error\n");
icn85xx_update_status(R_STATE_ERR);
return R_STATE_ERR;
}
msleep(10);
ret = icn85xx_read_reg(0xa, &version);
printk("after upgrdate Value: %x\n",version);
msleep(5);
}
}
else if(ICN85XX_WITHOUT_FLASH_87 == boot_mode)
{
if(icn87xx_boot_sram() < 0)
{
pr_err("icn85xx_bootfrom_sram error\n");
icn85xx_update_status(R_STATE_ERR);
return R_STATE_ERR;
}
}
icn85xx_update_status(R_OK);
pr_info("icn87xx upgrade ok\n");
//check crc in sram before boot
icnt87_sram_crc = sram_crc;
icnt87_sram_length = sram_len;
return R_OK;
}
#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"};
#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[] = {
{ 0x22, "/misc/modules/ICN8505_22_name9.BIN",fw_22_name9,sizeof(fw_22_name9)},//default bin or fw
{ 0x00, "/misc/modules/ICN8505_00_name1.BIN",fw_00_name1,sizeof(fw_00_name1)},
{ 0x20, "/misc/modules/ICN8505_20_name7.BIN",fw_20_name7,sizeof(fw_20_name7)},
{ 0x10, "/misc/modules/ICN8505_10_name4.BIN",fw_10_name4,sizeof(fw_10_name4)},
{ 0x11, "/misc/modules/ICN8505_11_name5.BIN",fw_11_name5,sizeof(fw_11_name5)},
{ 0x12, "/misc/modules/ICN8505_12_name6.BIN",fw_12_name6,sizeof(fw_12_name6)},
{ 0x01, "/misc/modules/ICN8505_01_name2.BIN",fw_01_name2,sizeof(fw_01_name2)},
{ 0x21, "/misc/modules/ICN8505_21_name8.BIN",fw_21_name8,sizeof(fw_21_name8)},
{ 0x02, "/misc/modules/ICN8505_02_name3.BIN",fw_02_name3,sizeof(fw_02_name3)},
// if you want support other sensor id value ,please add here
};
#endif
static 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 void icn85xx_log(char diff);
static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer);
#if SUPPORT_PROC_FS
pack_head cmd_head;
static struct proc_dir_entry *icn85xx_proc_entry;
int DATA_LENGTH = 0;
GESTURE_DATA structGestureData;
STRUCT_PANEL_PARA_H g_structPanelPara;
#endif
#if SUPPORT_SYSFS
static ssize_t icn85xx_store_update(struct device_driver *drv,const char *buf,size_t count);
static ssize_t icn85xx_show_update(struct device_driver *drv,char* buf);
static ssize_t icn85xx_show_process(struct device_driver *drv, char* buf);
static ssize_t icn85xx_store_process(struct device_driver *drv,const char *buf, size_t len);
static DRIVER_ATTR(icn_update, 0644, icn85xx_show_update, icn85xx_store_update);
static DRIVER_ATTR(icn_process, 0644, icn85xx_show_process, icn85xx_store_process);
static ssize_t icn85xx_show_process(struct device_driver *drv, 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_driver *drv,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);
pr_info("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_driver *drv, char* buf)
{
ssize_t ret = 0;
sprintf(buf, firmware);
ret = strlen(buf) + 1;
//pr_info("firmware: %s, ret: %d\n", firmware, ret);
return ret;
}
static ssize_t icn85xx_store_update(struct device_driver *drv,const char *buf, size_t len)
{
//pr_info("count: %d, update: %s\n", count, buf);
char val;
sscanf(buf,"%s",&val);
pr_info("val: %c\n", val);
switch(val){
case 'u':
case 'U':
pr_info("firmware: %s\n", firmware);
pr_info("fwVersion : 0x%x\n", icn85xx_read_fw_Ver("/mnt/sdcard/ICN8505.bin"));
pr_info("current version: 0x%x\n", icn85xx_readVersion());
if(R_OK == icn85xx_fw_update("/mnt/sdcard/ICN8505.bin"))
{
pr_info("update ok\n");
}
else
{
pr_info("update error\n");
}
break;
case 't':
case 'T':
icn85xx_ts_reset();
//DEBUG = 1;
break;
case 'r':
case 'R':
icn85xx_log(0);
break;
case 'd':
case 'D':
icn85xx_log(1);
msleep(100);
break;
default:
pr_info("this conmand is unknow!!\n");
break;
}
return len;
}
static struct attribute *icn_drv_attr[] = {
&driver_attr_icn_update.attr,
&driver_attr_icn_process.attr,
NULL
};
static struct attribute_group icn_drv_attr_grp = {
.attrs =icn_drv_attr,
};
static const struct attribute_group *icn_drv_grp[] = {
&icn_drv_attr_grp,
NULL
};
#endif
#if SUPPORT_PROC_FS
static struct task_struct *resume_download_task = NULL;
static ssize_t icn85xx_tool_write(struct file *file, const char __user * buffer, size_t count, loff_t * ppos)
{
int ret = 0;
int i;
unsigned short addr;
unsigned int prog_addr;
char retvalue;
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
pr_info("%s \n",__func__);
if(down_interruptible(&icn85xx_ts->sem))
{
return -1;
}
ret = copy_from_user(&cmd_head, buffer, CMD_HEAD_LENGTH);
if(ret)
{
pr_info("copy_from_user failed.\n");
goto write_out;
}
else
{
ret = CMD_HEAD_LENGTH;
}
pr_info("wr :0x%02x.\n", cmd_head.wr);
pr_info("flag:0x%02x.\n", cmd_head.flag);
pr_info("circle :%d.\n", (int)cmd_head.circle);
pr_info("times :%d.\n", (int)cmd_head.times);
pr_info("retry :%d.\n", (int)cmd_head.retry);
pr_info("data len:%d.\n", (int)cmd_head.data_len);
pr_info("addr len:%d.\n", (int)cmd_head.addr_len);
pr_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]);
pr_info("len:%d.\n", (int)count);
pr_info("data:0x%02x%02x.\n", buffer[CMD_HEAD_LENGTH], buffer[CMD_HEAD_LENGTH+1]);
if (1 == cmd_head.wr) // write para
{
pr_info("cmd_head_.wr == 1 \n");
ret = copy_from_user(&cmd_head.data[0], &buffer[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret)
{
pr_info("copy_from_user failed.\n");
goto write_out;
}
memcpy(&g_structPanelPara, &cmd_head.data[0], cmd_head.data_len);
//write para to tp
for(i=0; i<cmd_head.data_len; )
{
int size = ((i+64) > cmd_head.data_len)?(cmd_head.data_len-i):64;
ret = icn85xx_i2c_txdata(0x8000+i, &cmd_head.data[i], size);
if (ret < 0) {
pr_info("write para failed!\n");
goto write_out;
}
i = i + 64;
}
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
icn85xx_ts->work_mode = 4; //reinit
pr_info("reinit tp\n");
icn85xx_write_reg(0, 1);
mdelay(100);
icn85xx_write_reg(0, 0);
mdelay(100);
icn85xx_ts->work_mode = 0;
goto write_out;
}
else if(3 == cmd_head.wr) //set update file
{
pr_info("cmd_head_.wr == 3 \n");
ret = copy_from_user(&cmd_head.data[0], &buffer[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret)
{
pr_info("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);
pr_info("firmware : %s\n", firmware);
}
else if(5 == cmd_head.wr) //start update
{
pr_info("cmd_head_.wr == 5 \n");
icn85xx_update_status(1);
if((icn85xx_ts->ictype == ICN85XX_WITH_FLASH_87) || (icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH_87))
{
//ret = kernel_thread(icn87xx_fw_update,firmware,CLONE_KERNEL);
kthread_run(icn87xx_fw_update, firmware, "icn_update");
}
else
{
//ret = kernel_thread(icn85xx_fw_update,firmware,CLONE_KERNEL);
kthread_run(icn85xx_fw_update, firmware, "icn_update");
}
}
else if(11 == cmd_head.wr) //write hostcomm
{
icn85xx_ts->work_mode = cmd_head.flag; //for gesture test,you should set flag=6
structGestureData.u8Status = 0;
ret = copy_from_user(&cmd_head.data[0], &buffer[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret)
{
pr_info("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
{
pr_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);
pr_info("retvalue0: %d\n", retvalue);
while(retvalue != 1)
{
pr_info("retvalue: %d\n", retvalue);
mdelay(1);
icn85xx_read_reg(2, &retvalue);
}
if(icn85xx_goto_progmode() != 0)
{
pr_info("icn85xx_goto_progmode() != 0 error\n");
goto write_out;
}
icn85xx_prog_write_reg(0x040870, 1);
}
else if(15 == cmd_head.wr) // write hostcomm multibyte
{
pr_info("cmd_head_.wr == 15 \n");
ret = copy_from_user(&cmd_head.data[0], &buffer[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret)
{
pr_info("copy_from_user failed.\n");
goto write_out;
}
addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0];
pr_info("wr, addr: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", addr, cmd_head.data[0], cmd_head.data[1], cmd_head.data[2], cmd_head.data[3]);
ret = icn85xx_i2c_txdata(addr, &cmd_head.data[0], cmd_head.data_len);
if (ret < 0) {
pr_info("write hostcomm multibyte failed!\n");
goto write_out;
}
}
else if(17 == cmd_head.wr)// write iic porgmode multibyte
{
pr_info("cmd_head_.wr == 17 \n");
ret = copy_from_user(&cmd_head.data[0], &buffer[CMD_HEAD_LENGTH], cmd_head.data_len);
if(ret)
{
pr_info("copy_from_user failed.\n");
goto write_out;
}
prog_addr = (cmd_head.flag<<16) | (cmd_head.addr[1]<<8) | cmd_head.addr[0];
icn85xx_goto_progmode();
ret = icn85xx_prog_i2c_txdata(prog_addr, &cmd_head.data[0], cmd_head.data_len);
if (ret < 0) {
pr_info("write hostcomm multibyte failed!\n");
goto write_out;
}
}
write_out:
up(&icn85xx_ts->sem);
pr_info("icn85xx_tool_write write_out \n");
return count;
}
static ssize_t icn85xx_tool_read(struct file *file, char __user * buffer, size_t count, loff_t * ppos)
{
int i, j;
int ret = 0;
char row, column, retvalue, max_column;
unsigned short addr;
unsigned int prog_addr;
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
if(down_interruptible(&icn85xx_ts->sem))
{
return -1;
}
pr_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count,(int)(* ppos),(int)cmd_head.data_len);
if (cmd_head.wr % 2)
{
ret = 0;
pr_info("cmd_head_.wr == 1111111 \n");
goto read_out;
}
else if (0 == cmd_head.wr) //read para
{
//read para
pr_info("cmd_head_.wr == 0 \n");
ret = icn85xx_i2c_rxdata(0x8000, &g_structPanelPara, cmd_head.data_len);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
ret = copy_to_user(buffer, (void*)(&g_structPanelPara), cmd_head.data_len);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
goto read_out;
}
else if(2 == cmd_head.wr) //get update status
{
pr_info("cmd_head_.wr == 2 \n");
retvalue = icn85xx_get_status();
pr_info("status: %d\n", retvalue);
ret =copy_to_user(buffer, (void*)(&retvalue), 1);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
}
else if(4 == cmd_head.wr) //read rawdata
{
pr_info("cmd_head_.wr == 4 \n");
row = cmd_head.addr[1];
column = cmd_head.addr[0];
max_column = (cmd_head.flag==0)?(24):(cmd_head.flag);
//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; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x2000 + i*(max_column)*2,(char *) &log_rawdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
ret = copy_to_user(&buffer[column*2*i], (void*)(&log_rawdata[i][0]), column*2);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
}
//finish scan tp rawdata
icn85xx_write_reg(2, 0x0);
icn85xx_write_reg(4, 0x21);
goto read_out;
}
else if(6 == cmd_head.wr) //read diffdata
{
pr_info("cmd_head_.wr == 6 \n");
row = cmd_head.addr[1];
column = cmd_head.addr[0];
max_column = (cmd_head.flag==0)?(24):(cmd_head.flag);
//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; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x3000 + (i+1)*(max_column+2)*2 + 2,(char *) &log_diffdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
ret = copy_to_user(&buffer[column*2*i], (void*)(&log_diffdata[i][0]), column*2);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
}
//finish scan tp rawdata
icn85xx_write_reg(2, 0x0);
icn85xx_write_reg(4, 0x21);
goto read_out;
}
else if(8 == cmd_head.wr) //change TxVol, read diff
{
pr_info("cmd_head_.wr == 8 \n");
row = cmd_head.addr[1];
column = cmd_head.addr[0];
max_column = (cmd_head.flag==0)?(24):(cmd_head.flag);
//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; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x2000 + i*(max_column)*2,(char *) &log_rawdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
}
icn85xx_write_reg(2, 0x0);
icn85xx_write_reg(4, 0x21);
icn85xx_write_reg(4, 0x12);
//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; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x2000 + i*(max_column)*2,(char *) &log_diffdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
for(j=0; j<column; j++)
{
log_basedata[i][j] = log_rawdata[i][j] - log_diffdata[i][j];
}
ret = copy_to_user(&buffer[column*2*i], (void*)(&log_basedata[i][0]), column*2);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
}
//finish scan tp rawdata
icn85xx_write_reg(2, 0x0);
icn85xx_write_reg(4, 0x21);
icn85xx_write_reg(4, 0x10);
goto read_out;
}
else if(10 == cmd_head.wr) //read adc data
{
pr_info("cmd_head_.wr == 10 \n");
if(cmd_head.flag == 0)
{
icn85xx_prog_write_reg(0x040874, 0);
}
icn85xx_prog_read_page(2500*cmd_head.flag,(char *) &log_diffdata[0][0],cmd_head.data_len);
ret = copy_to_user(buffer, (void*)(&log_diffdata[0][0]), cmd_head.data_len);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
if(cmd_head.flag == 9)
{
//reload code
if((icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH_85) || (icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH_86))
{
if(R_OK == icn85xx_fw_update(firmware))
{
icn85xx_ts->code_loaded_flag = 1;
pr_info("ICN85XX_WITHOUT_FLASH, reload code ok\n");
}
else
{
icn85xx_ts->code_loaded_flag = 0;
pr_info("ICN85XX_WITHOUT_FLASH, reload code error\n");
}
}
else
{
icn85xx_bootfrom_flash(icn85xx_ts->ictype);
msleep(150);
}
icn85xx_ts->work_mode = 0;
}
}
else if(12 == cmd_head.wr) //read hostcomm
{
pr_info("cmd_head_.wr == 12 \n");
addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0];
icn85xx_read_reg(addr, &retvalue);
ret = copy_to_user(buffer, (void*)(&retvalue), 1);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
}
else if(14 == cmd_head.wr) //read adc status
{
pr_info("cmd_head_.wr == 14 \n");
icn85xx_prog_read_reg(0x4085E, &retvalue);
ret = copy_to_user(buffer, (void*)(&retvalue), 1);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
pr_info("0x4085E: 0x%x\n", retvalue);
}
else if(16 == cmd_head.wr) //read gesture data
{
pr_info("cmd_head_.wr == 16 \n");
ret = copy_to_user(buffer, (void*)(&structGestureData), sizeof(structGestureData));
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
if(structGestureData.u8Status == 1)
structGestureData.u8Status = 0;
}
else if(18 == cmd_head.wr) // read hostcomm multibyte
{
pr_info("cmd_head_.wr == 18 \n");
addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0];
ret = icn85xx_i2c_rxdata(addr, &cmd_head.data[0], cmd_head.data_len);
if(ret < 0)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
ret = copy_to_user(buffer, &cmd_head.data[0], cmd_head.data_len);
if (ret) {
pr_err("read hostcomm multibyte failed: %d\n", ret);
}
pr_info("rd, addr: 0x%x, data_len: %d, data: 0x%x\n", addr, cmd_head.data_len, cmd_head.data[0]);
goto read_out;
}
else if(20 == cmd_head.wr)// read iic porgmode multibyte
{
pr_info("cmd_head_.wr == 20 \n");
prog_addr = (cmd_head.flag<<16) | (cmd_head.addr[1]<<8) | cmd_head.addr[0];
icn85xx_goto_progmode();
ret = icn85xx_prog_i2c_rxdata(prog_addr, &cmd_head.data[0], cmd_head.data_len);
if (ret < 0) {
pr_err("read iic porgmode multibyte failed: %d\n", ret);
}
ret = copy_to_user(buffer, &cmd_head.data[0], cmd_head.data_len);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
icn85xx_bootfrom_sram();
goto read_out;
}
else if(22 == cmd_head.wr) //read ictype
{
pr_info("cmd_head_.wr == 22 \n");
ret = copy_to_user(buffer, (void*)(&icn85xx_ts->ictype), 1);
if(ret)
{
pr_info("copy_to_user failed.\n");
goto read_out;
}
}
read_out:
up(&icn85xx_ts->sem);
pr_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len);
return cmd_head.data_len;
}
static const struct file_operations icn85xx_proc_fops = {
.owner = THIS_MODULE,
.read = icn85xx_tool_read,
.write = icn85xx_tool_write,
};
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;
pr_info("alloc memory size:%d.\n", DATA_LENGTH);
}
else
{
pr_info("alloc for memory failed.\n");
return ;
}
icn85xx_proc_entry = proc_create(ICN85XX_ENTRY_NAME, 0666, NULL, &icn85xx_proc_fops);
if (icn85xx_proc_entry == NULL)
{
pr_info("Couldn't create proc entry!\n");
return ;
}
else
{
pr_info("Create proc entry success!\n");
}
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 = 0;
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
int icn85xx_ts_reset(void)
{
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
int err = 0;
err = gpio_request(icn85xx_ts->board_info->irq_pin, "tp irq_pin");
if (err) {
// printk("######%s----%d\n",__func__,__LINE__);
pr_err("icn87xx irq_pin gpio request failed.\n");
return -1;
}
gpio_set_value(icn85xx_ts->board_info->irq_pin, 0);
mdelay(10);
gpio_set_value(icn85xx_ts->board_info->reset_pin, 0);
mdelay(30);
gpio_set_value(icn85xx_ts->board_info->reset_pin, 1);
mdelay(50);
gpio_set_value(icn85xx_ts->board_info->irq_pin, 1);
gpio_free(icn85xx_ts->board_info->irq_pin);
return 1;
}
void icn85xx_set_prog_addr(void)
{
icn85xx_ts_reset();
}
/***********************************************************************************************
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;
disable_irq_nosync(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)
{
enable_irq(icn85xx_ts->irq);
icn85xx_ts->irq_is_disable = 0;
}
spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags);
}
int icn85xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length)
{
int ret = -1;
int retries = 0;
unsigned char tmp_buf[3];
struct i2c_msg msgs[] = {
{
.addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr,
.flags = 0,
.len = 3,
.buf = tmp_buf,
},
{
.addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
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)
{
pr_err("%s i2c read error: %d\n", __func__, ret);
}
return ret;
}
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 (length > 125)
{
pr_err("%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)
{
pr_err("%s i2c write error: %d\n", __func__, ret);
// icn85xx_ts_reset();
}
return ret;
}
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) {
pr_err("%s write reg failed! %#x ret: %d\n", __func__, buf[0], ret);
return -1;
}
return ret;
}
int icn85xx_prog_read_reg(unsigned int addr, char *pdata)
{
int ret = -1;
ret = icn85xx_prog_i2c_rxdata(addr, pdata, 1);
return ret;
}
int icn85xx_prog_read_page(unsigned int Addr,unsigned char *Buffer, unsigned int Length)
{
int ret =0;
unsigned int StartAddr = Addr;
while(Length){
if(Length > MAX_LENGTH_PER_TRANSFER){
ret = icn85xx_prog_i2c_rxdata(StartAddr, Buffer, MAX_LENGTH_PER_TRANSFER);
Length -= MAX_LENGTH_PER_TRANSFER;
Buffer += MAX_LENGTH_PER_TRANSFER;
StartAddr += MAX_LENGTH_PER_TRANSFER;
}
else{
ret = icn85xx_prog_i2c_rxdata(StartAddr, Buffer, Length);
Length = 0;
Buffer += Length;
StartAddr += Length;
break;
}
pr_err("\n icn85xx_prog_read_page StartAddr:0x%x, length: %d\n",StartAddr,Length);
}
if (ret < 0) {
pr_err("\n icn85xx_prog_read_page failed! StartAddr: 0x%x, ret: %d\n", StartAddr, ret);
return ret;
}
else{
pr_info("\n icn85xx_prog_read_page, StartAddr 0x%x, Length: %d\n", StartAddr, Length);
return ret;
}
}
int icn87xx_prog_read_page(unsigned int Addr,unsigned char *Buffer, unsigned int Length)
{
int ret =0;
unsigned int StartAddr = Addr;
while(Length){
if(Length > MAX_LENGTH_PER_TRANSFER){
ret = icn87xx_prog_i2c_rxdata(StartAddr, Buffer, MAX_LENGTH_PER_TRANSFER);
Length -= MAX_LENGTH_PER_TRANSFER;
Buffer += MAX_LENGTH_PER_TRANSFER;
StartAddr += MAX_LENGTH_PER_TRANSFER;
}
else{
ret = icn87xx_prog_i2c_rxdata(StartAddr, Buffer, Length);
Length = 0;
Buffer += Length;
StartAddr += Length;
break;
}
}
if (ret < 0) {
pr_err("\n icn87xx_prog_read_page failed! StartAddr: 0x%x, ret: %d\n", StartAddr, ret);
return ret;
}
else{
pr_info("\n icn87xx_prog_read_page, StartAddr 0x%x, Length: %d\n", StartAddr, Length);
return ret;
}
}
int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length)
{
int ret = -1;
int retries = 0;
unsigned char tmp_buf[2];
struct i2c_msg msgs[] = {
{
.addr = 0x48,
.flags = 0,
.len = 2,
.buf = tmp_buf,
},
{
.addr = 0x48,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
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)
{
pr_err("%s i2c read error: %d\n", __func__, ret);
}
return ret;
}
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 (length > 125)
{
pr_err("%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)
{
pr_err("%s i2c write error: %d\n", __func__, ret);
}
return ret;
}
int icn87xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length)
{
int ret = -1;
int retries = 0;
unsigned char tmp_buf[3];
struct i2c_msg msgs[] = {
{
.addr = ICN87XX_PROG_IIC_ADDR,//this_client->addr,
.flags = 0,
.len = 2,
.buf = tmp_buf,
},
{
.addr = ICN87XX_PROG_IIC_ADDR,//this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
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)
{
pr_err("%s i2c read error: %d\n", __func__, ret);
}
return ret;
}
int icn87xx_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 = ICN87XX_PROG_IIC_ADDR,//this_client->addr,
.flags = 0,
.len = length + 2,
.buf = tmp_buf,
},
};
if (length > 125)
{
pr_err("%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)
{
pr_err("%s i2c write error: %d\n", __func__, ret);
}
return ret;
}
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) {
pr_err("write reg failed! %#x ret: %d\n", buf[0], ret);
return -1;
}
return ret;
}
int icn85xx_read_reg(unsigned short addr, char *pdata)
{
int ret = -1;
ret = icn85xx_i2c_rxdata(addr, pdata, 1);
pr_info("addr: 0x%x: 0x%x\n", addr, *pdata);
return ret;
}
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; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x2000 + i*COL_NUM*2, (char *)&log_rawdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
icn85xx_rawdatadump(&log_rawdata[i][0], column, COL_NUM);
}
}
if(diff == 1)
{
for(i=0; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x3000 + (i+1)*(COL_NUM+2)*2 + 2, (char *)&log_diffdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
icn85xx_rawdatadump(&log_diffdata[i][0], column, COL_NUM);
}
}
else if(diff == 2)
{
for(i=0; i<row; i++)
{
ret = icn85xx_i2c_rxdata(0x2000 + i*COL_NUM*2, (char *)&log_rawdata[i][0], column*2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
}
if((log_basedata[0][0] != 0) || (log_basedata[0][1] != 0))
{
for(j=0; j<column; j++)
{
log_rawdata[i][j] = log_basedata[i][j] - log_rawdata[i][j];
}
}
icn85xx_rawdatadump(&log_rawdata[i][0], column, COL_NUM);
}
if((log_basedata[0][0] == 0) && (log_basedata[0][1] == 0))
{
memcpy(&log_basedata[0][0], &log_rawdata[0][0], COL_NUM*ROW_NUM*2);
}
}
//finish scan tp rawdata
icn85xx_write_reg(2, 0x0);
icn85xx_write_reg(4, 0x21);
}
static int icn85xx_iic_test(void)
{
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
int ret = -1;
unsigned char value = 0;
unsigned char buf[3];
int retry = 0;
int flashid;
icn85xx_ts->ictype = 0;
icn85xx_ts->ictype = ICTYPE_UNKNOWN;
while(retry++ < 3)
{
ret = icn85xx_read_reg(0xa, &value);
if(ret > 0)
{
if(value == 0x85)
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_85;
setbootmode(ICN85XX_WITH_FLASH_85);
return ret;
}
else if((value == 0x86)||(value == 0x88))
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_86;
setbootmode(ICN85XX_WITH_FLASH_86);
return ret;
}
else if(value == 0x87)
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_87;
setbootmode(ICN85XX_WITH_FLASH_87);
return ret;
}
else if(value == 0x81)
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_87;
setbootmode(ICN85XX_WITH_FLASH_87);
return ret;
}
}
pr_err("iic test error! retry = %d\n", retry);
msleep(3);
}
// force ic enter progmode
icn85xx_goto_progmode();
msleep(10);
retry = 0;
while(retry++ < 3)
{
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
ret = icn85xx_prog_i2c_txdata(0x040000, buf, 3);
if (ret < 0)
{
pr_info("%s, %d\n", __func__, __LINE__);
return ret;
}
ret = icn85xx_prog_i2c_rxdata(0x040000, buf, 3);
if(ret > 0)
{
//if(value == 0x85)
if((buf[2] == 0x85) && (buf[1] == 0x05))
{
flashid = icn85xx_read_flashid();
if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid)
||(MD25D20_ID1 == flashid) || (MD25D20_ID2 == flashid)
||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)
|| (MD25D05_ID == flashid)|| (MD25D10_ID == flashid))
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_85;
setbootmode(ICN85XX_WITH_FLASH_85);
}
else
{
icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH_85;
setbootmode(ICN85XX_WITHOUT_FLASH_85);
}
return ret;
}
else if((buf[2] == 0x85) && (buf[1] == 0x0e))
{
flashid = icn85xx_read_flashid();
if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid)
||(MD25D20_ID1 == flashid) || (MD25D20_ID2 == flashid)
||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)
|| (MD25D05_ID == flashid)|| (MD25D10_ID == flashid))
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_86;
setbootmode(ICN85XX_WITH_FLASH_86);
}
else
{
icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH_86;
setbootmode(ICN85XX_WITHOUT_FLASH_86);
}
return ret;
}
else //for ICNT87
{
ret = icn87xx_prog_i2c_rxdata(0xf001, buf, 2);
if(ret > 0)
{
if(buf[1] == 0x87)
{
flashid = icn87xx_read_flashid();
pr_info("icnt87 flashid: 0x%x\n",flashid);
if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid)
||(MD25D20_ID1 == flashid) || (MD25D20_ID2 == flashid)
||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)
|| (MD25D05_ID == flashid)|| (MD25D10_ID == flashid))
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_87;
setbootmode(ICN85XX_WITH_FLASH_87);
}
else
{
icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH_87;
setbootmode(ICN85XX_WITHOUT_FLASH_87);
}
return ret;
}
else if(buf[1] == 0x8b)
{
flashid = icn87xx_read_flashid();
pr_info("icnt87 flashid: 0x%x\n",flashid);
if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid)
||(MD25D20_ID1 == flashid) || (MD25D20_ID2 == flashid)
||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)
|| (MD25D05_ID == flashid)|| (MD25D10_ID == flashid))
{
icn85xx_ts->ictype = ICN85XX_WITH_FLASH_87;
setbootmode(ICN85XX_WITH_FLASH_87);
}
else
{
icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH_87;
setbootmode(ICN85XX_WITHOUT_FLASH_87);
}
return ret;
}
}
}
}
pr_err("iic2 test error! %d\n", retry);
msleep(3);
}
return ret;
}
#if !CTP_REPORT_PROTOCOL
static void icn85xx_ts_release(void)
{
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
//pr_info("==icn85xx_ts_release ==\n");
input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_sync(icn85xx_ts->input_dev);
}
static void icn85xx_report_value_A(void)
{ //printk("######%s-----%d\n",__func__,__LINE__);
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
unsigned char buf[POINT_NUM*POINT_SIZE+3]={0};
int ret = -1;
int i=0, j=0, nBytes=0;
#if TOUCH_VIRTUAL_KEYS
unsigned char button;
static unsigned char button_last;
#endif
nBytes = POINT_NUM*POINT_SIZE+2;
while (nBytes) {
i = nBytes > 4 ? 4 : nBytes;
ret = icn85xx_i2c_rxdata(0x1000+j, buf+j, i);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ;
}
j = j + i;
nBytes = nBytes - i;
}
#if TOUCH_VIRTUAL_KEYS
button = buf[0];
if((button_last != 0) && (button == 0))
{
icn85xx_ts_release();
button_last = button;
return ;
}
if(button != 0)
{
switch(button)
{
case ICN_VIRTUAL_BUTTON_HOME:
pr_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:
pr_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:
pr_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:
pr_info("other gesture\n");
break;
}
button_last = button;
return ;
}
#endif
// pr_err("=====%s-----%d\n",__func__,__LINE__);
icn85xx_ts->point_num = buf[1];
if (icn85xx_ts->point_num == 0) {
icn85xx_ts_release();
return ;
}
if (icn85xx_ts->point_num > POINT_NUM) {
icn85xx_ts->point_num = 1;
}
for(i=0;i<icn85xx_ts->point_num;i++){
if(buf[8 + POINT_SIZE*i] != 4)
{
break ;
}
else
{
}
}
if(i == icn85xx_ts->point_num) {
icn85xx_ts_release();
return ;
}
for(i=0; i<icn85xx_ts->point_num; i++)
{ // pr_err("=====%s-----%d\n",__func__,__LINE__);
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 = buf[7 + POINT_SIZE*i];
icn85xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i];
#if SWAP_X_Y
swap_ab(icn85xx_ts->point_info[i].u16PosX,icn85xx_ts->point_info[i].u16PosY);
#endif
if(1 == icn85xx_ts->board_info->revert_x_flag)
{
icn85xx_ts->point_info[i].u16PosX = icn85xx_ts->screen_max_x-1- icn85xx_ts->point_info[i].u16PosX;
}
if(1 == icn85xx_ts->board_info->revert_y_flag)
{
icn85xx_ts->point_info[i].u16PosY = icn85xx_ts->screen_max_y-1- icn85xx_ts->point_info[i].u16PosY;
}
if(icn85xx_ts->point_info[i].u8ID < POINT_NUM &&\
icn85xx_ts->point_info[i].u16PosX < SCREEN_MAX_X &&\
icn85xx_ts->point_info[i].u16PosY < SCREEN_MAX_Y &&\
icn85xx_ts->point_info[i].u8Pressure < SCREEN_PRESSURE&&\
icn85xx_ts->point_info[i].u8EventId < EVENT_ID){
//printk("\n before=====%s-----%d u16PosX=%d u16PosY=%d \n",__func__,__LINE__,icn85xx_ts->point_info[i].u16PosX,icn85xx_ts->point_info[i].u16PosY);
if(icn85xx_ts->point_info[i].u16PosX != 0)
{
icn85xx_ts->point_info[i].u16PosX = ((icn85xx_ts->point_info[i].u16PosX*800)/SCREEN_MAX_X);
}
if(icn85xx_ts->point_info[i].u16PosY != 0)
{
icn85xx_ts->point_info[i].u16PosY = ((icn85xx_ts->point_info[i].u16PosY*480)/SCREEN_MAX_Y);
}
//printk("\n after=====%s-----%d u16PosX=%d u16PosY=%d \n",__func__,__LINE__,icn85xx_ts->point_info[i].u16PosX,icn85xx_ts->point_info[i].u16PosY);
/*point_id default is 0,but in order to keep up with gsl3692, we take it as 1. */
// pr_err("=====%s-----%d\n",__func__,__LINE__);
///input_report_abs(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, icn85xx_ts->point_info[i].u8ID + 1);
///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);
input_sync(icn85xx_ts->input_dev);
}
}
}
#else
static void icn85xx_report_value_B(void)
{
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client);
unsigned char buf[POINT_NUM*POINT_SIZE+4]={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 i = 0, j = 0, nBytes = 0;
nBytes = POINT_NUM*POINT_SIZE+2;
while (nBytes) {
i = nBytes > 32 ? 32 : nBytes;
ret = icn85xx_i2c_rxdata(0x1000+j, buf+j, i);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ;
}
j = j + i;
nBytes = nBytes - i;
}
icn85xx_ts->point_num = buf[1];
if (icn85xx_ts->point_num > POINT_NUM)
{
return ;
}
if(icn85xx_ts->point_num > 0)
{
for(position = 0; position<icn85xx_ts->point_num; position++)
{
temp = buf[2 + POINT_SIZE*position] + 1;
if (temp > POINT_NUM) {
pr_info("ERROR: %s ,%d\n", __func__, __LINE__);
return;
}
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->board_info->revert_x_flag)
{
icn85xx_ts->point_info[temp].u16PosX = icn85xx_ts->screen_max_x -1- icn85xx_ts->point_info[temp].u16PosX;
}
if(1 == icn85xx_ts->board_info->revert_y_flag)
{
icn85xx_ts->point_info[temp].u16PosY = icn85xx_ts->screen_max_y-1- icn85xx_ts->point_info[temp].u16PosY;
}
pr_info("temp %d\n", temp);
pr_info("u8ID %d\n", icn85xx_ts->point_info[temp].u8ID);
pr_info("u16PosX %d\n", icn85xx_ts->point_info[temp].u16PosX);
pr_info("u16PosY %d\n", icn85xx_ts->point_info[temp].u16PosY);
pr_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure);
pr_info("u8EventId %d\n", icn85xx_ts->point_info[temp].u8EventId);
pr_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure*16);
}
}
else
{
for(position = 1; position < POINT_NUM+1; position++)
{
finger_current[position] = 0;
}
pr_info("no touch\n");
}
for(position = 1; position < POINT_NUM + 1; position++)
{
if((finger_current[position] == 0) && (finger_last[position] != 0))
{
pr_info("finger_current[position] == 0\n");
icn85xx_point_info("one touch up: %d\n", position);
}
else if(finger_current[position])
{
pr_info("u16PosX:%d u16PosY:%d\n", icn85xx_ts->point_info[position].u16PosX, icn85xx_ts->point_info[position].u16PosY);
/*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, icn85xx_ts->point_info[position].u16PosX);
input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, icn85xx_ts->point_info[position].u16PosY);*/
//pr_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);
}
}
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
// pr_err("=====%s-----%d\n",__func__,__LINE__);
if(icn85xx_ts->use_irq)
{
icn85xx_irq_enable();
}
if(log_on_off == 4)
{
pr_info("normal raw data\n");
icn85xx_log(0); //raw data
}
else if(log_on_off == 5)
{
pr_info("normal diff data\n");
icn85xx_log(1); //diff data
}
else if(log_on_off == 6)
{
pr_info("normal raw2diff\n");
icn85xx_log(2); //diff data
}
}
else if(icn85xx_ts->work_mode == 1)
{
pr_info("raw data\n");
icn85xx_log(0); //raw data
}
else if(icn85xx_ts->work_mode == 2)
{
pr_info("diff data\n");
icn85xx_log(1); //diff data
}
else if(icn85xx_ts->work_mode == 3)
{
pr_info("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
{
pr_info("reinit tp\n");
icn85xx_write_reg(0, 1);
mdelay(100);
icn85xx_write_reg(0, 0);
icn85xx_ts->work_mode = 0;
}
else if((icn85xx_ts->work_mode == 6) ||(icn85xx_ts->work_mode == 7)) //gesture test mode
{
#if SUPPORT_PROC_FS
char buf[sizeof(structGestureData)]={0};
int ret = -1;
int i;
ret = icn85xx_i2c_rxdata(0x7000, buf, 2);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ;
}
structGestureData.u8Status = 1;
structGestureData.u8Gesture = buf[0];
structGestureData.u8GestureNum = buf[1];
pr_debug("structGestureData.u8Gesture: 0x%x\n", structGestureData.u8Gesture);
pr_debug("structGestureData.u8GestureNum: %d\n", structGestureData.u8GestureNum);
ret = icn85xx_i2c_rxdata(0x7002, buf, structGestureData.u8GestureNum*6);
if (ret < 0) {
pr_err("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ;
}
for(i=0; i<structGestureData.u8GestureNum; i++)
{
structGestureData.point_info[i].u16PosX = (buf[1 + 6*i]<<8) + buf[0+ 6*i];
structGestureData.point_info[i].u16PosY = (buf[3 + 6*i]<<8) + buf[2 + 6*i];
structGestureData.point_info[i].u8EventId = buf[5 + 6*i];
pr_info("(%d, %d, %d)", structGestureData.point_info[i].u16PosX, structGestureData.point_info[i].u16PosY, structGestureData.point_info[i].u8EventId);
}
if(((icn85xx_ts->work_mode == 7) && (structGestureData.u8Gesture == 0xFB))
|| (icn85xx_ts->work_mode == 6))
{
pr_info("return normal mode\n");
icn85xx_ts->work_mode = 0; //return normal mode
}
#endif
}
#if SUPPORT_PROC_FS
up(&icn85xx_ts->sem);
#endif
}
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);
//pr_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;
}
/* interrupt service routine
** when there is data available(a press) or in other case,
** interrupt pin gets active to signal this to the CPU.
*/
static irqreturn_t icn85xx_ts_interrupt(int irq, void *dev_id)
{
struct icn85xx_ts_data *icn85xx_ts = dev_id;
//pr_info("==========------icn85xx_ts TS Interrupt-----============\n");
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;
}
static void icn85xx_request_io_port(struct icn85xx_ts_data *icn85xx_ts)
{
icn85xx_ts->screen_max_x = icn85xx_ts->board_info->screen_max_x;
icn85xx_ts->screen_max_y = icn85xx_ts->board_info->screen_max_y;
return ;
}
static void icn85xx_free_io_port(struct icn85xx_ts_data *icn85xx_ts)
{
return ;
}
static int icn85xx_request_irq(struct icn85xx_ts_data *icn85xx_ts)
{
int err = -1;
int irq = gpio_to_irq(icn85xx_ts->board_info->irq_pin);
icn85xx_ts->irq = irq;
gpio_direction_input(icn85xx_ts->board_info->irq_pin);
err = request_irq(irq, icn85xx_ts_interrupt, IRQF_TRIGGER_FALLING|IRQF_ONESHOT, "icn85xx_ts", icn85xx_ts);
if (err < 0)
{
icn85xx_ts->use_irq = 0;
pr_err("icn85xx_ts_probe: request irq failed\n");
return err;
}
icn85xx_irq_disable();
icn85xx_ts->use_irq = 1;
return 0;
}
/*
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);
}
}
}
*/
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) {
pr_err("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, 0);
#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
input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, icn85xx_ts->board_info->screen_max_x, 0, 0);
input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, icn85xx_ts->board_info->screen_max_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) {
pr_err("Register %s input device failed\n", input_dev->name);
input_free_device(input_dev);
return -ENODEV;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
pr_info("==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;
ret = icn85xx_read_reg(0x10, &cursensor_id);
if(ret > 0)
{
pr_info("cursensor_id= 0x%x\n", cursensor_id);
}
else
{
pr_err("icn85xx read cursensor_id failed.\n");
cursensor_id = -1;
}
ret = icn85xx_read_reg(0x1e, &tarsensor_id);
if(ret > 0)
{
pr_info("tarsensor_id= 0x%x\n", tarsensor_id);
tarsensor_id = -1;
}
else
{
pr_err("icn85xx read tarsensor_id failed.\n");
}
ret = icn85xx_read_reg(0x1f, &id_match);
if(ret > 0)
{
pr_info("match_flag= 0x%x\n", id_match); // 1: match; 0:not match
}
else
{
pr_err("icn85xx read id_match failed.\n");
id_match = -1;
}
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);
pr_info("icn85xx matched firmware = %s\n", firmware);
#endif
pr_info("icn85xx matched id = 0x%x\n", sensor_id_table[i].value);
invalid_id = 1;
break;
}
else
{
invalid_id = 0;
pr_info("icn85xx not matched id%d= 0x%x\n", i,sensor_id_table[i].value);
//pr_info("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
{
pr_info("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);
pr_info("match default firmware = %s\n", firmware);
#endif
while(retry > 0)
{
if(R_OK == icn85xx_fw_update(firmware))
{
pr_info("icn85xx upgrade default firmware ok\n");
break;
}
retry--;
pr_err("icn85xx_fw_update default firmware failed.\n");
}
}
if ((1 == invalid_id)&&(0 == id_match)) // tp is changed,update current fw or bin
{
pr_info("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))
{
pr_info("icn85xx upgrade cursensor id firmware ok\n");
break;
}
retry--;
pr_err("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_85) || (icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH_86))
{
#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
pr_info("invalid_id= %d\n", invalid_id);
}
#else
if(R_OK == icn85xx_fw_update(firmware))
{
icn85xx_ts->code_loaded_flag = 1;
pr_info("ICN85XX_WITHOUT_FLASH_85, update default fw ok\n");
}
else
{
icn85xx_ts->code_loaded_flag = 0;
pr_info("ICN85XX_WITHOUT_FLASH_85, update error\n");
}
#endif
}
else if((icn85xx_ts->ictype == ICN85XX_WITH_FLASH_85) || (icn85xx_ts->ictype == ICN85XX_WITH_FLASH_86))
{
#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)
{
pr_info("select sensor id ok. begin compare fwVersion with curversion\n");
}
}
#endif
fwVersion = icn85xx_read_fw_Ver(firmware);
curVersion = icn85xx_readVersion();
pr_info("fwVersion : 0x%x\n", fwVersion);
pr_info("current version: 0x%x\n", curVersion);
#if FORCE_UPDATA_FW
retry = 5;
while(retry > 0)
{
if(icn85xx_goto_progmode() != 0)
{
pr_info("icn85xx_goto_progmode() != 0 error\n");
return ;
}
icn85xx_read_flashid();
if(R_OK == icn85xx_fw_update(firmware))
{
break;
}
retry--;
pr_err("icn85xx_fw_update failed.\n");
}
#else
if(fwVersion > curVersion)
{
retry = 5;
while(retry > 0)
{
if(R_OK == icn85xx_fw_update(firmware))
{
break;
}
retry--;
pr_err("icn85xx_fw_update failed.\n");
}
}
#endif
}
else if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH_87)
{
pr_info("icn85xx_update 87 without flash\n");
#if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID)
icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]);
#endif
if(R_OK == icn87xx_fw_update(firmware))
{
icn85xx_ts->code_loaded_flag = 1;
pr_info("ICN85XX_WITHOUT_FLASH_87, update default fw ok\n");
}
else
{
icn85xx_ts->code_loaded_flag = 0;
pr_info("ICN85XX_WITHOUT_FLASH_87, update error\n");
}
}
else if(icn85xx_ts->ictype == ICN85XX_WITH_FLASH_87)
{
pr_info("icn85xx_update 87 with flash\n");
#if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID)
icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]);
#endif
fwVersion = icn85xx_read_fw_Ver(firmware);
curVersion = icn85xx_readVersion();
pr_info("fwVersion : 0x%x\n", fwVersion);
pr_info("current version: 0x%x\n", curVersion);
#if FORCE_UPDATA_FW
if(R_OK == icn87xx_fw_update(firmware))
{
icn85xx_ts->code_loaded_flag = 1;
pr_info("ICN87XX_WITH_FLASH, update default fw ok\n");
}
else
{
icn85xx_ts->code_loaded_flag = 0;
pr_info("ICN87XX_WITH_FLASH, update error\n");
}
#else
if(fwVersion > curVersion)
{
retry = 5;
while(retry > 0)
{
if(R_OK == icn87xx_fw_update(firmware))
{
break;
}
retry--;
pr_err("icn87xx_fw_update failed.\n");
}
}
#endif
}
else
{
//for next ic type
}
}
static struct tp_board_info tbi = {
.screen_max_x = 1280,//1024,
.screen_max_y = 800,//600,
.revert_x_flag = 0,
.revert_y_flag = 1,
};
//#define IRQ_PORT 36
//#define REST_PORT 38
static int icn85xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ //printk("######%s----%d\n",__func__,__LINE__);
struct device_node* np = client->dev.of_node;
struct icn85xx_ts_data *icn85xx_ts;
int err = 0;
pr_info("-----------------icnt ====%s begin=====.\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
pr_err("I2C check functionality failed.\n");
return -ENODEV;
}
icn85xx_ts = kzalloc(sizeof(*icn85xx_ts), GFP_KERNEL);
if (!icn85xx_ts)
{
pr_err("Alloc icn85xx_ts memory failed.\n");
return -ENOMEM;
}
memset(icn85xx_ts, 0, sizeof(*icn85xx_ts));
icn85xx_ts->board_info = &tbi;
this_client = client;
this_client->addr = client->addr;
i2c_set_clientdata(client, icn85xx_ts);
icn85xx_ts->client = client;
icn85xx_ts->work_mode = 0;
spin_lock_init(&icn85xx_ts->irq_lock);
icn85xx_ts->board_info->reset_pin = of_get_named_gpio(np, "chipone_rst", 0);
icn85xx_ts->board_info->irq_pin = of_get_named_gpio(np, "chipone_int", 0);
pr_err("+++++++reset_pin=%d, irq_pin=%d\n", icn85xx_ts->board_info->reset_pin, icn85xx_ts->board_info->irq_pin);
err = gpio_request(icn85xx_ts->board_info->reset_pin, "tp reset");
if (err) {
pr_err("icn83xx reset gpio request failed.\n");
return -1;
}
icn85xx_ts_reset();
err = icn85xx_iic_test();
if (err <= 0)
{
pr_err("icn85xx_iic_test failed.\n");
goto err_free_mem;
}
else
{
pr_info("iic communication ok: 0x%x\n", icn85xx_ts->ictype);
}
/* download the firmware */
icn85xx_update(icn85xx_ts);
/* download the firmware */
err= icn85xx_request_input_dev(icn85xx_ts);
if (err < 0)
{
pr_err("request input dev failed\n");
kfree(icn85xx_ts);
return err;
}
icn85xx_request_io_port(icn85xx_ts);
icn85xx_ts->irq = client->irq;
#if TOUCH_VIRTUAL_KEYS
icn85xx_ts_virtual_keys_init();
#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) {
pr_err("create_singlethread_workqueue failed.\n");
kfree(icn85xx_ts);
return -ESRCH;
}
/*
** here we can use interrupts or hrtimer mode.
** but we consider interrupts mode first.
*/
err = icn85xx_request_irq(icn85xx_ts);
if (err != 0)
{
pr_err("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);
}
/* support sysfs */
#if SUPPORT_SYSFS
// icn85xx_create_sysfs(client);
#endif
icn85xx_ts->irq_is_disable = 1;
if(icn85xx_ts->use_irq)
{
icn85xx_irq_enable();
}
icn85xx_ts->is_suspend = 0;
return 0;
err_free_mem:
//input_free_device(input_dev);
gpio_free(icn85xx_ts->board_info->reset_pin);
kfree(icn85xx_ts);
return err;
}
static int icn85xx_ts_remove(struct i2c_client *client)
{
struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client);
pr_info("==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
cancel_work_sync(&icn85xx_ts->pen_event_work);
destroy_workqueue(icn85xx_ts->ts_workqueue);
input_unregister_device(icn85xx_ts->input_dev);
input_free_device(icn85xx_ts->input_dev);
icn85xx_free_io_port(icn85xx_ts);
kfree(icn85xx_ts);
i2c_set_clientdata(client, NULL);
gpio_free(icn85xx_ts->board_info->reset_pin);
return 0;
}
static const struct of_device_id ak37d_touchscreen_of_ids[] = {
{ .compatible = "anyka,ak3790d-i2c-touchscreen-icn85xx" },
{},
};
MODULE_DEVICE_TABLE(of, ak37d_touchscreen_of_ids);
static const struct i2c_device_id icn85xx_ts_id[] = {
{ "chipone-icn85xx", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, icn85xx_ts_id);
static struct i2c_driver icn85xx_ts_driver = {
.class = I2C_CLASS_HWMON,
.probe = icn85xx_ts_probe,
.remove = icn85xx_ts_remove,
.id_table = icn85xx_ts_id,
.driver = {
.name = "icn85xx",
.of_match_table = of_match_ptr(ak37d_touchscreen_of_ids),
.owner = THIS_MODULE,
#if SUPPORT_SYSFS
.groups = icn_drv_grp,
#endif
},
};
static int icn85xx_ts_init(void)
{
int ret = -1;
ret = i2c_add_driver(&icn85xx_ts_driver);
return ret;
}
static void icn85xx_ts_exit(void)
{
i2c_del_driver(&icn85xx_ts_driver);
}
module_init(icn85xx_ts_init);
module_exit(icn85xx_ts_exit);
MODULE_AUTHOR("<zhangzhipeng@anyka.com>");
MODULE_DESCRIPTION("Anyka icn85xx TouchScreen controller driver");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL v2");