diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/touchscreen')
113 files changed, 54220 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig index 1e7c563c..873ca6c3 100644 --- a/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig +++ b/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig @@ -851,4 +851,28 @@ config TOUCHSCREEN_TPS6507X To compile this driver as a module, choose M here: the module will be called tps6507x_ts. +config TOUCHSCREEN_VT1609 + tristate "Vt1609 Dual-touch Support,Compatible with Vt1603a Single-touch" + default y + depends on ARCH_WMT + help + Say Y here if you have a vt1603a single or vt1609 dual touchscreen and + want to enable support for the built-in touchscreen. + + To compile this driver as a module, choose M here: the + module will be called vt1609_dual_ts. + +source "drivers/input/touchscreen/gsl1680_ts/Kconfig" +source "drivers/input/touchscreen/sitronix/Kconfig" +source "drivers/input/touchscreen/zet6221_ts/Kconfig" +source "drivers/input/touchscreen/cyp140_ts/Kconfig" +source "drivers/input/touchscreen/ft5x0x/Kconfig" +source "drivers/input/touchscreen/ft6x0x/Kconfig" +source "drivers/input/touchscreen/aw5306_ts/Kconfig" +source "drivers/input/touchscreen/ssd253x_ts/Kconfig" +source "drivers/input/touchscreen/lw86x0_ts/Kconfig" +source "drivers/input/touchscreen/gt9xx_ts/Kconfig" +source "drivers/input/touchscreen/icn83xx_ts/Kconfig" +source "drivers/input/touchscreen/icn85xx_ts/Kconfig" +source "drivers/input/touchscreen/sis_usbhid_ts/Kconfig" endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/Makefile index 175d6414..b632eb48 100644 --- a/ANDROID_3.4.5/drivers/input/touchscreen/Makefile +++ b/ANDROID_3.4.5/drivers/input/touchscreen/Makefile @@ -70,3 +70,19 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o + +obj-$(CONFIG_TOUCHSCREEN_VT1609) += vt1609_ts/ +#GSL1680 touchscreen +obj-$(CONFIG_TOUCHSCREEN_GSL1680) += gsl1680_ts/ +obj-$(CONFIG_TOUCHSCREEN_SITRONIX) += sitronix/ +obj-$(CONFIG_TOUCHSCREEN_ZET6221) += zet6221_ts/ +obj-$(CONFIG_TOUCHSCREEN_CYP140) += cyp140_ts/ +obj-$(CONFIG_TOUCHSCREEN_FT5X0X) += ft5x0x/ +obj-$(CONFIG_TOUCHSCREEN_FT6X0X) += ft6x0x/ +obj-$(CONFIG_TOUCHSCREEN_AW5306) += aw5306_ts/ +obj-$(CONFIG_TOUCHSCREEN_SSD253X) += ssd253x_ts/ +obj-$(CONFIG_TOUCHSCREEN_LW86X0) += lw86x0_ts/ +obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_ts/ +obj-$(CONFIG_TOUCHSCREEN_ICN83XX) += icn83xx_ts/ +obj-$(CONFIG_TOUCHSCREEN_ICN85XX) += icn85xx_ts/ +obj-$(CONFIG_TOUCHSCREEN_SIS) += sis_usbhid_ts/ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b Binary files differnew file mode 100755 index 00000000..e3e6c22a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Base.b diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b Binary files differnew file mode 100755 index 00000000..40e49326 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Clb.b diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b Binary files differnew file mode 100755 index 00000000..03f070a1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.b diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h new file mode 100755 index 00000000..47042361 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Drv.h @@ -0,0 +1,158 @@ +/************************************************************************** +* AW5306_Drv.h +* +* AW5306 Driver code version 1.0 +* +* Create Date : 2012/06/25 +* +* Modify Date : +* +* Create by : wuhaijun +* +**************************************************************************/ + +#ifndef AW5306_DRV_H + +#define AW5306_DRV_H + +#define Release_Ver 219 + + +#define MAX_POINT 5 + +#define NUM_TX 21 // TX number of TOUCH IC +#define NUM_RX 12 // RX number of TOUCH IC + +//#define NEWBASE_PROCESS //new base process need test!!! + +#define ABS(X) ((X > 0) ? (X) : (-X)) + + +typedef enum{ + RawDataMode = 0, + DeltaMode, + MonitorMode +}enumWorkMode; + +typedef enum{ + BASE_INITIAL, + BASE_FAST_TRACE, + BASE_STABLE, + TEMP_DRIFT +} CompensateMode; + +typedef struct { + unsigned short Base[NUM_TX][NUM_RX]; + unsigned short ChipBase[NUM_TX][NUM_RX]; + signed char Flag[NUM_TX][NUM_RX]; + signed char BaseCnt[NUM_TX][NUM_RX]; + unsigned char CompensateFlag; + unsigned char TraceTempIncCnt; + unsigned char TraceTempDecCnt; + unsigned char CompensateStateFrameCnt; + short LastMaxDiff; + CompensateMode CompensateState; + unsigned int InitialFrameCnt; + unsigned char PosBigAreaTouchFlag; + unsigned char NegBigAreaTouchFlag; + unsigned char BigAreaFirstFlag; + unsigned char BigAreaChangeFlag; + unsigned short BigTouchFrame; + unsigned short FrameCnt; + unsigned char LongStableCnt; + unsigned char PosPeakCnt; + unsigned char NegPeakCnt; + unsigned char PeakCheckFrameCnt; + unsigned char BaseFrozen; + unsigned char PosPeakCompensateCnt[MAX_POINT]; + unsigned char NegPeakCompensateCnt[MAX_POINT]; +}STRUCTBASE; + +typedef struct { + unsigned char Peak[MAX_POINT][2]; + unsigned char LastPeak[MAX_POINT][2]; + unsigned char NegPeak[MAX_POINT][2]; + unsigned char CurrentPointNum; + unsigned char CurrentNegPointNum; + unsigned char LastPointNum; +}STRUCTPEAK; + +typedef struct { + unsigned short X,Y; // X,Y coordinate + unsigned char PointID; // Assigned point ID + unsigned char Event; // Event of current point +}STRUCTPOINT; + +typedef struct { + STRUCTPOINT PointInfo[MAX_POINT]; + STRUCTPOINT RptPoint[MAX_POINT]; + unsigned char PointNum; + unsigned char LastPointNum; + unsigned char NegPointNum; + unsigned char FilterPointCnt; + unsigned char FirstLiftUpFlag; + unsigned char TouchStatus; + unsigned char PointHoldCnt[MAX_POINT]; + unsigned char PointPressCnt[MAX_POINT]; + +}STRUCTFRAME; + +typedef struct { + unsigned char fileflag[14]; + unsigned char TXOFFSET[(NUM_TX+1)/2]; + unsigned char RXOFFSET[(NUM_RX+1)/2]; + unsigned char TXCAC[NUM_TX]; + unsigned char RXCAC[NUM_RX]; + unsigned char TXGAIN[NUM_TX]; + short SOFTOFFSET[NUM_TX][NUM_RX]; +}STRUCTCALI; + +#define NOISE_LISTENING 0 +#define NOISE_SCAN 1 +#define NOISE_FREQ_JUMP 2 +#define NOISE_SEEK_FAIL 3 + +#define NOISE_FRM_NORMAL 0 +#define NOISE_FRM_PRE_MEASURE 1 +#define NOISE_FRM_MEASURE 2 + +typedef struct { + unsigned char AllFrmCnt; // Frame counter to generate noise meaure frame indicator + unsigned char NoiseFrmCnt; // Frame counter for noise level checking + unsigned char IdleFrmCnt; // No touch frame counter + unsigned char State; // Noise checking state: LISTENING, SCAN, JUMP + unsigned char FrmState; // Frame type indicator: PRE_MEAUSRE, MEAUSRE, NORMAL + short NoiseNormal; // Noise in working freq + short NoiseScan; // Noise in scan freq + short Better_NoiseScan; //pfx:smaller Noise in Scan freq + unsigned char Better_ScanFreqID; //pfx:the Scan Freq for the smaller Noise + unsigned char ScanFreqID; // Scan freq ID + unsigned char WorkFreqID; // Current freq ID + short NoiseTh1; // Diff threshold for noise too high judgement + char JumpTh; // frame number threshold for freq jumping + char FailedFreqList [32]; // Searched freq indicator for freq scanning +}STRUCTNOISE; + + +void AW5306_TP_Init(void); +void AW5306_TP_Reinit(void); +void AW5306_Sleep(void); +char AW5306_TouchProcess(void); +void AW5306_ChargeMode(char mode); +unsigned char AW5306_GetPointNum(void); +unsigned char AW5306_GetPeakNum(void); +char AW5306_GetPoint(int *x,int *y, int *id, int *event,char Index); +void AW5306_GetBase(unsigned short *data, char x,char y); +void AW5306_GetDiff(short *data, char x,char y); +char AW5306_GetPeak(unsigned char *x,unsigned char *y,unsigned char Index); +char AW5306_GetNegPeak(unsigned char *x,unsigned char *y,unsigned char Index); +char AW5306_GetCalcPoint(unsigned short *x,unsigned short *y,unsigned char Index); +char AW5306_CLB(void); +void AW5306_CLB_GetCfg(void); +void AW5306_CLB_WriteCfg(void); +void TP_Force_Calibration(void); +void FreqScan(unsigned char BaseFreq); + + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h new file mode 100755 index 00000000..2bbbeb00 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_Reg.h @@ -0,0 +1,187 @@ +/************************************************************************** +* AW5306_Reg.h +* +* AW5306 Driver code version 1.0 +* +* Create Date : 2012/06/25 +* +* Modify Date : +* +* Create by : wuhaijun +* +**************************************************************************/ + +#ifndef AW5306_REG_H + +#define AW5306_REG_H + +#define SA_PAGE 0x00 +#define SA_IDRST 0x01 +#define SA_CTRL 0x02 +#define SA_SCANMD 0x03 +#define SA_IER 0x04 +#define SA_RX_NUM 0x05 +#define SA_RX_START 0x06 +#define SA_TX_NUM 0x07 +#define SA_TX_INDEX0 0x08 +#define SA_TX_INDEX1 0x09 +#define SA_TX_INDEX2 0x0A +#define SA_TX_INDEX3 0x0B +#define SA_TX_INDEX4 0x0C +#define SA_TX_INDEX5 0x0D +#define SA_TX_INDEX6 0x0E +#define SA_TX_INDEX7 0x0F +#define SA_TX_INDEX8 0x10 +#define SA_TX_INDEX9 0x11 +#define SA_TX_INDEX10 0x12 +#define SA_TX_INDEX11 0x13 +#define SA_TX_INDEX12 0x14 +#define SA_TX_INDEX13 0x15 +#define SA_TX_INDEX14 0x16 +#define SA_TX_INDEX15 0x17 +#define SA_TX_INDEX16 0x18 +#define SA_TX_INDEX17 0x19 +#define SA_TX_INDEX18 0x1A +#define SA_TX_INDEX19 0x1B +#define SA_TX_INDEX20 0x1C +#define SA_TXCAC0 0x1D +#define SA_TXCAC1 0x1E +#define SA_TXCAC2 0x1F +#define SA_TXCAC3 0x20 +#define SA_TXCAC4 0x21 +#define SA_TXCAC5 0x22 +#define SA_TXCAC6 0x23 +#define SA_TXCAC7 0x24 +#define SA_TXCAC8 0x25 +#define SA_TXCAC9 0x26 +#define SA_TXCAC10 0x27 +#define SA_TXCAC11 0x28 +#define SA_TXCAC12 0x29 +#define SA_TXCAC13 0x2A +#define SA_TXCAC14 0x2B +#define SA_TXCAC15 0x2C +#define SA_TXCAC16 0x2D +#define SA_TXCAC17 0x2E +#define SA_TXCAC18 0x2F +#define SA_TXCAC19 0x30 +#define SA_TXCAC20 0x31 +#define SA_TXOFFSET0 0x32 +#define SA_TXOFFSET1 0x33 +#define SA_TXOFFSET2 0x34 +#define SA_TXOFFSET3 0x35 +#define SA_TXOFFSET4 0x36 +#define SA_TXOFFSET5 0x37 +#define SA_TXOFFSET6 0x38 +#define SA_TXOFFSET7 0x39 +#define SA_TXOFFSET8 0x3A +#define SA_TXOFFSET9 0x3B +#define SA_TXOFFSET10 0x3C +#define SA_RXCAC0 0x3E +#define SA_RXCAC1 0x3F +#define SA_RXCAC2 0x40 +#define SA_RXCAC3 0x41 +#define SA_RXCAC4 0x42 +#define SA_RXCAC5 0x43 +#define SA_RXCAC6 0x44 +#define SA_RXCAC7 0x45 +#define SA_RXCAC8 0x46 +#define SA_RXCAC9 0x47 +#define SA_RXCAC10 0x48 +#define SA_RXCAC11 0x49 +#define SA_RXOFFSET0 0x4A +#define SA_RXOFFSET1 0x4B +#define SA_RXOFFSET2 0x4C +#define SA_RXOFFSET3 0x4D +#define SA_RXOFFSET4 0x4E +#define SA_RXOFFSET5 0x4F +#define SA_DRV_VLT 0x51 +#define SA_SCANFREQ1 0x52 +#define SA_SCANFREQ2 0x53 +#define SA_SCANFREQ3 0x54 +#define SA_TXADCGAIN0 0x55 +#define SA_TXADCGAIN1 0x56 +#define SA_TXADCGAIN2 0x57 +#define SA_TXADCGAIN3 0x58 +#define SA_TXADCGAIN4 0x59 +#define SA_TXADCGAIN5 0x5A +#define SA_TXADCGAIN6 0x5B +#define SA_TXADCGAIN7 0x5C +#define SA_TXADCGAIN8 0x5D +#define SA_TXADCGAIN9 0x5E +#define SA_TXADCGAIN10 0x5F +#define SA_TXADCGAIN11 0x60 +#define SA_TXADCGAIN12 0x61 +#define SA_TXADCGAIN13 0x62 +#define SA_TXADCGAIN14 0x63 +#define SA_TXADCGAIN15 0x64 +#define SA_TXADCGAIN16 0x65 +#define SA_TXADCGAIN17 0x66 +#define SA_TXADCGAIN18 0x67 +#define SA_TXADCGAIN19 0x68 +#define SA_TXADCGAIN20 0x69 +#define SA_WAITTIME 0x6A +#define SA_TCLKDLY 0x6B +#define SA_FINEADJ 0x6C +#define SA_TXCLKFREQ 0x6D +#define SA_SCANTIM 0x6E +#define SA_READSEL 0x70 +#define SA_ISR 0x71 +#define SA_STATE1 0x72 +#define SA_POSCNT 0x73 +#define SA_NEGCNT 0x74 +#define SA_VLDNUM 0x75 +#define SA_ADDRH 0x7D +#define SA_ADDRL 0x7E +#define SA_RAWDATA 0x7F +//////////////////////// +// Page 2 +//////////////////////// +#define SA_SINETABE1 0x03 +#define SA_SINETABE2 0x04 +#define SA_DATAOFFSET 0x05 +#define SA_TRACECTRL1 0x10 +#define SA_TRACECTRL2 0x11 +#define SA_TRACECTRL3 0x12 +#define SA_TRACEST 0x13 +#define SA_RPTNEGTH 0x14 +#define SA_RPTPOSTH 0x15 +#define SA_TRACESTEP 0x16 +#define SA_TRCLVLLO 0x17 +#define SA_TRCLVLPOSHI 0x18 +#define SA_TRCLVLNEGHI 0x19 +#define SA_TRACEINTERVAL 0x1A +#define SA_RXSTABLETH 0x1B +#define SA_POSLEVELTH 0x1C +#define SA_POSNUMTH 0x1D +#define SA_NEGLEVELTH 0x1E +#define SA_NEGNUMTH 0x1F +#define SA_BIGPOINTTH 0x20 +#define SA_BIGPOSTIMTH 0x21 +#define SA_BIGNEGTIMTH 0x22 +#define SA_NEGTIMTH 0x23 +#define SA_TRACEHIGHTIM 0x24 +#define SA_INITPNTTH 0x25 +#define SA_TCHCLRTIMSET 0x26 +#define SA_INITLVTH 0x27 +#define SA_MAXCHKTH 0x28 +#define SA_MINCHKTH 0x29 +#define SA_INITFORCEQUIT 0x2A +#define SA_CHAMPCFG 0x30 +#define SA_ADCCFG 0x31 +#define SA_IBCFG1 0x32 +#define SA_IBCFG2 0x33 +#define SA_LDOCFG 0x34 +#define SA_OSCCFG1 0x35 +#define SA_OSCCFG2 0x36 +#define SA_OSCCFG3 0x37 +#define SA_EN_CLK_QNTZ1 0x38 +#define SA_EN_CLK_QNTZ2 0x39 +#define SA_CPFREQ 0x3A +#define SA_ATEST1 0x3B +#define SA_ATEST2 0x3C +#define SA_RAMTST 0x60 +#define SA_TESTCFG 0x61 +#define SA_TSTDATAH 0x62 +#define SA_TSTDATAL 0x63 +#endif + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c new file mode 100755 index 00000000..f623c646 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_ts.c @@ -0,0 +1,1614 @@ +/* + * drivers/input/touchscreen/aw5306/aw5306.c + * + * FocalTech aw5306 TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * note: only support mulititouch Wenfs 2010-10-01 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/input.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/platform_device.h> +#include <linux/suspend.h> +#include <linux/wait.h> +#include <asm/uaccess.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <linux/slab.h> +#include "AW5306_Drv.h" +#include "AW5306_userpara.h" +#include "irq_gpio.h" + +#define CONFIG_AW5306_MULTITOUCH (1) +#define DEV_AW5306 "touch_aw5306" +#define TS_I2C_NAME "aw5306-ts" +#define AW5306_I2C_ADDR 0x38 +#define AW5306_I2C_BUS 0x01 + +//#define DEBUG_EN + +#undef dbg +#ifdef DEBUG_EN + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + + + +struct ts_event { + int x[5]; + int y[5]; + int pressure; + int touch_ID[5]; + int touch_point; + int pre_point; +}; + +struct AW5306_ts_data { + const char *name; + struct input_dev *input_dev; + struct ts_event event; + struct work_struct pen_event_work; + struct workqueue_struct *ts_workqueue; + struct kobject *kobj; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct timer_list touch_timer; + + int irq; + int irqgpio; + int rstgpio; + + int reslx; + int resly; + int nt; + int nb; + int xch; + int ych; + int swap; + int dbg; + int lcd_exchg; +}; + + +struct AW5306_ts_data *pContext=NULL; +static struct i2c_client *l_client=NULL; +static unsigned char suspend_flag=0; //0: sleep out; 1: sleep in +static short tp_idlecnt = 0; +static char tp_SlowMode = 0; +//static struct class *i2c_dev_class; + +extern char AW5306_CLB(void); +extern void AW5306_CLB_GetCfg(void); +extern STRUCTCALI AW_Cali; +extern AW5306_UCF AWTPCfg; +extern STRUCTBASE AW_Base; +extern short Diff[NUM_TX][NUM_RX]; +extern short adbDiff[NUM_TX][NUM_RX]; +extern short AWDeltaData[32]; + +char AW_CALI_FILENAME[50] = {0,}; +char AW_UCF_FILENAME[50] = {0,}; + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + + +void __aeabi_unwind_cpp_pr0(void) +{ +} + +void __aeabi_unwind_cpp_pr1(void) +{ +} + + +int AW_nvram_read(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + //ssize_t ret; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_RDONLY, 0); + + if(IS_ERR(fd)) { + printk("[AW5306][nvram_read] : failed to open!!\n"); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) + { + printk("[AW5306][nvram_read] : file can not be read!!\n"); + break; + } + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + printk("[AW5306][nvram_read] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->read(fd, + buf, + len, + &fd->f_pos); + + }while(false); + + filp_close(fd, NULL); + + set_fs(old_fs); + + + return retLen; +} + +int AW_nvram_write(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + //ssize_t ret; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_WRONLY|O_CREAT, 0666); + + if(IS_ERR(fd)) { + printk("[AW5306][nvram_write] : failed to open!!\n"); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) + { + printk("[AW5306][nvram_write] : file can not be write!!\n"); + break; + } /* End of if */ + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + printk("[AW5306][nvram_write] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->write(fd, + buf, + len, + &fd->f_pos); + + }while(false); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; +} + + +int AW_I2C_WriteByte(u8 addr, u8 para) +{ + int ret; + u8 buf[3]; + struct i2c_msg msg[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, + }; + buf[0] = addr; + buf[1] = para; + ret = i2c_transfer(l_client->adapter, msg, 1); + return ret; +} + + +unsigned char AW_I2C_ReadByte(u8 addr) +{ + int ret; + u8 buf[2] = {0}; + struct i2c_msg msgs[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = 1, + .buf = buf, + }, + { + .addr = l_client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + }, + }; + buf[0] = addr; + //msleep(1); + ret = i2c_transfer(l_client->adapter, msgs, 2); + return buf[0]; +} + +unsigned char AW_I2C_ReadXByte( unsigned char *buf, unsigned char addr, unsigned short len) +{ + int ret,i; + u8 rdbuf[512] = {0}; + struct i2c_msg msgs[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = 1, + .buf = rdbuf, + }, + { + .addr = l_client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = rdbuf, + }, + }; + rdbuf[0] = addr; + //msleep(1); + ret = i2c_transfer(l_client->adapter, msgs, 2); + if (ret < 0) + pr_err("msg %s i2c read error: %d\n", __func__, ret); + for(i = 0; i < len; i++) + { + buf[i] = rdbuf[i]; + } + return ret; +} + +unsigned char AW_I2C_WriteXByte( unsigned char *buf, unsigned char addr, unsigned short len) +{ + int ret,i; + u8 wdbuf[512] = {0}; + + struct i2c_msg msgs[] = { + { + .addr = l_client->addr, + .flags = 0, + .len = len+1, + .buf = wdbuf, + } + }; + + wdbuf[0] = addr; + for(i = 0; i < len; i++) + { + wdbuf[i+1] = buf[i]; + } + //msleep(1); + ret = i2c_transfer(l_client->adapter, msgs, 1); + if (ret < 0) + pr_err("msg %s i2c read error: %d\n", __func__, ret); + return ret; +} + + +void AW_Sleep(unsigned int msec) +{ + msleep(msec); +} + +static ssize_t AW5306_get_Cali(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_set_Cali(struct device* cd,struct device_attribute *attr, const char *buf, size_t count); +static ssize_t AW5306_get_reg(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_write_reg(struct device* cd,struct device_attribute *attr, const char *buf, size_t count); +static ssize_t AW5306_get_Base(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_Diff(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_adbBase(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_adbDiff(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_get_FreqScan(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t AW5306_Set_FreqScan(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); +static ssize_t AW5306_GetUcf(struct device* cd,struct device_attribute *attr, char* buf); + + + +static DEVICE_ATTR(cali, S_IRUGO | S_IWUGO, AW5306_get_Cali, AW5306_set_Cali); +static DEVICE_ATTR(readreg, S_IRUGO | S_IWUGO, AW5306_get_reg, AW5306_write_reg); +static DEVICE_ATTR(base, S_IRUGO | S_IWUSR, AW5306_get_Base, NULL); +static DEVICE_ATTR(diff, S_IRUGO | S_IWUSR, AW5306_get_Diff, NULL); +static DEVICE_ATTR(adbbase, S_IRUGO | S_IWUSR, AW5306_get_adbBase, NULL); +static DEVICE_ATTR(adbdiff, S_IRUGO | S_IWUSR, AW5306_get_adbDiff, NULL); +static DEVICE_ATTR(freqscan, S_IRUGO | S_IWUGO, AW5306_get_FreqScan, AW5306_Set_FreqScan); +static DEVICE_ATTR(getucf, S_IRUGO | S_IWUSR, AW5306_GetUcf, NULL); + + +static ssize_t AW5306_get_Cali(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len,"AWINIC RELEASE CODE VER = %d\n", Release_Ver); + + len += snprintf(buf+len, PAGE_SIZE-len,"*****AW5306 Calibrate data*****\n"); + len += snprintf(buf+len, PAGE_SIZE-len,"TXOFFSET:"); + + for(i=0;i<11;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.TXOFFSET[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "RXOFFSET:"); + + for(i=0;i<6;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.RXOFFSET[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "TXCAC:"); + + for(i=0;i<21;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.TXCAC[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "RXCAC:"); + + for(i=0;i<12;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.RXCAC[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + len += snprintf(buf+len, PAGE_SIZE-len, "TXGAIN:"); + + for(i=0;i<21;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02X ", AW_Cali.TXGAIN[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + + for(i=0;i<AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j<AWTPCfg.RX_LOCAL;j++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "%4d ", AW_Cali.SOFTOFFSET[i][j]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + return len; + +} + +static ssize_t AW5306_set_Cali(struct device* cd,struct device_attribute *attr, const char* buf, size_t count) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + + unsigned long on_off = simple_strtoul(buf, NULL, 10); + + if(on_off == 1) + { + #ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + TP_Force_Calibration(); + + AW5306_TP_Reinit(); + wmt_enable_gpirq(data->irqgpio); + suspend_flag = 0; + + #else + suspend_flag = 1; + AW_Sleep(50); + + TP_Force_Calibration(); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); + #endif + } + + return count; +} + + +static ssize_t AW5306_get_adbBase(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "base: \n"); + for(i=0;i< AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j<AWTPCfg.RX_LOCAL;j++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "%4d, ",AW_Base.Base[i][j]+AW_Cali.SOFTOFFSET[i][j]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t AW5306_get_Base(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + *(buf+len) = AWTPCfg.TX_LOCAL; + len++; + *(buf+len) = AWTPCfg.RX_LOCAL; + len++; + + for(i=0;i< AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j<AWTPCfg.RX_LOCAL;j++) + { + *(buf+len) = (char)(((AW_Base.Base[i][j]+AW_Cali.SOFTOFFSET[i][j]) & 0xFF00)>>8); + len++; + *(buf+len) = (char)((AW_Base.Base[i][j]+AW_Cali.SOFTOFFSET[i][j]) & 0x00FF); + len++; + } + } + return len; + +} + +static ssize_t AW5306_get_adbDiff(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "Diff: \n"); + for(i=0;i< AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j<AWTPCfg.RX_LOCAL;j++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "%4d, ",adbDiff[i][j]); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + } + + return len; +} + +static ssize_t AW5306_get_Diff(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i,j; + ssize_t len = 0; + + *(buf+len) = AWTPCfg.TX_LOCAL; + len++; + *(buf+len) = AWTPCfg.RX_LOCAL; + len++; + + for(i=0;i< AWTPCfg.TX_LOCAL;i++) + { + for(j=0;j<AWTPCfg.RX_LOCAL;j++) + { + *(buf+len) = (char)((adbDiff[i][j] & 0xFF00)>>8); + len++; + *(buf+len) = (char)(adbDiff[i][j] & 0x00FF); + len++; + } + } + return len; +} + +static ssize_t AW5306_get_FreqScan(struct device* cd,struct device_attribute *attr, char* buf) +{ + unsigned char i; + ssize_t len = 0; + + for(i=0;i< 32;i++) + { + //*(buf+len) = (char)((AWDeltaData[i] & 0xFF00)>>8); + //len++; + //*(buf+len) = (char)(AWDeltaData[i] & 0x00FF); + //len++; + len += snprintf(buf+len, PAGE_SIZE-len, "%4d, ",AWDeltaData[i]); + } + + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + return len; +} + +static ssize_t AW5306_Set_FreqScan(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + unsigned long Basefreq = simple_strtoul(buf, NULL, 10); + + if(Basefreq < 16) + { + #ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + FreqScan(Basefreq); + + AW5306_TP_Reinit(); + wmt_enable_gpirq(data ->irqgpio); + suspend_flag = 0; + #else + suspend_flag = 1; + AW_Sleep(50); + + FreqScan(Basefreq); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); + #endif + } + + return len; +} + +static ssize_t AW5306_get_reg(struct device* cd,struct device_attribute *attr, char* buf) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + u8 reg_val[128]; + ssize_t len = 0; + u8 i; + + if(suspend_flag != 1) + { +#ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + AW_I2C_ReadXByte(reg_val,0,127); + + AW5306_TP_Reinit(); + wmt_enable_gpirq(data->irqgpio); + suspend_flag = 0; +#else + suspend_flag = 1; + + AW_Sleep(50); + + AW_I2C_ReadXByte(reg_val,0,127); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); +#endif + } + else + { + AW_I2C_ReadXByte(reg_val,0,127); + } + for(i=0;i<0x7F;i++) + { + len += snprintf(buf+len, PAGE_SIZE-len, "reg%02X = 0x%02X, ", i,reg_val[i]); + } + + return len; + +} + +static ssize_t AW5306_write_reg(struct device* cd,struct device_attribute *attr, const char *buf, size_t count) +{ + struct AW5306_ts_data *data = i2c_get_clientdata(l_client); + int databuf[2]; + + if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) + { + if(suspend_flag != 1) + { + #ifdef INTMODE + wmt_disable_gpirq(data ->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + AW_Sleep(50); + + AW_I2C_WriteByte((u8)databuf[0],(u8)databuf[1]); + + AW5306_TP_Reinit(); + //ctp_enable_irq(); + wmt_enable_gpirq(data->irqgpio); + suspend_flag = 0; + #else + suspend_flag = 1; + AW_Sleep(50); + + AW_I2C_WriteByte((u8)databuf[0],(u8)databuf[1]); + + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + data->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&data->touch_timer); + #endif + } + else + { + AW_I2C_WriteByte((u8)databuf[0],(u8)databuf[1]); + } + } + else + { + printk("invalid content: '%s', length = %d\n", buf, count); + } + return count; +} + +static ssize_t AW5306_GetUcf(struct device* cd,struct device_attribute *attr, char* buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len,"*****AW5306 UCF DATA*****\n"); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.TX_LOCAL,AWTPCfg.RX_LOCAL); + len += snprintf(buf+len, PAGE_SIZE-len,"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d}\n", + AWTPCfg.TX_ORDER[0],AWTPCfg.TX_ORDER[1],AWTPCfg.TX_ORDER[2],AWTPCfg.TX_ORDER[3],AWTPCfg.TX_ORDER[4], + AWTPCfg.TX_ORDER[5],AWTPCfg.TX_ORDER[6],AWTPCfg.TX_ORDER[7],AWTPCfg.TX_ORDER[8],AWTPCfg.TX_ORDER[9], + AWTPCfg.TX_ORDER[10],AWTPCfg.TX_ORDER[11],AWTPCfg.TX_ORDER[12],AWTPCfg.TX_ORDER[13],AWTPCfg.TX_ORDER[14], + AWTPCfg.TX_ORDER[15],AWTPCfg.TX_ORDER[16],AWTPCfg.TX_ORDER[17],AWTPCfg.TX_ORDER[19],AWTPCfg.TX_ORDER[19], + AWTPCfg.TX_ORDER[20]); + len += snprintf(buf+len, PAGE_SIZE-len,"{%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d},\n", + AWTPCfg.RX_ORDER[0],AWTPCfg.RX_ORDER[1],AWTPCfg.RX_ORDER[2],AWTPCfg.RX_ORDER[3], + AWTPCfg.RX_ORDER[4],AWTPCfg.RX_ORDER[5],AWTPCfg.RX_ORDER[6],AWTPCfg.RX_ORDER[7], + AWTPCfg.RX_ORDER[8],AWTPCfg.RX_ORDER[9],AWTPCfg.RX_ORDER[10],AWTPCfg.RX_ORDER[11]); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.RX_START,AWTPCfg.HAVE_KEY_LINE); + len += snprintf(buf+len, PAGE_SIZE-len,"{%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d},\n", + AWTPCfg.KeyLineValid[0],AWTPCfg.KeyLineValid[1],AWTPCfg.KeyLineValid[2],AWTPCfg.KeyLineValid[3], + AWTPCfg.KeyLineValid[4],AWTPCfg.KeyLineValid[5],AWTPCfg.KeyLineValid[6],AWTPCfg.KeyLineValid[7], + AWTPCfg.KeyLineValid[8],AWTPCfg.KeyLineValid[9],AWTPCfg.KeyLineValid[10],AWTPCfg.KeyLineValid[11]); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.MAPPING_MAX_X,AWTPCfg.MAPPING_MAX_Y); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.GainClbDeltaMax,AWTPCfg.GainClbDeltaMin); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.KeyLineDeltaMax,AWTPCfg.KeyLineDeltaMin); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.OffsetClbExpectedMax,AWTPCfg.OffsetClbExpectedMin); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.RawDataDeviation,AWTPCfg.CacMultiCoef); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.RawDataCheckMin,AWTPCfg.RawDataCheckMax); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.FLYING_TH,AWTPCfg.MOVING_TH,AWTPCfg.MOVING_ACCELER); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.PEAK_TH,AWTPCfg.GROUP_TH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.BIGAREA_TH,AWTPCfg.BIGAREA_CNT,AWTPCfg.BIGAREA_FRESHCNT); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.CACULATE_COEF,AWTPCfg.FIRST_CALI,AWTPCfg.RAWDATA_DUMP_SWITCH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,0x%x,\n",AWTPCfg.MULTI_SCANFREQ,AWTPCfg.BASE_FREQ,AWTPCfg.FREQ_OFFSET); + len += snprintf(buf+len, PAGE_SIZE-len,"0x%x,0x%x,0x%x,\n",AWTPCfg.WAIT_TIME,AWTPCfg.CHAMP_CFG,AWTPCfg.POSLEVEL_TH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,\n",AWTPCfg.ESD_PROTECT); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,%d,%d,\n",AWTPCfg.MARGIN_COMPENSATE,AWTPCfg.MARGIN_COMP_DATA_UP, + AWTPCfg.MARGIN_COMP_DATA_DOWN,AWTPCfg.MARGIN_COMP_DATA_LEFT,AWTPCfg.MARGIN_COMP_DATA_RIGHT); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,%d,\n",AWTPCfg.POINT_RELEASEHOLD,AWTPCfg.MARGIN_RELEASEHOLD, + AWTPCfg.POINT_PRESSHOLD,AWTPCfg.KEY_PRESSHOLD); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.PEAK_ROW_COMPENSATE,AWTPCfg.PEAK_COL_COMPENSATE, + AWTPCfg.PEAK_COMPENSATE_COEF); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.LCD_NOISE_PROCESS,AWTPCfg.LCD_NOISETH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.FALSE_PEAK_PROCESS,AWTPCfg.FALSE_PEAK_TH); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.STABLE_DELTA_X,AWTPCfg.STABLE_DELTA_Y); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,%d,\n",AWTPCfg.DEBUG_LEVEL,AWTPCfg.FAST_FRAME,AWTPCfg.SLOW_FRAME); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.GAIN_CLB_SEPERATE,AWTPCfg.MARGIN_PREFILTER); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.BIGAREA_HOLDPOINT,AWTPCfg.CHARGE_NOISE); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.FREQ_JUMP,AWTPCfg.PEAK_VALID_CHECK); + len += snprintf(buf+len, PAGE_SIZE-len,"%d,%d,\n",AWTPCfg.WATER_REMOVE,AWTPCfg.INT_MODE); + + return len; + +} + + +static int AW5306_create_sysfs(struct i2c_client *client) +{ + int err; + struct device *dev = &(client->dev); + + //TS_DBG("%s", __func__); + + err = device_create_file(dev, &dev_attr_cali); + err = device_create_file(dev, &dev_attr_readreg); + err = device_create_file(dev, &dev_attr_base); + err = device_create_file(dev, &dev_attr_diff); + err = device_create_file(dev, &dev_attr_adbbase); + err = device_create_file(dev, &dev_attr_adbdiff); + err = device_create_file(dev, &dev_attr_freqscan); + err = device_create_file(dev, &dev_attr_getucf); + return err; +} + +static void AW5306_ts_release(void) +{ + struct AW5306_ts_data *data = pContext; +#ifdef CONFIG_AW5306_MULTITOUCH + #ifdef TOUCH_KEY_SUPPORT + if(1 == key_tp){ + if(key_val == 1){ + input_report_key(data->input_dev, KEY_MENU, 0); + input_sync(data->input_dev); + } + else if(key_val == 2){ + input_report_key(data->input_dev, KEY_BACK, 0); + input_sync(data->input_dev); + // printk("===KEY 2 upupupupupu===++=\n"); + } + else if(key_val == 3){ + input_report_key(data->input_dev, KEY_SEARCH, 0); + input_sync(data->input_dev); + // printk("===KEY 3 upupupupupu===++=\n"); + } + else if(key_val == 4){ + input_report_key(data->input_dev, KEY_HOMEPAGE, 0); + input_sync(data->input_dev); + // printk("===KEY 4 upupupupupu===++=\n"); + } + else if(key_val == 5){ + input_report_key(data->input_dev, KEY_VOLUMEDOWN, 0); + input_sync(data->input_dev); + // printk("===KEY 5 upupupupupu===++=\n"); + } + else if(key_val == 6){ + input_report_key(data->input_dev, KEY_VOLUMEUP, 0); + input_sync(data->input_dev); + // printk("===KEY 6 upupupupupu===++=\n"); + } +// input_report_key(data->input_dev, key_val, 0); + //printk("Release Key = %d\n",key_val); + //printk("Release Keyi+++++++++++++++++++++++++++++\n"); + } else{ + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); + } + #else + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); + #endif + +#else + input_report_abs(data->input_dev, ABS_PRESSURE, 0); + input_report_key(data->input_dev, BTN_TOUCH, 0); +#endif + + input_mt_sync(data->input_dev); + input_sync(data->input_dev); + return; + +} + + +static void Point_adjust(int *x, int *y) +{ + struct AW5306_ts_data *AW5306_ts = pContext; + int temp; + + if (AW5306_ts->swap) { + temp = *x; + *x = *y; + *y = temp; + } + if (AW5306_ts->xch) + *x = AW5306_ts->reslx - *x; + if (AW5306_ts->ych) + *y = AW5306_ts->resly - *y; + + if (AW5306_ts->lcd_exchg) { + int tmp; + tmp = *x; + *x = *y; + *y = AW5306_ts->reslx - tmp; + } +} + + +static int AW5306_read_data(void) +{ + struct AW5306_ts_data *data = pContext; + struct ts_event *event = &data->event; + int Pevent; + int i = 0; + + AW5306_TouchProcess(); + + //memset(event, 0, sizeof(struct ts_event)); + event->touch_point = AW5306_GetPointNum(); + + for(i=0;i<event->touch_point;i++) + { + AW5306_GetPoint(&event->x[i],&event->y[i],&event->touch_ID[i],&Pevent,i); + //swap(event->x[i], event->y[i]); + Point_adjust(&event->x[i], &event->y[i]); +// printk("key%d = %d,%d,%d \n",i,event->x[i],event->y[i],event->touch_ID[i] ); + } + + if (event->touch_point == 0) + { + if(tp_idlecnt <= AWTPCfg.FAST_FRAME*5) + { + tp_idlecnt++; + } + if(tp_idlecnt > AWTPCfg.FAST_FRAME*5) + { + tp_SlowMode = 1; + } + + if (event->pre_point != 0) + { + AW5306_ts_release(); + event->pre_point = 0; + } + return 1; + } + else + { + tp_SlowMode = 0; + tp_idlecnt = 0; + event->pre_point = event->touch_point; + event->pressure = 200; + dbg("%s: 1:%d %d 2:%d %d \n", __func__, + event->x[0], event->y[0], event->x[1], event->y[1]); + + return 0; + } +} + +static void AW5306_report_multitouch(void) +{ + struct AW5306_ts_data *data = pContext; + struct ts_event *event = &data->event; + +#ifdef TOUCH_KEY_SUPPORT + if(1 == key_tp){ + return; + } +#endif + + switch(event->touch_point) { + case 5: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[4]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[4]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[4]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("=++==x5 = %d,y5 = %d ====\n",event->x[4],event->y[4]); + case 4: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[3]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[3]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[3]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x4 = %d,y4 = %d ====\n",event->x[3],event->y[3]); + case 3: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[2]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[2]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[2]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x3 = %d,y3 = %d ====\n",event->x[2],event->y[2]); + case 2: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[1]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[1]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[1]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x2 = %d,y2 = %d ====\n",event->x[1],event->y[1]); + case 1: + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID[0]); + //input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x[0]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y[0]); + //input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(data->input_dev); + // printk("===x1 = %d,y1 = %d ====\n",event->x[0],event->y[0]); + break; + default: +// print_point_info("==touch_point default =\n"); + break; + } + + input_sync(data->input_dev); + dbg("%s: 1:%d %d 2:%d %d \n", __func__, + event->x[0], event->y[0], event->x[1], event->y[1]); + return; +} + +#ifdef TOUCH_KEY_SUPPORT +static void AW5306_report_touchkey(void) +{ + struct AW5306_ts_data *data = pContext; + struct ts_event *event = &data->event; + //printk("x=%d===Y=%d\n",event->x[0],event->y[0]); + +#ifdef TOUCH_KEY_FOR_ANGDA + if((1==event->touch_point)&&(event->x1 > TOUCH_KEY_X_LIMIT)){ + key_tp = 1; + if(event->x1 < 40){ + key_val = 1; + input_report_key(data->input_dev, key_val, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 1====\n"); + }else if(event->y1 < 90){ + key_val = 2; + input_report_key(data->input_dev, key_val, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 2 ====\n"); + }else{ + key_val = 3; + input_report_key(data->input_dev, key_val, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 3====\n"); + } + } else{ + key_tp = 0; + } +#endif +#ifdef TOUCH_KEY_FOR_EVB13 + if((1==event->touch_point)&&((event->y[0] > 510)&&(event->y[0]<530))) + { + if(key_tp != 1) + { + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_sync(data->input_dev); + } + else + { + //printk("===KEY touch ++++++++++====++=\n"); + + if(event->x[0] < 90){ + key_val = 1; + input_report_key(data->input_dev, KEY_MENU, 1); + input_sync(data->input_dev); + // printk("===KEY 1===++=\n"); + }else if((event->x[0] < 230)&&(event->x[0]>185)){ + key_val = 2; + input_report_key(data->input_dev, KEY_BACK, 1); + input_sync(data->input_dev); + // printk("===KEY 2 ====\n"); + }else if((event->x[0] < 355)&&(event->x[0]>305)){ + key_val = 3; + input_report_key(data->input_dev, KEY_SEARCH, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 3====\n"); + }else if ((event->x[0] < 497)&&(event->x[0]>445)) { + key_val = 4; + input_report_key(data->input_dev, KEY_HOMEPAGE, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 4====\n"); + }else if ((event->x[0] < 615)&&(event->x[0]>570)) { + key_val = 5; + input_report_key(data->input_dev, KEY_VOLUMEDOWN, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 5====\n"); + }else if ((event->x[0] < 750)&&(event->x[0]>705)) { + key_val = 6; + input_report_key(data->input_dev, KEY_VOLUMEUP, 1); + input_sync(data->input_dev); + // print_point_info("===KEY 6====\n"); + } + } + key_tp = 1; + } + else + { + key_tp = 0; + } +#endif + +#ifdef TOUCH_KEY_LIGHT_SUPPORT + AW5306_lighting(); +#endif + return; +} +#endif + + +static void AW5306_report_value(void) +{ + AW5306_report_multitouch(); +#ifdef TOUCH_KEY_SUPPORT + AW5306_report_touchkey(); +#endif + return; +} /*end AW5306_report_value*/ + + +#ifdef INTMODE +static void AW5306_ts_pen_irq_work(struct work_struct *work) +{ + int ret = -1; + + ret = AW5306_read_data(); + if (ret == 0) + AW5306_report_value(); + + wmt_enable_gpirq(pContext->irqgpio); + + return; +} +#else +static void AW5306_ts_pen_irq_work(struct work_struct *work) +{ + int ret = -1; + + if(suspend_flag != 1) + { + ret = AW5306_read_data(); + if (ret == 0) { + AW5306_report_value(); + } + } + else + { + AW5306_Sleep(); + } +} + +#endif + + + +static irqreturn_t aw5306_interrupt(int irq, void *dev) +{ + struct AW5306_ts_data *AW5306_ts= dev; + +//printk("I\n"); + if (wmt_is_tsint(AW5306_ts->irqgpio)) + { + wmt_clr_int(AW5306_ts->irqgpio); + if (wmt_is_tsirq_enable(AW5306_ts->irqgpio)) + { + wmt_disable_gpirq(AW5306_ts->irqgpio); + #ifdef CONFIG_HAS_EARLYSUSPEND + if(!AW5306_ts->earlysus) queue_work(AW5306_ts->ts_workqueue , &AW5306_ts->pen_event_work); + #else + queue_work(AW5306_ts->ts_workqueue , &AW5306_ts->pen_event_work); + #endif + + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} +/* +static void aw5306_reset(struct AW5306_ts_data *aw5306) +{ + gpio_set_value(aw5306->rstgpio, 0); + mdelay(5); + gpio_set_value(aw5306->rstgpio, 1); + mdelay(5); + gpio_set_value(aw5306->rstgpio, 0); + mdelay(5); + + return; +} +*/ + +void AW5306_tpd_polling(unsigned long data) + { + struct AW5306_ts_data *AW5306_ts = i2c_get_clientdata(l_client); + +#ifdef INTMODE + if (!work_pending(&AW5306_ts->pen_event_work)) { + queue_work(AW5306_ts->ts_workqueue, &AW5306_ts->pen_event_work); + } +#else + + if (!work_pending(&AW5306_ts->pen_event_work)) { + queue_work(AW5306_ts->ts_workqueue, &AW5306_ts->pen_event_work); + } + if(suspend_flag != 1) + { + #ifdef AUTO_RUDUCEFRAME + if(tp_SlowMode) + { + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.SLOW_FRAME; + } + else + { + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + } + #else + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + #endif + add_timer(&AW5306_ts->touch_timer); + } +#endif + } + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void aw5306_early_suspend(struct early_suspend *handler) +{ +#ifdef INTMODE + if(suspend_flag != 1) + { + wmt_disable_gpirq(AW5306_ts->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + } +#else + if(suspend_flag != 1) + { + printk("AW5306 SLEEP!!!"); + suspend_flag = 1; + } +#endif + + return; +} + +static void aw5306_late_resume(struct early_suspend *handler) +{ + struct AW5306_ts_data *AW5306_ts= container_of(handler, struct AW5306_ts_data , early_suspend); +#ifdef INTMODE + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + wmt_enable_gpirq(AW5306_ts->irqgpio); + suspend_flag = 0; + } +#else + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + printk("AW5306 WAKE UP!!!"); + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&AW5306_ts->touch_timer); + } +#endif + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + +#ifdef CONFIG_PM +static int aw5306_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef INTMODE + if(suspend_flag != 1) + { + wmt_disable_gpirq(pContext->irqgpio); + AW5306_Sleep(); + suspend_flag = 1; + } +#else + if(suspend_flag != 1) + { + printk("AW5306 SLEEP!!!"); + suspend_flag = 1; + } +#endif + return 0; + +} + +static int aw5306_resume(struct platform_device *pdev) +{ + struct AW5306_ts_data *AW5306_ts= dev_get_drvdata(&pdev->dev); + +#ifdef INTMODE + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + suspend_flag = 0; + printk("AW5306 WAKE UP_intmode!!!"); + wmt_enable_gpirq(AW5306_ts->irqgpio); + } +#else + if(suspend_flag != 0) + { + gpio_direction_output(AW5306_ts->rstgpio, 0); + AW5306_User_Cfg1(); + AW5306_TP_Reinit(); + tp_idlecnt = 0; + tp_SlowMode = 0; + suspend_flag = 0; + printk("AW5306 WAKE UP!!!"); + AW5306_ts->touch_timer.expires = jiffies + HZ/AWTPCfg.FAST_FRAME; + add_timer(&AW5306_ts->touch_timer); + } +#endif + + return 0; +} + +#else +#define aw5306_suspend NULL +#define aw5306_resume NULL +#endif + +static int aw5306_probe(struct platform_device *pdev) +{ + int err = 0; + struct AW5306_ts_data *AW5306_ts = platform_get_drvdata( pdev); + u8 reg_value; + + //aw5306_reset(AW5306_ts); + + reg_value = AW_I2C_ReadByte(0x01); + if(reg_value != 0xA8) + { + //l_client->addr = 0x39; + dbg_err("AW5306_ts_probe: CHIP ID NOT CORRECT\n"); + return -ENODEV; + } + + i2c_set_clientdata(l_client, AW5306_ts); + + INIT_WORK(&AW5306_ts->pen_event_work, AW5306_ts_pen_irq_work); + AW5306_ts->ts_workqueue = create_singlethread_workqueue(AW5306_ts->name); + if (!AW5306_ts->ts_workqueue ) { + err = -ESRCH; + goto exit_create_singlethread; + } + + AW5306_ts->input_dev = input_allocate_device(); + if (!AW5306_ts->input_dev) { + err = -ENOMEM; + dbg_err("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + AW5306_ts->input_dev->name = AW5306_ts->name; + AW5306_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, AW5306_ts->input_dev->propbit); + + if (AW5306_ts->lcd_exchg) { + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_X, 0, AW5306_ts->resly, 0, 0); + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_Y, 0, AW5306_ts->reslx, 0, 0); + } else { + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_X, 0, AW5306_ts->reslx, 0, 0); + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_POSITION_Y, 0, AW5306_ts->resly, 0, 0); + } + input_set_abs_params(AW5306_ts->input_dev, + ABS_MT_TRACKING_ID, 0, 4, 0, 0); + + err = input_register_device(AW5306_ts->input_dev); + if (err) { + dbg_err("aw5306_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + AW5306_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + AW5306_ts->early_suspend.suspend = aw5306_early_suspend; + AW5306_ts->early_suspend.resume = aw5306_late_resume; + register_early_suspend(&AW5306_ts->early_suspend); +#endif + + AW5306_create_sysfs(l_client); + memcpy(AW_CALI_FILENAME,"/data/tpcali",12); + //memcpy(AW_UCF_FILENAME,"/data/AWTPucf",13); + printk("ucf file: %s\n", AW_UCF_FILENAME); + + AW5306_TP_Init(); + + AW5306_ts->touch_timer.function = AW5306_tpd_polling; + AW5306_ts->touch_timer.data = 0; + init_timer(&AW5306_ts->touch_timer); + AW5306_ts->touch_timer.expires = jiffies + HZ*10; + add_timer(&AW5306_ts->touch_timer); + +#ifdef INTMODE + + if(request_irq(AW5306_ts->irq, aw5306_interrupt, IRQF_SHARED, AW5306_ts->name, AW5306_ts) < 0){ + dbg_err("Could not allocate irq for ts_aw5306 !\n"); + err = -1; + goto exit_register_irq; + } + + wmt_set_gpirq(AW5306_ts->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(AW5306_ts->irqgpio); + +#endif + + + + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&AW5306_ts->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(AW5306_ts->input_dev); +exit_input_dev_alloc_failed: +//exit_create_group: + cancel_work_sync(&AW5306_ts->pen_event_work); + destroy_workqueue(AW5306_ts->ts_workqueue ); +exit_create_singlethread: + return err; +} + +static int aw5306_remove(struct platform_device *pdev) +{ + struct AW5306_ts_data *AW5306_ts= platform_get_drvdata( pdev); + + del_timer(&AW5306_ts->touch_timer); + + +#ifdef INTMODE + wmt_disable_gpirq(AW5306_ts->irqgpio); + free_irq(AW5306_ts->irq, AW5306_ts); +#endif + + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&AW5306_ts->early_suspend); +#endif + input_unregister_device(AW5306_ts->input_dev); + input_free_device(AW5306_ts->input_dev); + + cancel_work_sync(&AW5306_ts->pen_event_work); + flush_workqueue(AW5306_ts->ts_workqueue); + destroy_workqueue(AW5306_ts->ts_workqueue); + + dbg("remove...\n"); + return 0; +} + +static void aw5306_release(struct device *device) +{ + return; +} + +static struct platform_device aw5306_device = { + .name = DEV_AW5306, + .id = 0, + .dev = {.release = aw5306_release}, +}; + +static struct platform_driver aw5306_driver = { + .driver = { + .name = DEV_AW5306, + .owner = THIS_MODULE, + }, + .probe = aw5306_probe, + .remove = aw5306_remove, + .suspend = aw5306_suspend, + .resume = aw5306_resume, +}; + +static int check_touch_env(struct AW5306_ts_data *AW5306_ts) +{ + int ret = 0; + int len = 96; + int Enable; + char retval[96] = {0}; + char ucfname[20] = {0}; + char *p=NULL, *s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + //printk("MST FT5x0x:Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + //printk("FT5x0x Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"aw5306",6)) return -ENODEV; + AW5306_ts->name = DEV_AW5306; + s = strchr(p, ':'); + p = p + 7; + if (s <= p) + return -ENODEV; + strncpy(ucfname, p, s-p); + sprintf(AW_UCF_FILENAME, "/lib/firmware/%s", ucfname); + + s++; + sscanf(s,"%d:%d:%d:%d:%d:%d:%d:%d", &AW5306_ts->irqgpio, &AW5306_ts->reslx, &AW5306_ts->resly, &AW5306_ts->rstgpio, &AW5306_ts->swap, &AW5306_ts->xch, &AW5306_ts->ych, &AW5306_ts->nt); + + AW5306_ts->irq = IRQ_GPIO; + + printk("%s irqgpio=%d, reslx=%d, resly=%d, rstgpio=%d, swap=%d, xch=%d, ych=%d, nt=%d\n", AW5306_ts->name, AW5306_ts->irqgpio, AW5306_ts->reslx, AW5306_ts->resly, AW5306_ts->rstgpio, AW5306_ts->swap, AW5306_ts->xch, AW5306_ts->ych, AW5306_ts->nt); + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + AW5306_ts->lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = TS_I2C_NAME, + .flags = 0x00, + .addr = AW5306_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + //ts_i2c_board_info.addr = AW5306_I2C_ADDR; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(AW5306_I2C_BUS);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static int __init aw5306_init(void) +{ + int ret = -ENOMEM; + struct AW5306_ts_data *AW5306_ts=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + AW5306_ts = kzalloc(sizeof(struct AW5306_ts_data), GFP_KERNEL); + if(!AW5306_ts){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = AW5306_ts; + ret = check_touch_env(AW5306_ts); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(AW5306_ts->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", AW5306_ts->irqgpio); + goto exit_free_mem; + } + //wmt_gpio_setpull(AW5306_ts->irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(AW5306_ts->irqgpio); + + ret = gpio_request(AW5306_ts->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", AW5306_ts->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(AW5306_ts->rstgpio, 0); + + + ret = platform_device_register(&aw5306_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&aw5306_device, AW5306_ts); + + ret = platform_driver_register(&aw5306_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + +/* + i2c_dev_class = class_create(THIS_MODULE,"aw_i2c_dev"); + if (IS_ERR(i2c_dev_class)) { + ret = PTR_ERR(i2c_dev_class); + class_destroy(i2c_dev_class); + } +*/ + + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&aw5306_device); +exit_free_gpio: + gpio_free(AW5306_ts->rstgpio); +exit_free_irqgpio: + gpio_free(AW5306_ts->irqgpio); +exit_free_mem: + kfree(AW5306_ts); + pContext = NULL; + return ret; +} + +static void aw5306_exit(void) +{ + if(!pContext) return; + + platform_driver_unregister(&aw5306_driver); + platform_device_unregister(&aw5306_device); + gpio_free(pContext->rstgpio); + gpio_free(pContext->irqgpio); + kfree(pContext); + ts_i2c_unregister_device(); + return; +} + +late_initcall(aw5306_init); +module_exit(aw5306_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FocalTech.Touch"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c new file mode 100755 index 00000000..99f65f87 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.c @@ -0,0 +1,196 @@ +#include "AW5306_Reg.h" +#include "AW5306_Drv.h" +#include <linux/kernel.h> +#include <linux/string.h> +#include "AW5306_userpara.h" + +#define POS_PRECISION 64 + +extern AW5306_UCF AWTPCfg; +extern STRUCTCALI AW_Cali; +extern char AW5306_WorkMode; +extern STRUCTNOISE AW_Noise; + +extern void AW5306_CLB_WriteCfg(void); +extern int AW_I2C_WriteByte(unsigned char addr, unsigned char data); +extern unsigned char AW_I2C_ReadByte(unsigned char addr); +extern unsigned char AW_I2C_ReadXByte( unsigned char *buf, unsigned char addr, unsigned short len); +extern unsigned char AW5306_RAWDATACHK(void); + +const STRUCTCALI Default_Cali1 = +{ + "AWINIC TP CALI", + //{0x33,0x23,0x22,0x22,0x22,0x22,0x22,0x02,0x22,0x22}, //TXOFFSET + {0x32,0x32,0x23,0x32,0x33,0x33,0x33,0x03,0x22,0x22}, //TXOFFSET + //{0x9A,0xA9,0xAA,0xA9,0x9B,0x00}, //RXOFFSET + {0x35,0x44,0x55,0x54,0x34,0x00}, //RXOFFSET + //{0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c},//TXCAC + {0x2C,0x2B,0x2B,0x2A,0x2A,0x2C,0x2C,0x2C,0x2C,0x2C,0x2D,0x2D,0x2D,0x2D,0x31,0x2C,0x2C,0x2C,0x2C,0x2C},//TXCAC + //{0x3d,0x3c,0x3c,0x3c,0x3e,0x3a,0x3a,0x3e,0x3c,0x3b,0x3c,0x3c},//RXCAC + {0x84,0x84,0x82,0x82,0x80,0x86,0x86,0x80,0x8C,0x82,0x84,0x84},//RXCAC + //{0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x2e,0x2e,0x0e,0x0e,0x0e,0x0e,0x0e},//TXGAIN + {0x88,0x88,0x88,0x88,0x88,0x68,0x68,0x68,0x68,0x68,0x48,0x48,0x48,0x48,0x28,0x08,0x08,0x08,0x08,0x08},//TXGAIN +}; + +const AW5306_UCF Default_UCF = +{ + 15, //TX_NUM + 10, //RX_NUM + {17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0,0}, //TX_ORDER + {9,8,7,6,5,4,3,2,1,0,0,0}, //RX_ORDER + 0, //RX_START + 0, //HAVE_KEY_LINE + {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, //KeyLineValid + + 600, //MAPPING_MAX_X + 1024, //MAPPING_MAX_Y + + 350, //GainClbDeltaMin + 450, //GainClbDeltaMax + 550, //KeyLineDeltaMin + 650, //KeyLineDeltaMax + 8300, //OffsetClbExpectedMin + 8500, //OffsetClbExpectedMax + 300, //RawDataDeviation + 8, //CacMultiCoef + + 7000, //RawDataCheckMin + 10000, //RawDataCheckMax + + 200, //FLYING_TH + 100, //MOVING_TH + 50, //MOVING_ACCELER + + 70, //PEAK_TH + 80, //GROUP_TH + 90, //BIGAREA_TH + 25, //BIGAREA_CNT + 20, //BIGAREA_FRESHCNT + + 1, //CACULATE_COEF + + 1, //FIRST_CALI + 0, //RAWDATA_DUMP_SWITCH + + 1, //MULTI_SCANFREQ + 5, //BASE_FREQ + 0x83, //FREQ_OFFSET + 0x00, //WAIT_TIME + 0x2b, //CHAMP_CFG + 0x10, //POSLEVEL_TH + + 1, //ESD_PROTECT + + 0, //MARGIN_COMPENSATE + 0, //MARGIN_COMP_DATA_UP + 0, //MARGIN_COMP_DATA_DOWN + 0, //MARGIN_COMP_DATA_LEFT + 0, //MARGIN_COMP_DATA_RIGHT + + 1, //POINT_RELEASEHOLD + 0, //MARGIN_RELEASEHOLD + 0, //POINT_PRESSHOLD + 1, //KEY_PRESSHOLD + + 0, //PEAK_ROW_COMPENSATE + 1, //PEAK_COL_COMPENSATE + 3, //PEAK_COMPENSATE_COEF + + 0, //LCD_NOISE_PROCESS + 50, //LCD_NOISETH + + 0, //FALSE_PEAK_PROCESS + 100, //FALSE_PEAK_TH + + 6, //STABLE_DELTA_X + 6, //STABLE_DELTA_Y + + 0, //DEBUG_LEVEL + + 50, //FAST_FRAME + 20, //SLOW_FRAME + + 0, //GAIN_CLB_SEPERATE + 5, //MARGIN_PREFILTER + 0, //BIGAREA_HOLDPOINT + 50, //CHARGE_NOISE + 0, //FREQ_JUMP + 0, //PEAK_VALID_CHECK + 1, //WATER_REMOVE + +#ifdef INTMODE + 1 //INT_MODE +#else + 0 //POLL_MODE +#endif +}; + +void AW5306_User_Cfg1(void) +{ + unsigned char i; + + + for(i=0;i<AWTPCfg.TX_LOCAL;i++) + { + AW_I2C_WriteByte(SA_TX_INDEX0+i,AWTPCfg.TX_ORDER[i]); //TX REVERT + } + + AW_I2C_WriteByte(SA_TX_NUM,AWTPCfg.TX_LOCAL); + AW_I2C_WriteByte(SA_RX_NUM,AWTPCfg.RX_LOCAL); + + if(1 == AWTPCfg.MULTI_SCANFREQ) + { + AW_I2C_WriteByte(SA_SCANFREQ1,AWTPCfg.BASE_FREQ); + AW_I2C_WriteByte(SA_SCANFREQ2,AWTPCfg.BASE_FREQ); + AW_I2C_WriteByte(SA_SCANFREQ3,AWTPCfg.BASE_FREQ); + } + else + { + AW_I2C_WriteByte(SA_SCANFREQ1,AWTPCfg.BASE_FREQ); //3-5 + } + + + AW_I2C_WriteByte(SA_WAITTIME,AWTPCfg.WAIT_TIME); + AW_I2C_WriteByte(SA_RX_START,AWTPCfg.RX_START); + AW_I2C_WriteByte(SA_SCANTIM,4); // set to 32 TX cycles mode + + AW_I2C_WriteByte(SA_PAGE,1); + AW_I2C_WriteByte(SA_CHAMPCFG,AWTPCfg.CHAMP_CFG); // + AW_I2C_WriteByte(SA_OSCCFG1,AWTPCfg.FREQ_OFFSET); // + AW_I2C_WriteByte(SA_OSCCFG2,0x10); //TRIM register + AW_I2C_WriteByte(SA_POSLEVELTH,AWTPCfg.POSLEVEL_TH); + + AW_I2C_WriteByte(SA_CPFREQ,0x00); //for AW256 + AW_I2C_WriteByte(SA_PAGE,0); + + AW5306_CLB_WriteCfg(); + //printk("AW5306 user config finished TXCAC0 = %x",AW_Cali.TXCAC[0] ); +} + +void AW5306_User_Init(void) +{ + unsigned char ret; + + ret = 0; + + AW5306_WorkMode = DeltaMode; //DeltaMode: chip output delta data RawDataMode: chip output rawdata + + memcpy(&AWTPCfg,&Default_UCF,sizeof(AW5306_UCF)); + memcpy(&AW_Cali,&Default_Cali1,sizeof(STRUCTCALI)); //load default cali value + + + //AW_I2C_WriteByte(SA_PAGE,0); + //AW_I2C_WriteByte(SA_IDRST,0x55); + + AW5306_User_Cfg1(); + + AW_Noise.FrmState = NOISE_FRM_NORMAL; + AW_Noise.WorkFreqID = 16; + AW_Noise.ScanFreqID = AW_Noise.WorkFreqID; + AW_Noise.State = NOISE_LISTENING; + AW_Noise.NoiseTh1 = 60; + AW_Noise.JumpTh = 5; + AW_Noise.Better_NoiseScan = 1000; + //ret = AW5306_RAWDATACHK(); + +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.h b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.h new file mode 100755 index 00000000..15d5c180 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/AW5306_userpara.h @@ -0,0 +1,99 @@ +#ifndef AW5306_USERPARA_H + +#define AW5306_USERPARA_H + +#define INTMODE + +typedef struct { + unsigned char TX_LOCAL; // 15 //TX number of TP + unsigned char RX_LOCAL; // 10 //RX number of TP + unsigned char TX_ORDER[22]; // TX ORDER + unsigned char RX_ORDER[12]; // RX mapping in inverted order + unsigned char RX_START; //RX START LINE + unsigned char HAVE_KEY_LINE; // 0: no KEY line, 1: have key line on TX line TX_LOCAL-1 + unsigned char KeyLineValid[16]; + + unsigned short MAPPING_MAX_X; // 320 + unsigned short MAPPING_MAX_Y; // 460 + + unsigned short GainClbDeltaMin; // Expected minimum delta for GAIN calibration + unsigned short GainClbDeltaMax; // Expected maximum delta for GAIN calibration + unsigned short KeyLineDeltaMin; + unsigned short KeyLineDeltaMax; + unsigned short OffsetClbExpectedMin; // Expected minimum data for OFFSET calibration + unsigned short OffsetClbExpectedMax; // Expected minimum data for OFFSET calibration + unsigned short RawDataDeviation; // Maximum deviation in a frame + unsigned short CacMultiCoef; + + unsigned short RawDataCheckMin; + unsigned short RawDataCheckMax; + + unsigned short FLYING_TH; + unsigned short MOVING_TH; + unsigned short MOVING_ACCELER; + + unsigned char PEAK_TH; + unsigned char GROUP_TH; + unsigned char BIGAREA_TH; + unsigned char BIGAREA_CNT; + unsigned char BIGAREA_FRESHCNT; + + unsigned char CACULATE_COEF; + + unsigned char FIRST_CALI; + unsigned char RAWDATA_DUMP_SWITCH; + unsigned char MULTI_SCANFREQ; + unsigned char BASE_FREQ; + unsigned char FREQ_OFFSET; + unsigned char WAIT_TIME; + unsigned char CHAMP_CFG; + unsigned char POSLEVEL_TH; + + unsigned char ESD_PROTECT; + + unsigned char MARGIN_COMPENSATE; + unsigned char MARGIN_COMP_DATA_UP; + unsigned char MARGIN_COMP_DATA_DOWN; + unsigned char MARGIN_COMP_DATA_LEFT; + unsigned char MARGIN_COMP_DATA_RIGHT; + + unsigned char POINT_RELEASEHOLD; + unsigned char MARGIN_RELEASEHOLD; + unsigned char POINT_PRESSHOLD; + unsigned char KEY_PRESSHOLD; + + unsigned char PEAK_ROW_COMPENSATE; + unsigned char PEAK_COL_COMPENSATE; + unsigned char PEAK_COMPENSATE_COEF; + + unsigned char LCD_NOISE_PROCESS; + unsigned char LCD_NOISETH; + + unsigned char FALSE_PEAK_PROCESS; + unsigned char FALSE_PEAK_TH; + + unsigned char STABLE_DELTA_X; + unsigned char STABLE_DELTA_Y; + + unsigned char DEBUG_LEVEL; + + unsigned char FAST_FRAME; + unsigned char SLOW_FRAME; + + unsigned char GAIN_CLB_SEPERATE; + + unsigned char MARGIN_PREFILTER; + + unsigned char BIGAREA_HOLDPOINT; + unsigned char CHARGE_NOISE; + unsigned char FREQ_JUMP; + unsigned char PEAK_VALID_CHECK; + unsigned char WATER_REMOVE; + unsigned char INT_MODE; + +}AW5306_UCF; + +void AW5306_User_Init(void); +void AW5306_User_Cfg1(void); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Kconfig new file mode 100755 index 00000000..32029915 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_AW5306
+ tristate "AW5306 Capacity Touchscreen Device Support"
+ default y
+ depends on ARCH_WMT
+ ---help---
+ Say Y here if you have an WMT based board with touchscreen
+ attached to it.
+ If unsure, say N.
+ To compile this driver as a module, choose M here: the
+ module will be called s_wmt_ts_aw5306.
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Makefile new file mode 100755 index 00000000..2a79cbe6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/Makefile @@ -0,0 +1,35 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+ #DEBFLAGS = -O2 -Wall -L./libAW5306.a
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_aw5306
+
+#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := AW5306_ts.o irq_gpio.o AW5306_userpara.o AW5306_Base.b AW5306_Clb.b AW5306_Drv.b
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+# @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.c b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.c new file mode 100755 index 00000000..8bdf9f20 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.c @@ -0,0 +1,149 @@ +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include "irq_gpio.h" + +int wmt_enable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num < 4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) |= 1<<((num-12)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) &= ~(1<<((num-12)*8+7)); //enable interrupt + + return 0; +} + +int wmt_is_tsirq_enable(int num) +{ + int val = 0; + + if(num > 15) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else if(num >= 8 && num < 12) + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x030C) & (1<<((num-12)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(int num) +{ + if (num > 15) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(int num) +{ + if (num > 15) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +int wmt_set_gpirq(int num, int type) +{ + int shift; + int offset; + unsigned long reg; + + if(num >15) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num);//|=(1<<num);// //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else if(num >= 8 && num < 12){//[8,11] + shift = num-8; + offset = 0x0308; + }else{// [12,15] + shift = num-12; + offset = 0x030C; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.h b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.h new file mode 100755 index 00000000..0232bd04 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/aw5306_ts/irq_gpio.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_IRQ_GPIO_H +#define _LINUX_IRQ_GPIO_H + + +extern int wmt_enable_gpirq(int num); +extern int wmt_disable_gpirq(int num); +extern int wmt_is_tsirq_enable(int num); +extern int wmt_is_tsint(int num); +extern void wmt_clr_int(int num); +extern int wmt_set_gpirq(int num, int type); + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Kconfig new file mode 100755 index 00000000..3a8e1de0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Kconfig @@ -0,0 +1,16 @@ +# +# CYP140 capacity touch screen driver configuration +# +config TOUCHSCREEN_CYP140 + tristate "CYPRESS CYP140 I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_cyp140 + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Makefile new file mode 100755 index 00000000..46229059 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/Makefile @@ -0,0 +1,33 @@ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_cyp140
+
+obj-$(CONFIG_TOUCHSCREEN_CYP140) := $(MY_MODULE_NAME).o
+#obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := cyp140_i2c.o wmt_ts.o cyttsp_fw_upgrade.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyp140_i2c.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyp140_i2c.c new file mode 100755 index 00000000..ca4717ac --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyp140_i2c.c @@ -0,0 +1,1412 @@ +/* drivers/input/touchscreen/cyp140_i2c.c + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ZEITEC Semiconductor Co., Ltd + * Tel: +886-3-579-0045 + * Fax: +886-3-579-9960 + * http://www.zeitecsemi.com + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/jiffies.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include <linux/bitops.h> + +#include "wmt_ts.h" +#define TP_POINTS_CNT 5 +#define U8 unsigned char +//fw update. +//#include "cyp140_fw.h" + +//****************************add for cyp140 2013-1-6 +//extern struct tpd_device *tpd; +static struct i2c_client *i2c_client = NULL; +static struct task_struct *thread = NULL; + +static DECLARE_WAIT_QUEUE_HEAD(waiter); + +#define TPD_DEVICE "cyp140" +static int tpd_load_status = 0;//add !!!2013-1-6 +//static struct early_suspend early_suspend; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend early_suspend; +static void tpd_early_suspend(struct early_suspend *handler); +static void tpd_late_resume(struct early_suspend *handler); +#endif + +static int tilt = 1, rev_x = -1, rev_y = 1; +static int max_x = 1024, max_y = 600; +//static int max_x = 800, max_y = 480; + +//extern void mt65xx_eint_unmask(unsigned int line); +//extern void mt65xx_eint_mask(unsigned int line); +//extern void mt65xx_eint_set_hw_debounce(kal_uint8 eintno, kal_uint32 ms); +//extern kal_uint32 mt65xx_eint_set_sens(kal_uint8 eintno, kal_bool sens); +//extern mt65xx_eint_set_polarity(unsigned int eint_num, unsigned int pol); +//extern void mt65xx_eint_registration(kal_uint8 eintno, kal_bool Dbounce_En, + // kal_bool ACT_Polarity, void (EINT_FUNC_PTR)(void), + // kal_bool auto_umask); + + +static irqreturn_t tpd_eint_interrupt_handler(int irq, void *dev_id); +//static int tpd_get_bl_info(int show); +static int __devinit tpd_probe(struct i2c_client *client); +//static int tpd_detect(struct i2c_client *client, int kind, struct i2c_board_info *info); +//static int __devexit tpd_remove(struct i2c_client *client); +static int touch_event_handler(void *unused); +//static int tpd_initialize(struct i2c_client * client); + + +volatile static int tpd_flag = 0;//0; debug 2013-5-6 + +#ifdef TPD_HAVE_BUTTON +static int tpd_keys_local[TPD_KEY_COUNT] = TPD_KEYS; +static int tpd_keys_dim_local[TPD_KEY_COUNT][4] = TPD_KEYS_DIM; +#endif + +#define TPD_OK 0 +//#define TPD_EREA_Y 799 +//#define TPD_EREA_X 479 +#define TPD_EREA_Y 479 +#define TPD_EREA_X 319 + +#define TPD_DISTANCE_LIMIT 100 + +#define TPD_REG_BASE 0x00 +#define TPD_SOFT_RESET_MODE 0x01 +#define TPD_OP_MODE 0x00 +#define TPD_LOW_PWR_MODE 0x04 +#define TPD_SYSINFO_MODE 0x10 +#define GET_HSTMODE(reg) ((reg & 0x70) >> 4) // in op mode or not +#define GET_BOOTLOADERMODE(reg) ((reg & 0x10) >> 4) // in bl mode +//#define GPIO_CTP_EN_PIN_M_GPIO 0 +//#define GPIO_CTP_EN_PIN 0xff + +static u8 bl_cmd[] = { + 0x00, 0x00, 0xFF, 0xA5, + 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, + 0x06, 0x07}; +//exit bl mode +struct tpd_operation_data_t{ + U8 hst_mode; + U8 tt_mode; + U8 tt_stat; + + U8 x1_M,x1_L; + U8 y1_M,y1_L; + U8 x5_M; + U8 touch12_id; + + U8 x2_M,x2_L; + U8 y2_M,y2_L; + U8 x5_L; + U8 gest_cnt; + U8 gest_id; + //U8 gest_set; + + + U8 x3_M,x3_L; + U8 y3_M,y3_L; + U8 y5_M; + U8 touch34_id; + + U8 x4_M,x4_L; + U8 y4_M,y4_L; + U8 y5_L; + + //U8 x5_M,x5_L; + U8 Undefinei1B; + U8 Undefined1C; + U8 Undefined1D; + U8 GEST_SET; + U8 touch5_id; +}; + +struct tpd_bootloader_data_t{ + U8 bl_file; + U8 bl_status; + U8 bl_error; + U8 blver_hi,blver_lo; + U8 bld_blver_hi,bld_blver_lo; + + U8 ttspver_hi,ttspver_lo; + U8 appid_hi,appid_lo; + U8 appver_hi,appver_lo; + + U8 cid_0; + U8 cid_1; + U8 cid_2; + +}; + +struct tpd_sysinfo_data_t{ + U8 hst_mode; + U8 mfg_cmd; + U8 mfg_stat; + U8 cid[3]; + u8 tt_undef1; + + u8 uid[8]; + U8 bl_verh; + U8 bl_verl; + + u8 tts_verh; + u8 tts_verl; + + U8 app_idh; + U8 app_idl; + U8 app_verh; + U8 app_verl; + + u8 tt_undef2[6]; + U8 act_intrvl; + U8 tch_tmout; + U8 lp_intrvl; + +}; + +struct touch_info { + int x[5]; + int y[5]; + int p[5]; + int id[5]; + int count; +}; + +struct id_info{ + int pid1; + int pid2; + int reportid1; + int reportid2; + int id1; + int id2; + +}; +static struct tpd_operation_data_t g_operation_data; +//static struct tpd_bootloader_data_t g_bootloader_data; +//static struct tpd_sysinfo_data_t g_sysinfo_data; + +//******************************************************** + +/* -------------- global variable definition -----------*/ +#define _MACH_MSM_TOUCH_H_ + +#define ZET_TS_ID_NAME "cyp140-ts" + +#define MJ5_TS_NAME "cyp140_touchscreen" + +//#define TS_INT_GPIO S3C64XX_GPN(9) /*s3c6410*/ +//#define TS1_INT_GPIO AT91_PIN_PB17 /*AT91SAM9G45 external*/ +//#define TS1_INT_GPIO AT91_PIN_PA27 /*AT91SAM9G45 internal*/ +//#define TS_RST_GPIO S3C64XX_GPN(10) + +#define TS_RST_GPIO +#define TPINFO 1 +#define X_MAX 800 //1024 +#define Y_MAX 480 //576 +#define FINGER_NUMBER 5 +#define KEY_NUMBER 3 //0 +#define P_MAX 1 +#define D_POLLING_TIME 25000 +#define U_POLLING_TIME 25000 +#define S_POLLING_TIME 100 +#define REPORT_POLLING_TIME 5 + +#define MAX_KEY_NUMBER 8 +#define MAX_FINGER_NUMBER 16 +#define TRUE 1 +#define FALSE 0 + +//#define debug_mode 1 +//#define DPRINTK(fmt,args...) do { if (debug_mode) printk(KERN_EMERG "[%s][%d] "fmt"\n", __FUNCTION__, __LINE__, ##args);} while(0) + +//#define TRANSLATE_ENABLE 1 +#define TOPRIGHT 0 +#define TOPLEFT 1 +#define BOTTOMRIGHT 2 +#define BOTTOMLEFT 3 +#define ORIGIN BOTTOMRIGHT + +#define TIME_CHECK_CHARGE 3000 + +struct msm_ts_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +struct tpd_device{ + struct i2c_client * client;//i2c_ts; + struct work_struct work1; + struct input_dev *input; + struct timer_list polling_timer; + struct delayed_work work; // for polling + struct workqueue_struct *queue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + unsigned int gpio; /* GPIO used for interrupt of TS1*/ + unsigned int irq; + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; +// +struct tpd_device *tpd; + + +//static int l_suspend = 0; // 1:suspend, 0:normal state + +//static int resetCount = 0; //albert++ 20120807 + + +//static u16 polling_time = S_POLLING_TIME; + +//static int l_powermode = -1; +//static struct mutex i2c_mutex; + + +//static int __devinit cyp140_ts_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int __devexit cyp140_ts_remove(struct i2c_client *dev); + + + + + +//static int filterCount = 0; +//static u32 filterX[MAX_FINGER_NUMBER][2], filterY[MAX_FINGER_NUMBER][2]; + +//static u8 key_menu_pressed = 0x1; +//static u8 key_back_pressed = 0x1; +//static u8 key_search_pressed = 0x1; + +//static u16 ResolutionX=X_MAX; +//static u16 ResolutionY=Y_MAX; +//static u16 FingerNum=0; +//static u16 KeyNum=0; +//static int bufLength=0; +//static u8 xyExchange=0; +//static u16 inChargerMode = 0; +//static struct i2c_client *this_client; +struct workqueue_struct *ts_wq = NULL; +#if 0 +static int l_tskey[4][2] = { + {KEY_BACK,0}, + {KEY_MENU,0}, + {KEY_HOME,0}, + {KEY_SEARCH,0}, +}; +#endif +u8 pc[8]; +// {IC Model, FW Version, FW version,Codebase Type=0x08, Customer ID, Project ID, Config Board No, Config Serial No} + +//Touch Screen +/*static const struct i2c_device_id cyp140_ts_idtable[] = { + { ZET_TS_ID_NAME, 0 }, + { } +}; + +static struct i2c_driver cyp140_ts_driver = { + .driver = { + .owner = THIS_MODULE, + .name = ZET_TS_ID_NAME, + }, + .probe = cyp140_ts_probe, + .remove = __devexit_p(cyp140_ts_remove), + .id_table = cyp140_ts_idtable, +}; +*/ + + +/*********************************************************************** + [function]: + callback: Timer Function if there is no interrupt fuction; + [parameters]: + arg[in]: arguments; + [return]: + NULL; +************************************************************************/ + + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); +/*********************************************************************** + [function]: + callback: read data by i2c interface; + [parameters]: + client[in]: struct i2c_client — represent an I2C slave device; + data [out]: data buffer to read; + length[in]: data length to read; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int cyp140_i2c_read_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int rc = 0; + + memset(data, 0, length); + rc = i2c_master_recv(client, data, length); + if (rc <= 0) + { + errlog("error!\n"); + return -EINVAL; + } else if (rc != length) + { + dbg("want:%d,real:%d\n", length, rc); + } + return rc;*/ +} + +/*********************************************************************** + [function]: + callback: write data by i2c interface; + [parameters]: + client[in]: struct i2c_client — represent an I2C slave device; + data [out]: data buffer to write; + length[in]: data length to write; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int cyp140_i2c_write_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = 0; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int ret = i2c_master_recv(client, data, length); + if (ret <= 0) + { + errlog("error!\n"); + } + return ret; + */ +} + +/*********************************************************************** + [function]: + callback: coordinate traslating; + [parameters]: + px[out]: value of X axis; + py[out]: value of Y axis; + p [in]: pressed of released status of fingers; + [return]: + NULL; +************************************************************************/ +void touch_coordinate_traslating(u32 *px, u32 *py, u8 p) +{ + int i; + u8 pressure; + + #if ORIGIN == TOPRIGHT + for(i=0;i<MAX_FINGER_NUMBER;i++){ + pressure = (p >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + } + } + #elif ORIGIN == BOTTOMRIGHT + for(i=0;i<MAX_FINGER_NUMBER;i++){ + pressure = (p >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + py[i] = Y_MAX - py[i]; + } + } + #elif ORIGIN == BOTTOMLEFT + for(i=0;i<MAX_FINGER_NUMBER;i++){ + pressure = (p >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + py[i] = Y_MAX - py[i]; + } + } + #endif +} + +/*********************************************************************** + [function]: + callback: reset function; + [parameters]: + void; + [return]: + void; +************************************************************************/ +void ctp_reset(void) +{ +#if defined(TS_RST_GPIO) + //reset mcu + /* gpio_direction_output(TS_RST_GPIO, 1); + msleep(1); + gpio_direction_output(TS_RST_GPIO, 0); + msleep(10); + gpio_direction_output(TS_RST_GPIO, 1); + msleep(20);*/ + wmt_rst_output(1); + msleep(1); + wmt_rst_output(0); + msleep(10); + wmt_rst_output(1); + msleep(20); + dbg("has done\n"); +#else + u8 ts_reset_cmd[1] = {0xb0}; + cyp140_i2c_write_tsdata(this_client, ts_reset_cmd, 1); +#endif + +} + +//************************************************* +#if 1 +#include <linux/sched.h> //wake_up_process() +#include <linux/kthread.h> //kthread_create()ã€kthread_run() +//#include <err.h> //IS_ERR()ã€PTR_ERR() + +void cyttsp_sw_reset(void); +//static struct task_struct *esd_task; +volatile bool need_rst_flag = 0; +volatile int tp_interrupt_flag = 0; +volatile int tp_suspend_flag = 0; +volatile int tp_reseting_flag = 0; + +void cyttsp_print_reg(struct i2c_client *client) +{ +#if 1 + char buffer[20]; + int status=0; + int i; + + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 16, &(buffer[0])); + + printk("++++cyttsp_print_reg=%d: ",status); + for(i = 0; i<16;i++) + printk(" %02x", buffer[i]); + printk("\n"); +#endif + +} + +int exit_boot_mode(void) +{ + + //int retval = TPD_OK; + + char buffer[2]; + int status=0; + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &(buffer[0])); + if(status<0) { + printk ("++++exit_boot_mode failed---1\n"); + return status; + } + else + { + if(buffer[0] & 0x10) + { + status = i2c_master_send(i2c_client, bl_cmd, 12); + if( status < 0) + { + printk ("++++exit_boot_mode failed---2\n"); + return status; + } + else + { + //printk("++++exit_boot_mode ok\n"); + } + msleep(300); + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &(buffer[0])); + if(status<0) { + printk ("++++exit_boot_mode set failed\n"); + return status; + } +// printk("++++exit_boot_mode set: 0x%x\n",buffer[0]); + cyttsp_print_reg(i2c_client); + } + else + { + // printk("++++exit_boot_mode-- not in bootmode\n"); + } + + } + return 0; + +} + +void esd_check(void) +{ + if(need_rst_flag) + { + if(tp_suspend_flag == 0) + { + printk("++++esd_check---rst\n"); + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); + tp_reseting_flag = 1; + cyttsp_sw_reset(); + tp_reseting_flag = 0; + //mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); + } + need_rst_flag = 0; + } +} +static int fp_count = 0; +#if 0 //close 2013-1-6 +void esd_thread(void) +{ + static int i = 0, j = 0; + while(1) + { + printk("++++esd_thread, need_rst_flag=%d, fp_count=%d\n", need_rst_flag,fp_count); + fp_count = 0; + if(need_rst_flag) + { + j = 0; + while(tp_interrupt_flag==1 && j<200) //wujinyou + { + j ++; + if(tp_suspend_flag) + msleep(1000); + else + msleep(10); + } + if(tp_suspend_flag == 0) + { + printk("++++esd_thread, start reset, mask int\n"); + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); + tp_reseting_flag = 1; + cyttsp_sw_reset(); + i = 0; + need_rst_flag = 0; + tp_reseting_flag = 0; + //mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); + } + } + msleep(1000); + i ++; + if(i == 10) + { + i = 0; + //cyttsp_sw_reset(); + //need_rst_flag = 1; + } + } +} +static int esd_init_thread(void) +{ + int err; + printk("++++%s, line %d----\n", __FUNCTION__, __LINE__); + + esd_task = kthread_create(esd_thread, NULL, "esd_task"); + + if(IS_ERR(esd_task)){ + printk("++++Unable to start kernel thread.\n"); + err = PTR_ERR(esd_task); + esd_task = NULL; + return err; + } + + wake_up_process(esd_task); + + return 0; + +} +#endif //close 2013-1-6 + +#endif + +static void tpd_down(int x, int y, int p) { + + + //printk("<<<<<<x,y (%d, %d)\n", x, y);//debug 2013-5-6 + +//printk("++++tpd_down: %d,%d,%d\n", x, y, p); +#if 0 //def TPD_HAVE_BUTTON + if (boot_mode != NORMAL_BOOT) { + if(y > 480) { + tpd_button(x, y, 1); + } + } +#endif + //*****here process x y coord and then report!!!! 2013-1-7 + +#if 1//0 + int tmp; + if (tilt) + { + tmp = x; + x = y; + y =tmp; + } + if (rev_x < 0) + x = max_x -x; + if (rev_y < 0) + y = max_y -y; + + +#endif + if (wmt_ts_get_lcdexchg()) { + int t; + t = x; + x = y; + y = max_x - t; + } + + //printk("<<<<<< transfer x,y (%d, %d)\n", x, y);//debug 2013-5-6 + + input_report_abs(tpd->input, ABS_PRESSURE,p); + input_report_key(tpd->input, BTN_TOUCH, 1); + //input_report_abs(tpd->input,ABS_MT_TRACKING_ID,i); + input_report_abs(tpd->input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(tpd->input, ABS_MT_POSITION_X, x); + input_report_abs(tpd->input, ABS_MT_POSITION_Y, y); + ////TPD_DEBUG("Down x:%4d, y:%4d, p:%4d \n ", x, y, p); + input_mt_sync(tpd->input); + //TPD_DOWN_DEBUG_TRACK(x,y); + fp_count ++; +} + +static void tpd_up(int x, int y,int p) { + + input_report_abs(tpd->input, ABS_PRESSURE, 0); + input_report_key(tpd->input, BTN_TOUCH, 0); + // input_report_abs(tpd->input,ABS_MT_TRACKING_ID,i); + input_report_abs(tpd->input, ABS_MT_TOUCH_MAJOR, 0); + //input_report_abs(tpd->input, ABS_MT_POSITION_X, x); + //input_report_abs(tpd->input, ABS_MT_POSITION_Y, y); //!!!! + //TPD_DEBUG("Up x:%4d, y:%4d, p:%4d \n", x, y, 0); + input_mt_sync(tpd->input); + // TPD_UP_DEBUG_TRACK(x,y); +} +void test_retval(s32 ret) +{ +#if 1 + if(ret<0) + { + need_rst_flag = 1; + printk("++++test_retval=1-------\n"); + } +#endif +} +static int tpd_touchinfo(struct touch_info *cinfo, struct touch_info *pinfo) +{ + + s32 retval; + static u8 tt_mode; + //pinfo->count = cinfo->count; + u8 data0,data1; + + memcpy(pinfo, cinfo, sizeof(struct touch_info)); + memset(cinfo, 0, sizeof(struct touch_info)); +// printk("pinfo->count =%d\n",pinfo->count); + + retval = i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE, 8, (u8 *)&g_operation_data); + retval += i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE + 8, 8, (((u8 *)(&g_operation_data)) + 8)); + retval += i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE + 16, 8, (((u8 *)(&g_operation_data)) + 16)); + retval += i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE + 24, 8, (((u8 *)(&g_operation_data)) + 24)); + + + //cyttsp_print_reg(i2c_client); + ////TPD_DEBUG("received raw data from touch panel as following:\n"); + + /*("hst_mode = %02X, tt_mode = %02X, tt_stat = %02X\n", \ + g_operation_data.hst_mode,\ + g_operation_data.tt_mode,\ + g_operation_data.tt_stat); */ + + cinfo->count = (g_operation_data.tt_stat & 0x0f) ; //point count + + //TPD_DEBUG("cinfo->count =%d\n",cinfo->count); + + //TPD_DEBUG("Procss raw data...\n"); + + cinfo->x[0] = (( g_operation_data.x1_M << 8) | ( g_operation_data.x1_L)); //point 1 + cinfo->y[0] = (( g_operation_data.y1_M << 8) | ( g_operation_data.y1_L)); + cinfo->p[0] = 0;//g_operation_data.z1; + + //printk("Before: cinfo->x0 = %3d, cinfo->y0 = %3d, cinfo->p0 = %3d cinfo->id0 = %3d\n", cinfo->x[0] ,cinfo->y[0] ,cinfo->p[0], cinfo->id[0]); + if(cinfo->x[0] < 1) cinfo->x[0] = 1; + if(cinfo->y[0] < 1) cinfo->y[0] = 1; + cinfo->id[0] = ((g_operation_data.touch12_id & 0xf0) >>4) -1; + //printk("After: cinfo->x0 = %3d, cinfo->y0 = %3d, cinfo->p0 = %3d cinfo->id0 = %3d\n", cinfo->x[0] ,cinfo->y[0] ,cinfo->p[0], cinfo->id[0]); + + if(cinfo->count >1) + { + cinfo->x[1] = (( g_operation_data.x2_M << 8) | ( g_operation_data.x2_L)); //point 2 + cinfo->y[1] = (( g_operation_data.y2_M << 8) | ( g_operation_data.y2_L)); + cinfo->p[1] = 0;//g_operation_data.z2; + + //printk("before: cinfo->x2 = %3d, cinfo->y2 = %3d, cinfo->p2 = %3d\n", cinfo->x2, cinfo->y2, cinfo->p2); + if(cinfo->x[1] < 1) cinfo->x[1] = 1; + if(cinfo->y[1] < 1) cinfo->y[1] = 1; + cinfo->id[1] = ((g_operation_data.touch12_id & 0x0f)) -1; + //printk("After: cinfo->x[1] = %3d, cinfo->y[1] = %3d, cinfo->p[1] = %3d, cinfo->id[1] = %3d\n", cinfo->x[1], cinfo->y[1], cinfo->p[1], cinfo->id[1]); + + if (cinfo->count > 2) + { + cinfo->x[2]= (( g_operation_data.x3_M << 8) | ( g_operation_data.x3_L)); //point 3 + cinfo->y[2] = (( g_operation_data.y3_M << 8) | ( g_operation_data.y3_L)); + cinfo->p[2] = 0;//g_operation_data.z3; + cinfo->id[2] = ((g_operation_data.touch34_id & 0xf0) >> 4) -1; + + //printk("before: cinfo->x[2] = %3d, cinfo->y[2] = %3d, cinfo->p[2] = %3d\n", cinfo->x[2], cinfo->y[2], cinfo->p[2]); + if(cinfo->x[2] < 1) cinfo->x[2] = 1; + if(cinfo->y[2]< 1) cinfo->y[2] = 1; + //printk("After: cinfo->x[2]= %3d, cinfo->y[2] = %3d, cinfo->p[2]= %3d, cinfo->id[2] = %3d\n", cinfo->x[2], cinfo->y[2], cinfo->p[2], cinfo->id[2]); + + if (cinfo->count > 3) + { + cinfo->x[3] = (( g_operation_data.x4_M << 8) | ( g_operation_data.x4_L)); //point 3 + cinfo->y[3] = (( g_operation_data.y4_M << 8) | ( g_operation_data.y4_L)); + cinfo->p[3] = 0;//g_operation_data.z4; + cinfo->id[3] = ((g_operation_data.touch34_id & 0x0f)) -1; + + //printk("before: cinfo->x[3] = %3d, cinfo->y[3] = %3d, cinfo->p[3] = %3d, cinfo->id[3] = %3d\n", cinfo->x[3], cinfo->y[3], cinfo->p[3], cinfo->id[3]); + //printk("before: x4_M = %3d, x4_L = %3d\n", g_operation_data.x4_M, g_operation_data.x4_L); + if(cinfo->x[3] < 1) cinfo->x[3] = 1; + if(cinfo->y[3] < 1) cinfo->y[3] = 1; + //printk("After: cinfo->x[3] = %3d, cinfo->y[3] = %3d, cinfo->p[3]= %3d, cinfo->id[3] = %3d\n", cinfo->x[3], cinfo->y[3], cinfo->p[3], cinfo->id[3]); + } + if (cinfo->count > 4) + { + cinfo->x[4] = (( g_operation_data.x5_M << 8) | ( g_operation_data.x5_L)); //point 3 + cinfo->y[4] = (( g_operation_data.y5_M << 8) | ( g_operation_data.y5_L)); + cinfo->p[4] = 0;//g_operation_data.z4; + cinfo->id[4] = ((g_operation_data.touch5_id & 0xf0) >> 4) -1; + + //printk("before: cinfo->x[4] = %3d, cinfo->y[4] = %3d, cinfo->id[4] = %3d\n", cinfo->x[4], cinfo->y[4], cinfo->id[4]); + //printk("before: x5_M = %3d, x5_L = %3d\n", g_operation_data.x5_M, g_operation_data.x5_L); + if(cinfo->x[4] < 1) cinfo->x[4] = 1; + if(cinfo->y[4] < 1) cinfo->y[4] = 1; + //printk("After: cinfo->x[4] = %3d, cinfo->y[4] = %3d, cinfo->id[4] = %3d\n", cinfo->x[4], cinfo->y[4], cinfo->id[4]); + } + } + + } + + if (!cinfo->count) return true; // this is a touch-up event + + if (g_operation_data.tt_mode & 0x20) { + //TPD_DEBUG("uffer is not ready for use!\n"); + memcpy(cinfo, pinfo, sizeof(struct touch_info)); + return false; + }//return false; // buffer is not ready for use// buffer is not ready for use + + // data toggle + + data0 = i2c_smbus_read_i2c_block_data(i2c_client, TPD_REG_BASE, 1, (u8*)&g_operation_data); + ////TPD_DEBUG("before hst_mode = %02X \n", g_operation_data.hst_mode); + + if((g_operation_data.hst_mode & 0x80)==0) + g_operation_data.hst_mode = g_operation_data.hst_mode|0x80; + else + g_operation_data.hst_mode = g_operation_data.hst_mode & (~0x80); + + ////TPD_DEBUG("after hst_mode = %02X \n", g_operation_data.hst_mode); + data1 = i2c_smbus_write_i2c_block_data(i2c_client, TPD_REG_BASE, sizeof(g_operation_data.hst_mode), &g_operation_data.hst_mode); + + + if (tt_mode == g_operation_data.tt_mode) { + //TPD_DEBUG("sampling not completed!\n"); + memcpy(cinfo, pinfo, sizeof(struct touch_info)); + return false; + }// sampling not completed + else + tt_mode = g_operation_data.tt_mode; + + return true; + +}; + +static int touch_event_handler(void *unused) +{ + int i,j; + int keeppoint[5]; + struct touch_info cinfo, pinfo; + struct sched_param param = { .sched_priority = 70/*RTPM_PRIO_TPD*/ }; + sched_setscheduler(current, SCHED_RR, ¶m); + + do + { + //printk("++++%s, line %d----unmask int\n", __FUNCTION__, __LINE__); + // mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); + wmt_enable_gpirq(); + set_current_state(TASK_INTERRUPTIBLE); + tp_interrupt_flag = 0; + //printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + wait_event_interruptible(waiter,tpd_flag!=0); +// printk("++++%s, line %d----start\n", __FUNCTION__, __LINE__); + + tpd_flag = 0; //debg 2013-5-6 + set_current_state(TASK_RUNNING); + + exit_boot_mode(); + if (tpd_touchinfo(&cinfo, &pinfo)) + { + memset(keeppoint, 0x0, sizeof(keeppoint)); + if(cinfo.count >0 && cinfo.count < (TP_POINTS_CNT+1)) + { + switch(cinfo.count) + { + case 5: + { + tpd_down(cinfo.x[4], cinfo.y[4], cinfo.p[4]); + } + case 4: + { + tpd_down(cinfo.x[3], cinfo.y[3], cinfo.p[3]); + } + case 3: + { + tpd_down(cinfo.x[2], cinfo.y[2], cinfo.p[2]); + } + case 2: + { + tpd_down(cinfo.x[1], cinfo.y[1], cinfo.p[1]); + } + case 1: + { + tpd_down(cinfo.x[0], cinfo.y[0], cinfo.p[0]); + } + default: + break; + } + for(i = 0; i < cinfo.count; i++) + for(j = 0; j < pinfo.count; j++) + { + if(cinfo.id[i] == pinfo.id[j])keeppoint[j] = 1; + else if(keeppoint[j] != 1)keeppoint[j] = 0; + } + + for(j = 0; j < pinfo.count; j++) + { + if(keeppoint[j] != 1) + { + tpd_up(pinfo.x[j], pinfo.y[j], pinfo.p[j]); + } + } + + } + else if(cinfo.count == 0 && pinfo.count !=0) + { + switch(pinfo.count ) + { + case 5: + { + tpd_up(pinfo.x[4], pinfo.y[4], pinfo.p[4]); + } + case 4: + { + tpd_up(pinfo.x[3], pinfo.y[3], pinfo.p[3]); + } + case 3: + { + tpd_up(pinfo.x[2], pinfo.y[2], pinfo.p[2]); + } + case 2: + { + tpd_up(pinfo.x[1], pinfo.y[1], pinfo.p[1]); + } + case 1: + { + tpd_up(pinfo.x[0], pinfo.y[0], pinfo.p[0]); + } + default: + break; + } + } + + input_sync(tpd->input); + + } + + + + }while(!kthread_should_stop()); + tp_interrupt_flag = 0; + + return 0; +} + + + + +static irqreturn_t tpd_eint_interrupt_handler(int irq, void *dev_id) +{ + static int i = 0; + i ++; + //printk("++++eint=%d\n",i); + + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); +// printk("++++%s, line %d, tpd_flag=%d,i=%d\n", __FUNCTION__, __LINE__, tpd_flag,i); + + if (wmt_is_tsint()) + { + // printk("<<<<in %s\n", __FUNCTION__); + wmt_clr_int(); + //return IRQ_HANDLED;//!!!!! + if (wmt_is_tsirq_enable()) + { + wmt_disable_gpirq(); + } + tp_interrupt_flag = 1; + ////TPD_DEBUG("TPD interrupt has been triggered\n"); + //if(tpd_flag) + //return; + tpd_flag = 1; + wake_up_interruptible(&waiter); + + return IRQ_HANDLED; + + } + return IRQ_NONE; +} +static void ctp_power_on(int on) +{ + printk("++++ctp_power_on = %d\n",on); + //return ; + + if(on == 1) + { + //mt_set_gpio_mode(GPIO_CTP_EN_PIN, GPIO_CTP_EN_PIN_M_GPIO); + //mt_set_gpio_dir(GPIO_CTP_EN_PIN, GPIO_DIR_OUT); + //mt_set_gpio_out(GPIO_CTP_EN_PIN, GPIO_OUT_ONE); + ; + + } + else + { + //return -EIO; + ; + } +} +//} + +#include "cyttsp.h" +extern void cyttsp_fw_upgrade(void); +void cyttsp_hw_reset(void) +{ + ctp_power_on(0); //wujinyou + msleep(200); + + ctp_power_on(1); //wujinyou + msleep(100); + //mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); +// mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); + //mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); + msleep(100); + //mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO); + msleep(100); +} +void cyttsp_sw_reset(void) +{ + //int retval = TPD_OK; +// int status = 0; + printk("++++cyttsp_sw_reset---------start\n"); +#if 0//1 + mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); + msleep(20); + ctp_power_on(0); + msleep(200); + #if 1 + ctp_power_on(1); + #endif + + msleep(20); + mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO); + msleep(100); + + ////TPD_DEBUG("TPD wake up\n"); + status = i2c_master_send(i2c_client, bl_cmd, 12); + if( status < 0) + { + printk("++++ [cyttsp_sw_reset], cyttsp tpd exit bootloader mode failed--tpd_resume!\n"); + return status; + } + msleep(300); + //exit_boot_mode(); + //mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); +#endif + printk("++++cyttsp_sw_reset---------end\n"); + //return retval; +} + + +//***************cyp140 probe 2013-1-6 +// wmtenv set wmt.io.touch 1:cyp140:7:600:1024:4:0:1:-1:5 //ok 2013-5-8 +static int __devinit tpd_probe(struct i2c_client *client) +{ + struct input_dev *input_dev; + int retval = TPD_OK; + int gpio_irq = wmt_ts_get_irqgpnum(); + int gpio_rst = wmt_ts_get_resetgpnum(); + //int result; + i2c_client = client; + + retval = gpio_request(gpio_irq, "ts_irq"); + if (retval < 0) { + printk("gpio(%d) touchscreen irq request fail\n", gpio_irq); + return retval; + } + + retval = gpio_request(gpio_rst, "ts_rst"); + if (retval < 0) { + printk("gpio(%d) touchscreen reset request fail\n", gpio_rst); + goto Fail_request_rstgpio; + } + //char buffer[2]; + //int status=0; + + //int res_x, res_y; + + printk("<<< enter %s: %d\n",__FUNCTION__, __LINE__); + +#if 1 //0 + tilt = wmt_ts_get_xaxis(); + rev_x = wmt_ts_get_xdir(); + rev_y = wmt_ts_get_ydir(); +#if 0 + if (tilt){ + max_y = wmt_ts_get_resolvX(); + max_x = wmt_ts_get_resolvY(); + } + else + { + max_x = wmt_ts_get_resolvX(); + max_y =wmt_ts_get_resolvY(); + } +#else + max_x = wmt_ts_get_resolvX(); + max_y =wmt_ts_get_resolvY(); +#endif + +#endif +#if 0 + if (0) + { + res_x = max_y; + res_y = max_x; + } + else + { + res_x = max_x; + res_y = max_y; + } + max_x = res_x; + max_y = res_y; +#endif + //************************add input device 2013-1-6 + tpd = kzalloc(sizeof(struct tpd_device), GFP_KERNEL); + + input_dev = input_allocate_device(); + if (!input_dev || !tpd) { + return -ENOMEM; + } + + tpd->client/*i2c_ts*/ = client; + i2c_set_clientdata(client, tpd); + tpd->input = input_dev; + + input_dev->name = "touch_cyp140"; //MJ5_TS_NAME; + input_dev->phys = "cyp140_touch/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0002; + input_dev->id.version = 0x0100; + + input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, max_y/*480*//*600*//*ResolutionX*//*ResolutionX*/, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, max_x /*ResolutionY*//*800*//* 1024*/, 0, 0); + } else { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, max_x/*480*//*600*//*ResolutionX*//*ResolutionX*/, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, max_y /*ResolutionY*//*800*//* 1024*/, 0, 0); + } + + set_bit(KEY_BACK, input_dev->keybit); + set_bit(KEY_HOME, input_dev->keybit); + set_bit(KEY_MENU, input_dev->keybit); + retval = input_register_device(input_dev); + if (retval) + { + printk("%s input register device error!!\n", __FUNCTION__); + goto E_REG_INPUT; + } + //**************************** + //ctp_power_on(1); //wujinyou //!!!!2013-1-6 + + msleep(1000); + + //printk("<<<<here ??/\n"); + //************************add for wmt 2013-1-6 + wmt_tsreset_init(); + wmt_set_rst_pull(1); + //wmt_enable_rst_pull(1); + wmt_rst_output(1); + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + //wmt_set_gpirq(IRQ_TYPE_EDGE_RISING); //debug 2013-5-8 also no interrupt + wmt_disable_gpirq(); + + tpd->irq = wmt_get_tsirqnum(); + retval = request_irq(tpd->irq, tpd_eint_interrupt_handler,IRQF_SHARED, "cypcm", tpd); + //**************************************** + + printk("tpd_probe request_irq retval=%d!\n",retval); + msleep(100); + msleep(1000); + + cust_ts.client = i2c_client; +// cyttsp_fw_upgrade(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#if 0 //by linda 20130126 + status = i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &(buffer[0])); + printk("tpd_probe request_irq status=%d!\n",status); + + retval = i2c_master_send(i2c_client, bl_cmd, 12); + if( retval < 0) + { + printk("tpd_probe i2c_master_send retval=%d!\n",retval); + + //return retval; + goto I2C_ERR; + } +#else + retval = exit_boot_mode(); + if (retval) + { + printk("%s exit_boot_mod error!\n", __FUNCTION__); + goto I2C_ERR; + } + +#endif +/* + msleep(1000); + retval = i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0])); + if(retval<0) { + retval = i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0])); + if(retval<0) { + printk("error read !%d\n", __LINE__); + + goto I2C_ERR; + } + } +*/ + //TPD_DEBUG("[mtk-tpd], cyttsp tpd_i2c_probe success!!\n"); + tpd_load_status = 1; + thread = kthread_run(touch_event_handler, 0, TPD_DEVICE); + if (IS_ERR(thread)) { + retval = PTR_ERR(thread); + return retval; + + } + + + msleep(100); + printk("++++tpd_probe,retval=%d\n", retval); +#ifdef CONFIG_HAS_EARLYSUSPEND + tpd->early_suspend.suspend = tpd_early_suspend, + tpd->early_suspend.resume = tpd_late_resume, + tpd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;//,EARLY_SUSPEND_LEVEL_DISABLE_FB + 2; + register_early_suspend(&tpd->early_suspend); +#endif + //disable_irq(cyp140_ts->irq); + + wmt_enable_gpirq(); + +//cust_timer_init(); +// esd_init_thread(); //close it 2013-1-6 + return 0; //retval; + I2C_ERR: + free_irq(tpd->irq, tpd); + input_unregister_device(input_dev); // + E_REG_INPUT: + input_free_device(input_dev); + kfree(tpd); + //return retval; + Fail_request_rstgpio: + gpio_free(gpio_rst); + gpio_free(gpio_irq); + return retval; + +} +//******************************* + +//module_init(cyp140_ts_init); +static int tpd_local_init(void) +{ + if (tpd_probe(ts_get_i2c_client()))// ???? + { + return -1; + } + + + if(tpd_load_status == 0){ + //return -1; + ; + } + +#ifdef TPD_HAVE_BUTTON + tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data + boot_mode = get_boot_mode(); +#endif + return 0;//!!!!2013-1-7 +} + +//**********************suspend & resume +static int tpd_resume(/*struct i2c_client *client*/struct platform_device *pdev) +{ + int retval = TPD_OK; + int status = 0; + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + //mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); + msleep(100); + #if 1 + ctp_power_on(1); + #endif + + msleep(1); + wmt_rst_output(0); + msleep(1); + wmt_rst_output(1); + msleep(100); + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING);//sometimes gpio7 will in low after resume 2013-5-9 + wmt_enable_gpirq(); + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + + //TPD_DEBUG("TPD wake up\n"); + + #if 0 //0 // by linda 20120126 change rambo 2013-5-6 + status = i2c_master_send(i2c_client, bl_cmd, 12); + #else + exit_boot_mode(); + #endif + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + + if( status < 0) + { + printk("++++ [mtk-tpd], cyttsp tpd exit bootloader mode failed--tpd_resume!\n"); + return status; + } + //exit_boot_mode(); + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + msleep(300); + //wmt_enable_gpirq(); //debg 2013-5-6 + tp_suspend_flag = 0; + return retval; +} + +static int tpd_suspend(/*struct i2c_client *client*/struct platform_device *pdev, pm_message_t message) +{ + int i = 0; + int retval = TPD_OK; + //u8 sleep_mode = 0x02; // 0x02--CY_DEEP_SLEEP_MODE, 0x04--CY_LOW_PWR_MODE + //TPD_DEBUG("TPD enter sleep\n"); + //u8 sleep_reg[2] = {0, 2}; + printk("++++%s, line %d----end\n", __FUNCTION__, __LINE__); + wmt_disable_gpirq(); + //wmt_disable_gpirq(); //dbg 2013-5-6 + + while((tp_reseting_flag || tp_interrupt_flag) && i<30) + { + i ++; + msleep(100); + } + tp_suspend_flag = 1; +#if 1 + //retval = i2c_smbus_write_i2c_block_data(i2c_client,0x00,sizeof(sleep_mode), &sleep_mode); + //retval = i2c_master_send(i2c_client, sleep_reg, 2); //send cmd error -5! + msleep(1); + ctp_power_on(0); + mdelay(1); +#else + mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); +#endif + + return retval; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void tpd_early_suspend(struct early_suspend *handler) +{ + tpd_suspend(i2c_client, PMSG_SUSPEND); +} + +static void tpd_late_resume(struct early_suspend *handler) +{ + tpd_resume(i2c_client); +} +#endif +//**************************** + + +static void cyp140_ts_exit(void) +{ + printk("<<<%s\n", __FUNCTION__); + + wmt_disable_gpirq(); + free_irq(tpd->irq, tpd); + //kthread_stop(thread); // halt rmmod?? + input_unregister_device(tpd->input); // + + input_free_device(tpd->input); + kfree(tpd); + gpio_free(wmt_ts_get_irqgpnum()); + gpio_free(wmt_ts_get_resetgpnum()); +} +//module_exit(cyp140_ts_exit); + +void cyp140_set_ts_mode(u8 mode) +{ + dbg( "[Touch Screen]ts mode = %d \n", mode); +} +//EXPORT_SYMBOL_GPL(cyp140_set_ts_mode); + +struct wmtts_device cyp140_tsdev = { + .driver_name = WMT_TS_I2C_NAME, + .ts_id = "cyp140", + .init = tpd_local_init, + .exit = cyp140_ts_exit, + .suspend = tpd_suspend, + .resume = tpd_resume, +}; + + + +MODULE_DESCRIPTION("cyp140 I2C Touch Screen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h new file mode 100755 index 00000000..6020018f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp.h @@ -0,0 +1,696 @@ +/* Header file for: + * Cypress TrueTouch(TM) Standard Product touchscreen drivers. + * include/linux/cyttsp.h + * + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, and only version 2, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Cypress reserves the right to make changes without further notice + * to the materials described herein. Cypress does not assume any + * liability arising out of the application described herein. + * + * Contact Cypress Semiconductor at www.cypress.com + * + */ + + +#ifndef __CYTTSP_H__ +#define __CYTTSP_H__ + +#include <linux/input.h> +#include <linux/timer.h> +#include <linux/workqueue.h> +#include <linux/kernel.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> + +#define CYPRESS_TTSP_NAME "cyttsp" +#define CY_I2C_NAME "cyttsp-i2c" +#define CY_SPI_NAME "cyttsp-spi" + +#ifdef CY_DECLARE_GLOBALS + uint32_t cyttsp_tsdebug; + module_param_named(tsdebug, cyttsp_tsdebug, uint, 0664); + uint32_t cyttsp_tsxdebug; + module_param_named(tsxdebug, cyttsp_tsxdebug, uint, 0664); + + uint32_t cyttsp_disable_touch; + module_param_named(disable_touch, cyttsp_disable_touch, uint, 0664); +#else + extern uint32_t cyttsp_tsdebug; + extern uint32_t cyttsp_tsxdebug; + extern uint32_t cyttsp_disable_touch; +#endif + + + +/****************************************************************************** + * Global Control, Used to control the behavior of the driver + */ + +/* defines for Gen2 (Txx2xx); Gen3 (Txx3xx) + * use these defines to set cyttsp_platform_data.gen in board config file + */ +#define CY_GEN2 2 +#define CY_GEN3 3 + +/* define for using I2C driver + */ +#define CY_USE_I2C_DRIVER + +/* defines for using SPI driver */ +/* +#define CY_USE_SPI_DRIVER + */ +#define CY_SPI_DFLT_SPEED_HZ 1000000 +#define CY_SPI_MAX_SPEED_HZ 4000000 +#define CY_SPI_SPEED_HZ CY_SPI_DFLT_SPEED_HZ +#define CY_SPI_BITS_PER_WORD 8 +#define CY_SPI_DAV 139 /* set correct gpio id */ +#define CY_SPI_BUFSIZE 512 + +/* Voltage and Current ratings */ +#define CY_TMA300_VTG_MAX_UV 5500000 +#define CY_TMA300_VTG_MIN_UV 1710000 +#define CY_TMA300_CURR_24HZ_UA 17500 +#define CY_I2C_VTG_MAX_UV 1800000 +#define CY_I2C_VTG_MIN_UV 1800000 +#define CY_I2C_CURR_UA 9630 + + +/* define for inclusion of TTSP App Update Load File + * use this define if update to the TTSP Device is desired + */ +/* +#define CY_INCLUDE_LOAD_FILE +*/ + +/* define if force new load file for bootloader load */ +/* +#define CY_FORCE_FW_UPDATE +*/ + +/* undef for production use */ +/* +#define CY_USE_DEBUG +*/ + +/* undef for irq use; use this define in the board configuration file */ +/* +#define CY_USE_TIMER + */ + +/* undef to allow use of extra debug capability */ +/* +#define CY_ALLOW_EXTRA_DEBUG +*/ + +/* undef to remove additional debug prints */ +/* +#define CY_USE_EXTRA_DEBUG +*/ + +/* undef to remove additional debug prints */ +/* +#define CY_USE_EXTRA_DEBUG1 + */ + +/* undef to use operational touch timer jiffies; else use test jiffies */ +/* + */ + /* +#define CY_USE_TIMER_DEBUG +*/ +/* define to use canned test data */ +/* +#define CY_USE_TEST_DATA + */ + +/* define if gesture signaling is used + * and which gesture groups to use + */ +/* +#define CY_USE_GEST +#define CY_USE_GEST_GRP1 +#define CY_USE_GEST_GRP2 +#define CY_USE_GEST_GRP3 +#define CY_USE_GEST_GRP4 + */ +/* Active distance in pixels for a gesture to be reported + * if set to 0, then all gesture movements are reported + */ +#define CY_ACT_DIST_DFLT 8 +#define CY_ACT_DIST CY_ACT_DIST_DFLT + +/* define if MT signals are desired */ +/* +*/ +#define CY_USE_MT_SIGNALS + +/* define if MT tracking id signals are used */ +/* +#define CY_USE_MT_TRACK_ID + */ + +/* define if ST signals are required */ +/* +*/ +//#define CY_USE_ST_SIGNALS + +/* define to send handshake to device */ +/* +*/ +#define CY_USE_HNDSHK + +/* define if log all raw motion signals to a sysfs file */ +/* +#define CY_LOG_TO_FILE +*/ + + +/* End of the Global Control section + ****************************************************************************** + */ +#define CY_DIFF(m, n) ((m) != (n)) + +#ifdef CY_LOG_TO_FILE + #define cyttsp_openlog() /* use sysfs */ +#else + #define cyttsp_openlog() +#endif /* CY_LOG_TO_FILE */ + +/* see kernel.h for pr_xxx def'ns */ +#define cyttsp_info(f, a...) pr_info("%s:" f, __func__ , ## a) +#define cyttsp_error(f, a...) pr_err("%s:" f, __func__ , ## a) +#define cyttsp_alert(f, a...) pr_alert("%s:" f, __func__ , ## a) + +#ifdef CY_USE_DEBUG + #define cyttsp_debug(f, a...) pr_alert("%s:" f, __func__ , ## a) +#else + #define cyttsp_debug(f, a...) {if (cyttsp_tsdebug) \ + pr_alert("%s:" f, __func__ , ## a); } +#endif /* CY_USE_DEBUG */ + +#ifdef CY_ALLOW_EXTRA_DEBUG +#ifdef CY_USE_EXTRA_DEBUG + #define cyttsp_xdebug(f, a...) pr_alert("%s:" f, __func__ , ## a) +#else + #define cyttsp_xdebug(f, a...) {if (cyttsp_tsxdebug) \ + pr_alert("%s:" f, __func__ , ## a); } +#endif /* CY_USE_EXTRA_DEBUG */ + +#ifdef CY_USE_EXTRA_DEBUG1 + #define cyttsp_xdebug1(f, a...) pr_alert("%s:" f, __func__ , ## a) +#else + #define cyttsp_xdebug1(f, a...) +#endif /* CY_USE_EXTRA_DEBUG1 */ +#else + #define cyttsp_xdebug(f, a...) + #define cyttsp_xdebug1(f, a...) +#endif /* CY_ALLOW_EXTRA_DEBUG */ + +#ifdef CY_USE_TIMER_DEBUG + #define TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(1000)) +#else + #define TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(28)) +#endif + +/* reduce extra signals in MT only build + * be careful not to lose backward compatibility for pre-MT apps + */ +#ifdef CY_USE_ST_SIGNALS + #define CY_USE_ST 1 +#else + #define CY_USE_ST 0 +#endif /* CY_USE_ST_SIGNALS */ + +/* rely on kernel input.h to define Multi-Touch capability */ +/* if input.h defines the Multi-Touch signals, then use MT */ +#if defined(ABS_MT_TOUCH_MAJOR) && defined(CY_USE_MT_SIGNALS) + #define CY_USE_MT 1 + #define CY_MT_SYNC(input) input_mt_sync(input) +#else + #define CY_USE_MT 0 + #define CY_MT_SYNC(input) + /* the following includes are provided to ensure a compile; + * the code that compiles with these defines will not be executed if + * the CY_USE_MT is properly used in the platform structure init + */ + #ifndef ABS_MT_TOUCH_MAJOR + #define ABS_MT_TOUCH_MAJOR 0x30 /* touching ellipse */ + #define ABS_MT_TOUCH_MINOR 0x31 /* (omit if circular) */ + #define ABS_MT_WIDTH_MAJOR 0x32 /* approaching ellipse */ + #define ABS_MT_WIDTH_MINOR 0x33 /* (omit if circular) */ + #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ + #define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ + #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ + #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ + #define ABS_MT_BLOB_ID 0x38 /* Group set of pkts as blob */ + #endif /* ABS_MT_TOUCH_MAJOR */ +#endif /* ABS_MT_TOUCH_MAJOR and CY_USE_MT_SIGNALS */ +#if defined(ABS_MT_TRACKING_ID) && defined(CY_USE_MT_TRACK_ID) + #define CY_USE_TRACKING_ID 1 +#else + #define CY_USE_TRACKING_ID 0 +/* define only if not defined already by system; + * value based on linux kernel 2.6.30.10 + */ +#ifndef ABS_MT_TRACKING_ID + #define ABS_MT_TRACKING_ID (ABS_MT_BLOB_ID+1) +#endif +#endif /* ABS_MT_TRACKING_ID */ + +#define CY_USE_DEEP_SLEEP_SEL 0x80 +#define CY_USE_LOW_POWER_SEL 0x01 + +#ifdef CY_USE_TEST_DATA + #define cyttsp_testdat(ray1, ray2, sizeofray) \ + { \ + int i; \ + u8 *up1 = (u8 *)ray1; \ + u8 *up2 = (u8 *)ray2; \ + for (i = 0; i < sizeofray; i++) { \ + up1[i] = up2[i]; \ + } \ + } +#else + #define cyttsp_testdat(xy, test_xy, sizeofray) +#endif /* CY_USE_TEST_DATA */ + +/* helper macros */ +#define GET_NUM_TOUCHES(x) ((x) & 0x0F) +#define GET_TOUCH1_ID(x) (((x) & 0xF0) >> 4) +#define GET_TOUCH2_ID(x) ((x) & 0x0F) +#define GET_TOUCH3_ID(x) (((x) & 0xF0) >> 4) +#define GET_TOUCH4_ID(x) ((x) & 0x0F) +#define IS_LARGE_AREA(x) (((x) & 0x10) >> 4) +#define FLIP_DATA_FLAG 0x01 +#define REVERSE_X_FLAG 0x02 +#define REVERSE_Y_FLAG 0x04 +#define FLIP_DATA(flags) ((flags) & FLIP_DATA_FLAG) +#define REVERSE_X(flags) ((flags) & REVERSE_X_FLAG) +#define REVERSE_Y(flags) ((flags) & REVERSE_Y_FLAG) +#define FLIP_XY(x, y) { \ + u16 tmp; \ + tmp = (x); \ + (x) = (y); \ + (y) = tmp; \ + } +#define INVERT_X(x, xmax) ((xmax) - (x)) +#define INVERT_Y(y, maxy) ((maxy) - (y)) +#define SET_HSTMODE(reg, mode) ((reg) & (mode)) +#define GET_HSTMODE(reg) ((reg & 0x70) >> 4) +#define GET_BOOTLOADERMODE(reg) ((reg & 0x10) >> 4) + +/* constant definitions */ +/* maximum number of concurrent ST track IDs */ +#define CY_NUM_ST_TCH_ID 2 + +/* maximum number of concurrent MT track IDs */ +#define CY_NUM_MT_TCH_ID 4 + +/* maximum number of track IDs */ +#define CY_NUM_TRK_ID 16 + +#define CY_NTCH 0 /* no touch (lift off) */ +#define CY_TCH 1 /* active touch (touchdown) */ +#define CY_ST_FNGR1_IDX 0 +#define CY_ST_FNGR2_IDX 1 +#define CY_MT_TCH1_IDX 0 +#define CY_MT_TCH2_IDX 1 +#define CY_MT_TCH3_IDX 2 +#define CY_MT_TCH4_IDX 3 +#define CY_XPOS 0 +#define CY_YPOS 1 +#define CY_IGNR_TCH (-1) +#define CY_SMALL_TOOL_WIDTH 10 +#define CY_LARGE_TOOL_WIDTH 255 +#define CY_REG_BASE 0x00 +#define CY_REG_GEST_SET 0x1E +#define CY_REG_ACT_INTRVL 0x1D +#define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL+1) +#define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT+1) +#define CY_SOFT_RESET ((1 << 0)) +#define CY_DEEP_SLEEP ((1 << 1)) +#define CY_LOW_POWER ((1 << 2)) +#define CY_MAXZ 255 +#define CY_OK 0 +#define CY_INIT 1 +#define CY_DLY_DFLT 10 /* ms */ +#define CY_DLY_SYSINFO 20 /* ms */ +#define CY_DLY_BL 300 +#define CY_DLY_DNLOAD 100 /* ms */ +#define CY_NUM_RETRY 4 /* max num touch data read */ + +/* handshake bit in the hst_mode reg */ +#define CY_HNDSHK_BIT 0x80 +#ifdef CY_USE_HNDSHK + #define CY_SEND_HNDSHK 1 +#else + #define CY_SEND_HNDSHK 0 +#endif + +/* Bootloader File 0 offset */ +#define CY_BL_FILE0 0x00 + +/* Bootloader command directive */ +#define CY_BL_CMD 0xFF + +/* Bootloader Initiate Bootload */ +#define CY_BL_INIT_LOAD 0x38 + +/* Bootloader Write a Block */ +#define CY_BL_WRITE_BLK 0x39 + +/* Bootloader Terminate Bootload */ +#define CY_BL_TERMINATE 0x3B + +/* Bootloader Exit and Verify Checksum command */ +#define CY_BL_EXIT 0xA5 + +/* Bootloader default keys */ +#define CY_BL_KEY0 0x00 +#define CY_BL_KEY1 0x01 +#define CY_BL_KEY2 0x02 +#define CY_BL_KEY3 0x03 +#define CY_BL_KEY4 0x04 +#define CY_BL_KEY5 0x05 +#define CY_BL_KEY6 0x06 +#define CY_BL_KEY7 0x07 + +/* Active Power state scanning/processing refresh interval */ +#define CY_ACT_INTRVL_DFLT 0x00 + +/* touch timeout for the Active power */ +#define CY_TCH_TMOUT_DFLT 0xFF + +/* Low Power state scanning/processing refresh interval */ +#define CY_LP_INTRVL_DFLT 0x0A + +#define CY_IDLE_STATE 0 +#define CY_ACTIVE_STATE 1 +#define CY_LOW_PWR_STATE 2 +#define CY_SLEEP_STATE 3 + +/* device mode bits */ +#define CY_OP_MODE 0x00 +#define CY_SYSINFO_MODE 0x10 + +/* power mode select bits */ +#define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */ +#define CY_DEEP_SLEEP_MODE 0x02 +#define CY_LOW_PWR_MODE 0x04 + +#define CY_NUM_KEY 8 + +#ifdef CY_USE_GEST + #define CY_USE_GESTURES 1 +#else + #define CY_USE_GESTURES 0 +#endif /* CY_USE_GESTURE_SIGNALS */ + +#ifdef CY_USE_GEST_GRP1 + #define CY_GEST_GRP1 0x10 +#else + #define CY_GEST_GRP1 0x00 +#endif /* CY_USE_GEST_GRP1 */ +#ifdef CY_USE_GEST_GRP2 + #define CY_GEST_GRP2 0x20 +#else + #define CY_GEST_GRP2 0x00 +#endif /* CY_USE_GEST_GRP2 */ +#ifdef CY_USE_GEST_GRP3 + #define CY_GEST_GRP3 0x40 +#else + #define CY_GEST_GRP3 0x00 +#endif /* CY_USE_GEST_GRP3 */ +#ifdef CY_USE_GEST_GRP4 + #define CY_GEST_GRP4 0x80 +#else + #define CY_GEST_GRP4 0x00 +#endif /* CY_USE_GEST_GRP4 */ + +struct cyttsp_regulator { + const char *name; + u32 min_uV; + u32 max_uV; + u32 load_uA; +}; + +struct cyttsp_platform_data { + u32 panel_maxx; + u32 panel_maxy; + u32 disp_resx; + u32 disp_resy; + u32 disp_minx; + u32 disp_miny; + u32 disp_maxx; + u32 disp_maxy; + u8 correct_fw_ver; + u32 flags; + u8 gen; + u8 use_st; + u8 use_mt; + u8 use_hndshk; + u8 use_trk_id; + u8 use_sleep; + u8 use_gestures; + u8 gest_set; + u8 act_intrvl; + u8 tch_tmout; + u8 lp_intrvl; + u8 power_state; + bool wakeup; + int sleep_gpio; + int resout_gpio; + int irq_gpio; + struct cyttsp_regulator *regulator_info; + u8 num_regulators; + const char *fw_fname; +#ifdef CY_USE_I2C_DRIVER + s32 (*init)(struct i2c_client *client); + s32 (*resume)(struct i2c_client *client); +#endif +#ifdef CY_USE_SPI_DRIVER + s32 (*init)(struct spi_device *spi); + s32 (*resume)(struct spi_device *spi); +#endif +}; + +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ +struct cyttsp_gen3_xydata_t { + u8 hst_mode; + u8 tt_mode; + u8 tt_stat; + u16 x1 __attribute__ ((packed)); + u16 y1 __attribute__ ((packed)); + u8 z1; + u8 touch12_id; + u16 x2 __attribute__ ((packed)); + u16 y2 __attribute__ ((packed)); + u8 z2; + u8 gest_cnt; + u8 gest_id; + u16 x3 __attribute__ ((packed)); + u16 y3 __attribute__ ((packed)); + u8 z3; + u8 touch34_id; + u16 x4 __attribute__ ((packed)); + u16 y4 __attribute__ ((packed)); + u8 z4; + u8 tt_undef[3]; + u8 gest_set; + u8 tt_reserved; +}; + +/* TrueTouch Standard Product Gen2 (Txx2xx) interface definition */ +#define CY_GEN2_NOTOUCH 0x03 /* Both touches removed */ +#define CY_GEN2_GHOST 0x02 /* ghost */ +#define CY_GEN2_2TOUCH 0x03 /* 2 touch; no ghost */ +#define CY_GEN2_1TOUCH 0x01 /* 1 touch only */ +#define CY_GEN2_TOUCH2 0x01 /* 1st touch removed; + * 2nd touch remains */ +struct cyttsp_gen2_xydata_t { + u8 hst_mode; + u8 tt_mode; + u8 tt_stat; + u16 x1 __attribute__ ((packed)); + u16 y1 __attribute__ ((packed)); + u8 z1; + u8 evnt_idx; + u16 x2 __attribute__ ((packed)); + u16 y2 __attribute__ ((packed)); + u8 tt_undef1; + u8 gest_cnt; + u8 gest_id; + u8 tt_undef[14]; + u8 gest_set; + u8 tt_reserved; +}; + +/* TTSP System Information interface definition */ +struct cyttsp_sysinfo_data_t { + u8 hst_mode; + u8 mfg_cmd; + u8 mfg_stat; + u8 cid[3]; + u8 tt_undef1; + u8 uid[8]; + u8 bl_verh; + u8 bl_verl; + u8 tts_verh; + u8 tts_verl; + u8 app_idh; + u8 app_idl; + u8 app_verh; + u8 app_verl; + u8 tt_undef[6]; + u8 act_intrvl; + u8 tch_tmout; + u8 lp_intrvl; +}; + +/* TTSP Bootloader Register Map interface definition */ +#define CY_BL_CHKSUM_OK 0x01 +struct cyttsp_bootloader_data_t { + u8 bl_file; + u8 bl_status; + u8 bl_error; + u8 blver_hi; + u8 blver_lo; + u8 bld_blver_hi; + u8 bld_blver_lo; + u8 ttspver_hi; + u8 ttspver_lo; + u8 appid_hi; + u8 appid_lo; + u8 appver_hi; + u8 appver_lo; + u8 cid_0; + u8 cid_1; + u8 cid_2; +}; + +#define cyttsp_wake_data_t cyttsp_gen3_xydata_t +#ifdef CY_DECLARE_GLOBALS + #ifdef CY_INCLUDE_LOAD_FILE + /* this file declares: + * firmware download block array (cyttsp_fw[]), + * the number of command block records (cyttsp_fw_records), + * and the version variables + */ + #include "cyttsp_fw.h" /* imports cyttsp_fw[] array */ + #define cyttsp_app_load() 1 + #ifdef CY_FORCE_FW_UPDATE + #define cyttsp_force_fw_load() 1 + #else + #define cyttsp_force_fw_load() 0 + #endif + + #else + /* the following declarations are to allow + * some debugging capability + */ + unsigned char cyttsp_fw_tts_verh = 0x00; + unsigned char cyttsp_fw_tts_verl = 0x01; + unsigned char cyttsp_fw_app_idh = 0x02; + unsigned char cyttsp_fw_app_idl = 0x03; + unsigned char cyttsp_fw_app_verh = 0x04; + unsigned char cyttsp_fw_app_verl = 0x05; + unsigned char cyttsp_fw_cid_0 = 0x06; + unsigned char cyttsp_fw_cid_1 = 0x07; + unsigned char cyttsp_fw_cid_2 = 0x08; + #define cyttsp_app_load() 0 + #define cyttsp_force_fw_load() 0 + #endif + #define cyttsp_tts_verh() cyttsp_fw_tts_verh + #define cyttsp_tts_verl() cyttsp_fw_tts_verl + #define cyttsp_app_idh() cyttsp_fw_app_idh + #define cyttsp_app_idl() cyttsp_fw_app_idl + #define cyttsp_app_verh() cyttsp_fw_app_verh + #define cyttsp_app_verl() cyttsp_fw_app_verl + #define cyttsp_cid_0() cyttsp_fw_cid_0 + #define cyttsp_cid_1() cyttsp_fw_cid_1 + #define cyttsp_cid_2() cyttsp_fw_cid_2 + #ifdef CY_USE_TEST_DATA + static struct cyttsp_gen2_xydata_t tt_gen2_testray[] = { + {0x00}, {0x00}, {0x04}, + {0x4000}, {0x8000}, {0x80}, + {0x03}, + {0x2000}, {0x1000}, {0x00}, + {0x00}, + {0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00}, + {0x00} + }; + + static struct cyttsp_gen3_xydata_t tt_gen3_testray[] = { + {0x00}, {0x00}, {0x04}, + {0x4000}, {0x8000}, {0x80}, + {0x12}, + {0x2000}, {0x1000}, {0xA0}, + {0x00}, {0x00}, + {0x8000}, {0x4000}, {0xB0}, + {0x34}, + {0x4000}, {0x1000}, {0xC0}, + {0x00, 0x00, 0x00}, + {0x00}, + {0x00} + }; + #endif /* CY_USE_TEST_DATA */ + +#else + extern u8 g_appload_ray[]; +#endif +#define FW_FNAME_LEN 40 +#define TP_ID_GPIO 85 + + +/* CY TTSP I2C Driver private data */ +struct cyttsp { + struct i2c_client *client; + struct input_dev *input; + struct work_struct work; + struct timer_list timer; + struct mutex mutex; + char phys[32]; + struct cyttsp_platform_data *platform_data; + u8 num_prv_st_tch; + u16 act_trk[CY_NUM_TRK_ID]; + u16 prv_st_tch[CY_NUM_ST_TCH_ID]; + u16 prv_mt_tch[CY_NUM_MT_TCH_ID]; + u16 prv_mt_pos[CY_NUM_TRK_ID][2]; + atomic_t irq_enabled; + bool cyttsp_update_fw; + bool cyttsp_fwloader_mode; + bool is_suspended; + struct regulator **vdd; + char fw_fname[FW_FNAME_LEN]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + int tpid; + +}; +extern struct cyttsp cust_ts; +extern void cyttsp_fw_upgrade(void); +extern void cyttsp_hw_reset(void); + + +#endif /* __CYTTSP_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c new file mode 100755 index 00000000..ca6e9d10 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/cyttsp_fw_upgrade.c @@ -0,0 +1,993 @@ +/* Source for:
+ * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
+ * drivers/input/touchscreen/cyttsp-i2c.c
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Cypress reserves the right to make changes without further notice
+ * to the materials described herein. Cypress does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/byteorder/generic.h>
+#include <linux/bitops.h>
+#include <linux/pm_runtime.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+//#include <mach/vreg.h>
+
+#define CY_DECLARE_GLOBALS
+
+#include "cyttsp.h"
+
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+#include <linux/poll.h>
+
+#define LOG_TP() printk("++++%s, Line %d\n", __FUNCTION__, __LINE__);
+
+
+#define CYTTSP_SUPPORT_READ_TP_VERSION
+
+#define CYTTSP_SUPPORT_TP_SENSOR
+// need upgrade,add MACRO
+//#ifdef CONFIG_LCT_AW551_YL
+#define CYTTSP_SUPPORT_SYS_NODE
+//#endif
+
+extern struct tpd_device *tpd;//add 2013-1-7
+
+int cyttsp_vendor_id=20;
+int cyttsp_firmware_version= -1;
+
+int cyttsp_has_bootloader=0;
+
+#ifdef CYTTSP_SUPPORT_TP_SENSOR
+
+#define CYTTSP_DEBUG_TP_SENSOR
+
+#define CYTTSP_SUPPORT_TP_SENSOR_FIRMWARE_VERSION (0xc) //if we change this value we should also change func apds9900_init_dev in file apds9000.c
+static DEFINE_MUTEX(cyttsp_sensor_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(cyttsp_sensor_waitqueue);
+
+//static char cyttsp_sensor_data = 0; // 0 near 1 far
+//static int cyttsp_sensor_data_changed = 0;
+//static struct i2c_client *tp_sensor_I2Cclient = NULL;
+//static int cyttsp_sensor_opened = 0;
+
+
+
+#endif
+
+
+
+#define CYTTSP_AW551_OFILM "cyttspfw_aw551_ofilm.fw"
+#define CYTTSP_AW551_TRULY "cyttspfw_aw551_truly.fw"
+#define CYTTSP_AW550_TRULY "cyttspfw_aw550_truly.fw"
+
+uint32_t cyttsp_tsdebug1 = 0xff;
+
+module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
+
+#define FW_FNAME_LEN 40
+#define TP_ID_GPIO 85
+
+//static u8 irq_cnt; /* comparison counter with register valuw */
+//static u32 irq_cnt_total; /* total interrupts */
+//static u32 irq_err_cnt; /* count number of touch interrupts with err */
+#define CY_IRQ_CNT_MASK 0x000000FF /* mapped for sizeof count in reg */
+#define CY_IRQ_CNT_REG 0x00 /* tt_undef[0]=reg 0x1B - Gen3 only */
+
+
+
+/* ****************************************************************************
+ * Prototypes for static functions
+ * ************************************************************************** */
+
+static int cyttsp_putbl(struct cyttsp *ts, int show,
+ int show_status, int show_version, int show_cid);
+/*static int __devinit cyttsp_probe(struct i2c_client *client,
+ const struct i2c_device_id *id); */
+//static int __devexit cyttsp_remove(struct i2c_client *client);
+//static int cyttsp_resume(struct device *dev);
+//static int cyttsp_suspend(struct device *dev);
+
+#ifdef CYTTSP_SUPPORT_SYS_NODE
+//static int cyttsp_power_down(void);
+#endif
+
+
+
+/* Static variables */
+//static struct cyttsp_gen3_xydata_t g_xy_data;
+static struct cyttsp_bootloader_data_t g_bl_data;
+static struct cyttsp_sysinfo_data_t g_sysinfo_data;
+static const struct i2c_device_id cyttsp_id[] = {
+ { CY_I2C_NAME, 0 }, { }
+};
+static u8 bl_cmd[] = {
+ CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
+ CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
+ CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
+ CY_BL_KEY6, CY_BL_KEY7};
+
+MODULE_DEVICE_TABLE(i2c, cyttsp_id);
+
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver");
+MODULE_AUTHOR("Cypress");
+
+
+
+#ifdef CYTTSP_SUPPORT_TP_SENSOR
+#define CYTTSP_SENSOR_IOM 'r'
+
+#define CYTTSP_SENSOR_IOC_SET_PS_ENABLE _IOW(CYTTSP_SENSOR_IOM, 0, char *)
+#define CYTTSP_SENSOR_READ_PS_DATA _IOR(CYTTSP_SENSOR_IOM, 2, char *)
+
+
+
+
+#endif
+
+
+
+
+
+
+
+
+
+static void cyttsp_exit_bl_mode(struct cyttsp *ts);
+
+
+
+
+
+#ifdef CYTTSP_SUPPORT_SYS_NODE
+/* firmware flashing block */
+#define BLK_SIZE 16
+#define DATA_REC_LEN 64
+#define START_ADDR 0x0880//0x0b00
+#define BLK_SEED 0xff
+#define RECAL_REG 0x1b
+
+enum bl_commands {
+ BL_CMD_WRBLK = 0x39,
+ BL_CMD_INIT = 0x38,
+ BL_CMD_TERMINATE = 0x3b,
+};
+/* TODO: Add key as part of platform data */
+#define KEY_CS (0 + 1 + 2 + 3 + 4 + 5 + 6 + 7)
+#define KEY {0, 1, 2, 3, 4, 5, 6, 7}
+
+static const char _key[] = KEY;
+#define KEY_LEN sizeof(_key)
+
+static int rec_cnt;
+struct fw_record {
+ u8 seed;
+ u8 cmd;
+ u8 key[KEY_LEN];
+ u8 blk_hi;
+ u8 blk_lo;
+ u8 data[DATA_REC_LEN];
+ u8 data_cs;
+ u8 rec_cs;
+};
+#define fw_rec_size (sizeof(struct fw_record))
+
+struct cmd_record {
+ u8 reg;
+ u8 seed;
+ u8 cmd;
+ u8 key[KEY_LEN];
+};
+#define cmd_rec_size (sizeof(struct cmd_record))
+
+static struct fw_record data_record = {
+ .seed = BLK_SEED,
+ .cmd = BL_CMD_WRBLK,
+ .key = KEY,
+};
+
+static const struct cmd_record terminate_rec = {
+ .reg = 0,
+ .seed = BLK_SEED,
+ .cmd = BL_CMD_TERMINATE,
+ .key = KEY,
+};
+static const struct cmd_record initiate_rec = {
+ .reg = 0,
+ .seed = BLK_SEED,
+ .cmd = BL_CMD_INIT,
+ .key = KEY,
+};
+
+#define BL_REC1_ADDR 0x0780
+#define BL_REC2_ADDR 0x07c0
+
+#define ID_INFO_REC ":40078000"
+#define ID_INFO_OFFSET_IN_REC 77
+
+#define REC_START_CHR ':'
+#define REC_LEN_OFFSET 1
+#define REC_ADDR_HI_OFFSET 3
+#define REC_ADDR_LO_OFFSET 5
+#define REC_TYPE_OFFSET 7
+#define REC_DATA_OFFSET 9
+#define REC_LINE_SIZE 141
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+ int retval = 0, tries = 0;
+ u8 host_reg = CY_SOFT_RESET_MODE;
+
+ #if 0
+ gpio_set_value(ts->platform_data->resout_gpio, 1); //reset high valid
+ msleep(100);
+ gpio_set_value(ts->platform_data->resout_gpio, 0);
+ msleep(1000);
+ #endif
+ LOG_TP();
+
+ #if 1// 0 modify 2013-1-7!!!!!!!!!!!
+ do {
+ retval = i2c_smbus_write_i2c_block_data(ts->client,
+ CY_REG_BASE, sizeof(host_reg), &host_reg);
+ if (retval < 0)
+ msleep(20);
+ } while (tries++ < 10 && (retval < 0));
+
+ if (retval < 0) {
+ pr_err("%s: failed\n", __func__);
+ return retval;
+ }
+ #else
+ cyttsp_hw_reset(); //!!!! 2013-1-7 may not go here !!!
+ #endif
+
+ LOG_TP();
+ tries = 0;
+ do {
+ msleep(20);
+ cyttsp_putbl(ts, 1, true, true, false);
+ } while (g_bl_data.bl_status != 0x10 &&
+ g_bl_data.bl_status != 0x11 &&
+ tries++ < 100);
+ LOG_TP();
+ if (g_bl_data.bl_status != 0x11 && g_bl_data.bl_status != 0x10)
+ return -EINVAL;
+ LOG_TP();
+ return 0;
+}
+
+static void cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+ int retval, tries = 0;
+
+ do {
+ retval = i2c_smbus_write_i2c_block_data(ts->client,
+ CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
+ if (retval < 0)
+ msleep(20);
+ } while (tries++ < 10 && (retval < 0));
+}
+
+static void cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+ int retval, tries = 0;
+ u8 host_reg = CY_SYSINFO_MODE;
+
+ do {
+ retval = i2c_smbus_write_i2c_block_data(ts->client,
+ CY_REG_BASE, sizeof(host_reg), &host_reg);
+ if (retval < 0)
+ msleep(20);
+ } while (tries++ < 10 && (retval < 0));
+
+ /* wait for TTSP Device to complete switch to SysInfo mode */
+ if (!(retval < 0)) {
+ retval = i2c_smbus_read_i2c_block_data(ts->client,
+ CY_REG_BASE,
+ sizeof(struct cyttsp_sysinfo_data_t),
+ (u8 *)&g_sysinfo_data);
+ } else
+ pr_err("%s: failed\n", __func__);
+}
+
+static void cyttsp_set_opmode(struct cyttsp *ts)
+{
+ int retval, tries = 0;
+ u8 host_reg = CY_OP_MODE;
+
+ do {
+ retval = i2c_smbus_write_i2c_block_data(ts->client,
+ CY_REG_BASE, sizeof(host_reg), &host_reg);
+ if (retval < 0)
+ msleep(20);
+ } while (tries++ < 10 && (retval < 0));
+}
+
+static int str2uc(char *str, u8 *val)
+{
+ char substr[3];
+ unsigned long ulval;
+ int rc;
+
+ if (!str && strlen(str) < 2)
+ return -EINVAL;
+
+ substr[0] = str[0];
+ substr[1] = str[1];
+ substr[2] = '\0';
+
+ rc = strict_strtoul(substr, 16, &ulval);
+ if (rc != 0)
+ return rc;
+
+ *val = (u8) ulval;
+
+ return 0;
+}
+
+static int flash_block(struct cyttsp *ts, u8 *blk, int len)
+{
+ int retval, i, tries = 0;
+ char buf[(2 * (BLK_SIZE + 1)) + 1];
+ char *p = buf;
+
+ for (i = 0; i < len; i++, p += 2)
+ sprintf(p, "%02x", blk[i]);
+ pr_debug("%s: size %d, pos %ld payload %s\n",
+ __func__, len, (long)0, buf);
+
+ do {
+ retval = i2c_smbus_write_i2c_block_data(ts->client,
+ CY_REG_BASE, len, blk);
+ if (retval < 0)
+ msleep(20);
+ } while (tries++ < 20 && (retval < 0));
+
+ if (retval < 0) {
+ pr_err("%s: failed\n", __func__);
+ return retval;
+ }
+
+ return 0;
+}
+
+static int flash_command(struct cyttsp *ts, const struct cmd_record *record)
+{
+ return flash_block(ts, (u8 *)record, cmd_rec_size);
+}
+
+static void init_data_record(struct fw_record *rec, unsigned short addr)
+{
+ addr >>= 6;
+ rec->blk_hi = (addr >> 8) & 0xff;
+ rec->blk_lo = addr & 0xff;
+ rec->rec_cs = rec->blk_hi + rec->blk_lo +
+ (unsigned char)(BLK_SEED + BL_CMD_WRBLK + KEY_CS);
+ rec->data_cs = 0;
+}
+
+static int check_record(u8 *rec)
+{
+ int rc;
+ u16 addr;
+ u8 r_len, type, hi_off, lo_off;
+
+ rc = str2uc(rec + REC_LEN_OFFSET, &r_len);
+ if (rc < 0)
+ return rc;
+
+ rc = str2uc(rec + REC_TYPE_OFFSET, &type);
+ if (rc < 0)
+ return rc;
+
+ if (*rec != REC_START_CHR || r_len != DATA_REC_LEN || type != 0)
+ return -EINVAL;
+
+ rc = str2uc(rec + REC_ADDR_HI_OFFSET, &hi_off);
+ if (rc < 0)
+ return rc;
+
+ rc = str2uc(rec + REC_ADDR_LO_OFFSET, &lo_off);
+ if (rc < 0)
+ return rc;
+
+ addr = (hi_off << 8) | lo_off;
+
+ if (addr >= START_ADDR || addr == BL_REC1_ADDR || addr == BL_REC2_ADDR)
+ return 0;
+
+ return -EINVAL;
+}
+
+static struct fw_record *prepare_record(u8 *rec)
+{
+ int i, rc;
+ u16 addr;
+ u8 hi_off, lo_off;
+ u8 *p;
+
+ rc = str2uc(rec + REC_ADDR_HI_OFFSET, &hi_off);
+ if (rc < 0)
+ return ERR_PTR((long) rc);
+
+ rc = str2uc(rec + REC_ADDR_LO_OFFSET, &lo_off);
+ if (rc < 0)
+ return ERR_PTR((long) rc);
+
+ addr = (hi_off << 8) | lo_off;
+
+ init_data_record(&data_record, addr);
+ p = rec + REC_DATA_OFFSET;
+ for (i = 0; i < DATA_REC_LEN; i++) {
+ rc = str2uc(p, &data_record.data[i]);
+ if (rc < 0)
+ return ERR_PTR((long) rc);
+ data_record.data_cs += data_record.data[i];
+ data_record.rec_cs += data_record.data[i];
+ p += 2;
+ }
+ data_record.rec_cs += data_record.data_cs;
+
+ return &data_record;
+}
+
+static int flash_record(struct cyttsp *ts, const struct fw_record *record)
+{
+ int len = fw_rec_size;
+ int blk_len, rc;
+ u8 *rec = (u8 *)record;
+ u8 data[BLK_SIZE + 1];
+ u8 blk_offset;
+
+ for (blk_offset = 0; len; len -= blk_len) {
+ data[0] = blk_offset;
+ blk_len = len > BLK_SIZE ? BLK_SIZE : len;
+ memcpy(data + 1, rec, blk_len);
+ rec += blk_len;
+ rc = flash_block(ts, data, blk_len + 1);
+ if (rc < 0)
+ return rc;
+ blk_offset += blk_len;
+ }
+ return 0;
+}
+
+static int flash_data_rec(struct cyttsp *ts, u8 *buf)
+{
+ struct fw_record *rec;
+ int rc, tries;
+LOG_TP();
+ if (!buf)
+ return -EINVAL;
+
+ rc = check_record(buf);
+
+ if (rc < 0) {
+ pr_debug("%s: record ignored %s", __func__, buf);
+ return 0;
+ }
+
+ rec = prepare_record(buf);
+ if (IS_ERR_OR_NULL(rec))
+ return PTR_ERR(rec);
+
+ rc = flash_record(ts, rec);
+ if (rc < 0)
+ return rc;
+
+ tries = 0;
+ do {
+//printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries ); //wujinyou
+
+ //if (rec_cnt%2)
+ //msleep(20);
+ if(tries >50)
+ {
+ printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries ); //wujinyou
+ msleep(20);
+ }
+ cyttsp_putbl(ts, 4, true, false, false);
+ } while (g_bl_data.bl_status != 0x10 &&
+ g_bl_data.bl_status != 0x11 &&
+ tries++ < 100);
+ rec_cnt++;
+ return rc;
+}
+
+static int cyttspfw_flash_firmware(struct cyttsp *ts, const u8 *data,
+ int data_len)
+{
+ u8 *buf;
+ int i, j;
+ int rc, tries = 0;
+ LOG_TP();
+
+ /* initiate bootload: this will erase all the existing data */
+ rc = flash_command(ts, &initiate_rec);
+ if (rc < 0)
+ return rc;
+
+ do {
+// LOG_TP();
+printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries );
+ msleep(60);
+ cyttsp_putbl(ts, 4, true, false, false);
+ } while (g_bl_data.bl_status != 0x10 &&
+ g_bl_data.bl_status != 0x11 &&
+ tries++ < 100);
+
+ buf = kzalloc(REC_LINE_SIZE + 1, GFP_KERNEL);
+ if (!buf) {
+ pr_err("%s: no memory\n", __func__);
+ return -ENOMEM;
+ }
+ LOG_TP();
+ rec_cnt = 0;
+ /* flash data records */
+ for (i = 0, j = 0; i < data_len; i++, j++) {
+ if ((data[i] == REC_START_CHR) && j) {
+ buf[j] = 0;
+ rc = flash_data_rec(ts, buf);
+ if (rc < 0)
+ return rc;
+ j = 0;
+ }
+ buf[j] = data[i];
+ }
+ LOG_TP();
+ /* flash last data record */
+ if (j) {
+ buf[j] = 0;
+ rc = flash_data_rec(ts, buf);
+ if (rc < 0)
+ return rc;
+ }
+ LOG_TP();
+ kfree(buf);
+
+ /* termiate bootload */
+ tries = 0;
+ rc = flash_command(ts, &terminate_rec);
+ do {
+ msleep(100);
+printk("++++%s, Line %d, tries=%d\n", __FUNCTION__, __LINE__,tries );
+
+ cyttsp_putbl(ts, 4, true, false, false);
+ } while (g_bl_data.bl_status != 0x10 &&
+ g_bl_data.bl_status != 0x11 &&
+ tries++ < 100);
+ LOG_TP();
+ return rc;
+}
+
+static int get_hex_fw_ver(u8 *p, u8 *ttspver_hi, u8 *ttspver_lo,
+ u8 *appid_hi, u8 *appid_lo, u8 *appver_hi,
+ u8 *appver_lo, u8 *cid_0, u8 *cid_1, u8 *cid_2)
+{
+ int rc;
+
+ p = p + ID_INFO_OFFSET_IN_REC;
+ rc = str2uc(p, ttspver_hi);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, ttspver_lo);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, appid_hi);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, appid_lo);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, appver_hi);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, appver_lo);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, cid_0);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, cid_1);
+ if (rc < 0)
+ return rc;
+ p += 2;
+ rc = str2uc(p, cid_2);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static void cyttspfw_flash_start(struct cyttsp *ts, const u8 *data,
+ int data_len, u8 *buf, bool force)
+{
+ int rc;
+ u8 ttspver_hi = 0, ttspver_lo = 0, fw_upgrade = 0;
+ u8 appid_hi = 0, appid_lo = 0;
+ u8 appver_hi = 0, appver_lo = 0;
+ u8 cid_0 = 0, cid_1 = 0, cid_2 = 0;
+ char *p = buf;
+
+ /* get hex firmware version */
+ rc = get_hex_fw_ver(p, &ttspver_hi, &ttspver_lo,
+ &appid_hi, &appid_lo, &appver_hi,
+ &appver_lo, &cid_0, &cid_1, &cid_2);
+printk("++++tpd-fw-ver: %x %x %x %x %x %x %x %x %x\n", ttspver_hi, ttspver_lo, appid_hi, appid_lo, appver_hi,appver_lo, cid_0, cid_1,cid_2);
+ if (rc < 0) {
+ pr_err("%s: unable to get hex firmware version\n", __func__);
+ return;
+ }
+#if 0 //wujinyou
+ /* disable interrupts before flashing */
+ if (ts->client->irq == 0)
+ del_timer(&ts->timer);
+ else
+ disable_irq(ts->client->irq);
+
+ rc = cancel_work_sync(&ts->work);
+
+ if (rc && ts->client->irq)
+ enable_irq(ts->client->irq);
+#endif
+
+ /* enter bootloader idle mode */
+ rc = cyttsp_soft_reset(ts);
+ //LOG_TP();
+ printk("++++%s, Line %d, rc=%d\n", __FUNCTION__, __LINE__,rc);
+
+ if (rc < 0) {
+ LOG_TP();
+ pr_err("%s: cyttsp_soft_reset try entering into idle mode"
+ " second time\n", __func__);
+ msleep(1000);
+
+ rc = cyttsp_soft_reset(ts);
+ }
+
+ if (rc < 0) {
+ LOG_TP();
+ pr_err("%s:cyttsp_soft_reset try again later\n", __func__);
+ return;
+ }
+
+ LOG_TP();
+
+ pr_info("Current firmware:lusongbai %d.%d.%d", g_bl_data.appid_lo,
+ g_bl_data.appver_hi, g_bl_data.appver_lo);
+ pr_info("New firmware: %d.%d.%d", appid_lo, appver_hi, appver_lo);
+ LOG_TP();
+
+ if (force)
+ fw_upgrade = 1;
+ else
+ if ((appid_hi == g_bl_data.appid_hi) &&
+ (appid_lo == g_bl_data.appid_lo)) {
+ if (appver_hi > g_bl_data.appver_hi) {
+ fw_upgrade = 1;
+ } else if ((appver_hi == g_bl_data.appver_hi) &&
+ (appver_lo > g_bl_data.appver_lo)) {
+ fw_upgrade = 1;
+ } else {
+ fw_upgrade = 0;
+ pr_info("%s: Firmware version "
+ "lesser/equal to existing firmware, "
+ "upgrade not needed\n", __func__);
+ }
+ } else {
+ fw_upgrade = 0;
+ pr_info("%s: Firware versions do not match, "
+ "cannot upgrade\n", __func__);
+ }
+
+ printk("++++%s, Line %d, fw_upgrade=%d\n", __FUNCTION__, __LINE__,fw_upgrade);
+
+ if (fw_upgrade) {
+ pr_info("%s: Starting firmware upgrade\n", __func__);
+ rc = cyttspfw_flash_firmware(ts, data, data_len);
+ if (rc < 0)
+ pr_err("%s: firmware upgrade failed\n", __func__);
+ else
+ pr_info("%s: lusongbai firmware upgrade success\n", __func__);
+ }
+ LOG_TP();
+
+ /* enter bootloader idle mode */
+ cyttsp_soft_reset(ts);
+ LOG_TP();
+
+ /* exit bootloader mode */
+ cyttsp_exit_bl_mode(ts);
+ LOG_TP();
+
+ msleep(100);
+ /* set sysinfo details */
+ cyttsp_set_sysinfo_mode(ts);
+ LOG_TP();
+
+ /* enter application mode */
+ cyttsp_set_opmode(ts);
+ LOG_TP();
+
+ if((fw_upgrade == 1) && (rc >= 0))
+ {
+ u8 tmpData[18] = {0};
+ rc = i2c_smbus_read_i2c_block_data(ts->client,CY_REG_BASE,18, tmpData);
+ if(rc < 0)
+ {
+ printk(KERN_ERR"cyttspfw_flash_start read version and module error\n");
+ }
+ else
+ {
+ cyttsp_vendor_id=tmpData[16];
+ cyttsp_firmware_version = tmpData[17];
+ printk(KERN_ERR"cyttspfw_flash_start tp module is:%x firmware version is %x:\n",tmpData[16],tmpData[17]);
+ }
+ }
+ LOG_TP();
+
+ /* enable interrupts */
+#if 0
+ if (ts->client->irq == 0)
+ mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+ else
+ enable_irq(ts->client->irq);
+#endif
+ LOG_TP();
+
+}
+
+static void cyttspfw_upgrade_start(struct cyttsp *ts, const u8 *data,
+ int data_len, bool force)
+{
+ int i, j;
+ u8 *buf;
+
+ buf = kzalloc(REC_LINE_SIZE + 1, GFP_KERNEL);
+ if (!buf) {
+ pr_err("%s: no memory\n", __func__);
+ return;
+ }
+
+ for (i = 0, j = 0; i < data_len; i++, j++) {
+ if ((data[i] == REC_START_CHR) && j) {
+ buf[j] = 0;
+ j = 0;
+ if (!strncmp(buf, ID_INFO_REC, strlen(ID_INFO_REC))) {
+ cyttspfw_flash_start(ts, data, data_len,
+ buf, force);
+ break;
+ }
+ }
+ buf[j] = data[i];
+ }
+
+ /* check in the last record of firmware */
+ if (j) {
+ buf[j] = 0;
+ if (!strncmp(buf, ID_INFO_REC, strlen(ID_INFO_REC))) {
+ cyttspfw_flash_start(ts, data, data_len,
+ buf, force);
+ }
+ }
+
+ kfree(buf);
+}
+static bool cyttsp_IsTpInBootloader(struct cyttsp *ts)
+{
+ int retval = -1;
+ u8 tmpData[18] = {0};
+ retval = i2c_smbus_read_i2c_block_data(ts->client,CY_REG_BASE,18, tmpData);
+ if(retval < 0)
+ {
+ printk(KERN_ERR"cyttsp_IsTpInBootloader read version and module error\n");
+ return false;
+ }
+ else
+ {
+ retval = 0;
+ retval = ((tmpData[1] & 0x10) >> 4);
+
+ printk(KERN_ERR"cyttsp_IsTpInBootloader tmpData[1]:%x retval:%x\n",tmpData[1],retval);
+ }
+ if(retval == 0)
+ {
+ return false;
+ }
+ return true;
+
+}
+
+const u8 fw_hex_of[] = {
+// #include "BOOT_AG500_OF_DW_2802_V2_20120702.i"
+// #include "BOOT_AG500_OF_DW_2803_V3_20120711.i"
+};
+const u8 fw_hex_hhx[] = {
+// #include "BOOT_AG500_F5_HHX_2503_V3_20120711.i"
+};
+struct cyttsp cust_ts;
+const u8* fw_hex = fw_hex_hhx;
+extern void cyttsp_print_reg(struct i2c_client *client);
+
+int read_vender_id(void)
+{
+ char buffer[32];
+ int ret =0;
+
+ ret = i2c_smbus_read_i2c_block_data(cust_ts.client, 0x00, 24, &(buffer[0]));
+ if(ret<0)
+ {
+ return -1;
+ }
+ cyttsp_vendor_id = buffer[3];
+ printk("++++cyttp read_vender_id=0x%x\n", cyttsp_vendor_id);
+ cyttsp_print_reg(cust_ts.client);
+ return 0;
+}
+
+
+void cyttsp_fw_upgrade(void)
+{
+ struct cyttsp *ts = &cust_ts;
+ bool force = 1;
+ /* check and start upgrade */
+ //if upgrade failed we should force upgrage when next power up
+
+ if(read_vender_id() != 0)
+ {
+ printk("++++cyttspfw_upgrade read vender id failed!\n");
+ return;
+ }
+ switch(cyttsp_vendor_id)
+ {
+ case 0x28:
+ fw_hex = fw_hex_of;
+ break;
+ case 0x25:
+ fw_hex = fw_hex_hhx;
+ break;
+ case 0x0:
+ break;
+ default:
+ break;
+ }
+
+ if(cyttsp_IsTpInBootloader(ts) == true)
+ {
+ LOG_TP();
+ printk(KERN_ERR"cyttspfw_upgrade we should force upgrade tp fw\n");
+ cyttspfw_upgrade_start(ts, fw_hex,
+ sizeof(fw_hex_of), true);
+ }
+ else
+ {
+ LOG_TP();
+ cyttspfw_upgrade_start(ts, fw_hex,
+ sizeof(fw_hex_of), force);
+ }
+}
+
+#endif
+
+
+
+static int cyttsp_putbl(struct cyttsp *ts, int show,
+ int show_status, int show_version, int show_cid)
+{
+ int retval = CY_OK;
+
+ int num_bytes = (show_status * 3) + (show_version * 6) + (show_cid * 3);
+
+ if (show_cid)
+ num_bytes = sizeof(struct cyttsp_bootloader_data_t);
+ else if (show_version)
+ num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3;
+ else
+ num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9;
+ LOG_TP();
+
+ if (show) {
+ retval = i2c_smbus_read_i2c_block_data(ts->client,
+ CY_REG_BASE, num_bytes, (u8 *)&g_bl_data);
+
+ {
+ int i = 0;
+ printk("cyttsp_putbl:");
+ for(i=0; i<num_bytes; i++)
+ printk(" 0x%x",*((u8 *)&g_bl_data+i));
+ printk("\n");
+ }
+ if (show_status) {
+ cyttsp_debug("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
+ show, \
+ g_bl_data.bl_file, \
+ g_bl_data.bl_status, \
+ g_bl_data.bl_error, \
+ g_bl_data.blver_hi, g_bl_data.blver_lo, \
+ g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
+ }
+ if (show_version) {
+ cyttsp_debug("BL%d: ttspver=0x%02X%02X appid=0x%02X%02X appver=0x%02X%02X\n", \
+ show, \
+ g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
+ g_bl_data.appid_hi, g_bl_data.appid_lo, \
+ g_bl_data.appver_hi, g_bl_data.appver_lo);
+ }
+ if (show_cid) {
+ cyttsp_debug("BL%d: cid=0x%02X%02X%02X\n", \
+ show, \
+ g_bl_data.cid_0, \
+ g_bl_data.cid_1, \
+ g_bl_data.cid_2);
+ }
+ }
+ //LOG_TP();
+
+ return retval;
+}
+
+
+#ifndef CYTTSP_SUPPORT_SYS_NODE
+static void cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+ int retval, tries = 0;
+
+ do {
+ retval = i2c_smbus_write_i2c_block_data(ts->client,
+ CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
+ if (retval < 0)
+ msleep(20);
+ } while (tries++ < 10 && (retval < 0));
+}
+#endif
+
+
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt new file mode 100755 index 00000000..a424c186 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/debug.txt @@ -0,0 +1,3 @@ +/ # wmtenv get wmt.io.touch +1:cyp140:7:600:1024:4:0:1:-1:5 //it seems ok + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c new file mode 100755 index 00000000..d7234ac3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.c @@ -0,0 +1,1094 @@ +#include <linux/unistd.h> +#include <linux/time.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +//#include <asm/semaphore.h> +#include <linux/proc_fs.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/suspend.h> +#include <linux/input.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + +#include <asm/uaccess.h> +#include <linux/fs.h> +#include <linux/syscalls.h> + +#include "wmt_ts.h" +//#include "zet6221_ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +#define TP_INFOR_ARRAY_SIZE (sizeof(l_tpinfor)/sizeof(l_tpinfor[1])) +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int irq_gpio = 7;//!!!2012-12-28 +static int rst_gpio = 4;// +static int panelres_x; +static int panelres_y; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static CALIBRATION_PARAMETER g_CalcParam; +static TS_EVENT g_evLast; +static struct mutex cal_mutex; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); +static int lcd_exchg = 0; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +extern struct wmtts_device cyp140_tsdev; +static struct wmtts_device* l_tsdev = &cyp140_tsdev; +struct proc_dir_entry* l_tsproc = NULL; +static struct i2c_client *l_client=NULL; +static int l_penup = 1; // 1-pen up,0-pen down + +struct tp_infor +{ + //enum tp_type type; + char name[64]; + //unsigned int i2caddr; + unsigned int xaxis; //0: x,1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; +}; + +static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); +/////////////////////////////////////////////////////////////////////// +void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ) +{ + int x, y; + mutex_lock(&cal_mutex); + x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + + g_CalcParam.c2) / g_CalcParam.delta; + +//klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); + if ( x < 0 ) + x = 0; + + if ( y < 0 ) + y = 0; + if (x >= panelres_x) + x = panelres_x-1; + if (y >= panelres_y) + y = panelres_y-1; + + *pCalX = x; + *pCalY = y; + mutex_unlock(&cal_mutex); + return; +} + +int wmt_ts_if_updatefw(void) +{ + /*if ((!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7dgntpc0350")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7zcc1950")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_8dgntpc0406")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7adc700148")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_8xdc806")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7tp070005q8")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7yiheng7002")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7atc7031"))|| + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7xclg7027a")) || + (!strcmp(l_tpinfor[l_tpindex].name,"ZET6221_7est07000416"))) + { + return 1; + } + + return 0; + */ + + struct file *fp; + char filepath[128]; + + sprintf(filepath,"/lib/firmware/%s_fw.ts",l_tpinfor[l_tpindex].name); + + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) + { + //printk("create file error\n"); + return 0; + } + filp_close(fp, NULL); + return 1; +} + +unsigned int wmt_ts_get_xaxis(void) +{ + return l_tpinfor[l_tpindex].xaxis; +} + +unsigned int wmt_ts_get_xdir(void) +{ + return l_tpinfor[l_tpindex].xdir; +} + +unsigned int wmt_ts_get_ydir(void) +{ + return l_tpinfor[l_tpindex].ydir; +} + +unsigned int wmt_ts_get_maxfingernum(void) +{ + return l_tpinfor[l_tpindex].max_finger_num; +} + +#if 0 +static int parse_firmwarefile(char* filedata, unsigned char** firmarr, int maxlen) +{ + char endflag[]="/* End flag */"; + char* p = filedata; + int i = 0; + int j = 0; + char* s = NULL; + + s = p; + // calculate the number of array + while (strncmp(p,endflag,strlen(endflag))) + { + if (!strncmp(p,"0x",strlen("0x"))) + { + i++; + } + p++; + }; + dbg("the number of arry:0x%x\n", i); + // alloc the memory for array + j = i + i%4; + *firmarr = kzalloc(sizeof(unsigned char)*j, GFP_KERNEL); + // parse the value of array + p = s; + j = 0; + while (strncmp(p,endflag,strlen(endflag))) + { + if (!strncmp(p,"0x",strlen("0x"))) + { + //dbg("find 0x!\n"); + sscanf(p,"0x%x", &((*firmarr)[j])); + //dbg("arry[0x%x]:%x\n",j,(*firmarr)[j]); + j++; + p+=4; + } else { + p++; + } + //p = strchr(p,'}'); + if (j>=i-2) + { + dbg("%s",p); + } + + }; + if (i != j) + { + errlog("Error parsing file(the number of arry not match)!\n"); + return -1; + }; + dbg("paring firmware file end.\n"); + return i; +} + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//return:0-successful,negative-parsing error. +int read_firmwarefile(char* filepath, unsigned char** firmdata) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos; + char* data = NULL; + long fsize; + int alloclen = 2052*(8*5+2)+200; + int i = 0; + + klog("ts firmware file:%s\n",filepath); + data = kzalloc(alloclen, GFP_KERNEL); + if (data == NULL) + { + errlog("Error when alloc memory for firmware file!\n"); + return -1; + } + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + printk("create file error\n"); + goto error_flip_open; + } + fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + fsize = vfs_read(fp, data, alloclen, &pos); + dbg("filesize:0x%x,alloclen:0x%x\n",fsize,alloclen); + if (fsize <= 0) + { + errlog("alloc size is too small.\n"); + goto error_vfs_read; + } + i = parse_firmwarefile(data,firmdata,fsize); + // Check the parsing and ori file + /* for (i=0;i < maxlen; i++) + { + if (firmdata[i]!=nvctp_BinaryFile_default[i]) + { + errlog("Don't match:i=%x,parse:0x%x,ori:0x%x\n",i,firmdata[i], nvctp_BinaryFile_default[i]); + break; + } + }; + dbg("parsing match with ori.\n"); + */ + filp_close(fp, NULL); + set_fs(fs); + kfree(data); + dbg("success to read firmware file!\n");; + + //sscanf(data,"%hd %hd %hd",&offset.u.x,&offset.u.y,&offset.u.z); + return i; +error_vfs_read: + filp_close(fp, NULL); + set_fs(fs); +error_flip_open: + kfree(data); + return -1; +} +#endif + +void wmt_ts_get_firmwname(char* firmname) +{ + sprintf(firmname,"/lib/firmware/%s_fw.ts",l_tpinfor[l_tpindex].name); +} + + int wmt_ts_get_irqgpnum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + + int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +void wmt_tsreset_init(void) +{ + int num = rst_gpio; +/* + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num);//&= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<num); // out low + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //output enable + msleep(10); + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); // out high +*/ + gpio_direction_output(num, 0); + msleep(10); + gpio_set_value(num, 1); +} +/* +// enable:0-disable,1-enable +void wmt_enable_rst_pull(int enable) +{ + if (enable) + { + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<rst_gpio); //enable pull up/down + } else { + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<rst_gpio); //disable pull up/down + } +} +*/ + +// enable:0-disable,1-enable +void wmt_disable_rst_pull(void) +{ + wmt_gpio_setpull(rst_gpio, WMT_GPIO_PULL_NONE); + +} + +// up:0-pull down,1-pull up +void wmt_set_rst_pull(int up) +{ + wmt_gpio_setpull(rst_gpio, up ? WMT_GPIO_PULL_UP : WMT_GPIO_PULL_DOWN); +} + +// high:0-low level,1-high level +void wmt_rst_output(int high) +{ + if (high) + gpio_direction_output(rst_gpio, 1); + else + gpio_direction_output(rst_gpio, 0); +} + +void wmt_rst_input(void) +{ + gpio_direction_input(rst_gpio); +} + +void wmt_set_intasgp(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio +} + +// val:1--high,0-low +void wmt_intgp_out(int val) +{ + if (val) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<irq_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<irq_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set output +} + +void wmt_ts_set_irqinput(void) +{ + int num = irq_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input +} + +unsigned int wmt_ts_irqinval(void) +{ + return REG32_VAL(__GPIO_BASE+0x0000)&(1<<irq_gpio); +} + +int wmt_set_gpirq(int type) +{ + int shift; + int offset; + unsigned long reg; + int num = irq_gpio; + + if(num >11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num);//|=(1<<num);// //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull up + //REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down .debug pulldown 2013-5-8 + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<num); //enable pull up/down 2013-1-4 replace 2013-5-7 default enable!! + //REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + +int wmt_enable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + return l_tsdev->suspend(pdev, state); +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + return l_tsdev->resume(pdev); +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_ts_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + klog("wmt ts driver opening...\n"); + + //ts_clear(); + //try_module_get(THIS_MODULE); + + return ret; +} + +static int wmt_ts_close(struct inode *inode, struct file *filp) +{ + klog("wmt ts driver closing...\n"); + //ts_clear(); + //module_put(THIS_MODULE); + + return 0; +} + +static unsigned int wmt_ts_poll(struct file *filp, struct poll_table_struct *wait) +{ +#if 0 + poll_wait(filp, &queue, wait); + if ( head != tail ) + return (POLLIN | POLLRDNORM); +#endif + return 0; +} + +static long wmt_ts_ioctl(/*struct inode * node,*/ struct file *dev, unsigned int cmd, unsigned long arg) +{ + int nBuff[7]; + char env_val[96]={0}; + //dbg("wmt_ts_ioctl(node=0x%p, dev=0x%p, cmd=0x%08x, arg=0x%08lx)\n", node, dev, cmd, arg); + + if (_IOC_TYPE(cmd) != TS_IOC_MAGIC){ + dbg("CMD ERROR!"); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > TS_IOC_MAXNR){ + dbg("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + + case TS_IOCTL_CAL_DONE: + klog("wmt_ts_ioctl: TS_IOCTL_CAL_DONE\n"); + copy_from_user(nBuff, (unsigned int*)arg, 7*sizeof(int)); + + mutex_lock(&cal_mutex); + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero + + mutex_unlock(&cal_mutex); + + sprintf(env_val,"%d %d %d %d %d %d %d",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + wmt_setsyspara("wmt.io.ts.2dcal", env_val); + klog("Tsc calibrate done data: [%s]\n",env_val); + + return 0; + + + case TS_IOCTL_GET_RAWDATA: + // wait for point up + dbg("test wait_penup\n"); + //l_tsdev->wait_penup(>811_tsdev); + klog("wmt_ts_ioctl: TS_IOCTL_GET_RAWDATA\n"); + wmt_ts_wait_penup(); + + nBuff[0] = g_evLast.x; + nBuff[1] = g_evLast.y; + copy_to_user((unsigned int*)arg, nBuff, 2*sizeof(int)); + klog("raw data: x=%d, y=%d\n", nBuff[0], nBuff[1]); + + return 0; + } + + return -EINVAL; +} + +static ssize_t wmt_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) +{ + // read firmware file + + return 0; +} + + +static struct file_operations wmt_ts_fops = { + .read = wmt_ts_read, + .poll = wmt_ts_poll, + .unlocked_ioctl = wmt_ts_ioctl, + .open = wmt_ts_open, + .release = wmt_ts_close, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "reset=%d\n", &val)) + { + + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96, i = 0; + char retval[200] = {0},*p=NULL,*s=NULL; + //int nBuff[7] = {0}; + int Enable=0; //Gpio=0,PX=0,PY=0; + int val,val1; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(l_tpinfor,0,sizeof(l_tpinfor[0])); + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(l_tpinfor[0].name,p, (s-p)); + p = s+1; + dbg("ts_name=%s\n", l_tpinfor[0].name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tpinfor[0].xaxis),&(l_tpinfor[0].xdir),&(l_tpinfor[0].ydir), + &(l_tpinfor[0].max_finger_num)); + if (ret != 8) + { + dbg("Wrong format ts u-boot param(%d)!\n",ret); + return -ENODEV; + } + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + /*p = strchr(retval,':'); + p++; + if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID + //errlog(" %s!=====\n", l_tsdev->ts_id); + return -ENODEV; + }*/ + + //sscanf(p,"%s:", ); +#if 1 + if (strstr(l_tpinfor[0].name, l_tsdev->ts_id) == NULL)// cyp140 + { + dbg("Can't find %s!\n", l_tsdev->ts_id); + return -ENODEV; + } +#endif //comment 2012-12-31 + l_tpindex = 0; + +/* + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d",&irq_gpio,&panelres_x,&panelres_y,&rst_gpio); + + irq_gpio = Gpio; + panelres_x = PX; + panelres_y = PY; + */ + klog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_tpinfor[0].xaxis,l_tpinfor[0].xdir,l_tpinfor[0].ydir, + l_tpinfor[0].max_finger_num); + + // parse touch key param + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskeyindex", retval, &len); + if(ret){ + dbg("no touch key!\n"); + //return -EIO; + } else { + p = retval; + // the number of touch key + sscanf(retval,"%d:", &val); + dbg("tskey num:%d\n",val); + p = strchr(p,':'); + p++; + // touch key range + for (i=0;i<val;i++) + { + sscanf(p,"%d:",&val1); + p = strchr(p,':'); + p++; + //zet6221_set_tskey(i, val1); //own tp ic 2012-12-31??!!! + dbg("key%d:(%d)\n",i,val1); + }; + } + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + +/* memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + errlog("Read env wmt.io.ts.2dcal Failed.\n "); + //return -EIO; + } + i = 0; + while(i < sizeof(retval)){ + if(retval[i]==' ' || retval[i]==',' || retval[i]==':') + retval[i] = '\0'; + i++; + } + + i = 0; + p = retval; + while(i<7 && p < (retval + sizeof(retval))){ + if(*p == '\0') + p++; + else{ + sscanf(p,"%d",&nBuff[i]); + //printk("%d\n",nBuff[i]); + p=p+strlen(p); + i++; + } + } + //sscanf(retval,"%d %d %d %d %d %d %d %d",&nBuff[0],&nBuff[1],&nBuff[2],&nBuff[3],&nBuff[4],&nBuff[5],&nBuff[6]); + dbg("Tsc calibrate init data: [%d %d %d %d %d %d %d]\n",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero +*/ + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + + + if(wmt_check_touch_env()) + return -ENODEV; + + //ts_i2c_board_info.addr = l_tpinfor[l_tpindex].i2caddr; + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + // Create device node + if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + unregister_chrdev(TS_MAJOR, TS_NAME); + class_destroy(l_dev_class); + mutex_destroy(&cal_mutex); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h new file mode 100755 index 00000000..11261348 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/cyp140_ts/wmt_ts.h @@ -0,0 +1,120 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/suspend.h> +#include <linux/i2c.h> + + +//#define DEBUG_WMT_TS +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "cyp140-ts" +#define WMT_TS_I2C_ADDR 0x24 //0x76 + + + + + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_irqgpnum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_disable_rst_pull(void); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern void wmt_ts_get_firmwname(char* firmname); +extern unsigned int wmt_ts_get_maxfingernum(void); +extern unsigned int wmt_ts_get_ictype(void); +extern unsigned int wmt_ts_get_xaxis(void); +extern unsigned int wmt_ts_get_xdir(void); +extern unsigned int wmt_ts_get_ydir(void); +// short +extern unsigned int wmt_ts_get_touchheight(void); +// long +extern unsigned int wmt_ts_get_touchwidth(void); +extern int wmt_ts_if_updatefw(void); + + + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the length of firmware data,negative-parsing error. +//extern int read_firmwarefile(char* filepath, unsigned char** firmdata); + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig new file mode 100755 index 00000000..7dadb37f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_FT5X0X
+ tristate "FT5X0X Capacity Touchscreen Device Support"
+ default y
+ depends on ARCH_WMT
+ ---help---
+ Say Y here if you have an WMT based board with touchscreen
+ attached to it.
+ If unsure, say N.
+ To compile this driver as a module, choose M here: the
+ module will be called ft5x0x.
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile new file mode 100755 index 00000000..0283c3ec --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_ft5x0x
+
+#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := ft5x0x.o ft5x0x_upg.o ft5402_config.o ini.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c new file mode 100755 index 00000000..58683ebd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.c @@ -0,0 +1,2295 @@ +#include "ft5402_config.h"
+//#include <linux/i2c/ft5402_ts.h>
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+
+#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include "ini.h"
+#include "ft5402_ini_config.h"
+#include "ft5x0x.h"
+
+
+extern int ft5x0x_i2c_txdata(char *txdata, int length);
+
+int ft5402_write_reg(struct i2c_client * client, u8 regaddr, u8 regvalue)
+{
+ unsigned char buf[2] = {0};
+ buf[0] = regaddr;
+ buf[1] = regvalue;
+
+ return ft5x0x_i2c_txdata(buf, 2);
+}
+
+int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue)
+{
+ int ret;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ®addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = regvalue,
+ },
+ };
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret < 0)
+ pr_err("function:%s. i2c read error: %d\n", __func__, ret);
+ return ret;
+}
+
+/*set tx order
+*@txNO: offset from tx order start
+*@txNO1: tx NO.
+*/
+static int ft5402_set_tx_order(struct i2c_client * client, u8 txNO, u8 txNO1)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_write_reg(client, FT5402_REG_TX_ORDER_START + txNO,
+ txNO1);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1,
+ txNO1);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*set tx order
+*@txNO: offset from tx order start
+*@pTxNo: return value of tx NO.
+*/
+static int ft5402_get_tx_order(struct i2c_client * client, u8 txNO, u8 *pTxNo)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client, FT5402_REG_TX_ORDER_START + txNO,
+ pTxNo);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if(ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1,
+ pTxNo);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*set tx cap
+*@txNO: tx NO.
+*@cap_value: value of cap
+*/
+static int ft5402_set_tx_cap(struct i2c_client * client, u8 txNO, u8 cap_value)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_write_reg(client, FT5402_REG_TX_CAP_START + txNO,
+ cap_value);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1,
+ cap_value);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*get tx cap*/
+static int ft5402_get_tx_cap(struct i2c_client * client, u8 txNO, u8 *pCap)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client, FT5402_REG_TX_CAP_START + txNO,
+ pCap);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1,
+ pCap);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*set tx offset*/
+static int ft5402_set_tx_offset(struct i2c_client * client, u8 txNO, u8 offset_value)
+{
+ unsigned char temp=0;
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp);
+ if (ReCode >= 0) {
+ if (txNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1),
+ (temp&0xf0) + (offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1),
+ (temp&0x0f) + (offset_value<<4));
+ }
+ } else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_DEVICE_MODE+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ &temp); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ if(txNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value<<4));
+ }
+ }
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*get tx offset*/
+static int ft5402_get_tx_offset(struct i2c_client * client, u8 txNO, u8 *pOffset)
+{
+ unsigned char temp=0;
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ &temp);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ if (ReCode >= 0)
+ (txNO%2 == 0) ? (*pOffset = (temp&0x0f)) : (*pOffset = (temp>>4));
+ return ReCode;
+}
+
+/*set rx order*/
+static int ft5402_set_rx_order(struct i2c_client * client, u8 rxNO, u8 rxNO1)
+{
+ unsigned char ReCode = 0;
+ ReCode = ft5402_write_reg(client, FT5402_REG_RX_ORDER_START + rxNO,
+ rxNO1);
+ return ReCode;
+}
+
+/*get rx order*/
+static int ft5402_get_rx_order(struct i2c_client * client, u8 rxNO, u8 *prxNO1)
+{
+ unsigned char ReCode = 0;
+ ReCode = ft5402_read_reg(client, FT5402_REG_RX_ORDER_START + rxNO,
+ prxNO1);
+ return ReCode;
+}
+
+/*set rx cap*/
+static int ft5402_set_rx_cap(struct i2c_client * client, u8 rxNO, u8 cap_value)
+{
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1)
+ ReCode = ft5402_write_reg(client, FT5402_REG_RX_CAP_START + rxNO,
+ cap_value);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if(ReCode >= 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1,
+ cap_value);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*get rx cap*/
+static int ft5402_get_rx_cap(struct i2c_client * client, u8 rxNO, u8 *pCap)
+{
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client, FT5402_REG_RX_CAP_START + rxNO,
+ pCap);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if(ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1,
+ pCap);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*set rx offset*/
+static int ft5402_set_rx_offset(struct i2c_client * client, u8 rxNO, u8 offset_value)
+{
+ unsigned char temp=0;
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp);
+ if (ReCode >= 0) {
+ if (rxNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1),
+ (temp&0xf0) + (offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1),
+ (temp&0x0f) + (offset_value<<4));
+ }
+ }
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_DEVICE_MODE+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ &temp); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ if (rxNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value<<4));
+ }
+ }
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*get rx offset*/
+static int ft5402_get_rx_offset(struct i2c_client * client, u8 rxNO, u8 *pOffset)
+{
+ unsigned char temp = 0;
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ &temp);
+
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ if (ReCode >= 0) {
+ if (0 == (rxNO%2))
+ *pOffset = (temp&0x0f);
+ else
+ *pOffset = (temp>>4);
+ }
+
+ return ReCode;
+}
+
+/*set tx num*/
+static int ft5402_set_tx_num(struct i2c_client *client, u8 txnum)
+{
+ return ft5402_write_reg(client, FT5402_REG_TX_NUM, txnum);
+}
+
+/*get tx num*/
+static int ft5402_get_tx_num(struct i2c_client *client, u8 *ptxnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_TX_NUM, ptxnum);
+}
+
+/*set rx num*/
+static int ft5402_set_rx_num(struct i2c_client *client, u8 rxnum)
+{
+ return ft5402_write_reg(client, FT5402_REG_RX_NUM, rxnum);
+}
+
+/*get rx num*/
+static int ft5402_get_rx_num(struct i2c_client *client, u8 *prxnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_RX_NUM, prxnum);
+}
+
+/*set resolution*/
+static int ft5402_set_Resolution(struct i2c_client *client, u16 x, u16 y)
+{
+ unsigned char cRet = 0;
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_X_H, ((unsigned char)(x>>8)));
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_X_L, ((unsigned char)(x&0x00ff)));
+
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_Y_H, ((unsigned char)(y>>8)));
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_Y_L, ((unsigned char)(y&0x00ff)));
+
+ return cRet;
+}
+
+/*get resolution*/
+static int ft5402_get_Resolution(struct i2c_client *client,
+ u16 *px, u16 *py)
+{
+ unsigned char cRet = 0, temp1 = 0, temp2 = 0;
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_X_H, &temp1);
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_X_L, &temp2);
+ (*px) = (((u16)temp1) << 8) | ((u16)temp2);
+
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_Y_H, &temp1);
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_Y_L, &temp2);
+ (*py) = (((u16)temp1) << 8) | ((u16)temp2);
+
+ return cRet;
+}
+
+
+/*set voltage*/
+static int ft5402_set_vol(struct i2c_client *client, u8 Vol)
+{
+ return ft5402_write_reg(client, FT5402_REG_VOLTAGE, Vol);
+}
+
+/*get voltage*/
+static int ft5402_get_vol(struct i2c_client *client, u8 *pVol)
+{
+ return ft5402_read_reg(client, FT5402_REG_VOLTAGE, pVol);
+}
+
+/*set gain*/
+static int ft5402_set_gain(struct i2c_client *client, u8 Gain)
+{
+ return ft5402_write_reg(client, FT5402_REG_GAIN, Gain);
+}
+
+/*get gain*/
+static int ft5402_get_gain(struct i2c_client *client, u8 *pGain)
+{
+ return ft5402_read_reg(client, FT5402_REG_GAIN, pGain);
+}
+
+/*get start rx*/
+static int ft5402_get_start_rx(struct i2c_client *client, u8 *pRx)
+{
+ return ft5402_read_reg(client, FT5402_REG_START_RX, pRx);
+}
+
+
+/*get adc target*/
+static int ft5402_get_adc_target(struct i2c_client *client, u16 *pvalue)
+{
+ int err = 0;
+ u8 tmp1, tmp2;
+ err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_HIGH,
+ &tmp1);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get adc target high failed\n",
+ __func__);
+ err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_LOW,
+ &tmp2);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get adc target low failed\n",
+ __func__);
+
+ *pvalue = ((u16)tmp1<<8) + (u16)tmp2;
+ return err;
+}
+
+static int ft5402_set_face_detect_statistics_tx_num(struct i2c_client *client, u8 prevalue)
+{
+ return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM,
+ prevalue);
+}
+
+static int ft5402_get_face_detect_statistics_tx_num(struct i2c_client *client, u8 *pprevalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM,
+ pprevalue);
+}
+
+static int ft5402_set_face_detect_pre_value(struct i2c_client *client, u8 prevalue)
+{
+ return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE,
+ prevalue);
+}
+
+static int ft5402_get_face_detect_pre_value(struct i2c_client *client, u8 *pprevalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE,
+ pprevalue);
+}
+
+static int ft5402_set_face_detect_num(struct i2c_client *client, u8 num)
+{
+ return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_NUM,
+ num);
+}
+
+static int ft5402_get_face_detect_num(struct i2c_client *client, u8 *pnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_NUM,
+ pnum);
+}
+
+
+static int ft5402_set_peak_value_min(struct i2c_client *client, u8 min)
+{
+ return ft5402_write_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN,
+ min);
+}
+
+static int ft5402_get_peak_value_min(struct i2c_client *client, u8 *pmin)
+{
+ return ft5402_read_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN,
+ pmin);
+}
+
+static int ft5402_set_diff_value_over_num(struct i2c_client *client, u8 num)
+{
+ return ft5402_write_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM,
+ num);
+}
+static int ft5402_get_diff_value_over_num(struct i2c_client *client, u8 *pnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM,
+ pnum);
+}
+
+
+static int ft5402_set_customer_id(struct i2c_client *client, u8 num)
+{
+ return ft5402_write_reg(client, FT5402_REG_CUSTOMER_ID,
+ num);
+}
+static int ft5402_get_customer_id(struct i2c_client *client, u8 *pnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_CUSTOMER_ID,
+ pnum);
+}
+
+static int ft5402_set_kx(struct i2c_client *client, u16 value)
+{
+ int err = 0;
+ err = ft5402_write_reg(client, FT5402_REG_KX_H,
+ value >> 8);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set kx high failed\n",
+ __func__);
+ err = ft5402_write_reg(client, FT5402_REG_KX_L,
+ value);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set kx low failed\n",
+ __func__);
+
+ return err;
+}
+
+static int ft5402_get_kx(struct i2c_client *client, u16 *pvalue)
+{
+ int err = 0;
+ u8 tmp1, tmp2;
+ err = ft5402_read_reg(client, FT5402_REG_KX_H,
+ &tmp1);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get kx high failed\n",
+ __func__);
+ err = ft5402_read_reg(client, FT5402_REG_KX_L,
+ &tmp2);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get kx low failed\n",
+ __func__);
+
+ *pvalue = ((u16)tmp1<<8) + (u16)tmp2;
+ return err;
+}
+static int ft5402_set_ky(struct i2c_client *client, u16 value)
+{
+ int err = 0;
+ err = ft5402_write_reg(client, FT5402_REG_KY_H,
+ value >> 8);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set ky high failed\n",
+ __func__);
+ err = ft5402_write_reg(client, FT5402_REG_KY_L,
+ value);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set ky low failed\n",
+ __func__);
+
+ return err;
+}
+
+static int ft5402_get_ky(struct i2c_client *client, u16 *pvalue)
+{
+ int err = 0;
+ u8 tmp1, tmp2;
+ err = ft5402_read_reg(client, FT5402_REG_KY_H,
+ &tmp1);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get ky high failed\n",
+ __func__);
+ err = ft5402_read_reg(client, FT5402_REG_KY_L,
+ &tmp2);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get ky low failed\n",
+ __func__);
+
+ *pvalue = ((u16)tmp1<<8) + (u16)tmp2;
+ return err;
+}
+static int ft5402_set_lemda_x(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_LEMDA_X,
+ value);
+}
+
+static int ft5402_get_lemda_x(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_LEMDA_X,
+ pvalue);
+}
+static int ft5402_set_lemda_y(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_LEMDA_Y,
+ value);
+}
+
+static int ft5402_get_lemda_y(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_LEMDA_Y,
+ pvalue);
+}
+static int ft5402_set_pos_x(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_DIRECTION,
+ value);
+}
+
+static int ft5402_get_pos_x(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_DIRECTION,
+ pvalue);
+}
+
+static int ft5402_set_scan_select(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_SCAN_SELECT,
+ value);
+}
+
+static int ft5402_get_scan_select(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_SCAN_SELECT,
+ pvalue);
+}
+
+static int ft5402_set_other_param(struct i2c_client *client)
+{
+ int err = 0;
+ err = ft5402_write_reg(client, FT5402_REG_THGROUP, (u8)(g_param_ft5402.ft5402_THGROUP));
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_THPEAK, g_param_ft5402.ft5402_THPEAK);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THPEAK failed.\n",
+ __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_PWMODE_CTRL,
+ g_param_ft5402.ft5402_PWMODE_CTRL);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PERIOD_CTRL failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_PERIOD_ACTIVE,
+ g_param_ft5402.ft5402_PERIOD_ACTIVE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM,
+ g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FACE_DETECT_STATISTICS_TX_NUM failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH,
+ g_param_ft5402.ft5402_MAX_TOUCH_VALUE>>8);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW,
+ g_param_ft5402.ft5402_MAX_TOUCH_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_MODE,
+ g_param_ft5402.ft5402_FACE_DETECT_MODE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_DRAW_LINE_TH,
+ g_param_ft5402.ft5402_DRAW_LINE_TH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_POINTS_SUPPORTED,
+ g_param_ft5402.ft5402_POINTS_SUPPORTED);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write POINTS_SUPPORTED failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_ESD_FILTER_FRAME,
+ g_param_ft5402.ft5402_ESD_FILTER_FRAME);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAME failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO,
+ g_param_ft5402.ft5402_POINTS_STABLE_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_POINTS_STABLE_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_X,
+ g_param_ft5402.ft5402_MIN_DELTA_X);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_X failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y,
+ g_param_ft5402.ft5402_MIN_DELTA_Y);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_Y failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP,
+ g_param_ft5402.ft5402_MIN_DELTA_STEP);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_STEP failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO,
+ g_param_ft5402.ft5402_ESD_NOISE_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_NOISE_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL,
+ g_param_ft5402.ft5402_ESD_DIFF_VAL);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_DIFF_VAL failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE,
+ g_param_ft5402.ft5402_ESD_NEGTIVE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_NEGTIVE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES,
+ g_param_ft5402.ft5402_ESD_FILTER_FRAMES);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAMES failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT,
+ g_param_ft5402.ft5402_IO_LEVEL_SELECT);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_IO_LEVEL_SELECT failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT,
+ g_param_ft5402.ft5402_POINTID_DELAY_COUNT);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_POINTID_DELAY_COUNT failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO,
+ g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_LIFTUP_FILTER_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO,
+ g_param_ft5402.ft5402_DIFF_HANDLE_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_DIFF_HANDLE_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_WATER,
+ g_param_ft5402.ft5402_MIN_WATER);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_WATER failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MAX_NOISE,
+ g_param_ft5402.ft5402_MAX_NOISE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MAX_NOISE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_RX,
+ g_param_ft5402.ft5402_WATER_START_RX);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_WATER_START_RX failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_TX,
+ g_param_ft5402.ft5402_WATER_START_TX);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_WATER_START_TX failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO,
+ g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_RAISE_THGROUP,
+ g_param_ft5402.ft5402_RAISE_THGROUP);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_RAISE_THGROUP failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_CHARGER_STATE,
+ g_param_ft5402.ft5402_CHARGER_STATE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_CHARGER_STATE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FILTERID_START,
+ g_param_ft5402.ft5402_FILTERID_START);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FILTERID_START failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO,
+ g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_EN_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH,
+ g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH,
+ g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN,
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_EN failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH,
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__);
+ return err;
+ }
+
+ return err;
+}
+
+static int ft5402_get_other_param(struct i2c_client *client)
+{
+ int err = 0;
+ u8 value = 0x00;
+ err = ft5402_read_reg(client, FT5402_REG_THGROUP, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__);
+ return err;
+ } else
+ DBG("THGROUP=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_THPEAK, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THPEAK failed.\n",
+ __func__);
+ return err;
+ } else
+ DBG("THPEAK=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_PWMODE_CTRL, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PWMODE_CTRL failed.\n", __func__);
+ return err;
+ } else
+ DBG("CTRL=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_PERIOD_ACTIVE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__);
+ return err;
+ } else
+ DBG("PERIOD_ACTIVE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__);
+ return err;
+ } else
+ DBG("MAX_TOUCH_VALUE_HIGH=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__);
+ return err;
+ } else
+ DBG("MAX_TOUCH_VALUE_LOW=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_FACE_DETECT_MODE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FACE_DEC_MODE=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_DRAW_LINE_TH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__);
+ return err;
+ } else
+ DBG("DRAW_LINE_TH=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_POINTS_SUPPORTED,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_POINTS_SUPPORTED failed.\n", __func__);
+ return err;
+ } else
+ DBG("ft5402_POINTS_SUPPORTED=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_ESD_FILTER_FRAME,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_ESD_FILTER_FRAME failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_ESD_FILTER_FRAME=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTS_STABLE_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_POINTS_STABLE_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_X,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_X failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_DELTA_X=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_Y failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_DELTA_Y=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_STEP failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_DELTA_STEP=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NOISE_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_NOISE_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_DIFF_VAL failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_DIFF_VAL=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NEGTIVE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_NEGTIVE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_FILTER_FRAMES failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_FILTER_FRAMES=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_IO_LEVEL_SELECT failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_IO_LEVEL_SELECT=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTID_DELAY_COUNT failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_POINTID_DELAY_COUNT=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_LIFTUP_FILTER_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_LIFTUP_FILTER_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_DIFF_HANDLE_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_DIFF_HANDLE_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_WATER,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_WATER failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_WATER=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MAX_NOISE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MAX_NOISE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MAX_NOISE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_RX,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_RX failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_WATER_START_RX=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_TX,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_TX failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_WATER_START_TX=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_RAISE_THGROUP,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_RAISE_THGROUP failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_RAISE_THGROUP=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_CHARGER_STATE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_CHARGER_STATE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_CHARGER_STATE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FILTERID_START,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FILTERID_START failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FILTERID_START=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_EN failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_EN=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH=%02x\n", value);
+
+ return err;
+}
+int ft5402_get_ic_param(struct i2c_client *client)
+{
+ int err = 0;
+ int i = 0;
+ u8 value = 0x00;
+ u16 xvalue = 0x0000, yvalue = 0x0000;
+
+ /*enter factory mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__);
+ goto RETURN_WORK;
+ }
+
+ for (i = 0; i < g_ft5402_tx_num; i++) {
+ DBG("tx%d:", i);
+ /*get tx order*/
+ err = ft5402_get_tx_order(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("order=%d ", value);
+ /*get tx cap*/
+ err = ft5402_get_tx_cap(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("cap=%02x\n", value);
+ }
+ /*get tx offset*/
+ err = ft5402_get_tx_offset(client, 0, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx 0 offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("tx offset = %02x\n", value);
+
+ /*get rx offset and cap*/
+ for (i = 0; i < g_ft5402_rx_num; i++) {
+ /*get rx order*/
+ DBG("rx%d:", i);
+ err = ft5402_get_rx_order(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("order=%d ", value);
+ /*get rx cap*/
+ err = ft5402_get_rx_cap(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("cap=%02x ", value);
+ err = ft5402_get_rx_offset(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ DBG("offset=%02x\n", value);
+ }
+
+ /*get scan select*/
+ err = ft5402_get_scan_select(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get scan select.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("scan select = %02x\n", value);
+
+ /*get tx number*/
+ err = ft5402_get_tx_num(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("tx num = %02x\n", value);
+ /*get rx number*/
+ err = ft5402_get_rx_num(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("rx num = %02x\n", value);
+
+ /*get gain*/
+ err = ft5402_get_gain(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get gain.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("gain = %02x\n", value);
+ /*get voltage*/
+ err = ft5402_get_vol(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get voltage.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("voltage = %02x\n", value);
+ /*get start rx*/
+ err = ft5402_get_start_rx(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get start rx.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("start rx = %02x\n", value);
+ /*get adc target*/
+ err = ft5402_get_adc_target(client, &xvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get adc target.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("ADC target = %02x\n", xvalue);
+
+
+RETURN_WORK:
+ /*enter work mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter work mode failed.\n", __func__);
+ goto ERR_EXIT;
+ }
+
+ /*get resolution*/
+ err = ft5402_get_Resolution(client, &xvalue, &yvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get resolution.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("resolution X = %d Y = %d\n", xvalue, yvalue);
+
+
+ /*get face detect statistics tx num*/
+ err = ft5402_get_face_detect_statistics_tx_num(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not get face detect statistics tx num.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_FACE_DETECT_STATISTICS_TX_NUM = %02x\n", value);
+ /*get face detect pre value*/
+ err = ft5402_get_face_detect_pre_value(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not get face detect pre value.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_FACE_DETECT_PRE_VALUE = %02x\n", value);
+ /*get face detect num*/
+ err = ft5402_get_face_detect_num(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get face detect num.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("face detect num = %02x\n", value);
+
+ /*get min peak value*/
+ err = ft5402_get_peak_value_min(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get min peak value.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_BIGAREA_PEAK_VALUE_MIN = %02x\n", value);
+ /*get diff value over num*/
+ err = ft5402_get_diff_value_over_num(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get diff value over num.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_BIGAREA_DIFF_VALUE_OVER_NUM = %02x\n", value);
+ /*get customer id*/
+ err = ft5402_get_customer_id(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get customer id.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_CUSTOMER_ID = %02x\n", value);
+ /*get kx*/
+ err = ft5402_get_kx(client, &xvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get kx.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("kx = %02x\n", xvalue);
+ /*get ky*/
+ err = ft5402_get_ky(client, &xvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get ky.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("ky = %02x\n", xvalue);
+ /*get lemda x*/
+ err = ft5402_get_lemda_x(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get lemda x.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("lemda x = %02x\n", value);
+ /*get lemda y*/
+ err = ft5402_get_lemda_y(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get lemda y.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("lemda y = %02x\n", value);
+ /*get pos x*/
+ err = ft5402_get_pos_x(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get pos x.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("pos x = %02x\n", value);
+
+ err = ft5402_get_other_param(client);
+
+ERR_EXIT:
+ return err;
+}
+
+int ft5402_Init_IC_Param(struct i2c_client *client)
+{
+ int err = 0;
+ int i = 0;
+
+ /*enter factory mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__);
+ goto RETURN_WORK;
+ }
+
+ for (i = 0; i < g_ft5402_tx_num; i++) {
+ if (g_ft5402_tx_order[i] != 0xFF) {
+ /*set tx order*/
+ err = ft5402_set_tx_order(client, i, g_ft5402_tx_order[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ }
+ /*set tx cap*/
+ err = ft5402_set_tx_cap(client, i, g_ft5402_tx_cap[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ }
+ /*set tx offset*/
+ err = ft5402_set_tx_offset(client, 0, g_ft5402_tx_offset);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx 0 offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ /*set rx offset and cap*/
+ for (i = 0; i < g_ft5402_rx_num; i++) {
+ /*set rx order*/
+ err = ft5402_set_rx_order(client, i, g_ft5402_rx_order[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ /*set rx cap*/
+ err = ft5402_set_rx_cap(client, i, g_ft5402_rx_cap[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ }
+ for (i = 0; i < g_ft5402_rx_num/2; i++) {
+ err = ft5402_set_rx_offset(client, i*2, g_ft5402_rx_offset[i]>>4);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ err = ft5402_set_rx_offset(client, i*2+1, g_ft5402_rx_offset[i]&0x0F);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ }
+
+ /*set scan select*/
+ err = ft5402_set_scan_select(client, g_ft5402_scanselect);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set scan select.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ /*set tx number*/
+ err = ft5402_set_tx_num(client, g_ft5402_tx_num);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ /*set rx number*/
+ err = ft5402_set_rx_num(client, g_ft5402_rx_num);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ /*set gain*/
+ err = ft5402_set_gain(client, g_ft5402_gain);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set gain.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ /*set voltage*/
+ err = ft5402_set_vol(client, g_ft5402_voltage);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set voltage.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_HIGH,
+ g_param_ft5402.ft5402_ADC_TARGET>>8);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ADC_TARGET_HIGH failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_LOW,
+ g_param_ft5402.ft5402_ADC_TARGET);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ADC_TARGET_LOW failed.\n", __func__);
+ return err;
+ }
+
+RETURN_WORK:
+ /*enter work mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter work mode failed.\n", __func__);
+ goto ERR_EXIT;
+ }
+
+ /*set resolution*/
+ err = ft5402_set_Resolution(client, g_param_ft5402.ft5402_RESOLUTION_X,
+ g_param_ft5402.ft5402_RESOLUTION_Y);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set resolution.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+
+ /*set face detect statistics tx num*/
+ err = ft5402_set_face_detect_statistics_tx_num(client,
+ g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not set face detect statistics tx num.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set face detect pre value*/
+ err = ft5402_set_face_detect_pre_value(client,
+ g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not set face detect pre value.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set face detect num*/
+ err = ft5402_set_face_detect_num(client,
+ g_param_ft5402.ft5402_FACE_DETECT_NUM);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set face detect num.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+
+ /*set min peak value*/
+ err = ft5402_set_peak_value_min(client,
+ g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set min peak value.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set diff value over num*/
+ err = ft5402_set_diff_value_over_num(client,
+ g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set diff value over num.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set customer id*/
+ err = ft5402_set_customer_id(client,
+ g_param_ft5402.ft5402_CUSTOMER_ID);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set customer id.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set kx*/
+ err = ft5402_set_kx(client, g_param_ft5402.ft5402_KX);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set kx.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set ky*/
+ err = ft5402_set_ky(client, g_param_ft5402.ft5402_KY);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set ky.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set lemda x*/
+ err = ft5402_set_lemda_x(client,
+ g_param_ft5402.ft5402_LEMDA_X);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set lemda x.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set lemda y*/
+ err = ft5402_set_lemda_y(client,
+ g_param_ft5402.ft5402_LEMDA_Y);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set lemda y.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set pos x*/
+ err = ft5402_set_pos_x(client, g_param_ft5402.ft5402_DIRECTION);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set pos x.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+
+ err = ft5402_set_other_param(client);
+
+ERR_EXIT:
+ return err;
+}
+
+
+char dst[512];
+static char * ft5402_sub_str(char * src, int n)
+{
+ char *p = src;
+ int i;
+ int m = 0;
+ int len = strlen(src);
+
+ while (n >= 1 && m <= len) {
+ i = 0;
+ dst[10] = ' ';
+ n--;
+ while ( *p != ',' && *p != ' ') {
+ dst[i++] = *(p++);
+ m++;
+ if (i >= len)
+ break;
+ }
+ dst[i++] = '\0';
+ p++;
+ }
+ return dst;
+}
+static int ft5402_GetInISize(char *config_name)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize = 0;
+ char filepath[128];
+ memset(filepath, 0, sizeof(filepath));
+
+ sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name);
+
+ if (NULL == pfile)
+ pfile = filp_open(filepath, O_RDONLY, 0);
+
+ if (IS_ERR(pfile)) {
+ pr_err("error occured while opening file %s.\n", filepath);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ filp_close(pfile, NULL);
+ return fsize;
+}
+
+static int ft5x0x_ReadInIData(char *config_name,
+ char *config_buf)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize;
+ char filepath[128];
+ loff_t pos;
+ mm_segment_t old_fs;
+
+ memset(filepath, 0, sizeof(filepath));
+ sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name);
+ if (NULL == pfile)
+ pfile = filp_open(filepath, O_RDONLY, 0);
+ if (IS_ERR(pfile)) {
+ pr_err("error occured while opening file %s.\n", filepath);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ pos = 0;
+ vfs_read(pfile, config_buf, fsize, &pos);
+ filp_close(pfile, NULL);
+ set_fs(old_fs);
+
+ return 0;
+}
+
+int ft5402_Get_Param_From_Ini(char *config_name)
+{
+ char key[64];
+ char value[512];
+ char section[64];
+ int i = 0;//,ret=0;
+ int j = 0;
+ char *filedata = NULL;
+ unsigned char legal_byte1 = 0x00;
+ unsigned char legal_byte2 = 0x00;
+
+ int inisize = ft5402_GetInISize(config_name);
+
+ if (inisize <= 0) {
+ pr_err("%s ERROR:Get firmware size failed\n",
+ __func__);
+ return -EIO;
+ }
+
+ filedata = kmalloc(inisize + 1, GFP_ATOMIC);
+
+ if (ft5x0x_ReadInIData(config_name, filedata)) {
+ pr_err("%s() - ERROR: request_firmware failed\n",
+ __func__);
+ kfree(filedata);
+ return -EIO;
+ }
+
+ /*check ini if it is illegal*/
+ sprintf(section, "%s", FT5402_APP_LEGAL);
+ sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_1_STR);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ legal_byte1 = atoi(value);
+ DBG("legal_byte1=%s\n", value);
+ sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_2_STR);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ legal_byte2 = atoi(value);
+ DBG("lega2_byte1=%s\n", value);
+ if(FT5402_APP_LEGAL_BYTE_1_VALUE == legal_byte1 &&
+ FT5402_APP_LEGAL_BYTE_2_VALUE == legal_byte2)
+ DBG("the ini file is valid\n");
+ else {
+ pr_err("[FTS]-----the ini file is invalid!please check it.\n");
+ goto ERROR_RETURN;
+ }
+
+ /*get ini param*/
+ sprintf(section, "%s", FT5402_APP_NAME);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_KX = atoi(value);
+ DBG("ft5402_KX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_KY = atoi(value);
+ DBG("ft5402_KY=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_LEMDA_X = atoi(value);
+ DBG("ft5402_LEMDA_X=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_LEMDA_Y = atoi(value);
+ DBG("ft5402_LEMDA_Y=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_RESOLUTION_X = atoi(value);
+ DBG("ft5402_RESOLUTION_X=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_RESOLUTION_Y = atoi(value);
+ DBG("ft5402_RESOLUTION_Y=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_DIRECTION= atoi(value);
+ DBG("ft5402_DIRECTION=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE = atoi(value);
+ DBG("ft5402_FACE_DETECT_PRE_VALUE=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_NUM = atoi(value);
+ DBG("ft5402_FACE_DETECT_NUM=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN = atoi(value);/*The min value to be decided as the big point*/
+ DBG("ft5402_BIGAREA_PEAK_VALUE_MIN=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM = atoi(value);/*The min big points of the big area*/
+ DBG("ft5402_BIGAREA_DIFF_VALUE_OVER_NUM=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_CUSTOMER_ID = atoi(value);
+ DBG("ft5402_CUSTOM_ID=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_PERIOD_ACTIVE = atoi(value);
+ DBG("ft5402_PERIOD_ACTIVE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM = atoi(value);
+ DBG("ft5402_FACE_DETECT_STATISTICS_TX_NUM=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_THGROUP = atoi(value);
+ DBG("ft5402_THGROUP=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_THPEAK = atoi(value);
+ DBG("ft5402_THPEAK=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_MODE = atoi(value);
+ DBG("ft5402_FACE_DETECT_MODE=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MAX_TOUCH_VALUE = atoi(value);
+ DBG("ft5402_MAX_TOUCH_VALUE=%s\n", value);
+
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_PWMODE_CTRL= atoi(value);
+ DBG("ft5402_PWMODE_CTRL=%s\n", value);
+
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+
+ i++;
+ g_param_ft5402.ft5402_DRAW_LINE_TH = atoi(value);
+ DBG("ft5402_DRAW_LINE_TH=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_POINTS_SUPPORTED= atoi(value);
+ DBG("ft5402_POINTS_SUPPORTED=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_START_RX = atoi(value);
+ DBG("ft5402_START_RX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+
+ g_param_ft5402.ft5402_ADC_TARGET = atoi(value);
+ DBG("ft5402_ADC_TARGET=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+
+ g_param_ft5402.ft5402_ESD_FILTER_FRAME = atoi(value);
+ DBG("ft5402_ESD_FILTER_FRAME=%s\n", value);
+
+/*********************************************************************/
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_tx_num = atoi(value);
+ DBG("ft5402_tx_num=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_rx_num = atoi(value);
+ DBG("ft5402_rx_num=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_gain = atoi(value);
+ DBG("ft5402_gain=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_voltage = atoi(value);
+ DBG("ft5402_voltage=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_scanselect = atoi(value);
+ DBG("ft5402_scanselect=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_tx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_tx_order[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_tx_order=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_tx_offset = atoi(value);
+ DBG("ft5402_tx_offset=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_tx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_tx_cap[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_tx_cap=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_rx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_rx_order[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_rx_order=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_rx_num/2; j++)
+ {
+ char * psrc = value;
+ g_ft5402_rx_offset[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_rx_offset=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_rx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_rx_cap[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_rx_cap=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_POINTS_STABLE_MACRO = atoi(value);
+ DBG("ft5402_POINTS_STABLE_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_DELTA_X = atoi(value);
+ DBG("ft5402_MIN_DELTA_X=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_DELTA_Y = atoi(value);
+ DBG("ft5402_MIN_DELTA_Y=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_DELTA_STEP = atoi(value);
+ DBG("ft5402_MIN_DELTA_STEP=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_NOISE_MACRO = atoi(value);
+ DBG("ft5402_ESD_NOISE_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_DIFF_VAL = atoi(value);
+ DBG("ft5402_ESD_DIFF_VAL=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_NEGTIVE = atoi(value);
+ DBG("ft5402_ESD_NEGTIVE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_FILTER_FRAMES = atoi(value);
+ DBG("ft5402_ESD_FILTER_FRAMES=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_IO_LEVEL_SELECT = atoi(value);
+ DBG("ft5402_IO_LEVEL_SELECT=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_POINTID_DELAY_COUNT = atoi(value);
+ DBG("ft5402_POINTID_DELAY_COUNT=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO = atoi(value);
+ DBG("ft5402_LIFTUP_FILTER_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_DIFF_HANDLE_MACRO = atoi(value);
+ DBG("ft5402_DIFF_HANDLE_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_WATER = atoi(value);
+ DBG("ft5402_MIN_WATER=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MAX_NOISE = atoi(value);
+ DBG("ft5402_MAX_NOISE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_WATER_START_RX = atoi(value);
+ DBG("ft5402_WATER_START_RX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_WATER_START_TX = atoi(value);
+ DBG("ft5402_WATER_START_TX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO = atoi(value);
+ DBG("ft5402_HOST_NUMBER_SUPPORTED_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_RAISE_THGROUP = atoi(value);
+ DBG("ft5402_RAISE_THGROUP=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_CHARGER_STATE = atoi(value);
+ DBG("ft5402_CHARGER_STATE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FILTERID_START = atoi(value);
+ DBG("ft5402_FILTERID_START=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO = atoi(value);
+ DBG("ft5402_FRAME_FILTER_EN_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH = atoi(value);
+ DBG("ft5402_FRAME_FILTER_SUB_MAX_TH=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH = atoi(value);
+ DBG("ft5402_FRAME_FILTER_ADD_MAX_TH=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME = atoi(value);
+ DBG("ft5402_FRAME_FILTER_SKIP_START_FRAME=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN = atoi(value);
+ DBG("ft5402_FRAME_FILTER_BAND_EN=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH = atoi(value);
+ DBG("ft5402_FRAME_FILTER_BAND_WIDTH=%s\n", value);
+
+
+ if (filedata)
+ kfree(filedata);
+ return 0;
+ERROR_RETURN:
+ if (filedata)
+ kfree(filedata);
+ return -1;
+}
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h new file mode 100755 index 00000000..b0c63889 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_config.h @@ -0,0 +1,71 @@ +#ifndef __FT5402_CONFIG_H__
+#define __FT5402_CONFIG_H__
+/*FT5402 config*/
+
+
+#define FT5402_START_RX 0
+#define FT5402_ADC_TARGET 8500
+#define FT5402_KX 120
+#define FT5402_KY 120
+#define FT5402_RESOLUTION_X 480
+#define FT5402_RESOLUTION_Y 800
+#define FT5402_LEMDA_X 0
+#define FT5402_LEMDA_Y 0
+#define FT5402_PWMODE_CTRL 1
+#define FT5402_POINTS_SUPPORTED 5
+#define FT5402_DRAW_LINE_TH 150
+#define FT5402_FACE_DETECT_MODE 0
+#define FT5402_FACE_DETECT_STATISTICS_TX_NUM 3
+#define FT5402_FACE_DETECT_PRE_VALUE 20
+#define FT5402_FACE_DETECT_NUM 10
+#define FT5402_THGROUP 25
+#define FT5402_THPEAK 60
+#define FT5402_BIGAREA_PEAK_VALUE_MIN 100
+#define FT5402_BIGAREA_DIFF_VALUE_OVER_NUM 50
+#define FT5402_MIN_DELTA_X 2
+#define FT5402_MIN_DELTA_Y 2
+#define FT5402_MIN_DELTA_STEP 2
+#define FT5402_ESD_DIFF_VAL 20
+#define FT5402_ESD_NEGTIVE -50
+#define FT5402_ESD_FILTER_FRAME 10
+#define FT5402_MAX_TOUCH_VALUE 600
+#define FT5402_CUSTOMER_ID 121
+#define FT5402_IO_LEVEL_SELECT 0
+#define FT5402_DIRECTION 1
+#define FT5402_POINTID_DELAY_COUNT 3
+#define FT5402_LIFTUP_FILTER_MACRO 1
+#define FT5402_POINTS_STABLE_MACRO 1
+#define FT5402_ESD_NOISE_MACRO 1
+#define FT5402_RV_G_PERIOD_ACTIVE 16
+#define FT5402_DIFFDATA_HANDLE 1
+#define FT5402_MIN_WATER_VAL -50
+#define FT5402_MAX_NOISE_VAL 10
+#define FT5402_WATER_HANDLE_START_RX 0
+#define FT5402_WATER_HANDLE_START_TX 0
+#define FT5402_HOST_NUMBER_SUPPORTED 1
+#define FT5402_RV_G_RAISE_THGROUP 30
+#define FT5402_RV_G_CHARGER_STATE 0
+#define FT5402_RV_G_FILTERID_START 2
+#define FT5402_FRAME_FILTER_EN 1
+#define FT5402_FRAME_FILTER_SUB_MAX_TH 2
+#define FT5402_FRAME_FILTER_ADD_MAX_TH 2
+#define FT5402_FRAME_FILTER_SKIP_START_FRAME 6
+#define FT5402_FRAME_FILTER_BAND_EN 1
+#define FT5402_FRAME_FILTER_BAND_WIDTH 128
+#define FT5402_OTP_PARAM_ID 0
+
+
+unsigned char g_ft5402_tx_num = 27;
+unsigned char g_ft5402_rx_num = 16;
+unsigned char g_ft5402_gain = 10;
+unsigned char g_ft5402_voltage = 3;
+unsigned char g_ft5402_scanselect = 12;
+unsigned char g_ft5402_tx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26};
+unsigned char g_ft5402_tx_offset = 2;
+unsigned char g_ft5402_tx_cap[] = {42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42};
+unsigned char g_ft5402_rx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+unsigned char g_ft5402_rx_offset[] = {68,68,68,68,68,68,68,68};
+unsigned char g_ft5402_rx_cap[] = {84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84};
+
+
+#endif
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h new file mode 100755 index 00000000..138f42e2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5402_ini_config.h @@ -0,0 +1,411 @@ +#ifndef __LINUX_FT5402_INI_CONFIG_H__
+#define __LINUX_FT5402_INI_CONFIG_H
+
+
+/*Init param register address*/
+/*factory mode register from 14-131*/
+#define FT5402_REG_TX_NUM 0x03
+#define FT5402_REG_RX_NUM 0x04
+#define FT5402_REG_VOLTAGE 0x05
+#define FT5402_REG_GAIN 0x07
+#define FT5402_REG_SCAN_SELECT 0x4E
+#define FT5402_REG_TX_ORDER_START 0x50
+#define FT5402_REG_TX_CAP_START 0x78
+#define FT5402_REG_TX_OFFSET_START 0xBF
+#define FT5402_REG_RX_ORDER_START 0xeb
+#define FT5402_REG_RX_CAP_START 0xA0
+#define FT5402_REG_RX_OFFSET_START 0xD3
+#define FT5402_REG_START_RX 0x06
+#define FT5402_REG_ADC_TARGET_HIGH 0x08
+#define FT5402_REG_ADC_TARGET_LOW 0x09
+
+
+#define FT5402_REG_DEVICE_MODE 0x00
+
+
+/*work mode register from 0-13(0,1,12,13verify or Reserved)and 132-177(159 Reserved)*/
+#define FT5402_REG_THGROUP (0x00+0x80)
+#define FT5402_REG_THPEAK (0x01+0x80)
+#define FT5402_REG_PWMODE_CTRL (0x06+0x80)
+#define FT5402_REG_PERIOD_ACTIVE (0x59+0x80)
+#define FT5402_REG_POINTS_SUPPORTED (0x0A+0x80)
+#define FT5402_REG_ESD_FILTER_FRAME (0x4F+0x80)
+
+#define FT5402_REG_RESOLUTION_X_H (0x18+0x80)
+#define FT5402_REG_RESOLUTION_X_L (0x19+0x80)
+#define FT5402_REG_RESOLUTION_Y_H (0x1a+0x80)
+#define FT5402_REG_RESOLUTION_Y_L (0x1b+0x80)
+#define FT5402_REG_KX_H (0x1c+0x80)
+#define FT5402_REG_KX_L (0x9d)
+#define FT5402_REG_KY_H (0x9e)
+#define FT5402_REG_KY_L (0x1f+0x80)
+#define FT5402_REG_CUSTOMER_ID (0xA8)
+#define FT5402_REG_DRAW_LINE_TH (0xAe)
+#define FT5402_REG_FACE_DETECT_MODE (0xB0)
+#define FT5402_REG_MAX_TOUCH_VALUE_HIGH (0xD0)
+#define FT5402_REG_MAX_TOUCH_VALUE_LOW (0xD1)
+
+#define FT5402_REG_DIRECTION (0x53+0x80)
+#define FT5402_REG_LEMDA_X (0x41+0x80)
+#define FT5402_REG_LEMDA_Y (0x42+0x80)
+#define FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM (0x43+0x80)
+#define FT5402_REG_FACE_DETECT_PRE_VALUE (0x44+0x80)
+#define FT5402_REG_FACE_DETECT_NUM (0x45+0x80)
+#define FT5402_REG_BIGAREA_PEAK_VALUE_MIN (0x33+0x80)
+#define FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM (0x34+0x80)
+
+/**************************************************************************/
+#define FT5402_REG_FT5402_POINTS_STABLE_MACRO (0x57+0x80)
+#define FT5402_REG_FT5402_MIN_DELTA_X (0x4a+0x80)
+#define FT5402_REG_FT5402_MIN_DELTA_Y (0x4b+0x80)
+#define FT5402_REG_FT5402_MIN_DELTA_STEP (0x4c+0x80)
+
+#define FT5402_REG_FT5402_ESD_NOISE_MACRO (0x58+0x80)
+#define FT5402_REG_FT5402_ESD_DIFF_VAL (0x4d+0x80)
+#define FT5402_REG_FT5402_ESD_NEGTIVE (0xCe)
+#define FT5402_REG_FT5402_ESD_FILTER_FRAMES (0x4f+0x80)
+
+#define FT5402_REG_FT5402_IO_LEVEL_SELECT (0x52+0x80)
+
+#define FT5402_REG_FT5402_POINTID_DELAY_COUNT (0x54+0x80)
+
+#define FT5402_REG_FT5402_LIFTUP_FILTER_MACRO (0x55+0x80)
+
+#define FT5402_REG_FT5402_DIFF_HANDLE_MACRO (0x5A+0x80)
+#define FT5402_REG_FT5402_MIN_WATER (0x5B+0x80)
+#define FT5402_REG_FT5402_MAX_NOISE (0x5C+0x80)
+#define FT5402_REG_FT5402_WATER_START_RX (0x5D+0x80)
+#define FT5402_REG_FT5402_WATER_START_TX (0xDE)
+
+#define FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO (0x38+0x80)
+#define FT5402_REG_FT5402_RAISE_THGROUP (0x36+0x80)
+#define FT5402_REG_FT5402_CHARGER_STATE (0x35+0x80)
+
+#define FT5402_REG_FT5402_FILTERID_START (0x37+0x80)
+
+#define FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO (0x5F+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH (0x60+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH (0x61+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME (0x62+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_BAND_EN (0x63+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH (0x64+0x80)
+/**************************************************************************/
+
+#define FT5402_REG_TEST_MODE 0x04
+#define FT5402_REG_TEST_MODE_2 0x05
+#define FT5402_TX_TEST_MODE_1 0x28
+#define FT5402_RX_TEST_MODE_1 0x1E
+#define FT5402_FACTORYMODE_VALUE 0x40
+#define FT5402_WORKMODE_VALUE 0x00
+
+/************************************************************************/
+/* string */
+/************************************************************************/
+#define STRING_FT5402_KX "FT5X02_KX"
+#define STRING_FT5402_KY "FT5X02_KY"
+#define STRING_FT5402_LEMDA_X "FT5X02_LEMDA_X"
+#define STRING_FT5402_LEMDA_Y "FT5X02_LEMDA_Y"
+#define STRING_FT5402_RESOLUTION_X "FT5X02_RESOLUTION_X"
+#define STRING_FT5402_RESOLUTION_Y "FT5X02_RESOLUTION_Y"
+#define STRING_FT5402_DIRECTION "FT5X02_DIRECTION"
+
+
+
+#define STRING_FT5402_FACE_DETECT_PRE_VALUE "FT5X02_FACE_DETECT_PRE_VALUE"
+#define STRING_FT5402_FACE_DETECT_NUM "FT5X02_FACE_DETECT_NUM"
+#define STRING_FT5402_BIGAREA_PEAK_VALUE_MIN "FT5X02_BIGAREA_PEAK_VALUE_MIN"
+#define STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM "FT5X02_BIGAREA_DIFF_VALUE_OVER_NUM"
+#define STRING_FT5402_CUSTOMER_ID "FT5X02_CUSTOMER_ID"
+#define STRING_FT5402_PERIOD_ACTIVE "FT5X02_RV_G_PERIOD_ACTIVE"
+#define STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM "FT5X02_FACE_DETECT_STATISTICS_TX_NUM"
+
+#define STRING_FT5402_THGROUP "FT5X02_THGROUP"
+#define STRING_FT5402_THPEAK "FT5X02_THPEAK"
+#define STRING_FT5402_FACE_DETECT_MODE "FT5X02_FACE_DETECT_MODE"
+#define STRING_FT5402_MAX_TOUCH_VALUE "FT5X02_MAX_TOUCH_VALUE"
+
+#define STRING_FT5402_PWMODE_CTRL "FT5X02_PWMODE_CTRL"
+#define STRING_FT5402_DRAW_LINE_TH "FT5X02_DRAW_LINE_TH"
+
+#define STRING_FT5402_POINTS_SUPPORTED "FT5X02_POINTS_SUPPORTED"
+
+#define STRING_FT5402_START_RX "FT5X02_START_RX"
+#define STRING_FT5402_ADC_TARGET "FT5X02_ADC_TARGET"
+#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME"
+
+#define STRING_FT5402_POINTS_STABLE_MACRO "FT5X02_POINTS_STABLE_MACRO"
+#define STRING_FT5402_MIN_DELTA_X "FT5X02_MIN_DELTA_X"
+#define STRING_FT5402_MIN_DELTA_Y "FT5X02_MIN_DELTA_Y"
+#define STRING_FT5402_MIN_DELTA_STEP "FT5X02_MIN_DELTA_STEP"
+
+#define STRING_FT5402_ESD_NOISE_MACRO "FT5X02_ESD_NOISE_MACRO"
+#define STRING_FT5402_ESD_DIFF_VAL "FT5X02_ESD_DIFF_VAL"
+#define STRING_FT5402_ESD_NEGTIVE "FT5X02_ESD_NEGTIVE"
+#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME"
+
+#define STRING_FT5402_IO_LEVEL_SELECT "FT5X02_IO_LEVEL_SELECT"
+#define STRING_FT5402_POINTID_DELAY_COUNT "FT5X02_POINTID_DELAY_COUNT"
+
+#define STRING_FT5402_LIFTUP_FILTER_MACRO "FT5X02_LIFTUP_FILTER_MACRO"
+
+#define STRING_FT5402_DIFFDATA_HANDLE "FT5X02_DIFFDATA_HANDLE" //_MACRO
+#define STRING_FT5402_MIN_WATER_VAL "FT5X02_MIN_WATER_VAL"
+#define STRING_FT5402_MAX_NOISE_VAL "FT5X02_MAX_NOISE_VAL"
+#define STRING_FT5402_WATER_HANDLE_START_RX "FT5X02_WATER_HANDLE_START_RX"
+#define STRING_FT5402_WATER_HANDLE_START_TX "FT5X02_WATER_HANDLE_START_TX"
+
+#define STRING_FT5402_HOST_NUMBER_SUPPORTED "FT5X02_HOST_NUMBER_SUPPORTED"
+#define STRING_FT5402_RV_G_RAISE_THGROUP "FT5X02_RV_G_RAISE_THGROUP"
+#define STRING_FT5402_RV_G_CHARGER_STATE "FT5X02_RV_G_CHARGER_STATE"
+
+#define STRING_FT5402_RV_G_FILTERID_START "FT5X02_RV_G_FILTERID_START"
+
+#define STRING_FT5402_FRAME_FILTER_EN "FT5X02_FRAME_FILTER_EN"
+#define STRING_FT5402_FRAME_FILTER_SUB_MAX_TH "FT5X02_FRAME_FILTER_SUB_MAX_TH"
+#define STRING_FT5402_FRAME_FILTER_ADD_MAX_TH "FT5X02_FRAME_FILTER_ADD_MAX_TH"
+#define STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME "FT5X02_FRAME_FILTER_SKIP_START_FRAME"
+#define STRING_FT5402_FRAME_FILTER_BAND_EN "FT5X02_FRAME_FILTER_BAND_EN"
+#define STRING_FT5402_FRAME_FILTER_BAND_WIDTH "FT5X02_FRAME_FILTER_BAND_WIDTH"
+
+
+#define STRING_ft5402_tx_num "FT5X02_tx_num"
+#define STRING_ft5402_rx_num "FT5X02_rx_num"
+#define STRING_ft5402_gain "FT5X02_gain"
+#define STRING_ft5402_voltage "FT5X02_voltage"
+#define STRING_ft5402_scanselect "FT5X02_scanselect"
+
+#define STRING_ft5402_tx_order "FT5X02_tx_order"
+#define STRING_ft5402_tx_offset "FT5X02_tx_offset"
+#define STRING_ft5402_tx_cap "FT5X02_tx_cap"
+
+#define STRING_ft5402_rx_order "FT5X02_rx_order"
+#define STRING_ft5402_rx_offset "FT5X02_rx_offset"
+#define STRING_ft5402_rx_cap "FT5X02_rx_cap"
+
+struct Struct_Param_FT5402 {
+ short ft5402_KX;
+ short ft5402_KY;
+ unsigned char ft5402_LEMDA_X;
+ unsigned char ft5402_LEMDA_Y;
+ short ft5402_RESOLUTION_X;
+ short ft5402_RESOLUTION_Y;
+ unsigned char ft5402_DIRECTION;
+ unsigned char ft5402_FACE_DETECT_PRE_VALUE;
+ unsigned char ft5402_FACE_DETECT_NUM;
+
+ unsigned char ft5402_BIGAREA_PEAK_VALUE_MIN;
+ unsigned char ft5402_BIGAREA_DIFF_VALUE_OVER_NUM;
+ unsigned char ft5402_CUSTOMER_ID;
+ unsigned char ft5402_PERIOD_ACTIVE;
+ unsigned char ft5402_FACE_DETECT_STATISTICS_TX_NUM;
+
+ short ft5402_THGROUP;
+ unsigned char ft5402_THPEAK;
+ unsigned char ft5402_FACE_DETECT_MODE;
+ short ft5402_MAX_TOUCH_VALUE;
+
+ unsigned char ft5402_PWMODE_CTRL;
+ unsigned char ft5402_DRAW_LINE_TH;
+ unsigned char ft5402_POINTS_SUPPORTED;
+
+ unsigned char ft5402_START_RX;
+ short ft5402_ADC_TARGET;
+ unsigned char ft5402_ESD_FILTER_FRAME;
+
+ unsigned char ft5402_POINTS_STABLE_MACRO;
+ unsigned char ft5402_MIN_DELTA_X;
+ unsigned char ft5402_MIN_DELTA_Y;
+ unsigned char ft5402_MIN_DELTA_STEP;
+
+ unsigned char ft5402_ESD_NOISE_MACRO;
+ unsigned char ft5402_ESD_DIFF_VAL;
+ char ft5402_ESD_NEGTIVE; //negtive
+ unsigned char ft5402_ESD_FILTER_FRAMES;
+
+ unsigned char ft5402_IO_LEVEL_SELECT;
+
+ unsigned char ft5402_POINTID_DELAY_COUNT;
+
+ unsigned char ft5402_LIFTUP_FILTER_MACRO;
+
+ unsigned char ft5402_DIFF_HANDLE_MACRO;
+ char ft5402_MIN_WATER; //negtive
+ unsigned char ft5402_MAX_NOISE;
+ unsigned char ft5402_WATER_START_RX;
+ unsigned char ft5402_WATER_START_TX;
+
+ unsigned char ft5402_HOST_NUMBER_SUPPORTED_MACRO;
+ unsigned char ft5402_RAISE_THGROUP;
+ unsigned char ft5402_CHARGER_STATE;
+
+ unsigned char ft5402_FILTERID_START;
+
+ unsigned char ft5402_FRAME_FILTER_EN_MACRO;
+ unsigned char ft5402_FRAME_FILTER_SUB_MAX_TH;
+ unsigned char ft5402_FRAME_FILTER_ADD_MAX_TH;
+ unsigned char ft5402_FRAME_FILTER_SKIP_START_FRAME;
+ unsigned char ft5402_FRAME_FILTER_BAND_EN;
+ unsigned char ft5402_FRAME_FILTER_BAND_WIDTH;
+
+};
+
+struct Struct_Param_FT5402 g_param_ft5402 = {
+ FT5402_KX,
+ FT5402_KY,
+ FT5402_LEMDA_X,
+ FT5402_LEMDA_Y,
+ FT5402_RESOLUTION_X,
+ FT5402_RESOLUTION_Y,
+ FT5402_DIRECTION,
+
+ FT5402_FACE_DETECT_PRE_VALUE,
+ FT5402_FACE_DETECT_NUM,
+ FT5402_BIGAREA_PEAK_VALUE_MIN,
+ FT5402_BIGAREA_DIFF_VALUE_OVER_NUM,
+ FT5402_CUSTOMER_ID,
+ FT5402_RV_G_PERIOD_ACTIVE,
+ FT5402_FACE_DETECT_STATISTICS_TX_NUM,
+
+ FT5402_THGROUP,
+ FT5402_THPEAK,
+ FT5402_FACE_DETECT_MODE,
+ FT5402_MAX_TOUCH_VALUE,
+
+ FT5402_PWMODE_CTRL,
+ FT5402_DRAW_LINE_TH,
+ FT5402_POINTS_SUPPORTED,
+
+ FT5402_START_RX,
+ FT5402_ADC_TARGET,
+ FT5402_ESD_FILTER_FRAME,
+
+ FT5402_POINTS_STABLE_MACRO,
+ FT5402_MIN_DELTA_X,
+ FT5402_MIN_DELTA_Y,
+ FT5402_MIN_DELTA_STEP,
+
+ FT5402_ESD_NOISE_MACRO,
+ FT5402_ESD_DIFF_VAL,
+ FT5402_ESD_NEGTIVE,
+ FT5402_ESD_FILTER_FRAME,
+
+ FT5402_IO_LEVEL_SELECT,
+
+ FT5402_POINTID_DELAY_COUNT,
+
+ FT5402_LIFTUP_FILTER_MACRO,
+
+ FT5402_DIFFDATA_HANDLE,
+ FT5402_MIN_WATER_VAL,
+ FT5402_MAX_NOISE_VAL,
+ FT5402_WATER_HANDLE_START_RX,
+ FT5402_WATER_HANDLE_START_TX,
+
+ FT5402_HOST_NUMBER_SUPPORTED,
+ FT5402_RV_G_RAISE_THGROUP,
+ FT5402_RV_G_CHARGER_STATE,
+
+ FT5402_RV_G_FILTERID_START,
+
+ FT5402_FRAME_FILTER_EN,
+ FT5402_FRAME_FILTER_SUB_MAX_TH,
+ FT5402_FRAME_FILTER_ADD_MAX_TH,
+ FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ FT5402_FRAME_FILTER_BAND_EN,
+ FT5402_FRAME_FILTER_BAND_WIDTH,
+};
+
+char String_Param_FT5402[][64] = {
+ STRING_FT5402_KX,
+ STRING_FT5402_KY,
+ STRING_FT5402_LEMDA_X,
+ STRING_FT5402_LEMDA_Y,
+ STRING_FT5402_RESOLUTION_X,
+ STRING_FT5402_RESOLUTION_Y,
+ STRING_FT5402_DIRECTION,
+ STRING_FT5402_FACE_DETECT_PRE_VALUE,
+ STRING_FT5402_FACE_DETECT_NUM,
+ STRING_FT5402_BIGAREA_PEAK_VALUE_MIN,
+ STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM,
+ STRING_FT5402_CUSTOMER_ID,
+ STRING_FT5402_PERIOD_ACTIVE,
+ STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM,
+
+ STRING_FT5402_THGROUP,
+ STRING_FT5402_THPEAK,
+ STRING_FT5402_FACE_DETECT_MODE,
+ STRING_FT5402_MAX_TOUCH_VALUE,
+
+ STRING_FT5402_PWMODE_CTRL,
+ STRING_FT5402_DRAW_LINE_TH,
+ STRING_FT5402_POINTS_SUPPORTED,
+
+ STRING_FT5402_START_RX,
+ STRING_FT5402_ADC_TARGET,
+ STRING_FT5402_ESD_FILTER_FRAME,
+
+
+ STRING_ft5402_tx_num,
+ STRING_ft5402_rx_num,
+ STRING_ft5402_gain,
+ STRING_ft5402_voltage ,
+ STRING_ft5402_scanselect,
+
+ STRING_ft5402_tx_order,
+ STRING_ft5402_tx_offset,
+ STRING_ft5402_tx_cap,
+
+ STRING_ft5402_rx_order,
+ STRING_ft5402_rx_offset,
+ STRING_ft5402_rx_cap,
+
+ STRING_FT5402_POINTS_STABLE_MACRO,
+ STRING_FT5402_MIN_DELTA_X,
+ STRING_FT5402_MIN_DELTA_Y,
+ STRING_FT5402_MIN_DELTA_STEP,
+
+ STRING_FT5402_ESD_NOISE_MACRO,
+ STRING_FT5402_ESD_DIFF_VAL,
+ STRING_FT5402_ESD_NEGTIVE,
+ STRING_FT5402_ESD_FILTER_FRAME,
+
+ STRING_FT5402_IO_LEVEL_SELECT,
+
+ STRING_FT5402_POINTID_DELAY_COUNT,
+
+ STRING_FT5402_LIFTUP_FILTER_MACRO,
+
+ STRING_FT5402_DIFFDATA_HANDLE,
+ STRING_FT5402_MIN_WATER_VAL,
+ STRING_FT5402_MAX_NOISE_VAL,
+ STRING_FT5402_WATER_HANDLE_START_RX,
+ STRING_FT5402_WATER_HANDLE_START_TX,
+
+ STRING_FT5402_HOST_NUMBER_SUPPORTED,
+ STRING_FT5402_RV_G_RAISE_THGROUP,
+ STRING_FT5402_RV_G_CHARGER_STATE,
+
+ STRING_FT5402_RV_G_FILTERID_START,
+
+ STRING_FT5402_FRAME_FILTER_EN,
+ STRING_FT5402_FRAME_FILTER_SUB_MAX_TH,
+ STRING_FT5402_FRAME_FILTER_ADD_MAX_TH,
+ STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ STRING_FT5402_FRAME_FILTER_BAND_EN,
+ STRING_FT5402_FRAME_FILTER_BAND_WIDTH,
+
+};
+
+#define FT5402_APP_NAME "FT5X02_param"
+
+#define FT5402_APP_LEGAL "Legal_File"
+#define FT5402_APP_LEGAL_BYTE_1_STR "BYTE_1"
+#define FT5402_APP_LEGAL_BYTE_2_STR "BYTE_2"
+
+#define FT5402_APP_LEGAL_BYTE_1_VALUE 107
+#define FT5402_APP_LEGAL_BYTE_2_VALUE 201
+
+
+#define FT5402_INI_FILEPATH "/system/etc/firmware/"
+
+#endif
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c new file mode 100755 index 00000000..9bb63b83 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.c @@ -0,0 +1,937 @@ +/* + * drivers/input/touchscreen/ft5x0x/ft5x0x.c + * + * FocalTech ft5x0x TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * note: only support mulititouch Wenfs 2010-10-01 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/input.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/platform_device.h> +#include <linux/suspend.h> +#include <linux/wait.h> +#include <asm/uaccess.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <linux/slab.h> +#include "ft5x0x.h" +#include "../../../video/backlight/wmt_bl.h" + +struct ft5x0x_data *pContext=NULL; +static struct i2c_client *l_client=NULL; + +#ifdef TOUCH_KEY +static int keycodes[NUM_KEYS] ={ + KEY_MENU, + KEY_HOME, + KEY_BACK, + KEY_SEARCH +}; +#endif + +#define FT5402_CONFIG_NAME "fttpconfig_5402public.ini" +extern int ft5x0x_read_fw_ver(void); +extern int ft5x0x_auto_clb(void); +extern int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver); +extern int ft5402_Get_Param_From_Ini(char *config_name); +extern int ft5402_Init_IC_Param(struct i2c_client *client); +extern int ft5402_get_ic_param(struct i2c_client *client); +extern int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue); + +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); + + +int ft5x0x_i2c_rxdata(char *rxdata, int length) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = rxdata; + + msg[1].addr = pContext->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = rxdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 2); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + + +int ft5x0x_i2c_txdata(char *txdata, int length) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0; + msg[0].len = length; + msg[0].buf = txdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 1); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +static void ft5x0x_penup(struct ft5x0x_data *ft5x0x) +{ + input_mt_sync(ft5x0x->input_dev); + input_sync(ft5x0x->input_dev); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && ft5x0x->tkey_pressed && ft5x0x->tkey_idx < NUM_KEYS ){ + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 1); + input_sync(ft5x0x->input_dev); + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 0); + input_sync(ft5x0x->input_dev); + dbg("report as key event %d \n",ft5x0x->tkey_idx); + } +#endif + + dbg("pen up\n"); + return; +} + +#ifdef TOUCH_KEY +static int ft5x0x_read_tskey(struct ft5x0x_data *ft5x0x,int x,int y) +{ + int px,py; + + if(ft5x0x->tkey.axis){ + px = y; + py = x; + }else{ + px = x; + py = y; + } + + if(px >= ft5x0x->tkey.x_lower && px<=ft5x0x->tkey.x_upper){ + ft5x0x->tkey_pressed = 1; + if(py>= ft5x0x->tkey.ypos[0].y_lower && py<= ft5x0x->tkey.ypos[0].y_upper){ + ft5x0x->tkey_idx= 0; + }else if(py>= ft5x0x->tkey.ypos[1].y_lower && py<= ft5x0x->tkey.ypos[1].y_upper){ + ft5x0x->tkey_idx = 1; + }else if(py>= ft5x0x->tkey.ypos[2].y_lower && py<= ft5x0x->tkey.ypos[2].y_upper){ + ft5x0x->tkey_idx = 2; + }else if(py>= ft5x0x->tkey.ypos[3].y_lower && py<= ft5x0x->tkey.ypos[3].y_upper){ + ft5x0x->tkey_idx = 3; + }else{ + ft5x0x->tkey_idx = NUM_KEYS; + } + + return 1; + } + + ft5x0x->tkey_pressed = 0; + return 0; +} +#endif + +static int ft5x0x_read_data(struct ft5x0x_data *ft5x0x) +{ + int ret = -1; + int i = 0; + u16 x,y,px,py; + u8 buf[64] = {0}, id; + struct ts_event *event = &ft5x0x->event; + + if(ft5x0x->nt == 10) + ret = ft5x0x_i2c_rxdata(buf, 64); + else if(ft5x0x->nt == 5) + ret = ft5x0x_i2c_rxdata(buf, 31); + + if (ret <= 0) { + dbg_err("read_data i2c_rxdata failed: %d\n", ret); + return ret; + } + + memset(event, 0, sizeof(struct ts_event)); + //event->tpoint = buf[2] & 0x03;// 0000 0011 + //event->tpoint = buf[2] & 0x07;// 000 0111 + event->tpoint = buf[2]&0x0F; + if (event->tpoint == 0) { + ft5x0x_penup(ft5x0x); + return 1; + } + + if (event->tpoint > ft5x0x->nt){ + dbg_err("tounch pointnum=%d > max:%d\n", event->tpoint,ft5x0x->nt); + return -1; + } + + for (i = 0; i < event->tpoint; i++){ + id = (buf[5+i*6] >>4) & 0x0F;//get track id + if(ft5x0x->swap){ + px = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + py = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + }else{ + px = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + py = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + } + + x = px; + y = py; + + if(ft5x0x->xch) + x = ft5x0x->reslx - px; + + if(ft5x0x->ych) + y = ft5x0x->resly - py; + + if(ft5x0x->dbg) printk("F%d: Tid=%d,px=%d,py=%d; x=%d,y=%d\n", i, id, px, py, x, y); + +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && event->tpoint==1) { + if(ft5x0x_read_tskey(ft5x0x,px,py) > 0) return -1; + } +#endif + if (ft5x0x->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ft5x0x->reslx - tmp; + } + event->x[i] = x; + event->y[i] = y; + event->tid[i] = id; + + } + + return 0; +} + +static void ft5x0x_report(struct ft5x0x_data *ft5x0x) +{ + int i = 0; + struct ts_event *event = &ft5x0x->event; + + for (i = 0; i < event->tpoint; i++){ + input_report_abs(ft5x0x->input_dev, ABS_MT_TRACKING_ID, event->tid[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_X, event->x[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_Y, event->y[i]); + input_mt_sync(ft5x0x->input_dev); + } + input_sync(ft5x0x->input_dev); + + return; +} + +static void ft5x0x_read_work(struct work_struct *work) +{ + int ret = -1; + struct ft5x0x_data *ft5x0x = container_of(work, struct ft5x0x_data, read_work); + + mutex_lock(&ft5x0x->ts_mutex); + ret = ft5x0x_read_data(ft5x0x); + + if (ret == 0) ft5x0x_report(ft5x0x); + + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + mutex_unlock(&ft5x0x->ts_mutex); + + return; +} + +static irqreturn_t ft5x0x_interrupt(int irq, void *dev) +{ + struct ft5x0x_data *ft5x0x = dev; + + if (gpio_irqstatus(ft5x0x->irqgpio)) + { + wmt_gpio_ack_irq(ft5x0x->irqgpio); + if (is_gpio_irqenable(ft5x0x->irqgpio)) + { + wmt_gpio_mask_irq(ft5x0x->irqgpio); +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!ft5x0x->earlysus) queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#else + queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#endif + + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void ft5x0x_reset(struct ft5x0x_data *ft5x0x) +{ + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + gpio_set_value(ft5x0x->rstgpio, 0); + mdelay(20); + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + + return; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ft5x0x_early_suspend(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return; +} + +static void ft5x0x_late_resume(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + +#ifdef CONFIG_PM +static int ft5x0x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return 0; +} + +static int ft5x0x_resume(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + if (ft5x0x->load_cfg) { + msleep(350); + ft5402_Init_IC_Param(ft5x0x->client); + //msleep(50); + ft5402_get_ic_param(ft5x0x->client); + } + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + return 0; +} + +#else +#define ft5x0x_suspend NULL +#define ft5x0x_resume NULL +#endif + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "dbg \n"); +} + +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int dbg = simple_strtoul(buf, NULL, 10); + struct ft5x0x_data *ft5x0x = pContext; + + if(dbg){ + ft5x0x->dbg = 1; + }else{ + ft5x0x->dbg = 0; + } + + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +static ssize_t cat_clb(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "calibrate \n"); +} + +static ssize_t echo_clb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int cal = simple_strtoul(buf, NULL, 10); + + if(cal){ + if(ft5x0x_auto_clb()) printk("Calibrate Failed.\n"); + }else{ + printk("calibrate --echo 1 >clb.\n"); + } + + return count; +} + +static DEVICE_ATTR(clb, S_IRUGO | S_IWUSR, cat_clb, echo_clb); + +static ssize_t cat_fupg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "fupg \n"); +} + +static ssize_t echo_fupg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct ft5x0x_data *ft5x0x = pContext; + unsigned int upg = simple_strtoul(buf, NULL, 10); + + wmt_gpio_mask_irq(ft5x0x->irqgpio); + if(upg){ + if(ft5x0x_upg_fw_bin(ft5x0x, 0)) printk("Upgrade Failed.\n"); + }else{ + printk("upgrade --echo 1 > fupg.\n"); + } + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return count; +} +static DEVICE_ATTR(fupg, S_IRUGO | S_IWUSR, cat_fupg, echo_fupg); + + +static ssize_t cat_fver(struct device *dev, struct device_attribute *attr, char *buf) +{ + int fw_ver = ft5x0x_read_fw_ver(); + return sprintf(buf, "firmware version:0x%02x \n",fw_ver); +} + +static ssize_t echo_fver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} +static DEVICE_ATTR(fver, S_IRUGO | S_IWUSR, cat_fver, echo_fver); + +static ssize_t cat_addr(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret; + u8 addrs[32]; + int cnt=0; + struct i2c_msg msg[2]; + struct ft5x0x_data *ft5x0x = pContext; + u8 ver[1]= {0xa6}; + + ft5x0x->addr = 1; + + msg[0].addr = ft5x0x->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ver; + + msg[1].addr = ft5x0x->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = ver; + + while(ft5x0x->addr < 0x80){ + ret = i2c_transfer(ft5x0x->client->adapter, msg, 2); + if(ret == 2) sprintf(&addrs[5*cnt++], " 0x%02x",ft5x0x->addr); + + ft5x0x->addr++; + msg[0].addr = msg[1].addr = ft5x0x->addr; + } + + return sprintf(buf, "i2c addr:%s\n",addrs); +} + +static ssize_t echo_addr(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int addr; + struct ft5x0x_data *ft5x0x = pContext; + + sscanf(buf,"%x", &addr); + ft5x0x->addr = addr; + + return count; +} +static DEVICE_ATTR(addr, S_IRUGO | S_IWUSR, cat_addr, echo_addr); + +static struct attribute *ft5x0x_attributes[] = { + &dev_attr_clb.attr, + &dev_attr_fupg.attr, + &dev_attr_fver.attr, + &dev_attr_dbg.attr, + &dev_attr_addr.attr, + NULL +}; + +static const struct attribute_group ft5x0x_group = { + .attrs = ft5x0x_attributes, +}; + +static int ft5x0x_sysfs_create_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + int err; + + ft5x0x->kobj = kobject_create_and_add("wmtts", NULL) ; + if(!ft5x0x->kobj){ + dbg_err("kobj create failed.\n"); + return -ENOMEM; + } + + /* Register sysfs hooks */ + err = sysfs_create_group(ft5x0x->kobj, group); + if (err < 0){ + kobject_del(ft5x0x->kobj); + dbg_err("Create sysfs group failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void ft5x0x_sysfs_remove_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + sysfs_remove_group(ft5x0x->kobj, group); + kobject_del(ft5x0x->kobj); + return; +} + +static int bl_notify_irqgpio = -1; +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + switch (event) { + case BL_CLOSE: + errlog("ft5x0x: BL_CLOSE, disable irq\n"); + wmt_gpio_mask_irq(bl_notify_irqgpio); + break; + case BL_OPEN: + errlog("ft5x0x: BL_OPEN, enable irq\n"); + wmt_gpio_unmask_irq(bl_notify_irqgpio); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int ft5x0x_probe(struct platform_device *pdev) +{ + int i,err = 0; + u8 value = 0; + u8 cfg_name[32]; + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + ft5x0x->client = l_client; + INIT_WORK(&ft5x0x->read_work, ft5x0x_read_work); + mutex_init(&ft5x0x->ts_mutex); + + ft5x0x->workqueue = create_singlethread_workqueue(ft5x0x->name); + if (!ft5x0x->workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + err = ft5x0x_sysfs_create_group(ft5x0x, &ft5x0x_group); + if(err < 0){ + dbg("create sysfs group failed.\n"); + goto exit_create_group; + } + + ft5x0x->input_dev = input_allocate_device(); + if (!ft5x0x->input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + ft5x0x->input_dev->name = ft5x0x->name; + ft5x0x->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, ft5x0x->input_dev->propbit); + + if (ft5x0x->lcd_exchg) { + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_X, 0, ft5x0x->resly, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_Y, 0, ft5x0x->reslx, 0, 0); + } else { + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_X, 0, ft5x0x->reslx, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_Y, 0, ft5x0x->resly, 0, 0); + } + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_TRACKING_ID, 0, 20, 0, 0); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used){ + for (i = 0; i <NUM_KEYS; i++) + set_bit(keycodes[i], ft5x0x->input_dev->keybit); + + ft5x0x->input_dev->keycode = keycodes; + ft5x0x->input_dev->keycodesize = sizeof(unsigned int); + ft5x0x->input_dev->keycodemax = NUM_KEYS; + } +#endif + + err = input_register_device(ft5x0x->input_dev); + if (err) { + dbg_err("ft5x0x_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ft5x0x->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ft5x0x->early_suspend.suspend = ft5x0x_early_suspend; + ft5x0x->early_suspend.resume = ft5x0x_late_resume; + register_early_suspend(&ft5x0x->early_suspend); +#endif + + if(ft5x0x->upg){ + if(ft5x0x_upg_fw_bin(ft5x0x, 1)) printk("Upgrade Failed.\n"); + else wmt_setsyspara("wmt.io.ts.upg",""); + ft5x0x->upg = 0x00; + } + + if(request_irq(ft5x0x->irq, ft5x0x_interrupt, IRQF_SHARED, ft5x0x->name, ft5x0x) < 0){ + dbg_err("Could not allocate irq for ts_ft5x0x !\n"); + err = -1; + goto exit_register_irq; + } + + { // check if need to load config to IC or not + err = ft5402_read_reg(ft5x0x->client, 0xa3, &value); + if (err < 0) + dbg_err("Read reg 0xa3 failed.\n"); + else + printk("0xa3 reg = %d\n", value); + if (value == 3) + ft5x0x->load_cfg = 1; + else + ft5x0x->load_cfg = 0; + } + ft5x0x_reset(ft5x0x); + + if (ft5x0x->load_cfg) { + msleep(350); /*make sure CTP already finish startup process*/ + sprintf(cfg_name, "%s.ini", ft5x0x->cfg_name); + printk("Config file name: %s\n", cfg_name); + if (ft5402_Get_Param_From_Ini(cfg_name) >= 0) + ft5402_Init_IC_Param(ft5x0x->client); + else + dbg_err("[FTS]-------Get ft5402 param from INI file failed\n"); + ft5402_get_ic_param(ft5x0x->client); + } + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + if(bl_notify_irqgpio < 0){ + register_bl_notifier(&wmt_bl_notify); + bl_notify_irqgpio = ft5x0x->irqgpio; + } + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(ft5x0x->input_dev); +exit_input_dev_alloc_failed: + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); +exit_create_group: + cancel_work_sync(&ft5x0x->read_work); + destroy_workqueue(ft5x0x->workqueue); +exit_create_singlethread: + return err; +} + +static int ft5x0x_remove(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + if( bl_notify_irqgpio > 0){ + unregister_bl_notifier(&wmt_bl_notify); + bl_notify_irqgpio = -1; + } + cancel_work_sync(&ft5x0x->read_work); + flush_workqueue(ft5x0x->workqueue); + destroy_workqueue(ft5x0x->workqueue); + + free_irq(ft5x0x->irq, ft5x0x); + wmt_gpio_mask_irq(ft5x0x->irqgpio); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif + input_unregister_device(ft5x0x->input_dev); + + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); + + mutex_destroy(&ft5x0x->ts_mutex); + dbg("remove...\n"); + return 0; +} + +static void ft5x0x_release(struct device *device) +{ + return; +} + +static struct platform_device ft5x0x_device = { + .name = DEV_FT5X0X, + .id = 0, + .dev = {.release = ft5x0x_release}, +}; + +static struct platform_driver ft5x0x_driver = { + .driver = { + .name = DEV_FT5X0X, + .owner = THIS_MODULE, + }, + .probe = ft5x0x_probe, + .remove = ft5x0x_remove, + .suspend = ft5x0x_suspend, + .resume = ft5x0x_resume, +}; + +static int check_touch_env(struct ft5x0x_data *ft5x0x) +{ + int i,ret = 0; + int len = 96; + int Enable; + char retval[96] = {0}; + char *p=NULL; + char *s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + //printk("MST FT5x0x:Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + //printk("FT5x0x Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"ft5301",6)==0){//check touch ID + ft5x0x->id = FT5301; + ft5x0x->name = DEV_FT5301; + }else if(strncmp(p,"ft5406",6)==0){ + ft5x0x->id = FT5406; + ft5x0x->name = DEV_FT5406; + }else if(strncmp(p,"ft5206",6)==0){ + ft5x0x->id = FT5206; + ft5x0x->name = DEV_FT5206; + }else if(strncmp(p,"ft5606",6)==0){ + ft5x0x->id = FT5606; + ft5x0x->name = DEV_FT5606; + }else if(strncmp(p,"ft5306",6)==0){ + ft5x0x->id = FT5306; + ft5x0x->name = DEV_FT5306; + }else if(strncmp(p,"ft5302",6)==0){ + ft5x0x->id = FT5302; + ft5x0x->name = DEV_FT5302; + }else if(strncmp(p,"ft5",3)==0) + { + ft5x0x->id = FT5X0X; + ft5x0x->name = DEV_FT5X0X; + }else{ + printk("FT5x0x touch disabled.\n"); + return -ENODEV; + } + + s = strchr(p,':'); + strncpy(ft5x0x->cfg_name, p, s-p); + + p = s + 1; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", &ft5x0x->irqgpio, &ft5x0x->reslx, &ft5x0x->resly, &ft5x0x->rstgpio, &ft5x0x->swap, &ft5x0x->xch, &ft5x0x->ych, &ft5x0x->nt, &ft5x0x->addr); + + ft5x0x->irq = IRQ_GPIO; + printk("%s irqgpio=%d, reslx=%d, resly=%d, rstgpio=%d, swap=%d, xch=%d, ych=%d, nt=%d, addr=%x\n", ft5x0x->name, ft5x0x->irqgpio, ft5x0x->reslx, ft5x0x->resly, ft5x0x->rstgpio, ft5x0x->swap, ft5x0x->xch, ft5x0x->ych, ft5x0x->nt, ft5x0x->addr); + + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.upg", retval, &len); + if(!ret){ + ft5x0x->upg = 1; + strncpy(ft5x0x->fw_name, retval, sizeof(ft5x0x->fw_name)); + } + +#ifdef TOUCH_KEY + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskey", retval, &len); + if(!ret){ + sscanf(retval,"%d:", &ft5x0x->nkeys); + p = strchr(retval,':'); + p++; + for(i=0; i < ft5x0x->nkeys; i++ ){ + sscanf(p,"%d:%d", &ft5x0x->tkey.ypos[i].y_lower, &ft5x0x->tkey.ypos[i].y_upper); + p = strchr(p,':'); + p++; + p = strchr(p,':'); + p++; + } + sscanf(p,"%d:%d:%d", &ft5x0x->tkey.axis, &ft5x0x->tkey.x_lower, &ft5x0x->tkey.x_upper); + ft5x0x->tskey_used = 1; + } +#endif + + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + ft5x0x->lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = TS_I2C_NAME, + .flags = 0x00, + .addr = FT5406_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + //ts_i2c_board_info.addr = FT5406_I2C_ADDR; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(FT5X0X_I2C_BUS);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static int __init ft5x0x_init(void) +{ + int ret = -ENOMEM; + struct ft5x0x_data *ft5x0x=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ft5x0x = kzalloc(sizeof(struct ft5x0x_data), GFP_KERNEL); + if(!ft5x0x){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = ft5x0x; + ret = check_touch_env(ft5x0x); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(ft5x0x->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", ft5x0x->irqgpio); + goto exit_free_mem; + } + wmt_gpio_setpull(ft5x0x->irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(ft5x0x->irqgpio); + + ret = gpio_request(ft5x0x->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", ft5x0x->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(ft5x0x->rstgpio, 1); + + + ret = platform_device_register(&ft5x0x_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&ft5x0x_device, ft5x0x); + + ret = platform_driver_register(&ft5x0x_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&ft5x0x_device); +exit_free_gpio: + gpio_free(ft5x0x->rstgpio); +exit_free_irqgpio: + gpio_free(ft5x0x->irqgpio); +exit_free_mem: + kfree(ft5x0x); + pContext = NULL; + return ret; +} + +static void ft5x0x_exit(void) +{ + if(!pContext) return; + + gpio_free(pContext->rstgpio); + gpio_free(pContext->irqgpio); + platform_driver_unregister(&ft5x0x_driver); + platform_device_unregister(&ft5x0x_device); + kfree(pContext); + ts_i2c_unregister_device(); + return; +} + +late_initcall(ft5x0x_init); +module_exit(ft5x0x_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FocalTech.Touch"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h new file mode 100755 index 00000000..03836b49 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x.h @@ -0,0 +1,207 @@ +#ifndef __LINUX_FT5X0X_TS_H__ +#define __LINUX_FT5X0X_TS_H__ + +#define DEV_FT5206 "touch_ft5206" +#define DEV_FT5301 "touch_ft5301" +#define DEV_FT5302 "touch_ft5302" +#define DEV_FT5306 "touch_ft5306" +#define DEV_FT5406 "touch_ft5406" +#define DEV_FT5606 "touch_ft5606" + +#define DEV_FT5X0X "touch_ft5x0x" +#define TS_I2C_NAME "ft5x0x-ts" +#define FT5406_I2C_ADDR 0x38 +#define FT5X0X_I2C_BUS 0x01 + +enum FT5X0X_ID{ + FT5206 =1, + FT5301, + FT5302, + FT5306, + FT5406, + FT5606, + FT5X0X, +}; + +struct vt1603_ts_cal_info { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}; + +#define SUPPORT_POINT_NUM 10 +struct ts_event { + int x[SUPPORT_POINT_NUM]; + int y[SUPPORT_POINT_NUM]; + int tid[SUPPORT_POINT_NUM]; + int tpoint; +}; + +#define TOUCH_KEY + +#ifdef TOUCH_KEY +#define NUM_KEYS 4 +struct key_pos{ + int y_lower; + int y_upper; +}; + +struct ts_key{ + int axis; + int x_lower; + int x_upper; + struct key_pos ypos[NUM_KEYS]; +}; +#endif + +struct ft5x0x_data { + int id; + unsigned int addr; + const char *name; + u8 fw_name[64]; + u8 cfg_name[32]; + + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + struct work_struct read_work; + struct workqueue_struct *workqueue; + struct mutex ts_mutex; + struct kobject *kobj; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int earlysus; + + int reslx; + int resly; + + int tw; + int th; + + int irq; + int irqgpio; + int rstgpio; +/* + int igp_idx; + int igp_bit; + + int rgp_idx; + int rgp_bit; +*/ + + int nt; + int nb; + int xch; + int ych; + int swap; + int lcd_exchg; + + int upg; + int load_cfg; + int dbg; +#ifdef TOUCH_KEY + int tskey_used; + int tkey_pressed; + int nkeys; + int tkey_idx; + struct ts_key tkey; +#endif + +}; + +enum ft5x0x_ts_regs { + FT5X0X_REG_THGROUP = 0x80, /* touch threshold, related to sensitivity */ + FT5X0X_REG_THPEAK = 0x81, + FT5X0X_REG_THCAL = 0x82, + FT5X0X_REG_THWATER = 0x83, + FT5X0X_REG_THTEMP = 0x84, + FT5X0X_REG_THDIFF = 0x85, + FT5X0X_REG_CTRL = 0x86, + FT5X0X_REG_TIMEENTERMONITOR = 0x87, + FT5X0X_REG_PERIODACTIVE = 0x88, /* report rate */ + FT5X0X_REG_PERIODMONITOR = 0x89, + FT5X0X_REG_HEIGHT_B = 0x8a, + FT5X0X_REG_MAX_FRAME = 0x8b, + FT5X0X_REG_DIST_MOVE = 0x8c, + FT5X0X_REG_DIST_POINT = 0x8d, + FT5X0X_REG_FEG_FRAME = 0x8e, + FT5X0X_REG_SINGLE_CLICK_OFFSET = 0x8f, + FT5X0X_REG_DOUBLE_CLICK_TIME_MIN = 0x90, + FT5X0X_REG_SINGLE_CLICK_TIME = 0x91, + FT5X0X_REG_LEFT_RIGHT_OFFSET = 0x92, + FT5X0X_REG_UP_DOWN_OFFSET = 0x93, + FT5X0X_REG_DISTANCE_LEFT_RIGHT = 0x94, + FT5X0X_REG_DISTANCE_UP_DOWN = 0x95, + FT5X0X_REG_ZOOM_DIS_SQR = 0x96, + FT5X0X_REG_RADIAN_VALUE =0x97, + FT5X0X_REG_MAX_X_HIGH = 0x98, + FT5X0X_REG_MAX_X_LOW = 0x99, + FT5X0X_REG_MAX_Y_HIGH = 0x9a, + FT5X0X_REG_MAX_Y_LOW = 0x9b, + FT5X0X_REG_K_X_HIGH = 0x9c, + FT5X0X_REG_K_X_LOW = 0x9d, + FT5X0X_REG_K_Y_HIGH = 0x9e, + FT5X0X_REG_K_Y_LOW = 0x9f, + FT5X0X_REG_AUTO_CLB_MODE = 0xa0, + FT5X0X_REG_LIB_VERSION_H = 0xa1, + FT5X0X_REG_LIB_VERSION_L = 0xa2, + FT5X0X_REG_CIPHER = 0xa3, + FT5X0X_REG_MODE = 0xa4, + FT5X0X_REG_PMODE = 0xa5, /* Power Consume Mode */ + FT5X0X_REG_FIRMID = 0xa6, /* Firmware version */ + FT5X0X_REG_STATE = 0xa7, + FT5X0X_REG_FT5201ID = 0xa8, + FT5X0X_REG_ERR = 0xa9, + FT5X0X_REG_CLB = 0xaa, +}; + +//FT5X0X_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_STANDBY 0x02 +#define PMODE_HIBERNATE 0x03 + +#define DEV_NAME "wmtts" +#define DEV_MAJOR 11 + +#define TS_IOC_MAGIC 't' +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_CAL_CAP _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + +//#define FT_DEBUG + +#undef dbg +#ifdef FT_DEBUG + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + +//#define FTS_DBG +#ifdef FTS_DBG +#define DBG(fmt, args...) printk("[FTS]" fmt, ## args) +#else +#define DBG(fmt, args...) do{}while(0) +#endif + +#ifndef errlog +#define errlog(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__,__LINE__, ## args) +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c new file mode 100755 index 00000000..9db72130 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ft5x0x_upg.c @@ -0,0 +1,506 @@ +#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mount.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h>
+#endif +#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "ft5x0x.h"
+
+typedef enum
+{
+ ERR_OK,
+ ERR_MODE,
+ ERR_READID,
+ ERR_ERASE,
+ ERR_STATUS,
+ ERR_ECC,
+ ERR_DL_ERASE_FAIL,
+ ERR_DL_PROGRAM_FAIL,
+ ERR_DL_VERIFY_FAIL,
+ ERR_FMID
+}E_UPGRADE_ERR_TYPE;
+
+#define FT5X_CTPM_ID_L 0X79
+#define FT5X_CTPM_ID_H 0X03
+
+#define FT56_CTPM_ID_L 0X79
+#define FT56_CTPM_ID_H 0X06
+
+#define FTS_PACKET_LENGTH 128
+
+extern struct ft5x0x_data *pContext;
+extern int ft5x0x_i2c_rxdata(char *rxdata, int length);
+extern int ft5x0x_i2c_txdata(char *txdata, int length);
+
+static int ft5x0x_write_reg(u8 addr, u8 para)
+{
+ u8 buf[2];
+ int ret = -1;
+
+ buf[0] = addr;
+ buf[1] = para;
+ ret = ft5x0x_i2c_txdata(buf, 2);
+ if (ret <= 0) {
+ printk("write reg failed! %x ret: %d", buf[0], ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ft5x0x_read_reg(u8 addr, u8 *pdata)
+{
+ int ret;
+ u8 buf[2];
+ struct i2c_msg msgs[2];
+
+ //
+ buf[0] = addr; //register address
+
+ msgs[0].addr = pContext->addr;
+ msgs[0].flags = 0 | I2C_M_NOSTART;
+ msgs[0].len = 1;
+ msgs[0].buf = buf;
+
+ msgs[1].addr = pContext->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = 1;
+ msgs[1].buf = pdata;
+
+ //ret = wmt_i2c_xfer_continue_if_4(msgs, 2, FT5X0X_I2C_BUS);
+ ret = i2c_transfer(pContext->client->adapter, msgs, 2); + if (ret <= 0)
+ printk("msg %s i2c read error: %d\n", __func__, ret);
+
+ return ret;
+
+}
+
+
+/*
+[function]:
+ send a command to ctpm.
+[parameters]:
+ btcmd[in] :command code;
+ btPara1[in] :parameter 1;
+ btPara2[in] :parameter 2;
+ btPara3[in] :parameter 3;
+ num[in] :the valid input parameter numbers, if only command code needed and no parameters followed,then the num is 1;
+[return]:
+ FTS_TRUE :success;
+ FTS_FALSE :io fail;
+*/
+static u8 cmd_write(u8 *cmd,u8 num)
+{
+ return ft5x0x_i2c_txdata(cmd, num);
+}
+
+/*
+[function]:
+ write data to ctpm , the destination address is 0.
+[parameters]:
+ pbt_buf[in] :point to data buffer;
+ bt_len[in] :the data numbers;
+[return]:
+ FTS_TRUE :success;
+ FTS_FALSE :io fail;
+*/
+static u8 byte_write(u8* pbt_buf, int dw_len)
+{
+
+ return ft5x0x_i2c_txdata( pbt_buf, dw_len);
+}
+
+/*
+[function]:
+ read out data from ctpm,the destination address is 0.
+[parameters]:
+ pbt_buf[out] :point to data buffer;
+ bt_len[in] :the data numbers;
+[return]:
+ FTS_TRUE :success;
+ FTS_FALSE :io fail;
+*/
+static u8 byte_read(u8* pbt_buf, u8 bt_len)
+{
+ int ret;
+ struct i2c_msg msg[1];
+ + msg[0].addr = pContext->addr;
+ msg[0].flags = I2C_M_RD;
+ msg[0].len = bt_len;
+ msg[0].buf = pbt_buf;
+ + ret = i2c_transfer(pContext->client->adapter, msg, 1); + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, FT5X0X_I2C_BUS);
+ if (ret <= 0) + printk("msg i2c read error: %d\n", ret);
+ + return ret;
+}
+
+
+/*
+[function]:
+ burn the FW to ctpm.
+[parameters]:(ref. SPEC)
+ pbt_buf[in] :point to Head+FW ;
+ dw_lenth[in]:the length of the FW + 6(the Head length);
+ bt_ecc[in] :the ECC of the FW
+[return]:
+ ERR_OK :no error;
+ ERR_MODE :fail to switch to UPDATE mode;
+ ERR_READID :read id fail;
+ ERR_ERASE :erase chip fail;
+ ERR_STATUS :status error;
+ ERR_ECC :ecc error.
+*/
+static E_UPGRADE_ERR_TYPE ft5x0x_fw_upgrade(struct ft5x0x_data *ft5x0x, u8* pbt_buf, int dw_lenth)
+{
+ int i = 0,j = 0,i_ret;
+ int packet_number;
+ int temp,lenght;
+ u8 packet_buf[FTS_PACKET_LENGTH + 6];
+ u8 auc_i2c_write_buf[10];
+ u8 reg_val[2] = {0};
+ u8 ctpm_id[2] = {0};
+ u8 cmd[4];
+ u8 bt_ecc;
+
+ /*********Step 1:Reset CTPM *****/
+ /*write 0xaa to register 0xfc*/
+ ft5x0x_write_reg(0xfc,0xaa);
+ msleep(50);
+ /*write 0x55 to register 0xfc*/
+ ft5x0x_write_reg(0xfc,0x55);
+ printk("[FTS] Step 1: Reset CTPM.\n");
+ msleep(30);
+
+ /*********Step 2:Enter upgrade mode *****/
+ auc_i2c_write_buf[0] = 0x55;
+ auc_i2c_write_buf[1] = 0xaa;
+ do{
+ i ++;
+ i_ret = byte_write(auc_i2c_write_buf, 2);
+ mdelay(5);
+ }while(i_ret <= 0 && i < 5 );
+ msleep(20);
+
+ /*********Step 3:check READ-ID**********/
+ if(ft5x0x->id == FT5606){
+ ctpm_id[0] = FT56_CTPM_ID_L;
+ ctpm_id[1] = FT56_CTPM_ID_H;
+ }else{
+ ctpm_id[0] = FT5X_CTPM_ID_L;
+ ctpm_id[1] = FT5X_CTPM_ID_H;
+ }
+
+ cmd[0] = 0x90;
+ cmd[1] = 0x00;
+ cmd[2] = 0x00;
+ cmd[3] = 0x00;
+ cmd_write(cmd,4);
+ byte_read(reg_val,2);
+ if (reg_val[0] == ctpm_id[0] && reg_val[1] == ctpm_id[1]){
+ printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
+ }else{
+ printk("[FTS] ID_ERROR: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
+ return ERR_READID;
+ }
+
+ cmd[0] = 0xcd;
+ cmd_write(cmd,1);
+ byte_read(reg_val,1);
+ printk("[FTS] bootloader version = 0x%x\n", reg_val[0]);
+
+ /******Step 4:erase app and panel paramenter area *********/
+ cmd[0] = 0x61;
+ cmd_write(cmd,1); //erase app area
+ msleep(1500);
+ cmd[0] = 0x63;
+ cmd_write(cmd,1); //erase panel parameter area
+ msleep(100);
+ printk("[FTS] Step 4: erase. \n");
+
+ /*********Step 5:write firmware(FW) to ctpm flash*********/
+ bt_ecc = 0;
+ printk("[FTS] Step 5: start upgrade. \n");
+ dw_lenth = dw_lenth - 8;
+ packet_number = (dw_lenth) / FTS_PACKET_LENGTH;
+ packet_buf[0] = 0xbf;
+ packet_buf[1] = 0x00;
+ for (j=0;j<packet_number;j++){
+ temp = j * FTS_PACKET_LENGTH;
+ packet_buf[2] = (u8)(temp>>8);
+ packet_buf[3] = (u8)temp;
+ lenght = FTS_PACKET_LENGTH;
+ packet_buf[4] = (u8)(lenght>>8);
+ packet_buf[5] = (u8)lenght;
+
+ for (i=0;i<FTS_PACKET_LENGTH;i++){
+ packet_buf[6+i] = pbt_buf[j*FTS_PACKET_LENGTH + i];
+ bt_ecc ^= packet_buf[6+i];
+ }
+
+ byte_write(&packet_buf[0],FTS_PACKET_LENGTH + 6);
+ mdelay(FTS_PACKET_LENGTH/6 + 1);
+ if ((j * FTS_PACKET_LENGTH % 1024) == 0){
+ printk("[FTS] upgrade the 0x%x th byte.\n", ((unsigned int)j) * FTS_PACKET_LENGTH);
+ }
+ }
+
+ if ((dw_lenth) % FTS_PACKET_LENGTH > 0){
+ temp = packet_number * FTS_PACKET_LENGTH;
+ packet_buf[2] = (u8)(temp>>8);
+ packet_buf[3] = (u8)temp;
+
+ temp = (dw_lenth) % FTS_PACKET_LENGTH;
+ packet_buf[4] = (u8)(temp>>8);
+ packet_buf[5] = (u8)temp;
+
+ for (i=0;i<temp;i++){
+ packet_buf[6+i] = pbt_buf[ packet_number*FTS_PACKET_LENGTH + i];
+ bt_ecc ^= packet_buf[6+i];
+ }
+
+ byte_write(&packet_buf[0],temp+6);
+ mdelay(20);
+ }
+
+ //send the last six byte
+ for (i = 0; i<6; i++){
+ temp = 0x6ffa + i;
+ packet_buf[2] = (u8)(temp>>8);
+ packet_buf[3] = (u8)temp;
+ temp =1;
+ packet_buf[4] = (u8)(temp>>8);
+ packet_buf[5] = (u8)temp;
+ packet_buf[6] = pbt_buf[ dw_lenth + i];
+ bt_ecc ^= packet_buf[6];
+
+ byte_write(&packet_buf[0],7);
+ mdelay(20);
+ }
+
+ /*********Step 6: read out checksum********************/
+ /*send the opration head*/
+ cmd[0] = 0xcc;
+ cmd_write(cmd,1);
+ byte_read(reg_val,1);
+ printk("[FTS] Step 6:read ECC 0x%x, firmware ECC 0x%x. \n", reg_val[0], bt_ecc);
+ if(reg_val[0] != bt_ecc){
+ return ERR_ECC;
+ }
+
+ /*********Step 7: reset the new FW***********************/
+ cmd[0] = 0x07;
+ cmd_write(cmd,1);
+
+ msleep(300); //make sure CTP startup normally
+
+ return ERR_OK;
+}
+
+int ft5x0x_auto_clb(void)
+{
+ u8 uc_temp;
+ u8 i ;
+
+ printk("[FTS] start auto CLB.\n");
+ msleep(200);
+ ft5x0x_write_reg(0, 0x40);
+ msleep(100); //make sure already enter factory mode
+ ft5x0x_write_reg(2, 0x4); //write command to start calibration
+ msleep(300);
+ for(i=0;i<100;i++){
+ ft5x0x_read_reg(0,&uc_temp);
+ if ( ((uc_temp&0x70)>>4) == 0x0){ //return to normal mode, calibration finish
+ break;
+ }
+ msleep(200);
+ printk("[FTS] waiting calibration %d\n",i);
+ }
+ printk("[FTS] calibration OK.\n");
+
+ msleep(300);
+ ft5x0x_write_reg(0, 0x40); //goto factory mode
+ msleep(100); //make sure already enter factory mode
+ ft5x0x_write_reg(2, 0x5); //store CLB result
+ msleep(300);
+ ft5x0x_write_reg(0, 0x0); //return to normal mode
+ msleep(300);
+ printk("[FTS] store CLB result OK.\n");
+ return 0;
+}
+
+static int ft5x0x_get_bin_ver(const u8 *fw, int fw_szie)
+{
+ if (fw_szie > 2){
+ return fw[fw_szie - 2];
+ }else{
+ return 0xff; //default value
+ }
+ return 0xff;
+}
+
+int ft5x0x_read_fw_ver(void)
+{
+ u8 ver=0;
+ int ret=0;
+
+ ret = ft5x0x_read_reg(FT5X0X_REG_FIRMID, &ver);
+ if(ret > 0)
+ return ver;
+
+ return ret;
+}
+
+
+static int ft5x0x_get_fw_szie(const char *fw_name)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize = 0;
+
+ if(fw_name == NULL){
+ dbg_err("Firmware name error.\n");
+ return -EFAULT;
+ }
+
+ if (NULL == pfile)
+ pfile = filp_open(fw_name, O_RDONLY, 0);
+
+ if (IS_ERR(pfile)) {
+ dbg_err("File open error: %s.\n", fw_name);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ filp_close(pfile, NULL);
+ return fsize;
+}
+
+static int ft5x0x_read_fw(const char *fw_name, u8 *buf)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize;
+ loff_t pos;
+ mm_segment_t fs;
+
+ if(fw_name == NULL){
+ dbg_err("Firmware name error.\n");
+ return -EFAULT;
+ }
+
+ if (NULL == pfile)
+ pfile = filp_open(fw_name, O_RDONLY, 0);
+ if (IS_ERR(pfile)) {
+ dbg_err("File open error: %s.\n", fw_name);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ pos = 0;
+ vfs_read(pfile, buf, fsize, &pos);
+ filp_close(pfile, NULL);
+ set_fs(fs);
+
+ return 0;
+}
+
+#define FW_SUFFFIX ".bin"
+#define SD_UPG_BIN_PATH "/sdcard/_wmt_ft5x0x_fw_app.bin"
+#define FS_UPG_BIN_PATH "/lib/firmware/"
+
+int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver)
+{
+ int i_ret = 0;
+ int fwsize = 0;
+ int hw_fw_ver;
+ int bin_fw_ver;
+ int do_upg;
+ u8 *pbt_buf = NULL;
+ u8 fw_path[128] = {0};
+
+ if(ft5x0x->upg)
+ sprintf(fw_path,"%s%s%s", FS_UPG_BIN_PATH, ft5x0x->fw_name,FW_SUFFFIX);//get fw binary file from filesystem
+ else
+ strcpy(fw_path,SD_UPG_BIN_PATH); //get fw binary file from SD card
+
+ fwsize = ft5x0x_get_fw_szie(fw_path);
+ if (fwsize <= 0) {
+ dbg_err("Get firmware size failed\n");
+ return -EIO;
+ }
+
+ if (fwsize < 8 || fwsize > 32 * 1024) {
+ dbg_err("FW length error\n");
+ return -EIO;
+ }
+
+ pbt_buf = kmalloc(fwsize + 1, GFP_KERNEL);
+ if (ft5x0x_read_fw(fw_path, pbt_buf)) {
+ dbg_err("Request_firmware failed\n");
+ i_ret = -EIO;
+ goto exit;
+ }
+
+ hw_fw_ver =ft5x0x_read_fw_ver();
+ if(hw_fw_ver <= 0){
+ dbg_err("Read firmware version failed\n");
+ i_ret = hw_fw_ver;
+ goto exit;
+ }
+
+ bin_fw_ver = ft5x0x_get_bin_ver(pbt_buf, fwsize);
+ printk("[FTS] hardware fw ver 0x%0x, binary ver 0x%0x\n",hw_fw_ver, bin_fw_ver);
+
+ if(check_ver){
+ if(hw_fw_ver == 0xa6 || hw_fw_ver < bin_fw_ver)
+ do_upg = 1;
+ else
+ do_upg = 0;
+ }else{
+ do_upg = 1;
+ }
+
+ if(do_upg){
+ if ((pbt_buf[fwsize - 8] ^ pbt_buf[fwsize - 6]) == 0xFF &&
+ (pbt_buf[fwsize - 7] ^ pbt_buf[fwsize - 5]) == 0xFF &&
+ (pbt_buf[fwsize - 3] ^ pbt_buf[fwsize - 4]) == 0xFF) {
+ i_ret = ft5x0x_fw_upgrade(ft5x0x, pbt_buf, fwsize);
+ if (i_ret)
+ dbg_err("Upgrade failed, i_ret=%d\n",i_ret);
+ else {
+ hw_fw_ver = ft5x0x_read_fw_ver();
+ printk("[FTS] upgrade to new version 0x%x\n", hw_fw_ver);
+ }
+ } else {
+ dbg_err("FW format error\n");
+ }
+ }
+
+ ft5x0x_auto_clb();/*start auto CLB*/
+
+exit:
+ kfree(pbt_buf);
+ return i_ret;
+}
+
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c new file mode 100755 index 00000000..a4f8dc38 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.c @@ -0,0 +1,406 @@ +#include <linux/string.h>
+#include <asm/unistd.h>
+#include <linux/slab.h> +
+#include "ini.h"
+
+
+char CFG_SSL = '['; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/
+char CFG_SSR = ']'; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/ +char CFG_NIS = ':'; /* name Óë index Ö®¼äµÄ·Ö¸ô·û */ +char CFG_NTS = '#'; /* ×¢ÊÍ·û*/ + +static char * ini_str_trim_r(char * buf);
+static char * ini_str_trim_l(char * buf);
+static int ini_file_get_line(char *filedata, char *buffer, int maxlen);
+static int ini_split_key_value(char *buf, char **key, char **val);
+static long atol(char *nptr);
+
+
+/*************************************************************
+Function: »ñµÃkeyµÄÖµ
+Input: char * filedata¡¡Îļþ£»char * section¡¡ÏîÖµ£»char * key¡¡¼üÖµ
+Output: char * value¡¡keyµÄÖµ
+Return: 0 SUCCESS
+ -1 δÕÒµ½section
+ -2 δÕÒµ½key
+ -10 Îļþ´ò¿ªÊ§°Ü
+ -12 ¶ÁÈ¡Îļþʧ°Ü
+ -14 Îļþ¸ñʽ´íÎó
+ -22 ³¬³ö»º³åÇø´óС
+Note:
+*************************************************************/
+int ini_get_key(char *filedata, char * section, char * key, char * value)
+{
+ //char buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1];
+ char *buf1, *buf2;
+ char *key_ptr, *val_ptr;
+ int n, ret;
+ int dataoff = 0;
+
+ *value='\0';
+
+ buf1 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf1){ + printk("buf1: mem alloc failed.\n"); + return -ENOMEM; + } + buf2 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf2){ + printk("buf2: mem alloc failed.\n"); + kfree(buf1); + return -ENOMEM; + } + + while(1) { /* ËÑÕÒÏîsection */
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto r_cfg_end;
+ ret = CFG_SECTION_NOT_FOUND;
+ if(n < 0)
+ goto r_cfg_end; /* Îļþβ£¬Î´·¢ÏÖ */
+
+ n = strlen(ini_str_trim_l(ini_str_trim_r(buf1)));
+ if(n == 0 || buf1[0] == CFG_NTS)
+ continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */
+
+ ret = CFG_ERR_FILE_FORMAT;
+ if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR)))
+ goto r_cfg_end;
+ if(buf1[0] == CFG_SSL) {
+ buf1[n-1] = 0x00;
+ if(strcmp(buf1+1, section) == 0)
+ break; /* ÕÒµ½Ïîsection */
+ }
+ }
+
+ while(1){ /* ËÑÕÒkey */
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto r_cfg_end;
+ ret = CFG_KEY_NOT_FOUND;
+ if(n < 0)
+ goto r_cfg_end;/* Îļþβ£¬Î´·¢ÏÖkey */
+
+ n = strlen(ini_str_trim_l(ini_str_trim_r(buf1)));
+ if(n == 0 || buf1[0] == CFG_NTS)
+ continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */
+ ret = CFG_KEY_NOT_FOUND;
+ if(buf1[0] == CFG_SSL)
+ goto r_cfg_end;
+ if(buf1[n-1] == '+') { /* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */
+ buf1[n-1] = 0x00;
+ while(1) {
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf2, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto r_cfg_end;
+ if(n < 0)
+ break;/* Îļþ½áÊø */
+
+ n = strlen(ini_str_trim_r(buf2));
+ ret = CFG_ERR_EXCEED_BUF_SIZE;
+ if(n > 0 && buf2[n-1] == '+'){/* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */
+ buf2[n-1] = 0x00;
+ if( (strlen(buf1) + strlen(buf2)) > MAX_CFG_BUF)
+ goto r_cfg_end;
+ strcat(buf1, buf2);
+ continue;
+ }
+ if(strlen(buf1) + strlen(buf2) > MAX_CFG_BUF)
+ goto r_cfg_end;
+ strcat(buf1, buf2);
+ break;
+ }
+ }
+ ret = CFG_ERR_FILE_FORMAT;
+ if(ini_split_key_value(buf1, &key_ptr, &val_ptr) != 1)
+ goto r_cfg_end;
+ ini_str_trim_l(ini_str_trim_r(key_ptr));
+ if(strcmp(key_ptr, key) != 0)
+ continue; /* ºÍkeyÖµ²»Æ¥Åä */
+ strcpy(value, val_ptr);
+ break;
+ }
+ ret = CFG_OK;
+r_cfg_end:
+ //if(fp != NULL) fclose(fp);
+ kfree(buf1); + kfree(buf2); + return ret;
+}
+/*************************************************************
+Function: »ñµÃËùÓÐsection
+Input: char *filename¡¡Îļþ,int max ×î´ó¿É·µ»ØµÄsectionµÄ¸öÊý
+Output: char *sections[]¡¡´æ·ÅsectionÃû×Ö
+Return: ·µ»Øsection¸öÊý¡£Èô³ö´í£¬·µ»Ø¸ºÊý¡£
+ -10 Îļþ´ò¿ª³ö´í
+ -12 Îļþ¶ÁÈ¡´íÎó
+ -14 Îļþ¸ñʽ´íÎó
+Note:
+*************************************************************/
+int ini_get_sections(char *filedata, unsigned char * sections[], int max)
+{
+ //FILE *fp;
+ char buf1[MAX_CFG_BUF + 1];
+ int n, n_sections = 0, ret;
+ int dataoff = 0;
+
+// if((fp = fopen(filename, "rb")) == NULL)
+// return CFG_ERR_OPEN_FILE;
+
+ while(1) {/*ËÑÕÒÏîsection */
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto cfg_scts_end;
+ if(n < 0)
+ break;/* Îļþβ */
+ n = strlen(ini_str_trim_l(ini_str_trim_r(buf1)));
+ if(n == 0 || buf1[0] == CFG_NTS)
+ continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */
+ ret = CFG_ERR_FILE_FORMAT;
+ if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR)))
+ goto cfg_scts_end;
+ if(buf1[0] == CFG_SSL) {
+ if (max!=0){
+ buf1[n-1] = 0x00;
+ strcpy((char *)sections[n_sections], buf1+1);
+ if (n_sections>=max)
+ break; /* ³¬¹ý¿É·µ»Ø×î´ó¸öÊý */
+ }
+ n_sections++;
+ }
+
+ }
+ ret = n_sections;
+cfg_scts_end:
+// if(fp != NULL)
+// fclose(fp);
+ return ret;
+}
+
+
+/*************************************************************
+Function: È¥³ý×Ö·û´®ÓұߵĿÕ×Ö·û
+Input: char * buf ×Ö·û´®Ö¸Õë
+Output:
+Return: ×Ö·û´®Ö¸Õë
+Note:
+*************************************************************/
+static char * ini_str_trim_r(char * buf)
+{
+ int len,i;
+ char tmp[128];
+
+ memset(tmp, 0, sizeof(tmp));
+ len = strlen(buf);
+// tmp = (char *)malloc(len);
+
+ memset(tmp,0x00,len);
+ for(i = 0;i < len;i++) {
+ if (buf[i] !=' ')
+ break;
+ }
+ if (i < len) {
+ strncpy(tmp,(buf+i),(len-i));
+ }
+ strncpy(buf,tmp,len);
+// free(tmp);
+ return buf;
+}
+
+/*************************************************************
+Function: È¥³ý×Ö·û´®×ó±ßµÄ¿Õ×Ö·û
+Input: char * buf ×Ö·û´®Ö¸Õë
+Output:
+Return: ×Ö·û´®Ö¸Õë
+Note:
+*************************************************************/
+static char * ini_str_trim_l(char * buf)
+{
+ int len,i;
+ char tmp[128];
+
+ memset(tmp, 0, sizeof(tmp));
+ len = strlen(buf);
+ //tmp = (char *)malloc(len);
+
+ memset(tmp,0x00,len);
+
+ for(i = 0;i < len;i++) {
+ if (buf[len-i-1] !=' ')
+ break;
+ }
+ if (i < len) {
+ strncpy(tmp,buf,len-i);
+ }
+ strncpy(buf,tmp,len);
+ //free(tmp);
+ return buf;
+}
+/*************************************************************
+Function: ´ÓÎļþÖжÁÈ¡Ò»ÐÐ
+Input: FILE *fp Îļþ¾ä±ú£»int maxlen »º³åÇø×î´ó³¤¶È
+Output: char *buffer Ò»ÐÐ×Ö·û´®
+Return: >0 ʵ¼Ê¶ÁµÄ³¤¶È
+ -1 Îļþ½áÊø
+ -2 ¶ÁÎļþ³ö´í
+Note:
+*************************************************************/
+static int ini_file_get_line(char *filedata, char *buffer, int maxlen)
+{
+ int i, j;
+ char ch1;
+
+ for(i=0, j=0; i<maxlen; j++) {
+ ch1 = filedata[j];
+ if(ch1 == '\n' || ch1 == 0x00)
+ break; /* »»ÐÐ */
+ if(ch1 == '\f' || ch1 == 0x1A) { /* '\f':»»Ò³·ûÒ²ËãÓÐЧ×Ö·û */
+ buffer[i++] = ch1;
+ break;
+ }
+ if(ch1 != '\r') buffer[i++] = ch1; /* ºöÂԻسµ·û */
+ }
+ buffer[i] = '\0';
+ return i+2;
+}
+/*************************************************************
+Function: ·ÖÀëkeyºÍvalue
+ key=val
+ jack = liaoyuewang
+ | | |
+ k1 k2 i
+Input: char *buf
+Output: char **key, char **val
+Return: 1 --- ok
+ 0 --- blank line
+ -1 --- no key, "= val"
+ -2 --- only key, no '='
+Note:
+*************************************************************/
+static int ini_split_key_value(char *buf, char **key, char **val)
+{
+ int i, k1, k2, n;
+
+ if((n = strlen((char *)buf)) < 1)
+ return 0;
+ for(i = 0; i < n; i++)
+ if(buf[i] != ' ' && buf[i] != '\t')
+ break;
+
+ if(i >= n)
+ return 0;
+
+ if(buf[i] == '=')
+ return -1;
+
+ k1 = i;
+ for(i++; i < n; i++)
+ if(buf[i] == '=')
+ break;
+
+ if(i >= n)
+ return -2;
+ k2 = i;
+
+ for(i++; i < n; i++)
+ if(buf[i] != ' ' && buf[i] != '\t')
+ break;
+
+ buf[k2] = '\0';
+
+ *key = buf + k1;
+ *val = buf + i;
+ return 1;
+}
+
+int my_atoi(const char *str)
+{
+ int result = 0;
+ int signal = 1; /* ĬÈÏΪÕýÊý */
+ if((*str>='0'&&*str<='9')||*str=='-'||*str=='+') {
+ if(*str=='-'||*str=='+') {
+ if(*str=='-')
+ signal = -1; /*ÊäÈ븺Êý*/
+ str++;
+ }
+ }
+ else
+ return 0;
+ /*¿ªÊ¼×ª»»*/
+ while(*str>='0' && *str<='9')
+ result = result*10 + (*str++ - '0' );
+
+ return signal*result;
+}
+
+int isspace(int x)
+{
+ if(x==' '||x=='\t'||x=='\n'||x=='\f'||x=='\b'||x=='\r')
+ return 1;
+ else
+ return 0;
+}
+
+int isdigit(int x)
+{
+ if(x<='9' && x>='0')
+ return 1;
+ else
+ return 0;
+
+}
+
+static long atol(char *nptr)
+{
+ int c; /* current char */
+ long total; /* current total */
+ int sign; /* if ''-'', then negative, otherwise positive */
+ /* skip whitespace */
+ while ( isspace((int)(unsigned char)*nptr) )
+ ++nptr;
+ c = (int)(unsigned char)*nptr++;
+ sign = c; /* save sign indication */
+ if (c == '-' || c == '+')
+ c = (int)(unsigned char)*nptr++; /* skip sign */
+ total = 0;
+ while (isdigit(c)) {
+ total = 10 * total + (c - '0'); /* accumulate digit */
+ c = (int)(unsigned char)*nptr++; /* get next char */
+ }
+ if (sign == '-')
+ return -total;
+ else
+ return total; /* return result, negated if necessary */
+}
+/***
+*int atoi(char *nptr) - Convert string to long
+*
+*Purpose:
+* Converts ASCII string pointed to by nptr to binary.
+* Overflow is not detected. Because of this, we can just use
+* atol().
+*
+*Entry:
+* nptr = ptr to string to convert
+*
+*Exit:
+* return int value of the string
+*
+*Exceptions:
+* None - overflow is not detected.
+*
+*******************************************************************************/
+int atoi(char *nptr)
+{
+ return (int)atol(nptr);
+}
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h new file mode 100755 index 00000000..72434b53 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft5x0x/ini.h @@ -0,0 +1,43 @@ +#ifndef INI_H +#define INI_H + +#define MAX_CFG_BUF 512 +#define SUCCESS 0 +/* return value */ +#define CFG_OK SUCCESS +#define CFG_SECTION_NOT_FOUND -1 +#define CFG_KEY_NOT_FOUND -2 +#define CFG_ERR -10 + +#define CFG_ERR_OPEN_FILE -10 +#define CFG_ERR_CREATE_FILE -11 +#define CFG_ERR_READ_FILE -12 +#define CFG_ERR_WRITE_FILE -13 +#define CFG_ERR_FILE_FORMAT -14 + + +#define CFG_ERR_EXCEED_BUF_SIZE -22 + +#define COPYF_OK SUCCESS +#define COPYF_ERR_OPEN_FILE -10 +#define COPYF_ERR_CREATE_FILE -11 +#define COPYF_ERR_READ_FILE -12 +#define COPYF_ERR_WRITE_FILE -13 + + +struct ini_key_location { + int ini_section_line_no; + int ini_key_line_no; + int ini_key_lines; +}; + + +int ini_get_key(char *filedata, char * section, char * key, char * value); +int ini_get_sections(char *filedata, unsigned char * sections[], int max); + +int ini_split_section(char *section, char **name, char **index); +//int ini_join_section(char **section, char *name, char *index); + +int atoi(char *nptr); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig new file mode 100755 index 00000000..eb11a558 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_FT6X0X
+ tristate "FT5X0X Capacity Touchscreen Device Support"
+ default y
+ depends on ARCH_WMT
+ ---help---
+ Say Y here if you have an WMT based board with touchscreen
+ attached to it.
+ If unsure, say N.
+ To compile this driver as a module, choose M here: the
+ module will be called ft5x0x.
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile new file mode 100755 index 00000000..859008b8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_ft6x0x
+
+#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := ft5x0x.o ft5x0x_upg.o ft5402_config.o ft6x06_ex_fun.o ini.o ft6x06_ts.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h new file mode 100755 index 00000000..7c58a15a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/focaltech_ctl.h @@ -0,0 +1,27 @@ +#ifndef __FOCALTECH_CTL_H__
+#define __FOCALTECH_CTL_H__
+
+#define FT_RW_IIC_DRV "ft_rw_iic_drv"
+#define FT_RW_IIC_DRV_MAJOR 210 /*Ô¤ÉèµÄft_rw_iic_drvµÄÖ÷É豸ºÅ*/
+
+#define FT_I2C_RDWR_MAX_QUEUE 36
+#define FT_I2C_SLAVEADDR 11
+#define FT_I2C_RW 12
+#define FT_RESET_TP 13
+
+typedef struct ft_rw_i2c
+{
+ u8 *buf;
+ u8 flag; /*0-write 1-read*/
+ __u16 length; //the length of data
+}*pft_rw_i2c;
+
+typedef struct ft_rw_i2c_queue
+{
+ struct ft_rw_i2c __user *i2c_queue;
+ int queuenum;
+}*pft_rw_i2c_queue;
+
+int ft_rw_iic_drv_init(struct i2c_client *client);
+void ft_rw_iic_drv_exit(void);
+#endif
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c new file mode 100755 index 00000000..58683ebd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.c @@ -0,0 +1,2295 @@ +#include "ft5402_config.h"
+//#include <linux/i2c/ft5402_ts.h>
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+
+#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include "ini.h"
+#include "ft5402_ini_config.h"
+#include "ft5x0x.h"
+
+
+extern int ft5x0x_i2c_txdata(char *txdata, int length);
+
+int ft5402_write_reg(struct i2c_client * client, u8 regaddr, u8 regvalue)
+{
+ unsigned char buf[2] = {0};
+ buf[0] = regaddr;
+ buf[1] = regvalue;
+
+ return ft5x0x_i2c_txdata(buf, 2);
+}
+
+int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue)
+{
+ int ret;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ®addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = regvalue,
+ },
+ };
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret < 0)
+ pr_err("function:%s. i2c read error: %d\n", __func__, ret);
+ return ret;
+}
+
+/*set tx order
+*@txNO: offset from tx order start
+*@txNO1: tx NO.
+*/
+static int ft5402_set_tx_order(struct i2c_client * client, u8 txNO, u8 txNO1)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_write_reg(client, FT5402_REG_TX_ORDER_START + txNO,
+ txNO1);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1,
+ txNO1);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*set tx order
+*@txNO: offset from tx order start
+*@pTxNo: return value of tx NO.
+*/
+static int ft5402_get_tx_order(struct i2c_client * client, u8 txNO, u8 *pTxNo)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client, FT5402_REG_TX_ORDER_START + txNO,
+ pTxNo);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if(ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_ORDER_START + txNO - FT5402_TX_TEST_MODE_1,
+ pTxNo);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*set tx cap
+*@txNO: tx NO.
+*@cap_value: value of cap
+*/
+static int ft5402_set_tx_cap(struct i2c_client * client, u8 txNO, u8 cap_value)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_write_reg(client, FT5402_REG_TX_CAP_START + txNO,
+ cap_value);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1,
+ cap_value);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*get tx cap*/
+static int ft5402_get_tx_cap(struct i2c_client * client, u8 txNO, u8 *pCap)
+{
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client, FT5402_REG_TX_CAP_START + txNO,
+ pCap);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_CAP_START + txNO - FT5402_TX_TEST_MODE_1,
+ pCap);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+ return ReCode;
+}
+
+/*set tx offset*/
+static int ft5402_set_tx_offset(struct i2c_client * client, u8 txNO, u8 offset_value)
+{
+ unsigned char temp=0;
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp);
+ if (ReCode >= 0) {
+ if (txNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1),
+ (temp&0xf0) + (offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1),
+ (temp&0x0f) + (offset_value<<4));
+ }
+ } else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_DEVICE_MODE+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ &temp); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ if(txNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value<<4));
+ }
+ }
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*get tx offset*/
+static int ft5402_get_tx_offset(struct i2c_client * client, u8 txNO, u8 *pOffset)
+{
+ unsigned char temp=0;
+ unsigned char ReCode = 0;
+ if (txNO < FT5402_TX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_OFFSET_START + (txNO>>1), &temp);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_TX_OFFSET_START+((txNO-FT5402_TX_TEST_MODE_1)>>1),
+ &temp);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ if (ReCode >= 0)
+ (txNO%2 == 0) ? (*pOffset = (temp&0x0f)) : (*pOffset = (temp>>4));
+ return ReCode;
+}
+
+/*set rx order*/
+static int ft5402_set_rx_order(struct i2c_client * client, u8 rxNO, u8 rxNO1)
+{
+ unsigned char ReCode = 0;
+ ReCode = ft5402_write_reg(client, FT5402_REG_RX_ORDER_START + rxNO,
+ rxNO1);
+ return ReCode;
+}
+
+/*get rx order*/
+static int ft5402_get_rx_order(struct i2c_client * client, u8 rxNO, u8 *prxNO1)
+{
+ unsigned char ReCode = 0;
+ ReCode = ft5402_read_reg(client, FT5402_REG_RX_ORDER_START + rxNO,
+ prxNO1);
+ return ReCode;
+}
+
+/*set rx cap*/
+static int ft5402_set_rx_cap(struct i2c_client * client, u8 rxNO, u8 cap_value)
+{
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1)
+ ReCode = ft5402_write_reg(client, FT5402_REG_RX_CAP_START + rxNO,
+ cap_value);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if(ReCode >= 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1,
+ cap_value);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*get rx cap*/
+static int ft5402_get_rx_cap(struct i2c_client * client, u8 rxNO, u8 *pCap)
+{
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client, FT5402_REG_RX_CAP_START + rxNO,
+ pCap);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if(ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_CAP_START + rxNO - FT5402_RX_TEST_MODE_1,
+ pCap);
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*set rx offset*/
+static int ft5402_set_rx_offset(struct i2c_client * client, u8 rxNO, u8 offset_value)
+{
+ unsigned char temp=0;
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp);
+ if (ReCode >= 0) {
+ if (rxNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1),
+ (temp&0xf0) + (offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1),
+ (temp&0x0f) + (offset_value<<4));
+ }
+ }
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_DEVICE_MODE+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ &temp); /*enter Test mode 2*/
+ if (ReCode >= 0) {
+ if (rxNO%2 == 0)
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value&0x0f));
+ else
+ ReCode = ft5402_write_reg(client,
+ FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ (temp&0xf0)+(offset_value<<4));
+ }
+ }
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ return ReCode;
+}
+
+/*get rx offset*/
+static int ft5402_get_rx_offset(struct i2c_client * client, u8 rxNO, u8 *pOffset)
+{
+ unsigned char temp = 0;
+ unsigned char ReCode = 0;
+ if (rxNO < FT5402_RX_TEST_MODE_1)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_OFFSET_START + (rxNO>>1), &temp);
+ else {
+ ReCode = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE_2<<4); /*enter Test mode 2*/
+ if (ReCode >= 0)
+ ReCode = ft5402_read_reg(client,
+ FT5402_REG_RX_OFFSET_START+((rxNO-FT5402_RX_TEST_MODE_1)>>1),
+ &temp);
+
+ ft5402_write_reg(client, FT5402_REG_DEVICE_MODE,
+ FT5402_REG_TEST_MODE<<4); /*enter Test mode*/
+ }
+
+ if (ReCode >= 0) {
+ if (0 == (rxNO%2))
+ *pOffset = (temp&0x0f);
+ else
+ *pOffset = (temp>>4);
+ }
+
+ return ReCode;
+}
+
+/*set tx num*/
+static int ft5402_set_tx_num(struct i2c_client *client, u8 txnum)
+{
+ return ft5402_write_reg(client, FT5402_REG_TX_NUM, txnum);
+}
+
+/*get tx num*/
+static int ft5402_get_tx_num(struct i2c_client *client, u8 *ptxnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_TX_NUM, ptxnum);
+}
+
+/*set rx num*/
+static int ft5402_set_rx_num(struct i2c_client *client, u8 rxnum)
+{
+ return ft5402_write_reg(client, FT5402_REG_RX_NUM, rxnum);
+}
+
+/*get rx num*/
+static int ft5402_get_rx_num(struct i2c_client *client, u8 *prxnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_RX_NUM, prxnum);
+}
+
+/*set resolution*/
+static int ft5402_set_Resolution(struct i2c_client *client, u16 x, u16 y)
+{
+ unsigned char cRet = 0;
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_X_H, ((unsigned char)(x>>8)));
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_X_L, ((unsigned char)(x&0x00ff)));
+
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_Y_H, ((unsigned char)(y>>8)));
+ cRet &= ft5402_write_reg(client,
+ FT5402_REG_RESOLUTION_Y_L, ((unsigned char)(y&0x00ff)));
+
+ return cRet;
+}
+
+/*get resolution*/
+static int ft5402_get_Resolution(struct i2c_client *client,
+ u16 *px, u16 *py)
+{
+ unsigned char cRet = 0, temp1 = 0, temp2 = 0;
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_X_H, &temp1);
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_X_L, &temp2);
+ (*px) = (((u16)temp1) << 8) | ((u16)temp2);
+
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_Y_H, &temp1);
+ cRet &= ft5402_read_reg(client,
+ FT5402_REG_RESOLUTION_Y_L, &temp2);
+ (*py) = (((u16)temp1) << 8) | ((u16)temp2);
+
+ return cRet;
+}
+
+
+/*set voltage*/
+static int ft5402_set_vol(struct i2c_client *client, u8 Vol)
+{
+ return ft5402_write_reg(client, FT5402_REG_VOLTAGE, Vol);
+}
+
+/*get voltage*/
+static int ft5402_get_vol(struct i2c_client *client, u8 *pVol)
+{
+ return ft5402_read_reg(client, FT5402_REG_VOLTAGE, pVol);
+}
+
+/*set gain*/
+static int ft5402_set_gain(struct i2c_client *client, u8 Gain)
+{
+ return ft5402_write_reg(client, FT5402_REG_GAIN, Gain);
+}
+
+/*get gain*/
+static int ft5402_get_gain(struct i2c_client *client, u8 *pGain)
+{
+ return ft5402_read_reg(client, FT5402_REG_GAIN, pGain);
+}
+
+/*get start rx*/
+static int ft5402_get_start_rx(struct i2c_client *client, u8 *pRx)
+{
+ return ft5402_read_reg(client, FT5402_REG_START_RX, pRx);
+}
+
+
+/*get adc target*/
+static int ft5402_get_adc_target(struct i2c_client *client, u16 *pvalue)
+{
+ int err = 0;
+ u8 tmp1, tmp2;
+ err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_HIGH,
+ &tmp1);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get adc target high failed\n",
+ __func__);
+ err = ft5402_read_reg(client, FT5402_REG_ADC_TARGET_LOW,
+ &tmp2);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get adc target low failed\n",
+ __func__);
+
+ *pvalue = ((u16)tmp1<<8) + (u16)tmp2;
+ return err;
+}
+
+static int ft5402_set_face_detect_statistics_tx_num(struct i2c_client *client, u8 prevalue)
+{
+ return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM,
+ prevalue);
+}
+
+static int ft5402_get_face_detect_statistics_tx_num(struct i2c_client *client, u8 *pprevalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM,
+ pprevalue);
+}
+
+static int ft5402_set_face_detect_pre_value(struct i2c_client *client, u8 prevalue)
+{
+ return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE,
+ prevalue);
+}
+
+static int ft5402_get_face_detect_pre_value(struct i2c_client *client, u8 *pprevalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_PRE_VALUE,
+ pprevalue);
+}
+
+static int ft5402_set_face_detect_num(struct i2c_client *client, u8 num)
+{
+ return ft5402_write_reg(client, FT5402_REG_FACE_DETECT_NUM,
+ num);
+}
+
+static int ft5402_get_face_detect_num(struct i2c_client *client, u8 *pnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_FACE_DETECT_NUM,
+ pnum);
+}
+
+
+static int ft5402_set_peak_value_min(struct i2c_client *client, u8 min)
+{
+ return ft5402_write_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN,
+ min);
+}
+
+static int ft5402_get_peak_value_min(struct i2c_client *client, u8 *pmin)
+{
+ return ft5402_read_reg(client, FT5402_REG_BIGAREA_PEAK_VALUE_MIN,
+ pmin);
+}
+
+static int ft5402_set_diff_value_over_num(struct i2c_client *client, u8 num)
+{
+ return ft5402_write_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM,
+ num);
+}
+static int ft5402_get_diff_value_over_num(struct i2c_client *client, u8 *pnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM,
+ pnum);
+}
+
+
+static int ft5402_set_customer_id(struct i2c_client *client, u8 num)
+{
+ return ft5402_write_reg(client, FT5402_REG_CUSTOMER_ID,
+ num);
+}
+static int ft5402_get_customer_id(struct i2c_client *client, u8 *pnum)
+{
+ return ft5402_read_reg(client, FT5402_REG_CUSTOMER_ID,
+ pnum);
+}
+
+static int ft5402_set_kx(struct i2c_client *client, u16 value)
+{
+ int err = 0;
+ err = ft5402_write_reg(client, FT5402_REG_KX_H,
+ value >> 8);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set kx high failed\n",
+ __func__);
+ err = ft5402_write_reg(client, FT5402_REG_KX_L,
+ value);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set kx low failed\n",
+ __func__);
+
+ return err;
+}
+
+static int ft5402_get_kx(struct i2c_client *client, u16 *pvalue)
+{
+ int err = 0;
+ u8 tmp1, tmp2;
+ err = ft5402_read_reg(client, FT5402_REG_KX_H,
+ &tmp1);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get kx high failed\n",
+ __func__);
+ err = ft5402_read_reg(client, FT5402_REG_KX_L,
+ &tmp2);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get kx low failed\n",
+ __func__);
+
+ *pvalue = ((u16)tmp1<<8) + (u16)tmp2;
+ return err;
+}
+static int ft5402_set_ky(struct i2c_client *client, u16 value)
+{
+ int err = 0;
+ err = ft5402_write_reg(client, FT5402_REG_KY_H,
+ value >> 8);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set ky high failed\n",
+ __func__);
+ err = ft5402_write_reg(client, FT5402_REG_KY_L,
+ value);
+ if (err < 0)
+ dev_err(&client->dev, "%s:set ky low failed\n",
+ __func__);
+
+ return err;
+}
+
+static int ft5402_get_ky(struct i2c_client *client, u16 *pvalue)
+{
+ int err = 0;
+ u8 tmp1, tmp2;
+ err = ft5402_read_reg(client, FT5402_REG_KY_H,
+ &tmp1);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get ky high failed\n",
+ __func__);
+ err = ft5402_read_reg(client, FT5402_REG_KY_L,
+ &tmp2);
+ if (err < 0)
+ dev_err(&client->dev, "%s:get ky low failed\n",
+ __func__);
+
+ *pvalue = ((u16)tmp1<<8) + (u16)tmp2;
+ return err;
+}
+static int ft5402_set_lemda_x(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_LEMDA_X,
+ value);
+}
+
+static int ft5402_get_lemda_x(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_LEMDA_X,
+ pvalue);
+}
+static int ft5402_set_lemda_y(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_LEMDA_Y,
+ value);
+}
+
+static int ft5402_get_lemda_y(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_LEMDA_Y,
+ pvalue);
+}
+static int ft5402_set_pos_x(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_DIRECTION,
+ value);
+}
+
+static int ft5402_get_pos_x(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_DIRECTION,
+ pvalue);
+}
+
+static int ft5402_set_scan_select(struct i2c_client *client, u8 value)
+{
+ return ft5402_write_reg(client, FT5402_REG_SCAN_SELECT,
+ value);
+}
+
+static int ft5402_get_scan_select(struct i2c_client *client, u8 *pvalue)
+{
+ return ft5402_read_reg(client, FT5402_REG_SCAN_SELECT,
+ pvalue);
+}
+
+static int ft5402_set_other_param(struct i2c_client *client)
+{
+ int err = 0;
+ err = ft5402_write_reg(client, FT5402_REG_THGROUP, (u8)(g_param_ft5402.ft5402_THGROUP));
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_THPEAK, g_param_ft5402.ft5402_THPEAK);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THPEAK failed.\n",
+ __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_PWMODE_CTRL,
+ g_param_ft5402.ft5402_PWMODE_CTRL);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PERIOD_CTRL failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_PERIOD_ACTIVE,
+ g_param_ft5402.ft5402_PERIOD_ACTIVE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM,
+ g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FACE_DETECT_STATISTICS_TX_NUM failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH,
+ g_param_ft5402.ft5402_MAX_TOUCH_VALUE>>8);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW,
+ g_param_ft5402.ft5402_MAX_TOUCH_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FACE_DETECT_MODE,
+ g_param_ft5402.ft5402_FACE_DETECT_MODE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_DRAW_LINE_TH,
+ g_param_ft5402.ft5402_DRAW_LINE_TH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_POINTS_SUPPORTED,
+ g_param_ft5402.ft5402_POINTS_SUPPORTED);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write POINTS_SUPPORTED failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_ESD_FILTER_FRAME,
+ g_param_ft5402.ft5402_ESD_FILTER_FRAME);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAME failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO,
+ g_param_ft5402.ft5402_POINTS_STABLE_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_POINTS_STABLE_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_X,
+ g_param_ft5402.ft5402_MIN_DELTA_X);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_X failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y,
+ g_param_ft5402.ft5402_MIN_DELTA_Y);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_Y failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP,
+ g_param_ft5402.ft5402_MIN_DELTA_STEP);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_DELTA_STEP failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO,
+ g_param_ft5402.ft5402_ESD_NOISE_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_NOISE_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL,
+ g_param_ft5402.ft5402_ESD_DIFF_VAL);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_DIFF_VAL failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE,
+ g_param_ft5402.ft5402_ESD_NEGTIVE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_NEGTIVE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES,
+ g_param_ft5402.ft5402_ESD_FILTER_FRAMES);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_ESD_FILTER_FRAMES failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT,
+ g_param_ft5402.ft5402_IO_LEVEL_SELECT);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_IO_LEVEL_SELECT failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT,
+ g_param_ft5402.ft5402_POINTID_DELAY_COUNT);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_POINTID_DELAY_COUNT failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO,
+ g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_LIFTUP_FILTER_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO,
+ g_param_ft5402.ft5402_DIFF_HANDLE_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_DIFF_HANDLE_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MIN_WATER,
+ g_param_ft5402.ft5402_MIN_WATER);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MIN_WATER failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_MAX_NOISE,
+ g_param_ft5402.ft5402_MAX_NOISE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_MAX_NOISE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_RX,
+ g_param_ft5402.ft5402_WATER_START_RX);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_WATER_START_RX failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_WATER_START_TX,
+ g_param_ft5402.ft5402_WATER_START_TX);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_WATER_START_TX failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO,
+ g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_RAISE_THGROUP,
+ g_param_ft5402.ft5402_RAISE_THGROUP);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_RAISE_THGROUP failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_CHARGER_STATE,
+ g_param_ft5402.ft5402_CHARGER_STATE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_CHARGER_STATE failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FILTERID_START,
+ g_param_ft5402.ft5402_FILTERID_START);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FILTERID_START failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO,
+ g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_EN_MACRO failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH,
+ g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH,
+ g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN,
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_EN failed.\n", __func__);
+ return err;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH,
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__);
+ return err;
+ }
+
+ return err;
+}
+
+static int ft5402_get_other_param(struct i2c_client *client)
+{
+ int err = 0;
+ u8 value = 0x00;
+ err = ft5402_read_reg(client, FT5402_REG_THGROUP, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THGROUP failed.\n", __func__);
+ return err;
+ } else
+ DBG("THGROUP=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_THPEAK, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write THPEAK failed.\n",
+ __func__);
+ return err;
+ } else
+ DBG("THPEAK=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_PWMODE_CTRL, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PWMODE_CTRL failed.\n", __func__);
+ return err;
+ } else
+ DBG("CTRL=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_PERIOD_ACTIVE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write PERIOD_ACTIVE failed.\n", __func__);
+ return err;
+ } else
+ DBG("PERIOD_ACTIVE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_HIGH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_HIGH failed.\n", __func__);
+ return err;
+ } else
+ DBG("MAX_TOUCH_VALUE_HIGH=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_MAX_TOUCH_VALUE_LOW,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write MAX_TOUCH_VALUE_LOW failed.\n", __func__);
+ return err;
+ } else
+ DBG("MAX_TOUCH_VALUE_LOW=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_FACE_DETECT_MODE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FACE_DETECT_MODE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FACE_DEC_MODE=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_DRAW_LINE_TH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write DRAW_LINE_TH failed.\n", __func__);
+ return err;
+ } else
+ DBG("DRAW_LINE_TH=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_POINTS_SUPPORTED,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ft5402_POINTS_SUPPORTED failed.\n", __func__);
+ return err;
+ } else
+ DBG("ft5402_POINTS_SUPPORTED=%02x\n", value);
+ err = ft5402_read_reg(client, FT5402_REG_ESD_FILTER_FRAME,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_ESD_FILTER_FRAME failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_ESD_FILTER_FRAME=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTS_STABLE_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTS_STABLE_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_POINTS_STABLE_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_X,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_X failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_DELTA_X=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_Y,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_Y failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_DELTA_Y=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_DELTA_STEP,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_DELTA_STEP failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_DELTA_STEP=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NOISE_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NOISE_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_NOISE_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_DIFF_VAL,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_DIFF_VAL failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_DIFF_VAL=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_NEGTIVE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_NEGTIVE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_NEGTIVE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_ESD_FILTER_FRAMES,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_ESD_FILTER_FRAMES failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_ESD_FILTER_FRAMES=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_IO_LEVEL_SELECT,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_IO_LEVEL_SELECT failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_IO_LEVEL_SELECT=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_POINTID_DELAY_COUNT,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_POINTID_DELAY_COUNT failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_POINTID_DELAY_COUNT=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_LIFTUP_FILTER_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_LIFTUP_FILTER_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_LIFTUP_FILTER_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_DIFF_HANDLE_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_DIFF_HANDLE_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_DIFF_HANDLE_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MIN_WATER,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MIN_WATER failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MIN_WATER=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_MAX_NOISE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_MAX_NOISE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_MAX_NOISE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_RX,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_RX failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_WATER_START_RX=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_WATER_START_TX,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_WATER_START_TX failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_WATER_START_TX=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_RAISE_THGROUP,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_RAISE_THGROUP failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_RAISE_THGROUP=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_CHARGER_STATE,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_CHARGER_STATE failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_CHARGER_STATE=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FILTERID_START,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FILTERID_START failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FILTERID_START=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_EN,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_EN failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_EN=%02x\n", value);
+
+ err = ft5402_read_reg(client, FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH failed.\n", __func__);
+ return err;
+ } else
+ DBG("FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH=%02x\n", value);
+
+ return err;
+}
+int ft5402_get_ic_param(struct i2c_client *client)
+{
+ int err = 0;
+ int i = 0;
+ u8 value = 0x00;
+ u16 xvalue = 0x0000, yvalue = 0x0000;
+
+ /*enter factory mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__);
+ goto RETURN_WORK;
+ }
+
+ for (i = 0; i < g_ft5402_tx_num; i++) {
+ DBG("tx%d:", i);
+ /*get tx order*/
+ err = ft5402_get_tx_order(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("order=%d ", value);
+ /*get tx cap*/
+ err = ft5402_get_tx_cap(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("cap=%02x\n", value);
+ }
+ /*get tx offset*/
+ err = ft5402_get_tx_offset(client, 0, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx 0 offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("tx offset = %02x\n", value);
+
+ /*get rx offset and cap*/
+ for (i = 0; i < g_ft5402_rx_num; i++) {
+ /*get rx order*/
+ DBG("rx%d:", i);
+ err = ft5402_get_rx_order(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("order=%d ", value);
+ /*get rx cap*/
+ err = ft5402_get_rx_cap(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ DBG("cap=%02x ", value);
+ err = ft5402_get_rx_offset(client, i, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ DBG("offset=%02x\n", value);
+ }
+
+ /*get scan select*/
+ err = ft5402_get_scan_select(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get scan select.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("scan select = %02x\n", value);
+
+ /*get tx number*/
+ err = ft5402_get_tx_num(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get tx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("tx num = %02x\n", value);
+ /*get rx number*/
+ err = ft5402_get_rx_num(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get rx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("rx num = %02x\n", value);
+
+ /*get gain*/
+ err = ft5402_get_gain(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get gain.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("gain = %02x\n", value);
+ /*get voltage*/
+ err = ft5402_get_vol(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get voltage.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("voltage = %02x\n", value);
+ /*get start rx*/
+ err = ft5402_get_start_rx(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get start rx.\n",
+ __func__);
+ goto RETURN_WORK;
+ } else
+ DBG("start rx = %02x\n", value);
+ /*get adc target*/
+ err = ft5402_get_adc_target(client, &xvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get adc target.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("ADC target = %02x\n", xvalue);
+
+
+RETURN_WORK:
+ /*enter work mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter work mode failed.\n", __func__);
+ goto ERR_EXIT;
+ }
+
+ /*get resolution*/
+ err = ft5402_get_Resolution(client, &xvalue, &yvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get resolution.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("resolution X = %d Y = %d\n", xvalue, yvalue);
+
+
+ /*get face detect statistics tx num*/
+ err = ft5402_get_face_detect_statistics_tx_num(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not get face detect statistics tx num.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_FACE_DETECT_STATISTICS_TX_NUM = %02x\n", value);
+ /*get face detect pre value*/
+ err = ft5402_get_face_detect_pre_value(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not get face detect pre value.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_FACE_DETECT_PRE_VALUE = %02x\n", value);
+ /*get face detect num*/
+ err = ft5402_get_face_detect_num(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get face detect num.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("face detect num = %02x\n", value);
+
+ /*get min peak value*/
+ err = ft5402_get_peak_value_min(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get min peak value.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_BIGAREA_PEAK_VALUE_MIN = %02x\n", value);
+ /*get diff value over num*/
+ err = ft5402_get_diff_value_over_num(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get diff value over num.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_BIGAREA_DIFF_VALUE_OVER_NUM = %02x\n", value);
+ /*get customer id*/
+ err = ft5402_get_customer_id(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get customer id.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("FT5402_CUSTOMER_ID = %02x\n", value);
+ /*get kx*/
+ err = ft5402_get_kx(client, &xvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get kx.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("kx = %02x\n", xvalue);
+ /*get ky*/
+ err = ft5402_get_ky(client, &xvalue);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get ky.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("ky = %02x\n", xvalue);
+ /*get lemda x*/
+ err = ft5402_get_lemda_x(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get lemda x.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("lemda x = %02x\n", value);
+ /*get lemda y*/
+ err = ft5402_get_lemda_y(client,
+ &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get lemda y.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("lemda y = %02x\n", value);
+ /*get pos x*/
+ err = ft5402_get_pos_x(client, &value);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not get pos x.\n",
+ __func__);
+ goto ERR_EXIT;
+ } else
+ DBG("pos x = %02x\n", value);
+
+ err = ft5402_get_other_param(client);
+
+ERR_EXIT:
+ return err;
+}
+
+int ft5402_Init_IC_Param(struct i2c_client *client)
+{
+ int err = 0;
+ int i = 0;
+
+ /*enter factory mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_FACTORYMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter factory mode failed.\n", __func__);
+ goto RETURN_WORK;
+ }
+
+ for (i = 0; i < g_ft5402_tx_num; i++) {
+ if (g_ft5402_tx_order[i] != 0xFF) {
+ /*set tx order*/
+ err = ft5402_set_tx_order(client, i, g_ft5402_tx_order[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ }
+ /*set tx cap*/
+ err = ft5402_set_tx_cap(client, i, g_ft5402_tx_cap[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ }
+ /*set tx offset*/
+ err = ft5402_set_tx_offset(client, 0, g_ft5402_tx_offset);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx 0 offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ /*set rx offset and cap*/
+ for (i = 0; i < g_ft5402_rx_num; i++) {
+ /*set rx order*/
+ err = ft5402_set_rx_order(client, i, g_ft5402_rx_order[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx%d order.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ /*set rx cap*/
+ err = ft5402_set_rx_cap(client, i, g_ft5402_rx_cap[i]);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx%d cap.\n",
+ __func__, i);
+ goto RETURN_WORK;
+ }
+ }
+ for (i = 0; i < g_ft5402_rx_num/2; i++) {
+ err = ft5402_set_rx_offset(client, i*2, g_ft5402_rx_offset[i]>>4);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ err = ft5402_set_rx_offset(client, i*2+1, g_ft5402_rx_offset[i]&0x0F);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx offset.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ }
+
+ /*set scan select*/
+ err = ft5402_set_scan_select(client, g_ft5402_scanselect);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set scan select.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ /*set tx number*/
+ err = ft5402_set_tx_num(client, g_ft5402_tx_num);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set tx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ /*set rx number*/
+ err = ft5402_set_rx_num(client, g_ft5402_rx_num);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set rx num.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ /*set gain*/
+ err = ft5402_set_gain(client, g_ft5402_gain);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set gain.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+ /*set voltage*/
+ err = ft5402_set_vol(client, g_ft5402_voltage);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set voltage.\n",
+ __func__);
+ goto RETURN_WORK;
+ }
+
+ err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_HIGH,
+ g_param_ft5402.ft5402_ADC_TARGET>>8);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ADC_TARGET_HIGH failed.\n", __func__);
+ return err;
+ }
+ err = ft5402_write_reg(client, FT5402_REG_ADC_TARGET_LOW,
+ g_param_ft5402.ft5402_ADC_TARGET);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:write ADC_TARGET_LOW failed.\n", __func__);
+ return err;
+ }
+
+RETURN_WORK:
+ /*enter work mode*/
+ err = ft5402_write_reg(client, FT5402_REG_DEVICE_MODE, FT5402_WORKMODE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:enter work mode failed.\n", __func__);
+ goto ERR_EXIT;
+ }
+
+ /*set resolution*/
+ err = ft5402_set_Resolution(client, g_param_ft5402.ft5402_RESOLUTION_X,
+ g_param_ft5402.ft5402_RESOLUTION_Y);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set resolution.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+
+ /*set face detect statistics tx num*/
+ err = ft5402_set_face_detect_statistics_tx_num(client,
+ g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not set face detect statistics tx num.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set face detect pre value*/
+ err = ft5402_set_face_detect_pre_value(client,
+ g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s:could not set face detect pre value.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set face detect num*/
+ err = ft5402_set_face_detect_num(client,
+ g_param_ft5402.ft5402_FACE_DETECT_NUM);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set face detect num.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+
+ /*set min peak value*/
+ err = ft5402_set_peak_value_min(client,
+ g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set min peak value.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set diff value over num*/
+ err = ft5402_set_diff_value_over_num(client,
+ g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set diff value over num.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set customer id*/
+ err = ft5402_set_customer_id(client,
+ g_param_ft5402.ft5402_CUSTOMER_ID);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set customer id.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set kx*/
+ err = ft5402_set_kx(client, g_param_ft5402.ft5402_KX);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set kx.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set ky*/
+ err = ft5402_set_ky(client, g_param_ft5402.ft5402_KY);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set ky.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set lemda x*/
+ err = ft5402_set_lemda_x(client,
+ g_param_ft5402.ft5402_LEMDA_X);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set lemda x.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set lemda y*/
+ err = ft5402_set_lemda_y(client,
+ g_param_ft5402.ft5402_LEMDA_Y);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set lemda y.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+ /*set pos x*/
+ err = ft5402_set_pos_x(client, g_param_ft5402.ft5402_DIRECTION);
+ if (err < 0) {
+ dev_err(&client->dev, "%s:could not set pos x.\n",
+ __func__);
+ goto ERR_EXIT;
+ }
+
+ err = ft5402_set_other_param(client);
+
+ERR_EXIT:
+ return err;
+}
+
+
+char dst[512];
+static char * ft5402_sub_str(char * src, int n)
+{
+ char *p = src;
+ int i;
+ int m = 0;
+ int len = strlen(src);
+
+ while (n >= 1 && m <= len) {
+ i = 0;
+ dst[10] = ' ';
+ n--;
+ while ( *p != ',' && *p != ' ') {
+ dst[i++] = *(p++);
+ m++;
+ if (i >= len)
+ break;
+ }
+ dst[i++] = '\0';
+ p++;
+ }
+ return dst;
+}
+static int ft5402_GetInISize(char *config_name)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize = 0;
+ char filepath[128];
+ memset(filepath, 0, sizeof(filepath));
+
+ sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name);
+
+ if (NULL == pfile)
+ pfile = filp_open(filepath, O_RDONLY, 0);
+
+ if (IS_ERR(pfile)) {
+ pr_err("error occured while opening file %s.\n", filepath);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ filp_close(pfile, NULL);
+ return fsize;
+}
+
+static int ft5x0x_ReadInIData(char *config_name,
+ char *config_buf)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize;
+ char filepath[128];
+ loff_t pos;
+ mm_segment_t old_fs;
+
+ memset(filepath, 0, sizeof(filepath));
+ sprintf(filepath, "%s%s", FT5402_INI_FILEPATH, config_name);
+ if (NULL == pfile)
+ pfile = filp_open(filepath, O_RDONLY, 0);
+ if (IS_ERR(pfile)) {
+ pr_err("error occured while opening file %s.\n", filepath);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ pos = 0;
+ vfs_read(pfile, config_buf, fsize, &pos);
+ filp_close(pfile, NULL);
+ set_fs(old_fs);
+
+ return 0;
+}
+
+int ft5402_Get_Param_From_Ini(char *config_name)
+{
+ char key[64];
+ char value[512];
+ char section[64];
+ int i = 0;//,ret=0;
+ int j = 0;
+ char *filedata = NULL;
+ unsigned char legal_byte1 = 0x00;
+ unsigned char legal_byte2 = 0x00;
+
+ int inisize = ft5402_GetInISize(config_name);
+
+ if (inisize <= 0) {
+ pr_err("%s ERROR:Get firmware size failed\n",
+ __func__);
+ return -EIO;
+ }
+
+ filedata = kmalloc(inisize + 1, GFP_ATOMIC);
+
+ if (ft5x0x_ReadInIData(config_name, filedata)) {
+ pr_err("%s() - ERROR: request_firmware failed\n",
+ __func__);
+ kfree(filedata);
+ return -EIO;
+ }
+
+ /*check ini if it is illegal*/
+ sprintf(section, "%s", FT5402_APP_LEGAL);
+ sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_1_STR);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ legal_byte1 = atoi(value);
+ DBG("legal_byte1=%s\n", value);
+ sprintf(key, "%s", FT5402_APP_LEGAL_BYTE_2_STR);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ legal_byte2 = atoi(value);
+ DBG("lega2_byte1=%s\n", value);
+ if(FT5402_APP_LEGAL_BYTE_1_VALUE == legal_byte1 &&
+ FT5402_APP_LEGAL_BYTE_2_VALUE == legal_byte2)
+ DBG("the ini file is valid\n");
+ else {
+ pr_err("[FTS]-----the ini file is invalid!please check it.\n");
+ goto ERROR_RETURN;
+ }
+
+ /*get ini param*/
+ sprintf(section, "%s", FT5402_APP_NAME);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_KX = atoi(value);
+ DBG("ft5402_KX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_KY = atoi(value);
+ DBG("ft5402_KY=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_LEMDA_X = atoi(value);
+ DBG("ft5402_LEMDA_X=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_LEMDA_Y = atoi(value);
+ DBG("ft5402_LEMDA_Y=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_RESOLUTION_X = atoi(value);
+ DBG("ft5402_RESOLUTION_X=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_RESOLUTION_Y = atoi(value);
+ DBG("ft5402_RESOLUTION_Y=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_DIRECTION= atoi(value);
+ DBG("ft5402_DIRECTION=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_PRE_VALUE = atoi(value);
+ DBG("ft5402_FACE_DETECT_PRE_VALUE=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_NUM = atoi(value);
+ DBG("ft5402_FACE_DETECT_NUM=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_BIGAREA_PEAK_VALUE_MIN = atoi(value);/*The min value to be decided as the big point*/
+ DBG("ft5402_BIGAREA_PEAK_VALUE_MIN=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_BIGAREA_DIFF_VALUE_OVER_NUM = atoi(value);/*The min big points of the big area*/
+ DBG("ft5402_BIGAREA_DIFF_VALUE_OVER_NUM=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_CUSTOMER_ID = atoi(value);
+ DBG("ft5402_CUSTOM_ID=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_PERIOD_ACTIVE = atoi(value);
+ DBG("ft5402_PERIOD_ACTIVE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_STATISTICS_TX_NUM = atoi(value);
+ DBG("ft5402_FACE_DETECT_STATISTICS_TX_NUM=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_THGROUP = atoi(value);
+ DBG("ft5402_THGROUP=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_THPEAK = atoi(value);
+ DBG("ft5402_THPEAK=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FACE_DETECT_MODE = atoi(value);
+ DBG("ft5402_FACE_DETECT_MODE=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MAX_TOUCH_VALUE = atoi(value);
+ DBG("ft5402_MAX_TOUCH_VALUE=%s\n", value);
+
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_PWMODE_CTRL= atoi(value);
+ DBG("ft5402_PWMODE_CTRL=%s\n", value);
+
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+
+ i++;
+ g_param_ft5402.ft5402_DRAW_LINE_TH = atoi(value);
+ DBG("ft5402_DRAW_LINE_TH=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_POINTS_SUPPORTED= atoi(value);
+ DBG("ft5402_POINTS_SUPPORTED=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_START_RX = atoi(value);
+ DBG("ft5402_START_RX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+
+ g_param_ft5402.ft5402_ADC_TARGET = atoi(value);
+ DBG("ft5402_ADC_TARGET=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+
+ g_param_ft5402.ft5402_ESD_FILTER_FRAME = atoi(value);
+ DBG("ft5402_ESD_FILTER_FRAME=%s\n", value);
+
+/*********************************************************************/
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_tx_num = atoi(value);
+ DBG("ft5402_tx_num=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_rx_num = atoi(value);
+ DBG("ft5402_rx_num=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_gain = atoi(value);
+ DBG("ft5402_gain=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_voltage = atoi(value);
+ DBG("ft5402_voltage=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_scanselect = atoi(value);
+ DBG("ft5402_scanselect=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_tx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_tx_order[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_tx_order=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_ft5402_tx_offset = atoi(value);
+ DBG("ft5402_tx_offset=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_tx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_tx_cap[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_tx_cap=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_rx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_rx_order[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_rx_order=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_rx_num/2; j++)
+ {
+ char * psrc = value;
+ g_ft5402_rx_offset[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_rx_offset=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ for(j = 0; j < g_ft5402_rx_num; j++)
+ {
+ char * psrc = value;
+ g_ft5402_rx_cap[j] = atoi(ft5402_sub_str(psrc, j+1));
+ }
+ DBG("ft5402_rx_cap=%s\n", value);
+
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_POINTS_STABLE_MACRO = atoi(value);
+ DBG("ft5402_POINTS_STABLE_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_DELTA_X = atoi(value);
+ DBG("ft5402_MIN_DELTA_X=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_DELTA_Y = atoi(value);
+ DBG("ft5402_MIN_DELTA_Y=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_DELTA_STEP = atoi(value);
+ DBG("ft5402_MIN_DELTA_STEP=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_NOISE_MACRO = atoi(value);
+ DBG("ft5402_ESD_NOISE_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_DIFF_VAL = atoi(value);
+ DBG("ft5402_ESD_DIFF_VAL=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_NEGTIVE = atoi(value);
+ DBG("ft5402_ESD_NEGTIVE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_ESD_FILTER_FRAMES = atoi(value);
+ DBG("ft5402_ESD_FILTER_FRAMES=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_IO_LEVEL_SELECT = atoi(value);
+ DBG("ft5402_IO_LEVEL_SELECT=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_POINTID_DELAY_COUNT = atoi(value);
+ DBG("ft5402_POINTID_DELAY_COUNT=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_LIFTUP_FILTER_MACRO = atoi(value);
+ DBG("ft5402_LIFTUP_FILTER_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_DIFF_HANDLE_MACRO = atoi(value);
+ DBG("ft5402_DIFF_HANDLE_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MIN_WATER = atoi(value);
+ DBG("ft5402_MIN_WATER=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_MAX_NOISE = atoi(value);
+ DBG("ft5402_MAX_NOISE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_WATER_START_RX = atoi(value);
+ DBG("ft5402_WATER_START_RX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_WATER_START_TX = atoi(value);
+ DBG("ft5402_WATER_START_TX=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_HOST_NUMBER_SUPPORTED_MACRO = atoi(value);
+ DBG("ft5402_HOST_NUMBER_SUPPORTED_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_RAISE_THGROUP = atoi(value);
+ DBG("ft5402_RAISE_THGROUP=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_CHARGER_STATE = atoi(value);
+ DBG("ft5402_CHARGER_STATE=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FILTERID_START = atoi(value);
+ DBG("ft5402_FILTERID_START=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_EN_MACRO = atoi(value);
+ DBG("ft5402_FRAME_FILTER_EN_MACRO=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_SUB_MAX_TH = atoi(value);
+ DBG("ft5402_FRAME_FILTER_SUB_MAX_TH=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_ADD_MAX_TH = atoi(value);
+ DBG("ft5402_FRAME_FILTER_ADD_MAX_TH=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_SKIP_START_FRAME = atoi(value);
+ DBG("ft5402_FRAME_FILTER_SKIP_START_FRAME=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_EN = atoi(value);
+ DBG("ft5402_FRAME_FILTER_BAND_EN=%s\n", value);
+
+ sprintf(key, "%s", String_Param_FT5402[i]);
+ if (ini_get_key(filedata,section,key,value)<0)
+ goto ERROR_RETURN;
+ i++;
+ g_param_ft5402.ft5402_FRAME_FILTER_BAND_WIDTH = atoi(value);
+ DBG("ft5402_FRAME_FILTER_BAND_WIDTH=%s\n", value);
+
+
+ if (filedata)
+ kfree(filedata);
+ return 0;
+ERROR_RETURN:
+ if (filedata)
+ kfree(filedata);
+ return -1;
+}
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h new file mode 100755 index 00000000..4d4935ed --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_config.h @@ -0,0 +1,71 @@ +#ifndef __FT5402_CONFIG_H__
+#define __FT5402_CONFIG_H__
+/*FT5402 config*/
+
+
+#define FT5402_START_RX 0
+#define FT5402_ADC_TARGET 8500
+#define FT5402_KX 120
+#define FT5402_KY 120
+#define FT5402_RESOLUTION_X 480
+#define FT5402_RESOLUTION_Y 800
+#define FT5402_LEMDA_X 0
+#define FT5402_LEMDA_Y 0
+#define FT5402_PWMODE_CTRL 1
+#define FT5402_POINTS_SUPPORTED 5
+#define FT5402_DRAW_LINE_TH 150
+#define FT5402_FACE_DETECT_MODE 0
+#define FT5402_FACE_DETECT_STATISTICS_TX_NUM 3
+#define FT5402_FACE_DETECT_PRE_VALUE 20
+#define FT5402_FACE_DETECT_NUM 10
+#define FT5402_THGROUP 25
+#define FT5402_THPEAK 60
+#define FT5402_BIGAREA_PEAK_VALUE_MIN 100
+#define FT5402_BIGAREA_DIFF_VALUE_OVER_NUM 50
+#define FT5402_MIN_DELTA_X 2
+#define FT5402_MIN_DELTA_Y 2
+#define FT5402_MIN_DELTA_STEP 2
+#define FT5402_ESD_DIFF_VAL 20
+#define FT5402_ESD_NEGTIVE -50
+#define FT5402_ESD_FILTER_FRAME 10
+#define FT5402_MAX_TOUCH_VALUE 600
+#define FT5402_CUSTOMER_ID 121
+#define FT5402_IO_LEVEL_SELECT 0
+#define FT5402_DIRECTION 1
+#define FT5402_POINTID_DELAY_COUNT 3
+#define FT5402_LIFTUP_FILTER_MACRO 1
+#define FT5402_POINTS_STABLE_MACRO 1
+#define FT5402_ESD_NOISE_MACRO 1
+#define FT5402_RV_G_PERIOD_ACTIVE 16
+#define FT5402_DIFFDATA_HANDLE 1
+#define FT5402_MIN_WATER_VAL -50
+#define FT5402_MAX_NOISE_VAL 10
+#define FT5402_WATER_HANDLE_START_RX 0
+#define FT5402_WATER_HANDLE_START_TX 0
+#define FT5402_HOST_NUMBER_SUPPORTED 1
+#define FT5402_RV_G_RAISE_THGROUP 30
+#define FT5402_RV_G_CHARGER_STATE 0
+#define FT5402_RV_G_FILTERID_START 2
+#define FT5402_FRAME_FILTER_EN 1
+#define FT5402_FRAME_FILTER_SUB_MAX_TH 2
+#define FT5402_FRAME_FILTER_ADD_MAX_TH 2
+#define FT5402_FRAME_FILTER_SKIP_START_FRAME 6
+#define FT5402_FRAME_FILTER_BAND_EN 1
+#define FT5402_FRAME_FILTER_BAND_WIDTH 128
+#define FT5402_OTP_PARAM_ID 0
+
+
+unsigned char g_ft5402_tx_num = 27;
+unsigned char g_ft5402_rx_num = 16;
+unsigned char g_ft5402_gain = 10;
+unsigned char g_ft5402_voltage = 3;
+unsigned char g_ft5402_scanselect = 8;
+unsigned char g_ft5402_tx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26};
+unsigned char g_ft5402_tx_offset = 2;
+unsigned char g_ft5402_tx_cap[] = {42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42};
+unsigned char g_ft5402_rx_order[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+unsigned char g_ft5402_rx_offset[] = {68,68,68,68,68,68,68,68};
+unsigned char g_ft5402_rx_cap[] = {84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84};
+
+
+#endif
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h new file mode 100755 index 00000000..138f42e2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5402_ini_config.h @@ -0,0 +1,411 @@ +#ifndef __LINUX_FT5402_INI_CONFIG_H__
+#define __LINUX_FT5402_INI_CONFIG_H
+
+
+/*Init param register address*/
+/*factory mode register from 14-131*/
+#define FT5402_REG_TX_NUM 0x03
+#define FT5402_REG_RX_NUM 0x04
+#define FT5402_REG_VOLTAGE 0x05
+#define FT5402_REG_GAIN 0x07
+#define FT5402_REG_SCAN_SELECT 0x4E
+#define FT5402_REG_TX_ORDER_START 0x50
+#define FT5402_REG_TX_CAP_START 0x78
+#define FT5402_REG_TX_OFFSET_START 0xBF
+#define FT5402_REG_RX_ORDER_START 0xeb
+#define FT5402_REG_RX_CAP_START 0xA0
+#define FT5402_REG_RX_OFFSET_START 0xD3
+#define FT5402_REG_START_RX 0x06
+#define FT5402_REG_ADC_TARGET_HIGH 0x08
+#define FT5402_REG_ADC_TARGET_LOW 0x09
+
+
+#define FT5402_REG_DEVICE_MODE 0x00
+
+
+/*work mode register from 0-13(0,1,12,13verify or Reserved)and 132-177(159 Reserved)*/
+#define FT5402_REG_THGROUP (0x00+0x80)
+#define FT5402_REG_THPEAK (0x01+0x80)
+#define FT5402_REG_PWMODE_CTRL (0x06+0x80)
+#define FT5402_REG_PERIOD_ACTIVE (0x59+0x80)
+#define FT5402_REG_POINTS_SUPPORTED (0x0A+0x80)
+#define FT5402_REG_ESD_FILTER_FRAME (0x4F+0x80)
+
+#define FT5402_REG_RESOLUTION_X_H (0x18+0x80)
+#define FT5402_REG_RESOLUTION_X_L (0x19+0x80)
+#define FT5402_REG_RESOLUTION_Y_H (0x1a+0x80)
+#define FT5402_REG_RESOLUTION_Y_L (0x1b+0x80)
+#define FT5402_REG_KX_H (0x1c+0x80)
+#define FT5402_REG_KX_L (0x9d)
+#define FT5402_REG_KY_H (0x9e)
+#define FT5402_REG_KY_L (0x1f+0x80)
+#define FT5402_REG_CUSTOMER_ID (0xA8)
+#define FT5402_REG_DRAW_LINE_TH (0xAe)
+#define FT5402_REG_FACE_DETECT_MODE (0xB0)
+#define FT5402_REG_MAX_TOUCH_VALUE_HIGH (0xD0)
+#define FT5402_REG_MAX_TOUCH_VALUE_LOW (0xD1)
+
+#define FT5402_REG_DIRECTION (0x53+0x80)
+#define FT5402_REG_LEMDA_X (0x41+0x80)
+#define FT5402_REG_LEMDA_Y (0x42+0x80)
+#define FT5402_REG_FACE_DETECT_STATISTICS_TX_NUM (0x43+0x80)
+#define FT5402_REG_FACE_DETECT_PRE_VALUE (0x44+0x80)
+#define FT5402_REG_FACE_DETECT_NUM (0x45+0x80)
+#define FT5402_REG_BIGAREA_PEAK_VALUE_MIN (0x33+0x80)
+#define FT5402_REG_BIGAREA_DIFF_VALUE_OVER_NUM (0x34+0x80)
+
+/**************************************************************************/
+#define FT5402_REG_FT5402_POINTS_STABLE_MACRO (0x57+0x80)
+#define FT5402_REG_FT5402_MIN_DELTA_X (0x4a+0x80)
+#define FT5402_REG_FT5402_MIN_DELTA_Y (0x4b+0x80)
+#define FT5402_REG_FT5402_MIN_DELTA_STEP (0x4c+0x80)
+
+#define FT5402_REG_FT5402_ESD_NOISE_MACRO (0x58+0x80)
+#define FT5402_REG_FT5402_ESD_DIFF_VAL (0x4d+0x80)
+#define FT5402_REG_FT5402_ESD_NEGTIVE (0xCe)
+#define FT5402_REG_FT5402_ESD_FILTER_FRAMES (0x4f+0x80)
+
+#define FT5402_REG_FT5402_IO_LEVEL_SELECT (0x52+0x80)
+
+#define FT5402_REG_FT5402_POINTID_DELAY_COUNT (0x54+0x80)
+
+#define FT5402_REG_FT5402_LIFTUP_FILTER_MACRO (0x55+0x80)
+
+#define FT5402_REG_FT5402_DIFF_HANDLE_MACRO (0x5A+0x80)
+#define FT5402_REG_FT5402_MIN_WATER (0x5B+0x80)
+#define FT5402_REG_FT5402_MAX_NOISE (0x5C+0x80)
+#define FT5402_REG_FT5402_WATER_START_RX (0x5D+0x80)
+#define FT5402_REG_FT5402_WATER_START_TX (0xDE)
+
+#define FT5402_REG_FT5402_HOST_NUMBER_SUPPORTED_MACRO (0x38+0x80)
+#define FT5402_REG_FT5402_RAISE_THGROUP (0x36+0x80)
+#define FT5402_REG_FT5402_CHARGER_STATE (0x35+0x80)
+
+#define FT5402_REG_FT5402_FILTERID_START (0x37+0x80)
+
+#define FT5402_REG_FT5402_FRAME_FILTER_EN_MACRO (0x5F+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_SUB_MAX_TH (0x60+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_ADD_MAX_TH (0x61+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_SKIP_START_FRAME (0x62+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_BAND_EN (0x63+0x80)
+#define FT5402_REG_FT5402_FRAME_FILTER_BAND_WIDTH (0x64+0x80)
+/**************************************************************************/
+
+#define FT5402_REG_TEST_MODE 0x04
+#define FT5402_REG_TEST_MODE_2 0x05
+#define FT5402_TX_TEST_MODE_1 0x28
+#define FT5402_RX_TEST_MODE_1 0x1E
+#define FT5402_FACTORYMODE_VALUE 0x40
+#define FT5402_WORKMODE_VALUE 0x00
+
+/************************************************************************/
+/* string */
+/************************************************************************/
+#define STRING_FT5402_KX "FT5X02_KX"
+#define STRING_FT5402_KY "FT5X02_KY"
+#define STRING_FT5402_LEMDA_X "FT5X02_LEMDA_X"
+#define STRING_FT5402_LEMDA_Y "FT5X02_LEMDA_Y"
+#define STRING_FT5402_RESOLUTION_X "FT5X02_RESOLUTION_X"
+#define STRING_FT5402_RESOLUTION_Y "FT5X02_RESOLUTION_Y"
+#define STRING_FT5402_DIRECTION "FT5X02_DIRECTION"
+
+
+
+#define STRING_FT5402_FACE_DETECT_PRE_VALUE "FT5X02_FACE_DETECT_PRE_VALUE"
+#define STRING_FT5402_FACE_DETECT_NUM "FT5X02_FACE_DETECT_NUM"
+#define STRING_FT5402_BIGAREA_PEAK_VALUE_MIN "FT5X02_BIGAREA_PEAK_VALUE_MIN"
+#define STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM "FT5X02_BIGAREA_DIFF_VALUE_OVER_NUM"
+#define STRING_FT5402_CUSTOMER_ID "FT5X02_CUSTOMER_ID"
+#define STRING_FT5402_PERIOD_ACTIVE "FT5X02_RV_G_PERIOD_ACTIVE"
+#define STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM "FT5X02_FACE_DETECT_STATISTICS_TX_NUM"
+
+#define STRING_FT5402_THGROUP "FT5X02_THGROUP"
+#define STRING_FT5402_THPEAK "FT5X02_THPEAK"
+#define STRING_FT5402_FACE_DETECT_MODE "FT5X02_FACE_DETECT_MODE"
+#define STRING_FT5402_MAX_TOUCH_VALUE "FT5X02_MAX_TOUCH_VALUE"
+
+#define STRING_FT5402_PWMODE_CTRL "FT5X02_PWMODE_CTRL"
+#define STRING_FT5402_DRAW_LINE_TH "FT5X02_DRAW_LINE_TH"
+
+#define STRING_FT5402_POINTS_SUPPORTED "FT5X02_POINTS_SUPPORTED"
+
+#define STRING_FT5402_START_RX "FT5X02_START_RX"
+#define STRING_FT5402_ADC_TARGET "FT5X02_ADC_TARGET"
+#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME"
+
+#define STRING_FT5402_POINTS_STABLE_MACRO "FT5X02_POINTS_STABLE_MACRO"
+#define STRING_FT5402_MIN_DELTA_X "FT5X02_MIN_DELTA_X"
+#define STRING_FT5402_MIN_DELTA_Y "FT5X02_MIN_DELTA_Y"
+#define STRING_FT5402_MIN_DELTA_STEP "FT5X02_MIN_DELTA_STEP"
+
+#define STRING_FT5402_ESD_NOISE_MACRO "FT5X02_ESD_NOISE_MACRO"
+#define STRING_FT5402_ESD_DIFF_VAL "FT5X02_ESD_DIFF_VAL"
+#define STRING_FT5402_ESD_NEGTIVE "FT5X02_ESD_NEGTIVE"
+#define STRING_FT5402_ESD_FILTER_FRAME "FT5X02_ESD_FILTER_FRAME"
+
+#define STRING_FT5402_IO_LEVEL_SELECT "FT5X02_IO_LEVEL_SELECT"
+#define STRING_FT5402_POINTID_DELAY_COUNT "FT5X02_POINTID_DELAY_COUNT"
+
+#define STRING_FT5402_LIFTUP_FILTER_MACRO "FT5X02_LIFTUP_FILTER_MACRO"
+
+#define STRING_FT5402_DIFFDATA_HANDLE "FT5X02_DIFFDATA_HANDLE" //_MACRO
+#define STRING_FT5402_MIN_WATER_VAL "FT5X02_MIN_WATER_VAL"
+#define STRING_FT5402_MAX_NOISE_VAL "FT5X02_MAX_NOISE_VAL"
+#define STRING_FT5402_WATER_HANDLE_START_RX "FT5X02_WATER_HANDLE_START_RX"
+#define STRING_FT5402_WATER_HANDLE_START_TX "FT5X02_WATER_HANDLE_START_TX"
+
+#define STRING_FT5402_HOST_NUMBER_SUPPORTED "FT5X02_HOST_NUMBER_SUPPORTED"
+#define STRING_FT5402_RV_G_RAISE_THGROUP "FT5X02_RV_G_RAISE_THGROUP"
+#define STRING_FT5402_RV_G_CHARGER_STATE "FT5X02_RV_G_CHARGER_STATE"
+
+#define STRING_FT5402_RV_G_FILTERID_START "FT5X02_RV_G_FILTERID_START"
+
+#define STRING_FT5402_FRAME_FILTER_EN "FT5X02_FRAME_FILTER_EN"
+#define STRING_FT5402_FRAME_FILTER_SUB_MAX_TH "FT5X02_FRAME_FILTER_SUB_MAX_TH"
+#define STRING_FT5402_FRAME_FILTER_ADD_MAX_TH "FT5X02_FRAME_FILTER_ADD_MAX_TH"
+#define STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME "FT5X02_FRAME_FILTER_SKIP_START_FRAME"
+#define STRING_FT5402_FRAME_FILTER_BAND_EN "FT5X02_FRAME_FILTER_BAND_EN"
+#define STRING_FT5402_FRAME_FILTER_BAND_WIDTH "FT5X02_FRAME_FILTER_BAND_WIDTH"
+
+
+#define STRING_ft5402_tx_num "FT5X02_tx_num"
+#define STRING_ft5402_rx_num "FT5X02_rx_num"
+#define STRING_ft5402_gain "FT5X02_gain"
+#define STRING_ft5402_voltage "FT5X02_voltage"
+#define STRING_ft5402_scanselect "FT5X02_scanselect"
+
+#define STRING_ft5402_tx_order "FT5X02_tx_order"
+#define STRING_ft5402_tx_offset "FT5X02_tx_offset"
+#define STRING_ft5402_tx_cap "FT5X02_tx_cap"
+
+#define STRING_ft5402_rx_order "FT5X02_rx_order"
+#define STRING_ft5402_rx_offset "FT5X02_rx_offset"
+#define STRING_ft5402_rx_cap "FT5X02_rx_cap"
+
+struct Struct_Param_FT5402 {
+ short ft5402_KX;
+ short ft5402_KY;
+ unsigned char ft5402_LEMDA_X;
+ unsigned char ft5402_LEMDA_Y;
+ short ft5402_RESOLUTION_X;
+ short ft5402_RESOLUTION_Y;
+ unsigned char ft5402_DIRECTION;
+ unsigned char ft5402_FACE_DETECT_PRE_VALUE;
+ unsigned char ft5402_FACE_DETECT_NUM;
+
+ unsigned char ft5402_BIGAREA_PEAK_VALUE_MIN;
+ unsigned char ft5402_BIGAREA_DIFF_VALUE_OVER_NUM;
+ unsigned char ft5402_CUSTOMER_ID;
+ unsigned char ft5402_PERIOD_ACTIVE;
+ unsigned char ft5402_FACE_DETECT_STATISTICS_TX_NUM;
+
+ short ft5402_THGROUP;
+ unsigned char ft5402_THPEAK;
+ unsigned char ft5402_FACE_DETECT_MODE;
+ short ft5402_MAX_TOUCH_VALUE;
+
+ unsigned char ft5402_PWMODE_CTRL;
+ unsigned char ft5402_DRAW_LINE_TH;
+ unsigned char ft5402_POINTS_SUPPORTED;
+
+ unsigned char ft5402_START_RX;
+ short ft5402_ADC_TARGET;
+ unsigned char ft5402_ESD_FILTER_FRAME;
+
+ unsigned char ft5402_POINTS_STABLE_MACRO;
+ unsigned char ft5402_MIN_DELTA_X;
+ unsigned char ft5402_MIN_DELTA_Y;
+ unsigned char ft5402_MIN_DELTA_STEP;
+
+ unsigned char ft5402_ESD_NOISE_MACRO;
+ unsigned char ft5402_ESD_DIFF_VAL;
+ char ft5402_ESD_NEGTIVE; //negtive
+ unsigned char ft5402_ESD_FILTER_FRAMES;
+
+ unsigned char ft5402_IO_LEVEL_SELECT;
+
+ unsigned char ft5402_POINTID_DELAY_COUNT;
+
+ unsigned char ft5402_LIFTUP_FILTER_MACRO;
+
+ unsigned char ft5402_DIFF_HANDLE_MACRO;
+ char ft5402_MIN_WATER; //negtive
+ unsigned char ft5402_MAX_NOISE;
+ unsigned char ft5402_WATER_START_RX;
+ unsigned char ft5402_WATER_START_TX;
+
+ unsigned char ft5402_HOST_NUMBER_SUPPORTED_MACRO;
+ unsigned char ft5402_RAISE_THGROUP;
+ unsigned char ft5402_CHARGER_STATE;
+
+ unsigned char ft5402_FILTERID_START;
+
+ unsigned char ft5402_FRAME_FILTER_EN_MACRO;
+ unsigned char ft5402_FRAME_FILTER_SUB_MAX_TH;
+ unsigned char ft5402_FRAME_FILTER_ADD_MAX_TH;
+ unsigned char ft5402_FRAME_FILTER_SKIP_START_FRAME;
+ unsigned char ft5402_FRAME_FILTER_BAND_EN;
+ unsigned char ft5402_FRAME_FILTER_BAND_WIDTH;
+
+};
+
+struct Struct_Param_FT5402 g_param_ft5402 = {
+ FT5402_KX,
+ FT5402_KY,
+ FT5402_LEMDA_X,
+ FT5402_LEMDA_Y,
+ FT5402_RESOLUTION_X,
+ FT5402_RESOLUTION_Y,
+ FT5402_DIRECTION,
+
+ FT5402_FACE_DETECT_PRE_VALUE,
+ FT5402_FACE_DETECT_NUM,
+ FT5402_BIGAREA_PEAK_VALUE_MIN,
+ FT5402_BIGAREA_DIFF_VALUE_OVER_NUM,
+ FT5402_CUSTOMER_ID,
+ FT5402_RV_G_PERIOD_ACTIVE,
+ FT5402_FACE_DETECT_STATISTICS_TX_NUM,
+
+ FT5402_THGROUP,
+ FT5402_THPEAK,
+ FT5402_FACE_DETECT_MODE,
+ FT5402_MAX_TOUCH_VALUE,
+
+ FT5402_PWMODE_CTRL,
+ FT5402_DRAW_LINE_TH,
+ FT5402_POINTS_SUPPORTED,
+
+ FT5402_START_RX,
+ FT5402_ADC_TARGET,
+ FT5402_ESD_FILTER_FRAME,
+
+ FT5402_POINTS_STABLE_MACRO,
+ FT5402_MIN_DELTA_X,
+ FT5402_MIN_DELTA_Y,
+ FT5402_MIN_DELTA_STEP,
+
+ FT5402_ESD_NOISE_MACRO,
+ FT5402_ESD_DIFF_VAL,
+ FT5402_ESD_NEGTIVE,
+ FT5402_ESD_FILTER_FRAME,
+
+ FT5402_IO_LEVEL_SELECT,
+
+ FT5402_POINTID_DELAY_COUNT,
+
+ FT5402_LIFTUP_FILTER_MACRO,
+
+ FT5402_DIFFDATA_HANDLE,
+ FT5402_MIN_WATER_VAL,
+ FT5402_MAX_NOISE_VAL,
+ FT5402_WATER_HANDLE_START_RX,
+ FT5402_WATER_HANDLE_START_TX,
+
+ FT5402_HOST_NUMBER_SUPPORTED,
+ FT5402_RV_G_RAISE_THGROUP,
+ FT5402_RV_G_CHARGER_STATE,
+
+ FT5402_RV_G_FILTERID_START,
+
+ FT5402_FRAME_FILTER_EN,
+ FT5402_FRAME_FILTER_SUB_MAX_TH,
+ FT5402_FRAME_FILTER_ADD_MAX_TH,
+ FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ FT5402_FRAME_FILTER_BAND_EN,
+ FT5402_FRAME_FILTER_BAND_WIDTH,
+};
+
+char String_Param_FT5402[][64] = {
+ STRING_FT5402_KX,
+ STRING_FT5402_KY,
+ STRING_FT5402_LEMDA_X,
+ STRING_FT5402_LEMDA_Y,
+ STRING_FT5402_RESOLUTION_X,
+ STRING_FT5402_RESOLUTION_Y,
+ STRING_FT5402_DIRECTION,
+ STRING_FT5402_FACE_DETECT_PRE_VALUE,
+ STRING_FT5402_FACE_DETECT_NUM,
+ STRING_FT5402_BIGAREA_PEAK_VALUE_MIN,
+ STRING_FT5402_BIGAREA_DIFF_VALUE_OVER_NUM,
+ STRING_FT5402_CUSTOMER_ID,
+ STRING_FT5402_PERIOD_ACTIVE,
+ STRING_FT5402_FACE_DETECT_STATISTICS_TX_NUM,
+
+ STRING_FT5402_THGROUP,
+ STRING_FT5402_THPEAK,
+ STRING_FT5402_FACE_DETECT_MODE,
+ STRING_FT5402_MAX_TOUCH_VALUE,
+
+ STRING_FT5402_PWMODE_CTRL,
+ STRING_FT5402_DRAW_LINE_TH,
+ STRING_FT5402_POINTS_SUPPORTED,
+
+ STRING_FT5402_START_RX,
+ STRING_FT5402_ADC_TARGET,
+ STRING_FT5402_ESD_FILTER_FRAME,
+
+
+ STRING_ft5402_tx_num,
+ STRING_ft5402_rx_num,
+ STRING_ft5402_gain,
+ STRING_ft5402_voltage ,
+ STRING_ft5402_scanselect,
+
+ STRING_ft5402_tx_order,
+ STRING_ft5402_tx_offset,
+ STRING_ft5402_tx_cap,
+
+ STRING_ft5402_rx_order,
+ STRING_ft5402_rx_offset,
+ STRING_ft5402_rx_cap,
+
+ STRING_FT5402_POINTS_STABLE_MACRO,
+ STRING_FT5402_MIN_DELTA_X,
+ STRING_FT5402_MIN_DELTA_Y,
+ STRING_FT5402_MIN_DELTA_STEP,
+
+ STRING_FT5402_ESD_NOISE_MACRO,
+ STRING_FT5402_ESD_DIFF_VAL,
+ STRING_FT5402_ESD_NEGTIVE,
+ STRING_FT5402_ESD_FILTER_FRAME,
+
+ STRING_FT5402_IO_LEVEL_SELECT,
+
+ STRING_FT5402_POINTID_DELAY_COUNT,
+
+ STRING_FT5402_LIFTUP_FILTER_MACRO,
+
+ STRING_FT5402_DIFFDATA_HANDLE,
+ STRING_FT5402_MIN_WATER_VAL,
+ STRING_FT5402_MAX_NOISE_VAL,
+ STRING_FT5402_WATER_HANDLE_START_RX,
+ STRING_FT5402_WATER_HANDLE_START_TX,
+
+ STRING_FT5402_HOST_NUMBER_SUPPORTED,
+ STRING_FT5402_RV_G_RAISE_THGROUP,
+ STRING_FT5402_RV_G_CHARGER_STATE,
+
+ STRING_FT5402_RV_G_FILTERID_START,
+
+ STRING_FT5402_FRAME_FILTER_EN,
+ STRING_FT5402_FRAME_FILTER_SUB_MAX_TH,
+ STRING_FT5402_FRAME_FILTER_ADD_MAX_TH,
+ STRING_FT5402_FRAME_FILTER_SKIP_START_FRAME,
+ STRING_FT5402_FRAME_FILTER_BAND_EN,
+ STRING_FT5402_FRAME_FILTER_BAND_WIDTH,
+
+};
+
+#define FT5402_APP_NAME "FT5X02_param"
+
+#define FT5402_APP_LEGAL "Legal_File"
+#define FT5402_APP_LEGAL_BYTE_1_STR "BYTE_1"
+#define FT5402_APP_LEGAL_BYTE_2_STR "BYTE_2"
+
+#define FT5402_APP_LEGAL_BYTE_1_VALUE 107
+#define FT5402_APP_LEGAL_BYTE_2_VALUE 201
+
+
+#define FT5402_INI_FILEPATH "/system/etc/firmware/"
+
+#endif
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c new file mode 100755 index 00000000..a3f6c4c9 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.c @@ -0,0 +1,896 @@ +/* + * drivers/input/touchscreen/ft5x0x/ft5x0x.c + * + * FocalTech ft5x0x TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * note: only support mulititouch Wenfs 2010-10-01 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/input.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/platform_device.h> +#include <linux/suspend.h> +#include <linux/wait.h> +#include <asm/uaccess.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <linux/slab.h> +#include "ft5x0x.h" + +struct ft5x0x_data *pContext=NULL; +static struct i2c_client *l_client=NULL; + +#ifdef TOUCH_KEY +static int keycodes[NUM_KEYS] ={ + KEY_MENU, + KEY_HOME, + KEY_BACK, + KEY_SEARCH +}; +#endif + +#define FT5402_CONFIG_NAME "fttpconfig_5402public.ini" +extern int ft5x0x_read_fw_ver(void); +extern int ft5x0x_auto_clb(void); +extern int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver); +extern int ft5402_Get_Param_From_Ini(char *config_name); +extern int ft5402_Init_IC_Param(struct i2c_client *client); +extern int ft5402_get_ic_param(struct i2c_client *client); +extern int ft5402_read_reg(struct i2c_client * client, u8 regaddr, u8 * regvalue); +static unsigned char ft5x0x_debug = 0; + +extern int fts_ctpm_fw_upgrade_with_i_file(struct i2c_client * client); +int ft5x0x_i2c_rxdata(char *rxdata, int length) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = rxdata; + + msg[1].addr = pContext->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = rxdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 2); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + + +int ft5x0x_i2c_txdata(char *txdata, int length) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = pContext->addr; + msg[0].flags = 0; + msg[0].len = length; + msg[0].buf = txdata; + + ret = i2c_transfer(pContext->client->adapter, msg, 1); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +static void ft5x0x_penup(struct ft5x0x_data *ft5x0x) +{ + input_mt_sync(ft5x0x->input_dev); + input_sync(ft5x0x->input_dev); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && ft5x0x->tkey_pressed && ft5x0x->tkey_idx < NUM_KEYS ){ + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 1); + input_sync(ft5x0x->input_dev); + input_report_key(ft5x0x->input_dev, keycodes[ft5x0x->tkey_idx], 0); + input_sync(ft5x0x->input_dev); + dbg("report as key event %d \n",ft5x0x->tkey_idx); + } +#endif + + dbg("pen up\n"); + return; +} + +#ifdef TOUCH_KEY +static int ft5x0x_read_tskey(struct ft5x0x_data *ft5x0x,int x,int y) +{ + int px,py; + + if(ft5x0x->tkey.axis){ + px = y; + py = x; + }else{ + px = x; + py = y; + } + + if(px >= ft5x0x->tkey.x_lower && px<=ft5x0x->tkey.x_upper){ + ft5x0x->tkey_pressed = 1; + if(py>= ft5x0x->tkey.ypos[0].y_lower && py<= ft5x0x->tkey.ypos[0].y_upper){ + ft5x0x->tkey_idx= 0; + }else if(py>= ft5x0x->tkey.ypos[1].y_lower && py<= ft5x0x->tkey.ypos[1].y_upper){ + ft5x0x->tkey_idx = 1; + }else if(py>= ft5x0x->tkey.ypos[2].y_lower && py<= ft5x0x->tkey.ypos[2].y_upper){ + ft5x0x->tkey_idx = 2; + }else if(py>= ft5x0x->tkey.ypos[3].y_lower && py<= ft5x0x->tkey.ypos[3].y_upper){ + ft5x0x->tkey_idx = 3; + }else{ + ft5x0x->tkey_idx = NUM_KEYS; + } + + return 1; + } + + ft5x0x->tkey_pressed = 0; + return 0; +} +#endif + +static int ft5x0x_read_data(struct ft5x0x_data *ft5x0x) +{ + int ret = -1; + int i = 0; + u16 x,y,px,py; + u8 buf[64] = {0}, id; + struct ts_event *event = &ft5x0x->event; + + if(ft5x0x->nt == 10) + ret = ft5x0x_i2c_rxdata(buf, 64); + else if(ft5x0x->nt == 5) + ret = ft5x0x_i2c_rxdata(buf, 31); + + if (ret <= 0) { + dbg_err("read_data i2c_rxdata failed: %d\n", ret); + return ret; + } + + memset(event, 0, sizeof(struct ts_event)); + //event->tpoint = buf[2] & 0x03;// 0000 0011 + //event->tpoint = buf[2] & 0x07;// 000 0111 + event->tpoint = buf[2]&0x0F; + if (event->tpoint == 0) { + ft5x0x_penup(ft5x0x); + return 1; + } + + if (event->tpoint > ft5x0x->nt){ + dbg_err("tounch pointnum=%d > max:%d\n", event->tpoint,ft5x0x->nt); + return -1; + } + + for (i = 0; i < event->tpoint; i++){ + id = (buf[5+i*6] >>4) & 0x0F;//get track id + if(ft5x0x->swap){ + px = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + py = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + }else{ + px = (buf[5+i*6] & 0x0F)<<8 |buf[6+i*6]; + py = (buf[3+i*6] & 0x0F)<<8 |buf[4+i*6]; + } + + x = px; + y = py; + + if(ft5x0x->xch) + x = ft5x0x->reslx - px; + + if(ft5x0x->ych) + y = ft5x0x->resly - py; + + if(ft5x0x->dbg) printk("F%d: Tid=%d,px=%d,py=%d; x=%d,y=%d\n", i, id, px, py, x, y); + +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used && event->tpoint==1) { + if(ft5x0x_read_tskey(ft5x0x,px,py) > 0) return -1; + } +#endif + event->x[i] = x; + event->y[i] = y; + event->tid[i] = id; + + } + + return 0; +} + +static void ft5x0x_report(struct ft5x0x_data *ft5x0x) +{ + int i = 0; + struct ts_event *event = &ft5x0x->event; + + for (i = 0; i < event->tpoint; i++){ + input_report_abs(ft5x0x->input_dev, ABS_MT_TRACKING_ID, event->tid[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_X, event->x[i]); + input_report_abs(ft5x0x->input_dev, ABS_MT_POSITION_Y, event->y[i]); + input_mt_sync(ft5x0x->input_dev); + } + input_sync(ft5x0x->input_dev); + + return; +} + +static void ft5x0x_read_work(struct work_struct *work) +{ + int ret = -1; + struct ft5x0x_data *ft5x0x = container_of(work, struct ft5x0x_data, read_work); + + mutex_lock(&ft5x0x->ts_mutex); + ret = ft5x0x_read_data(ft5x0x); + + if (ret == 0) ft5x0x_report(ft5x0x); + + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + mutex_unlock(&ft5x0x->ts_mutex); + + return; +} + +static irqreturn_t ft5x0x_interrupt(int irq, void *dev) +{ + struct ft5x0x_data *ft5x0x = dev; + + if (gpio_irqstatus(ft5x0x->irqgpio)) + { + + if(ft5x0x_debug == 1) + { + printk("++++++++++++%s\n",__func__); + } + wmt_gpio_ack_irq(ft5x0x->irqgpio); + if (is_gpio_irqenable(ft5x0x->irqgpio)) + { + wmt_gpio_mask_irq(ft5x0x->irqgpio); +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!ft5x0x->earlysus) queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#else + queue_work(ft5x0x->workqueue, &ft5x0x->read_work); +#endif + + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void ft5x0x_reset(struct ft5x0x_data *ft5x0x) +{ + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + gpio_set_value(ft5x0x->rstgpio, 0); + mdelay(20); + gpio_set_value(ft5x0x->rstgpio, 1); + mdelay(5); + + return; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ft5x0x_early_suspend(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return; +} + +static void ft5x0x_late_resume(struct early_suspend *handler) +{ + struct ft5x0x_data *ft5x0x = container_of(handler, struct ft5x0x_data, early_suspend); + + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + +#ifdef CONFIG_PM +static int ft5x0x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x->earlysus = 1; + wmt_gpio_mask_irq(ft5x0x->irqgpio); + return 0; +} + +static int ft5x0x_resume(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = dev_get_drvdata(&pdev->dev); + ft5x0x_reset(ft5x0x); + ft5x0x->earlysus = 0; + + if (ft5x0x->load_cfg) { + msleep(350); + ft5402_Init_IC_Param(ft5x0x->client); + //msleep(50); + ft5402_get_ic_param(ft5x0x->client); + } + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + return 0; +} + +#else +#define ft5x0x_suspend NULL +#define ft5x0x_resume NULL +#endif + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "dbg \n"); +} + +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int dbg = simple_strtoul(buf, NULL, 10); + struct ft5x0x_data *ft5x0x = pContext; + + if(dbg){ + ft5x0x->dbg = 1; + }else{ + ft5x0x->dbg = 0; + } + + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +static ssize_t cat_clb(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "calibrate \n"); +} + +static ssize_t echo_clb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int cal = simple_strtoul(buf, NULL, 10); + + if(cal){ + if(ft5x0x_auto_clb()) printk("Calibrate Failed.\n"); + }else{ + printk("calibrate --echo 1 >clb.\n"); + } + + return count; +} + +static DEVICE_ATTR(clb, S_IRUGO | S_IWUSR, cat_clb, echo_clb); + +static ssize_t cat_fupg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "fupg \n"); +} + +static ssize_t echo_fupg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct ft5x0x_data *ft5x0x = pContext; + unsigned int upg = simple_strtoul(buf, NULL, 10); + + wmt_gpio_mask_irq(ft5x0x->irqgpio); + if(upg){ + if(ft5x0x_upg_fw_bin(ft5x0x, 0)) printk("Upgrade Failed.\n"); + }else{ + printk("upgrade --echo 1 > fupg.\n"); + } + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + return count; +} +static DEVICE_ATTR(fupg, S_IRUGO | S_IWUSR, cat_fupg, echo_fupg); + + +static ssize_t cat_fver(struct device *dev, struct device_attribute *attr, char *buf) +{ + int fw_ver = ft5x0x_read_fw_ver(); + return sprintf(buf, "firmware version:0x%02x \n",fw_ver); +} + +static ssize_t echo_fver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} +static DEVICE_ATTR(fver, S_IRUGO | S_IWUSR, cat_fver, echo_fver); + +static ssize_t cat_addr(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret; + u8 addrs[32]; + int cnt=0; + struct i2c_msg msg[2]; + struct ft5x0x_data *ft5x0x = pContext; + u8 ver[1]= {0xa6}; + + ft5x0x->addr = 1; + + msg[0].addr = ft5x0x->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ver; + + msg[1].addr = ft5x0x->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = ver; + + while(ft5x0x->addr < 0x80){ + ret = i2c_transfer(ft5x0x->client->adapter, msg, 2); + if(ret == 2) sprintf(&addrs[5*cnt++], " 0x%02x",ft5x0x->addr); + + ft5x0x->addr++; + msg[0].addr = msg[1].addr = ft5x0x->addr; + } + + return sprintf(buf, "i2c addr:%s\n",addrs); +} + +static ssize_t echo_addr(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int addr; + struct ft5x0x_data *ft5x0x = pContext; + + sscanf(buf,"%x", &addr); + ft5x0x->addr = addr; + + return count; +} +static DEVICE_ATTR(addr, S_IRUGO | S_IWUSR, cat_addr, echo_addr); + +static struct attribute *ft5x0x_attributes[] = { + &dev_attr_clb.attr, + &dev_attr_fupg.attr, + &dev_attr_fver.attr, + &dev_attr_dbg.attr, + &dev_attr_addr.attr, + NULL +}; + +static const struct attribute_group ft5x0x_group = { + .attrs = ft5x0x_attributes, +}; + +static int ft5x0x_sysfs_create_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + int err; + + ft5x0x->kobj = kobject_create_and_add("wmtts", NULL) ; + if(!ft5x0x->kobj){ + dbg_err("kobj create failed.\n"); + return -ENOMEM; + } + + /* Register sysfs hooks */ + err = sysfs_create_group(ft5x0x->kobj, group); + if (err < 0){ + kobject_del(ft5x0x->kobj); + dbg_err("Create sysfs group failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void ft5x0x_sysfs_remove_group(struct ft5x0x_data *ft5x0x, const struct attribute_group *group) +{ + sysfs_remove_group(ft5x0x->kobj, group); + kobject_del(ft5x0x->kobj); + return; +} + +static int ft5x0x_probe(struct platform_device *pdev) +{ + int i,err = 0; + u8 value = 0; + u8 cfg_name[32]; + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + ft5x0x->client = l_client; + INIT_WORK(&ft5x0x->read_work, ft5x0x_read_work); + mutex_init(&ft5x0x->ts_mutex); + + ft5x0x->workqueue = create_singlethread_workqueue(ft5x0x->name); + if (!ft5x0x->workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + err = ft5x0x_sysfs_create_group(ft5x0x, &ft5x0x_group); + if(err < 0){ + dbg("create sysfs group failed.\n"); + goto exit_create_group; + } + + ft5x0x->input_dev = input_allocate_device(); + if (!ft5x0x->input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + ft5x0x->input_dev->name = ft5x0x->name; + ft5x0x->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, ft5x0x->input_dev->propbit); + + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_X, 0, ft5x0x->reslx, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_POSITION_Y, 0, ft5x0x->resly, 0, 0); + input_set_abs_params(ft5x0x->input_dev, + ABS_MT_TRACKING_ID, 0, 20, 0, 0); +#ifdef TOUCH_KEY + if(ft5x0x->tskey_used){ + for (i = 0; i <NUM_KEYS; i++) + set_bit(keycodes[i], ft5x0x->input_dev->keybit); + + ft5x0x->input_dev->keycode = keycodes; + ft5x0x->input_dev->keycodesize = sizeof(unsigned int); + ft5x0x->input_dev->keycodemax = NUM_KEYS; + } +#endif + + err = input_register_device(ft5x0x->input_dev); + if (err) { + dbg_err("ft5x0x_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ft5x0x->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ft5x0x->early_suspend.suspend = ft5x0x_early_suspend; + ft5x0x->early_suspend.resume = ft5x0x_late_resume; + register_early_suspend(&ft5x0x->early_suspend); +#endif + + if(ft5x0x->upg){ + if (fts_ctpm_fw_upgrade_with_i_file(ft5x0x->client) < 0) { + printk("ft5x0x_probe -----upgrade failed!-\n"); + } + else + { + printk("ft5x0x_probe -----upgrade successful!-\n"); + wmt_setsyspara("wmt.io.ts.upg",""); + ft5x0x_reset(ft5x0x); + } + ft5x0x->upg = 0x00; + } + + if(request_irq(ft5x0x->irq, ft5x0x_interrupt, IRQF_SHARED, ft5x0x->name, ft5x0x) < 0){ + dbg_err("Could not allocate irq for ts_ft5x0x !\n"); + err = -1; + goto exit_register_irq; + } + + { // check if need to load config to IC or not + err = ft5402_read_reg(ft5x0x->client, 0xa3, &value); + if (err < 0) + dbg_err("Read reg 0xa3 failed.\n"); + else + printk("0xa3 reg = %d\n", value); + if (value == 3) + ft5x0x->load_cfg = 1; + else + ft5x0x->load_cfg = 0; + } + ft5x0x_reset(ft5x0x); + + if (ft5x0x->load_cfg) { + msleep(350); /*make sure CTP already finish startup process*/ + sprintf(cfg_name, "%s.ini", ft5x0x->cfg_name); + printk("Config file name: %s\n", cfg_name); + if (ft5402_Get_Param_From_Ini(cfg_name) >= 0) + ft5402_Init_IC_Param(ft5x0x->client); + else + dbg_err("[FTS]-------Get ft5402 param from INI file failed\n"); + ft5402_get_ic_param(ft5x0x->client); + } + + wmt_gpio_set_irq_type(ft5x0x->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ft5x0x->irqgpio); + + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(ft5x0x->input_dev); +exit_input_dev_alloc_failed: + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); +exit_create_group: + cancel_work_sync(&ft5x0x->read_work); + destroy_workqueue(ft5x0x->workqueue); +exit_create_singlethread: + return err; +} + +static int ft5x0x_remove(struct platform_device *pdev) +{ + struct ft5x0x_data *ft5x0x = platform_get_drvdata( pdev); + + cancel_work_sync(&ft5x0x->read_work); + flush_workqueue(ft5x0x->workqueue); + destroy_workqueue(ft5x0x->workqueue); + + free_irq(ft5x0x->irq, ft5x0x); + wmt_gpio_mask_irq(ft5x0x->irqgpio); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ft5x0x->early_suspend); +#endif + input_unregister_device(ft5x0x->input_dev); + + ft5x0x_sysfs_remove_group(ft5x0x, &ft5x0x_group); + + mutex_destroy(&ft5x0x->ts_mutex); + dbg("remove...\n"); + return 0; +} + +static void ft5x0x_release(struct device *device) +{ + return; +} + +static struct platform_device ft5x0x_device = { + .name = DEV_FT5X0X, + .id = 0, + .dev = {.release = ft5x0x_release}, +}; + +static struct platform_driver ft5x0x_driver = { + .driver = { + .name = DEV_FT5X0X, + .owner = THIS_MODULE, + }, + .probe = ft5x0x_probe, + .remove = ft5x0x_remove, + .suspend = ft5x0x_suspend, + .resume = ft5x0x_resume, +}; + +static int check_touch_env(struct ft5x0x_data *ft5x0x) +{ + int i,ret = 0; + int len = 96; + int Enable; + char retval[96] = {0}; + char *p=NULL; + char *s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + //printk("MST FT5x0x:Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + //printk("FT5x0x Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"ft5301",6)==0){//check touch ID + ft5x0x->id = FT5301; + ft5x0x->name = DEV_FT5301; + }else if(strncmp(p,"ft5406",6)==0){ + ft5x0x->id = FT5406; + ft5x0x->name = DEV_FT5406; + }else if(strncmp(p,"ft6336",6)==0){ + ft5x0x->id = FT6336; + ft5x0x->name = DEV_FT6336; + }else if(strncmp(p,"ft5206",6)==0){ + ft5x0x->id = FT5206; + ft5x0x->name = DEV_FT5206; + }else if(strncmp(p,"ft5606",6)==0){ + ft5x0x->id = FT5606; + ft5x0x->name = DEV_FT5606; + }else if(strncmp(p,"ft5306",6)==0){ + ft5x0x->id = FT5306; + ft5x0x->name = DEV_FT5306; + }else if(strncmp(p,"ft5302",6)==0){ + ft5x0x->id = FT5302; + ft5x0x->name = DEV_FT5302; + }else if(strncmp(p,"ft5",3)==0) + { + ft5x0x->id = FT5X0X; + ft5x0x->name = DEV_FT5X0X; + }else{ + printk("FT5x0x touch disabled.\n"); + return -ENODEV; + } + + s = strchr(p,':'); + strncpy(ft5x0x->cfg_name, p, s-p); + + p = s + 1; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", &ft5x0x->irqgpio, &ft5x0x->reslx, &ft5x0x->resly, &ft5x0x->rstgpio, &ft5x0x->swap, &ft5x0x->xch, &ft5x0x->ych, &ft5x0x->nt, &ft5x0x->addr); + + ft5x0x->irq = IRQ_GPIO; + printk("%s irqgpio=%d, reslx=%d, resly=%d, rstgpio=%d, swap=%d, xch=%d, ych=%d, nt=%d, addr=%x\n", ft5x0x->name, ft5x0x->irqgpio, ft5x0x->reslx, ft5x0x->resly, ft5x0x->rstgpio, ft5x0x->swap, ft5x0x->xch, ft5x0x->ych, ft5x0x->nt, ft5x0x->addr); + + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.upg", retval, &len); + if(!ret){ + ft5x0x->upg = 1; + strncpy(ft5x0x->fw_name, retval, sizeof(ft5x0x->fw_name)); + } + +#ifdef TOUCH_KEY + memset(retval,0x00,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskey", retval, &len); + if(!ret){ + sscanf(retval,"%d:", &ft5x0x->nkeys); + p = strchr(retval,':'); + p++; + for(i=0; i < ft5x0x->nkeys; i++ ){ + sscanf(p,"%d:%d", &ft5x0x->tkey.ypos[i].y_lower, &ft5x0x->tkey.ypos[i].y_upper); + p = strchr(p,':'); + p++; + p = strchr(p,':'); + p++; + } + sscanf(p,"%d:%d:%d", &ft5x0x->tkey.axis, &ft5x0x->tkey.x_lower, &ft5x0x->tkey.x_upper); + ft5x0x->tskey_used = 1; + } +#endif + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = TS_I2C_NAME, + .flags = 0x00, + .addr = FT5406_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + //ts_i2c_board_info.addr = FT5406_I2C_ADDR; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(FT5X0X_I2C_BUS);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static int __init ft5x0x_init(void) +{ + int ret = -ENOMEM; + struct ft5x0x_data *ft5x0x=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ft5x0x = kzalloc(sizeof(struct ft5x0x_data), GFP_KERNEL); + if(!ft5x0x){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = ft5x0x; + ret = check_touch_env(ft5x0x); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(ft5x0x->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", ft5x0x->irqgpio); + goto exit_free_mem; + } + wmt_gpio_setpull(ft5x0x->irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(ft5x0x->irqgpio); + + ret = gpio_request(ft5x0x->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", ft5x0x->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(ft5x0x->rstgpio, 1); + + + ret = platform_device_register(&ft5x0x_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&ft5x0x_device, ft5x0x); + + ret = platform_driver_register(&ft5x0x_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&ft5x0x_device); +exit_free_gpio: + gpio_free(ft5x0x->rstgpio); +exit_free_irqgpio: + gpio_free(ft5x0x->irqgpio); +exit_free_mem: + kfree(ft5x0x); + pContext = NULL; + return ret; +} + +static void ft5x0x_exit(void) +{ + if(!pContext) return; + + gpio_free(pContext->rstgpio); + gpio_free(pContext->irqgpio); + platform_driver_unregister(&ft5x0x_driver); + platform_device_unregister(&ft5x0x_device); + kfree(pContext); + ts_i2c_unregister_device(); + return; +} + +late_initcall(ft5x0x_init); +module_exit(ft5x0x_exit); +module_param (ft5x0x_debug, byte, 0644); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FocalTech.Touch"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h new file mode 100755 index 00000000..417af1f5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x.h @@ -0,0 +1,205 @@ +#ifndef __LINUX_FT5X0X_TS_H__ +#define __LINUX_FT5X0X_TS_H__ + +#define DEV_FT5206 "touch_ft5206" +#define DEV_FT5301 "touch_ft5301" +#define DEV_FT5302 "touch_ft5302" +#define DEV_FT5306 "touch_ft5306" +#define DEV_FT5406 "touch_ft5406" +#define DEV_FT5606 "touch_ft5606" +#define DEV_FT6336 "touch_ft6336" + + +#define DEV_FT5X0X "touch_ft5x0x" +#define TS_I2C_NAME "ft5x0x-ts" +#define FT5406_I2C_ADDR 0x38 +#define FT5X0X_I2C_BUS 0x01 + +enum FT5X0X_ID{ + FT5206 =1, + FT5301, + FT5302, + FT5306, + FT5406, + FT5606, + FT6336, + FT5X0X, +}; + +struct vt1603_ts_cal_info { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}; + +#define SUPPORT_POINT_NUM 5//10 +struct ts_event { + int x[SUPPORT_POINT_NUM]; + int y[SUPPORT_POINT_NUM]; + int tid[SUPPORT_POINT_NUM]; + int tpoint; +}; + +#define TOUCH_KEY + +#ifdef TOUCH_KEY +#define NUM_KEYS 4 +struct key_pos{ + int y_lower; + int y_upper; +}; + +struct ts_key{ + int axis; + int x_lower; + int x_upper; + struct key_pos ypos[NUM_KEYS]; +}; +#endif + +struct ft5x0x_data { + int id; + unsigned int addr; + const char *name; + u8 fw_name[64]; + u8 cfg_name[32]; + + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + struct work_struct read_work; + struct workqueue_struct *workqueue; + struct mutex ts_mutex; + struct kobject *kobj; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int earlysus; + + int reslx; + int resly; + + int tw; + int th; + + int irq; + int irqgpio; + int rstgpio; +/* + int igp_idx; + int igp_bit; + + int rgp_idx; + int rgp_bit; +*/ + + int nt; + int nb; + int xch; + int ych; + int swap; + + int upg; + int load_cfg; + int dbg; +#ifdef TOUCH_KEY + int tskey_used; + int tkey_pressed; + int nkeys; + int tkey_idx; + struct ts_key tkey; +#endif + +}; + +enum ft5x0x_ts_regs { + FT5X0X_REG_THGROUP = 0x80, /* touch threshold, related to sensitivity */ + FT5X0X_REG_THPEAK = 0x81, + FT5X0X_REG_THCAL = 0x82, + FT5X0X_REG_THWATER = 0x83, + FT5X0X_REG_THTEMP = 0x84, + FT5X0X_REG_THDIFF = 0x85, + FT5X0X_REG_CTRL = 0x86, + FT5X0X_REG_TIMEENTERMONITOR = 0x87, + FT5X0X_REG_PERIODACTIVE = 0x88, /* report rate */ + FT5X0X_REG_PERIODMONITOR = 0x89, + FT5X0X_REG_HEIGHT_B = 0x8a, + FT5X0X_REG_MAX_FRAME = 0x8b, + FT5X0X_REG_DIST_MOVE = 0x8c, + FT5X0X_REG_DIST_POINT = 0x8d, + FT5X0X_REG_FEG_FRAME = 0x8e, + FT5X0X_REG_SINGLE_CLICK_OFFSET = 0x8f, + FT5X0X_REG_DOUBLE_CLICK_TIME_MIN = 0x90, + FT5X0X_REG_SINGLE_CLICK_TIME = 0x91, + FT5X0X_REG_LEFT_RIGHT_OFFSET = 0x92, + FT5X0X_REG_UP_DOWN_OFFSET = 0x93, + FT5X0X_REG_DISTANCE_LEFT_RIGHT = 0x94, + FT5X0X_REG_DISTANCE_UP_DOWN = 0x95, + FT5X0X_REG_ZOOM_DIS_SQR = 0x96, + FT5X0X_REG_RADIAN_VALUE =0x97, + FT5X0X_REG_MAX_X_HIGH = 0x98, + FT5X0X_REG_MAX_X_LOW = 0x99, + FT5X0X_REG_MAX_Y_HIGH = 0x9a, + FT5X0X_REG_MAX_Y_LOW = 0x9b, + FT5X0X_REG_K_X_HIGH = 0x9c, + FT5X0X_REG_K_X_LOW = 0x9d, + FT5X0X_REG_K_Y_HIGH = 0x9e, + FT5X0X_REG_K_Y_LOW = 0x9f, + FT5X0X_REG_AUTO_CLB_MODE = 0xa0, + FT5X0X_REG_LIB_VERSION_H = 0xa1, + FT5X0X_REG_LIB_VERSION_L = 0xa2, + FT5X0X_REG_CIPHER = 0xa3, + FT5X0X_REG_MODE = 0xa4, + FT5X0X_REG_PMODE = 0xa5, /* Power Consume Mode */ + FT5X0X_REG_FIRMID = 0xa6, /* Firmware version */ + FT5X0X_REG_STATE = 0xa7, + FT5X0X_REG_FT5201ID = 0xa8, + FT5X0X_REG_ERR = 0xa9, + FT5X0X_REG_CLB = 0xaa, +}; + +//FT5X0X_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_STANDBY 0x02 +#define PMODE_HIBERNATE 0x03 + +#define DEV_NAME "wmtts" +#define DEV_MAJOR 11 + +#define TS_IOC_MAGIC 't' +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_CAL_CAP _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + +//#define FT_DEBUG + +#undef dbg +#ifdef FT_DEBUG + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + +//#define FTS_DBG +#ifdef FTS_DBG +#define DBG(fmt, args...) printk("[FTS]" fmt, ## args) +#else +#define DBG(fmt, args...) do{}while(0) +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c new file mode 100755 index 00000000..9db72130 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft5x0x_upg.c @@ -0,0 +1,506 @@ +#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mount.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h>
+#endif +#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "ft5x0x.h"
+
+typedef enum
+{
+ ERR_OK,
+ ERR_MODE,
+ ERR_READID,
+ ERR_ERASE,
+ ERR_STATUS,
+ ERR_ECC,
+ ERR_DL_ERASE_FAIL,
+ ERR_DL_PROGRAM_FAIL,
+ ERR_DL_VERIFY_FAIL,
+ ERR_FMID
+}E_UPGRADE_ERR_TYPE;
+
+#define FT5X_CTPM_ID_L 0X79
+#define FT5X_CTPM_ID_H 0X03
+
+#define FT56_CTPM_ID_L 0X79
+#define FT56_CTPM_ID_H 0X06
+
+#define FTS_PACKET_LENGTH 128
+
+extern struct ft5x0x_data *pContext;
+extern int ft5x0x_i2c_rxdata(char *rxdata, int length);
+extern int ft5x0x_i2c_txdata(char *txdata, int length);
+
+static int ft5x0x_write_reg(u8 addr, u8 para)
+{
+ u8 buf[2];
+ int ret = -1;
+
+ buf[0] = addr;
+ buf[1] = para;
+ ret = ft5x0x_i2c_txdata(buf, 2);
+ if (ret <= 0) {
+ printk("write reg failed! %x ret: %d", buf[0], ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ft5x0x_read_reg(u8 addr, u8 *pdata)
+{
+ int ret;
+ u8 buf[2];
+ struct i2c_msg msgs[2];
+
+ //
+ buf[0] = addr; //register address
+
+ msgs[0].addr = pContext->addr;
+ msgs[0].flags = 0 | I2C_M_NOSTART;
+ msgs[0].len = 1;
+ msgs[0].buf = buf;
+
+ msgs[1].addr = pContext->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = 1;
+ msgs[1].buf = pdata;
+
+ //ret = wmt_i2c_xfer_continue_if_4(msgs, 2, FT5X0X_I2C_BUS);
+ ret = i2c_transfer(pContext->client->adapter, msgs, 2); + if (ret <= 0)
+ printk("msg %s i2c read error: %d\n", __func__, ret);
+
+ return ret;
+
+}
+
+
+/*
+[function]:
+ send a command to ctpm.
+[parameters]:
+ btcmd[in] :command code;
+ btPara1[in] :parameter 1;
+ btPara2[in] :parameter 2;
+ btPara3[in] :parameter 3;
+ num[in] :the valid input parameter numbers, if only command code needed and no parameters followed,then the num is 1;
+[return]:
+ FTS_TRUE :success;
+ FTS_FALSE :io fail;
+*/
+static u8 cmd_write(u8 *cmd,u8 num)
+{
+ return ft5x0x_i2c_txdata(cmd, num);
+}
+
+/*
+[function]:
+ write data to ctpm , the destination address is 0.
+[parameters]:
+ pbt_buf[in] :point to data buffer;
+ bt_len[in] :the data numbers;
+[return]:
+ FTS_TRUE :success;
+ FTS_FALSE :io fail;
+*/
+static u8 byte_write(u8* pbt_buf, int dw_len)
+{
+
+ return ft5x0x_i2c_txdata( pbt_buf, dw_len);
+}
+
+/*
+[function]:
+ read out data from ctpm,the destination address is 0.
+[parameters]:
+ pbt_buf[out] :point to data buffer;
+ bt_len[in] :the data numbers;
+[return]:
+ FTS_TRUE :success;
+ FTS_FALSE :io fail;
+*/
+static u8 byte_read(u8* pbt_buf, u8 bt_len)
+{
+ int ret;
+ struct i2c_msg msg[1];
+ + msg[0].addr = pContext->addr;
+ msg[0].flags = I2C_M_RD;
+ msg[0].len = bt_len;
+ msg[0].buf = pbt_buf;
+ + ret = i2c_transfer(pContext->client->adapter, msg, 1); + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, FT5X0X_I2C_BUS);
+ if (ret <= 0) + printk("msg i2c read error: %d\n", ret);
+ + return ret;
+}
+
+
+/*
+[function]:
+ burn the FW to ctpm.
+[parameters]:(ref. SPEC)
+ pbt_buf[in] :point to Head+FW ;
+ dw_lenth[in]:the length of the FW + 6(the Head length);
+ bt_ecc[in] :the ECC of the FW
+[return]:
+ ERR_OK :no error;
+ ERR_MODE :fail to switch to UPDATE mode;
+ ERR_READID :read id fail;
+ ERR_ERASE :erase chip fail;
+ ERR_STATUS :status error;
+ ERR_ECC :ecc error.
+*/
+static E_UPGRADE_ERR_TYPE ft5x0x_fw_upgrade(struct ft5x0x_data *ft5x0x, u8* pbt_buf, int dw_lenth)
+{
+ int i = 0,j = 0,i_ret;
+ int packet_number;
+ int temp,lenght;
+ u8 packet_buf[FTS_PACKET_LENGTH + 6];
+ u8 auc_i2c_write_buf[10];
+ u8 reg_val[2] = {0};
+ u8 ctpm_id[2] = {0};
+ u8 cmd[4];
+ u8 bt_ecc;
+
+ /*********Step 1:Reset CTPM *****/
+ /*write 0xaa to register 0xfc*/
+ ft5x0x_write_reg(0xfc,0xaa);
+ msleep(50);
+ /*write 0x55 to register 0xfc*/
+ ft5x0x_write_reg(0xfc,0x55);
+ printk("[FTS] Step 1: Reset CTPM.\n");
+ msleep(30);
+
+ /*********Step 2:Enter upgrade mode *****/
+ auc_i2c_write_buf[0] = 0x55;
+ auc_i2c_write_buf[1] = 0xaa;
+ do{
+ i ++;
+ i_ret = byte_write(auc_i2c_write_buf, 2);
+ mdelay(5);
+ }while(i_ret <= 0 && i < 5 );
+ msleep(20);
+
+ /*********Step 3:check READ-ID**********/
+ if(ft5x0x->id == FT5606){
+ ctpm_id[0] = FT56_CTPM_ID_L;
+ ctpm_id[1] = FT56_CTPM_ID_H;
+ }else{
+ ctpm_id[0] = FT5X_CTPM_ID_L;
+ ctpm_id[1] = FT5X_CTPM_ID_H;
+ }
+
+ cmd[0] = 0x90;
+ cmd[1] = 0x00;
+ cmd[2] = 0x00;
+ cmd[3] = 0x00;
+ cmd_write(cmd,4);
+ byte_read(reg_val,2);
+ if (reg_val[0] == ctpm_id[0] && reg_val[1] == ctpm_id[1]){
+ printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
+ }else{
+ printk("[FTS] ID_ERROR: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
+ return ERR_READID;
+ }
+
+ cmd[0] = 0xcd;
+ cmd_write(cmd,1);
+ byte_read(reg_val,1);
+ printk("[FTS] bootloader version = 0x%x\n", reg_val[0]);
+
+ /******Step 4:erase app and panel paramenter area *********/
+ cmd[0] = 0x61;
+ cmd_write(cmd,1); //erase app area
+ msleep(1500);
+ cmd[0] = 0x63;
+ cmd_write(cmd,1); //erase panel parameter area
+ msleep(100);
+ printk("[FTS] Step 4: erase. \n");
+
+ /*********Step 5:write firmware(FW) to ctpm flash*********/
+ bt_ecc = 0;
+ printk("[FTS] Step 5: start upgrade. \n");
+ dw_lenth = dw_lenth - 8;
+ packet_number = (dw_lenth) / FTS_PACKET_LENGTH;
+ packet_buf[0] = 0xbf;
+ packet_buf[1] = 0x00;
+ for (j=0;j<packet_number;j++){
+ temp = j * FTS_PACKET_LENGTH;
+ packet_buf[2] = (u8)(temp>>8);
+ packet_buf[3] = (u8)temp;
+ lenght = FTS_PACKET_LENGTH;
+ packet_buf[4] = (u8)(lenght>>8);
+ packet_buf[5] = (u8)lenght;
+
+ for (i=0;i<FTS_PACKET_LENGTH;i++){
+ packet_buf[6+i] = pbt_buf[j*FTS_PACKET_LENGTH + i];
+ bt_ecc ^= packet_buf[6+i];
+ }
+
+ byte_write(&packet_buf[0],FTS_PACKET_LENGTH + 6);
+ mdelay(FTS_PACKET_LENGTH/6 + 1);
+ if ((j * FTS_PACKET_LENGTH % 1024) == 0){
+ printk("[FTS] upgrade the 0x%x th byte.\n", ((unsigned int)j) * FTS_PACKET_LENGTH);
+ }
+ }
+
+ if ((dw_lenth) % FTS_PACKET_LENGTH > 0){
+ temp = packet_number * FTS_PACKET_LENGTH;
+ packet_buf[2] = (u8)(temp>>8);
+ packet_buf[3] = (u8)temp;
+
+ temp = (dw_lenth) % FTS_PACKET_LENGTH;
+ packet_buf[4] = (u8)(temp>>8);
+ packet_buf[5] = (u8)temp;
+
+ for (i=0;i<temp;i++){
+ packet_buf[6+i] = pbt_buf[ packet_number*FTS_PACKET_LENGTH + i];
+ bt_ecc ^= packet_buf[6+i];
+ }
+
+ byte_write(&packet_buf[0],temp+6);
+ mdelay(20);
+ }
+
+ //send the last six byte
+ for (i = 0; i<6; i++){
+ temp = 0x6ffa + i;
+ packet_buf[2] = (u8)(temp>>8);
+ packet_buf[3] = (u8)temp;
+ temp =1;
+ packet_buf[4] = (u8)(temp>>8);
+ packet_buf[5] = (u8)temp;
+ packet_buf[6] = pbt_buf[ dw_lenth + i];
+ bt_ecc ^= packet_buf[6];
+
+ byte_write(&packet_buf[0],7);
+ mdelay(20);
+ }
+
+ /*********Step 6: read out checksum********************/
+ /*send the opration head*/
+ cmd[0] = 0xcc;
+ cmd_write(cmd,1);
+ byte_read(reg_val,1);
+ printk("[FTS] Step 6:read ECC 0x%x, firmware ECC 0x%x. \n", reg_val[0], bt_ecc);
+ if(reg_val[0] != bt_ecc){
+ return ERR_ECC;
+ }
+
+ /*********Step 7: reset the new FW***********************/
+ cmd[0] = 0x07;
+ cmd_write(cmd,1);
+
+ msleep(300); //make sure CTP startup normally
+
+ return ERR_OK;
+}
+
+int ft5x0x_auto_clb(void)
+{
+ u8 uc_temp;
+ u8 i ;
+
+ printk("[FTS] start auto CLB.\n");
+ msleep(200);
+ ft5x0x_write_reg(0, 0x40);
+ msleep(100); //make sure already enter factory mode
+ ft5x0x_write_reg(2, 0x4); //write command to start calibration
+ msleep(300);
+ for(i=0;i<100;i++){
+ ft5x0x_read_reg(0,&uc_temp);
+ if ( ((uc_temp&0x70)>>4) == 0x0){ //return to normal mode, calibration finish
+ break;
+ }
+ msleep(200);
+ printk("[FTS] waiting calibration %d\n",i);
+ }
+ printk("[FTS] calibration OK.\n");
+
+ msleep(300);
+ ft5x0x_write_reg(0, 0x40); //goto factory mode
+ msleep(100); //make sure already enter factory mode
+ ft5x0x_write_reg(2, 0x5); //store CLB result
+ msleep(300);
+ ft5x0x_write_reg(0, 0x0); //return to normal mode
+ msleep(300);
+ printk("[FTS] store CLB result OK.\n");
+ return 0;
+}
+
+static int ft5x0x_get_bin_ver(const u8 *fw, int fw_szie)
+{
+ if (fw_szie > 2){
+ return fw[fw_szie - 2];
+ }else{
+ return 0xff; //default value
+ }
+ return 0xff;
+}
+
+int ft5x0x_read_fw_ver(void)
+{
+ u8 ver=0;
+ int ret=0;
+
+ ret = ft5x0x_read_reg(FT5X0X_REG_FIRMID, &ver);
+ if(ret > 0)
+ return ver;
+
+ return ret;
+}
+
+
+static int ft5x0x_get_fw_szie(const char *fw_name)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize = 0;
+
+ if(fw_name == NULL){
+ dbg_err("Firmware name error.\n");
+ return -EFAULT;
+ }
+
+ if (NULL == pfile)
+ pfile = filp_open(fw_name, O_RDONLY, 0);
+
+ if (IS_ERR(pfile)) {
+ dbg_err("File open error: %s.\n", fw_name);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ filp_close(pfile, NULL);
+ return fsize;
+}
+
+static int ft5x0x_read_fw(const char *fw_name, u8 *buf)
+{
+ struct file *pfile = NULL;
+ struct inode *inode;
+ unsigned long magic;
+ off_t fsize;
+ loff_t pos;
+ mm_segment_t fs;
+
+ if(fw_name == NULL){
+ dbg_err("Firmware name error.\n");
+ return -EFAULT;
+ }
+
+ if (NULL == pfile)
+ pfile = filp_open(fw_name, O_RDONLY, 0);
+ if (IS_ERR(pfile)) {
+ dbg_err("File open error: %s.\n", fw_name);
+ return -EIO;
+ }
+
+ inode = pfile->f_dentry->d_inode;
+ magic = inode->i_sb->s_magic;
+ fsize = inode->i_size;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ pos = 0;
+ vfs_read(pfile, buf, fsize, &pos);
+ filp_close(pfile, NULL);
+ set_fs(fs);
+
+ return 0;
+}
+
+#define FW_SUFFFIX ".bin"
+#define SD_UPG_BIN_PATH "/sdcard/_wmt_ft5x0x_fw_app.bin"
+#define FS_UPG_BIN_PATH "/lib/firmware/"
+
+int ft5x0x_upg_fw_bin(struct ft5x0x_data *ft5x0x, int check_ver)
+{
+ int i_ret = 0;
+ int fwsize = 0;
+ int hw_fw_ver;
+ int bin_fw_ver;
+ int do_upg;
+ u8 *pbt_buf = NULL;
+ u8 fw_path[128] = {0};
+
+ if(ft5x0x->upg)
+ sprintf(fw_path,"%s%s%s", FS_UPG_BIN_PATH, ft5x0x->fw_name,FW_SUFFFIX);//get fw binary file from filesystem
+ else
+ strcpy(fw_path,SD_UPG_BIN_PATH); //get fw binary file from SD card
+
+ fwsize = ft5x0x_get_fw_szie(fw_path);
+ if (fwsize <= 0) {
+ dbg_err("Get firmware size failed\n");
+ return -EIO;
+ }
+
+ if (fwsize < 8 || fwsize > 32 * 1024) {
+ dbg_err("FW length error\n");
+ return -EIO;
+ }
+
+ pbt_buf = kmalloc(fwsize + 1, GFP_KERNEL);
+ if (ft5x0x_read_fw(fw_path, pbt_buf)) {
+ dbg_err("Request_firmware failed\n");
+ i_ret = -EIO;
+ goto exit;
+ }
+
+ hw_fw_ver =ft5x0x_read_fw_ver();
+ if(hw_fw_ver <= 0){
+ dbg_err("Read firmware version failed\n");
+ i_ret = hw_fw_ver;
+ goto exit;
+ }
+
+ bin_fw_ver = ft5x0x_get_bin_ver(pbt_buf, fwsize);
+ printk("[FTS] hardware fw ver 0x%0x, binary ver 0x%0x\n",hw_fw_ver, bin_fw_ver);
+
+ if(check_ver){
+ if(hw_fw_ver == 0xa6 || hw_fw_ver < bin_fw_ver)
+ do_upg = 1;
+ else
+ do_upg = 0;
+ }else{
+ do_upg = 1;
+ }
+
+ if(do_upg){
+ if ((pbt_buf[fwsize - 8] ^ pbt_buf[fwsize - 6]) == 0xFF &&
+ (pbt_buf[fwsize - 7] ^ pbt_buf[fwsize - 5]) == 0xFF &&
+ (pbt_buf[fwsize - 3] ^ pbt_buf[fwsize - 4]) == 0xFF) {
+ i_ret = ft5x0x_fw_upgrade(ft5x0x, pbt_buf, fwsize);
+ if (i_ret)
+ dbg_err("Upgrade failed, i_ret=%d\n",i_ret);
+ else {
+ hw_fw_ver = ft5x0x_read_fw_ver();
+ printk("[FTS] upgrade to new version 0x%x\n", hw_fw_ver);
+ }
+ } else {
+ dbg_err("FW format error\n");
+ }
+ }
+
+ ft5x0x_auto_clb();/*start auto CLB*/
+
+exit:
+ kfree(pbt_buf);
+ return i_ret;
+}
+
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c new file mode 100755 index 00000000..08fc6069 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c @@ -0,0 +1,1021 @@ +/* + *drivers/input/touchscreen/ft5x06_ex_fun.c + * + *FocalTech ft6x06 expand function for debug. + * + *Copyright (c) 2010 Focal tech Ltd. + * + *This software is licensed under the terms of the GNU General Public + *License version 2, as published by the Free Software Foundation, and + *may be copied, distributed, and modified under those terms. + * + *This program is distributed in the hope that it will be useful, + *but WITHOUT ANY WARRANTY; without even the implied warranty of + *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + *GNU General Public License for more details. + * + *Note:the error code of EIO is the general error in this file. + */ + + +#include "ft6x06_ex_fun.h" +#include "ft6x06_ts.h" + +#include <linux/mount.h> +#include <linux/netdevice.h> +#include <linux/proc_fs.h> + +struct Upgrade_Info { + u16 delay_aa; /*delay of write FT_UPGRADE_AA */ + u16 delay_55; /*delay of write FT_UPGRADE_55 */ + u8 upgrade_id_1; /*upgrade id 1 */ + u8 upgrade_id_2; /*upgrade id 2 */ + u16 delay_readid; /*delay of read id */ + u16 delay_earse_flash; /*delay of earse flash*/ +}; + + +int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, + u32 dw_lenth); + +static unsigned char CTPM_FW[] = { + #include "FT5406.i" +}; + +static struct mutex g_device_mutex; + +int ft6x06_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue) +{ + unsigned char buf[2] = {0}; + buf[0] = regaddr; + buf[1] = regvalue; + + return ft6x06_i2c_Write(client, buf, sizeof(buf)); +} + + +int ft6x06_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue) +{ + return ft6x06_i2c_Read(client, ®addr, 1, regvalue, 1); +} + + +int fts_ctpm_auto_clb(struct i2c_client *client) +{ + unsigned char uc_temp = 0x00; + unsigned char i = 0; + + /*start auto CLB */ + msleep(200); + + ft6x06_write_reg(client, 0, FTS_FACTORYMODE_VALUE); + /*make sure already enter factory mode */ + msleep(100); + /*write command to start calibration */ + ft6x06_write_reg(client, 2, 0x4); + msleep(300); + for (i = 0; i < 100; i++) { + ft6x06_read_reg(client, 0, &uc_temp); + /*return to normal mode, calibration finish */ + if (0x0 == ((uc_temp & 0x70) >> 4)) + break; + } + + msleep(200); + /*calibration OK */ + msleep(300); + ft6x06_write_reg(client, 0, FTS_FACTORYMODE_VALUE); /*goto factory mode for store */ + msleep(100); /*make sure already enter factory mode */ + ft6x06_write_reg(client, 2, 0x5); /*store CLB result */ + msleep(300); + ft6x06_write_reg(client, 0, FTS_WORKMODE_VALUE); /*return to normal mode */ + msleep(300); + + /*store CLB result OK */ + return 0; +} + +/* +upgrade with *.i file +*/ +int fts_ctpm_fw_upgrade_with_i_file(struct i2c_client *client) +{ + u8 *pbt_buf = NULL; + int i_ret; + int fw_len = sizeof(CTPM_FW); + + /*judge the fw that will be upgraded + * if illegal, then stop upgrade and return. + */ + + if (fw_len < 8 || fw_len > 32 * 1024) { + dev_err(&client->dev, "%s:FW length error\n", __func__); + return -EIO; + } + + /*FW upgrade */ + pbt_buf = CTPM_FW; + /*call the upgrade function */ + + i_ret = fts_ctpm_fw_upgrade(client, pbt_buf, sizeof(CTPM_FW)); + if (i_ret != 0) + dev_err(&client->dev, "%s:upgrade failed. err.\n", + __func__); + + return i_ret; +} + +u8 fts_ctpm_get_i_file_ver(void) +{ + u16 ui_sz; + ui_sz = sizeof(CTPM_FW); + if (ui_sz > 2) + return CTPM_FW[0x10a]; + + return 0x00; /*default value */ +} + +/*update project setting +*only update these settings for COB project, or for some special case +*/ +int fts_ctpm_update_project_setting(struct i2c_client *client) +{ + u8 uc_i2c_addr; /*I2C slave address (7 bit address)*/ + u8 uc_io_voltage; /*IO Voltage 0---3.3v; 1----1.8v*/ + u8 uc_panel_factory_id; /*TP panel factory ID*/ + u8 buf[FTS_SETTING_BUF_LEN]; + u8 reg_val[2] = {0}; + u8 auc_i2c_write_buf[10] = {0}; + u8 packet_buf[FTS_SETTING_BUF_LEN + 6]; + u32 i = 0; + int i_ret; + + uc_i2c_addr = client->addr; + uc_io_voltage = 0x0; + uc_panel_factory_id = 0x5a; + + + /*Step 1:Reset CTPM + *write 0xaa to register 0xfc + */ + ft6x06_write_reg(client, 0xfc, 0xaa); + msleep(50); + + /*write 0x55 to register 0xfc */ + ft6x06_write_reg(client, 0xfc, 0x55); + msleep(30); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = 0x55; + auc_i2c_write_buf[1] = 0xaa; + do { + i++; + i_ret = ft6x06_i2c_Write(client, auc_i2c_write_buf, 2); + msleep(5); + } while (i_ret <= 0 && i < 5); + + + /*********Step 3:check READ-ID***********************/ + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = + 0x00; + + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + + if (reg_val[0] == 0x79 && reg_val[1] == 0x3) + dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + else + return -EIO; + + auc_i2c_write_buf[0] = 0xcd; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + dev_dbg(&client->dev, "bootloader version = 0x%x\n", reg_val[0]); + + /*--------- read current project setting ---------- */ + /*set read start address */ + buf[0] = 0x3; + buf[1] = 0x0; + buf[2] = 0x78; + buf[3] = 0x0; + + ft6x06_i2c_Read(client, buf, 4, buf, FTS_SETTING_BUF_LEN); + dev_dbg(&client->dev, "[FTS] old setting: uc_i2c_addr = 0x%x,\ + uc_io_voltage = %d, uc_panel_factory_id = 0x%x\n", + buf[0], buf[2], buf[4]); + + /*--------- Step 4:erase project setting --------------*/ + auc_i2c_write_buf[0] = 0x63; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(100); + + /*---------- Set new settings ---------------*/ + buf[0] = uc_i2c_addr; + buf[1] = ~uc_i2c_addr; + buf[2] = uc_io_voltage; + buf[3] = ~uc_io_voltage; + buf[4] = uc_panel_factory_id; + buf[5] = ~uc_panel_factory_id; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + packet_buf[2] = 0x78; + packet_buf[3] = 0x0; + packet_buf[4] = 0; + packet_buf[5] = FTS_SETTING_BUF_LEN; + + for (i = 0; i < FTS_SETTING_BUF_LEN; i++) + packet_buf[6 + i] = buf[i]; + + ft6x06_i2c_Write(client, packet_buf, FTS_SETTING_BUF_LEN + 6); + msleep(100); + + /********* reset the new FW***********************/ + auc_i2c_write_buf[0] = 0x07; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + + msleep(200); + return 0; +} + +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + u8 uc_host_fm_ver = FT6x06_REG_FW_VER; + u8 uc_tp_fm_ver; + int i_ret; + + ft6x06_read_reg(client, FT6x06_REG_FW_VER, &uc_tp_fm_ver); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + + if (/*the firmware in touch panel maybe corrupted */ + uc_tp_fm_ver == FT6x06_REG_FW_VER || + /*the firmware in host flash is new, need upgrade */ + uc_tp_fm_ver < uc_host_fm_ver + ) { + msleep(100); + dev_dbg(&client->dev, "[FTS] uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x\n", + uc_tp_fm_ver, uc_host_fm_ver); + i_ret = fts_ctpm_fw_upgrade_with_i_file(client); + if (i_ret == 0) { + msleep(300); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + dev_dbg(&client->dev, "[FTS] upgrade to new version 0x%x\n", + uc_host_fm_ver); + } else { + pr_err("[FTS] upgrade failed ret=%d.\n", i_ret); + return -EIO; + } + } + + return 0; +} + +void delay_qt_ms(unsigned long w_ms) +{ + unsigned long i; + unsigned long j; + + for (i = 0; i < w_ms; i++) + { + for (j = 0; j < 1000; j++) + { + udelay(1); + } + } +} + +int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, + u32 dw_lenth) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u32 packet_number; + u32 j; + u32 temp; + u32 lenght; + u32 fw_length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 bt_ecc; + int i_ret; + + + if(pbt_buf[0] != 0x02) + { + DBG("[FTS] FW first byte is not 0x02. so it is invalid \n"); + return -1; + } + + if(dw_lenth > 0x11f) + { + fw_length = ((u32)pbt_buf[0x100]<<8) + pbt_buf[0x101]; + if(dw_lenth < fw_length) + { + DBG("[FTS] Fw length is invalid \n"); + return -1; + } + } + else + { + DBG("[FTS] Fw length is invalid \n"); + return -1; + } + + //DBG("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", reg_val[0], reg_val[1]); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*********Step 1:Reset CTPM *****/ + /*write 0xaa to register 0xbc */ + + ft6x06_write_reg(client, 0xbc, FT_UPGRADE_AA); + msleep(FT6X06_UPGRADE_AA_DELAY); + + /*write 0x55 to register 0xbc */ + ft6x06_write_reg(client, 0xbc, FT_UPGRADE_55); + + msleep(FT6X06_UPGRADE_55_DELAY); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = FT_UPGRADE_55; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + + auc_i2c_write_buf[0] = FT_UPGRADE_AA; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(FT6X06_UPGRADE_READID_DELAY); + + /*********Step 3:check READ-ID***********************/ + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = + 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + + + if (reg_val[0] == FT6X06_UPGRADE_ID_1 + && reg_val[1] == FT6X06_UPGRADE_ID_2) { + //dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", + //reg_val[0], reg_val[1]); + DBG("[FTS] Step 3: GET CTPM ID OK,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + break; + } else { + dev_err(&client->dev, "[FTS] Step 3: GET CTPM ID FAIL,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + } + } + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + auc_i2c_write_buf[4] = 0x00; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 5); + + //auc_i2c_write_buf[0] = 0xcd; + //ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + + + /*Step 4:erase app and panel paramenter area*/ + DBG("Step 4:erase app and panel paramenter area\n"); + auc_i2c_write_buf[0] = 0x61; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); /*erase app area */ + msleep(FT6X06_UPGRADE_EARSE_DELAY); + + for(i = 0;i < 200;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == reg_val[0] && 0x02 == reg_val[1]) + { + DBG("[FTS] erase app finished \n"); + break; + } + msleep(50); + } + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + bt_ecc = 0; + DBG("Step 5:write firmware(FW) to ctpm flash\n"); + + dw_lenth = fw_length; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (lenght >> 8); + packet_buf[5] = (u8) lenght; + + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + bt_ecc ^= packet_buf[6 + i]; + } + + ft6x06_i2c_Write(client, packet_buf, FTS_PACKET_LENGTH + 6); + + for(i = 0;i < 30;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) == (((reg_val[0] & 0x0f) << 8) |reg_val[1])) + { + DBG("[FTS] write a block data finished \n"); + break; + } + msleep(1); + } + //msleep(FTS_PACKET_LENGTH / 6 + 1); + //DBG("write bytes:0x%04x\n", (j+1) * FTS_PACKET_LENGTH); + //delay_qt_ms(FTS_PACKET_LENGTH / 6 + 1); + } + + if ((dw_lenth) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number * FTS_PACKET_LENGTH + i]; + bt_ecc ^= packet_buf[6 + i]; + } + + ft6x06_i2c_Write(client, packet_buf, temp + 6); + + for(i = 0;i < 30;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) == (((reg_val[0] & 0x0f) << 8) |reg_val[1])) + { + DBG("[FTS] write a block data finished \n"); + break; + } + msleep(1); + } + //msleep(20); + } + + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + DBG("Step 6: read out checksum\n"); + auc_i2c_write_buf[0] = 0xcc; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != bt_ecc) { + dev_err(&client->dev, "[FTS]--ecc error! FW=%02x bt_ecc=%02x\n", + reg_val[0], + bt_ecc); + return -EIO; + } + + /*********Step 7: reset the new FW***********************/ + DBG("Step 7: reset the new FW\n"); + auc_i2c_write_buf[0] = 0x07; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(300); /*make sure CTP startup normally */ + + return 0; +} + +/*sysfs debug*/ + +/* +*get firmware size + +@firmware_name:firmware name +*note:the firmware default path is sdcard. + if you want to change the dir, please modify by yourself. +*/ +static int ft6x06_GetFirmwareSize(char *firmware_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + char filepath[128]; + memset(filepath, 0, sizeof(filepath)); + + sprintf(filepath, "/sdcard/%s", firmware_name); + + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + + + +/* +*read firmware buf for .bin file. + +@firmware_name: fireware name +@firmware_buf: data buf of fireware + +note:the firmware default path is sdcard. + if you want to change the dir, please modify by yourself. +*/ +static int ft6x06_ReadFirmware(char *firmware_name, + unsigned char *firmware_buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + char filepath[128]; + loff_t pos; + mm_segment_t old_fs; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "/sdcard/%s", firmware_name); + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, firmware_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + return 0; +} + + + +/* +upgrade with *.bin file +*/ + +int fts_ctpm_fw_upgrade_with_app_file(struct i2c_client *client, + char *firmware_name) +{ + u8 *pbt_buf = NULL; + int i_ret; + int fwsize = ft6x06_GetFirmwareSize(firmware_name); + + if (fwsize <= 0) { + dev_err(&client->dev, "%s ERROR:Get firmware size failed\n", + __func__); + return -EIO; + } + + if (fwsize < 8 || fwsize > 32 * 1024) { + dev_dbg(&client->dev, "%s:FW length error\n", __func__); + return -EIO; + } + + /*=========FW upgrade========================*/ + pbt_buf = kmalloc(fwsize + 1, GFP_ATOMIC); + + if (ft6x06_ReadFirmware(firmware_name, pbt_buf)) { + dev_err(&client->dev, "%s() - ERROR: request_firmware failed\n", + __func__); + kfree(pbt_buf); + return -EIO; + } + + /*call the upgrade function */ + i_ret = fts_ctpm_fw_upgrade(client, pbt_buf, fwsize); + if (i_ret != 0) + dev_err(&client->dev, "%s() - ERROR:[FTS] upgrade failed..\n", + __func__); + //else + //fts_ctpm_auto_clb(client); + kfree(pbt_buf); + + return i_ret; +} + +static ssize_t ft6x06_tpfwver_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t num_read_chars = 0; + u8 fwver = 0; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&g_device_mutex); + + if (ft6x06_read_reg(client, FT6x06_REG_FW_VER, &fwver) < 0) + num_read_chars = snprintf(buf, PAGE_SIZE, + "get tp fw version fail!\n"); + else + num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver); + + mutex_unlock(&g_device_mutex); + + return num_read_chars; +} + +static ssize_t ft6x06_tpfwver_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /*place holder for future use*/ + return -EPERM; +} + + + +static ssize_t ft6x06_tprwreg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /*place holder for future use*/ + return -EPERM; +} + +static ssize_t ft6x06_tprwreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + ssize_t num_read_chars = 0; + int retval; + long unsigned int wmreg = 0; + u8 regaddr = 0xff, regvalue = 0xff; + u8 valbuf[5] = {0}; + + memset(valbuf, 0, sizeof(valbuf)); + mutex_lock(&g_device_mutex); + num_read_chars = count - 1; + + if (num_read_chars != 2) { + if (num_read_chars != 4) { + pr_info("please input 2 or 4 character\n"); + goto error_return; + } + } + + memcpy(valbuf, buf, num_read_chars); + retval = strict_strtoul(valbuf, 16, &wmreg); + + if (0 != retval) { + dev_err(&client->dev, "%s() - ERROR: Could not convert the "\ + "given input to a number." \ + "The given input was: \"%s\"\n", + __func__, buf); + goto error_return; + } + + if (2 == num_read_chars) { + /*read register*/ + regaddr = wmreg; + if (ft6x06_read_reg(client, regaddr, ®value) < 0) + dev_err(&client->dev, "Could not read the register(0x%02x)\n", + regaddr); + else + pr_info("the register(0x%02x) is 0x%02x\n", + regaddr, regvalue); + } else { + regaddr = wmreg >> 8; + regvalue = wmreg; + if (ft6x06_write_reg(client, regaddr, regvalue) < 0) + dev_err(&client->dev, "Could not write the register(0x%02x)\n", + regaddr); + else + dev_err(&client->dev, "Write 0x%02x into register(0x%02x) successful\n", + regvalue, regaddr); + } + +error_return: + mutex_unlock(&g_device_mutex); + + return count; +} + +static ssize_t ft6x06_fwupdate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/*upgrade from *.i*/ +static ssize_t ft6x06_fwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ft6x06_ts_data *data = NULL; + u8 uc_host_fm_ver; + int i_ret; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + data = (struct ft6x06_ts_data *)i2c_get_clientdata(client); + + mutex_lock(&g_device_mutex); + + disable_irq(client->irq); + i_ret = fts_ctpm_fw_upgrade_with_i_file(client); + if (i_ret == 0) { + msleep(300); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + pr_info("%s [FTS] upgrade to new version 0x%x\n", __func__, + uc_host_fm_ver); + } else + dev_err(&client->dev, "%s ERROR:[FTS] upgrade failed.\n", + __func__); + + enable_irq(client->irq); + mutex_unlock(&g_device_mutex); + + return count; +} + +static ssize_t ft6x06_fwupgradeapp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /*place holder for future use*/ + return -EPERM; +} + + +/*upgrade from app.bin*/ +static ssize_t ft6x06_fwupgradeapp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char fwname[128]; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + memset(fwname, 0, sizeof(fwname)); + sprintf(fwname, "%s", buf); + fwname[count - 1] = '\0'; + + mutex_lock(&g_device_mutex); + disable_irq(client->irq); + + fts_ctpm_fw_upgrade_with_app_file(client, fwname); + + enable_irq(client->irq); + mutex_unlock(&g_device_mutex); + + return count; +} + + +/*sysfs */ +/*get the fw version +*example:cat ftstpfwver +*/ +static DEVICE_ATTR(ftstpfwver, S_IRUGO | S_IWUSR, ft6x06_tpfwver_show, + ft6x06_tpfwver_store); + +/*upgrade from *.i +*example: echo 1 > ftsfwupdate +*/ +static DEVICE_ATTR(ftsfwupdate, S_IRUGO | S_IWUSR, ft6x06_fwupdate_show, + ft6x06_fwupdate_store); + +/*read and write register +*read example: echo 88 > ftstprwreg ---read register 0x88 +*write example:echo 8807 > ftstprwreg ---write 0x07 into register 0x88 +* +*note:the number of input must be 2 or 4.if it not enough,please fill in the 0. +*/ +static DEVICE_ATTR(ftstprwreg, S_IRUGO | S_IWUSR, ft6x06_tprwreg_show, + ft6x06_tprwreg_store); + + +/*upgrade from app.bin +*example:echo "*_app.bin" > ftsfwupgradeapp +*/ +static DEVICE_ATTR(ftsfwupgradeapp, S_IRUGO | S_IWUSR, ft6x06_fwupgradeapp_show, + ft6x06_fwupgradeapp_store); + + +/*add your attr in here*/ +static struct attribute *ft6x06_attributes[] = { + &dev_attr_ftstpfwver.attr, + &dev_attr_ftsfwupdate.attr, + &dev_attr_ftstprwreg.attr, + &dev_attr_ftsfwupgradeapp.attr, + NULL +}; + +static struct attribute_group ft6x06_attribute_group = { + .attrs = ft6x06_attributes +}; + +/*create sysfs for debug*/ +int ft6x06_create_sysfs(struct i2c_client *client) +{ + int err; + err = sysfs_create_group(&client->dev.kobj, &ft6x06_attribute_group); + if (0 != err) { + dev_err(&client->dev, + "%s() - ERROR: sysfs_create_group() failed.\n", + __func__); + sysfs_remove_group(&client->dev.kobj, &ft6x06_attribute_group); + return -EIO; + } else { + mutex_init(&g_device_mutex); + pr_info("ft6x06:%s() - sysfs_create_group() succeeded.\n", + __func__); + } + return err; +} + +void ft6x06_release_sysfs(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &ft6x06_attribute_group); + mutex_destroy(&g_device_mutex); +} + +/*create apk debug channel*/ +#define PROC_UPGRADE 0 +#define PROC_READ_REGISTER 1 +#define PROC_WRITE_REGISTER 2 +#define PROC_AUTOCLB 4 +#define PROC_UPGRADE_INFO 5 +#define PROC_WRITE_DATA 6 +#define PROC_READ_DATA 7 + + +#define PROC_NAME "ft5x0x-debug" +static unsigned char proc_operate_mode = PROC_UPGRADE; +static struct proc_dir_entry *ft6x06_proc_entry; +/*interface of write proc*/ +static int ft6x06_debug_write(struct file *filp, + const char __user *buff, unsigned long len, void *data) +{ + struct i2c_client *client = (struct i2c_client *)ft6x06_proc_entry->data; + unsigned char writebuf[FTS_PACKET_LENGTH]; + int buflen = len; + int writelen = 0; + int ret = 0; + + if (copy_from_user(&writebuf, buff, buflen)) { + dev_err(&client->dev, "%s:copy from user error\n", __func__); + return -EFAULT; + } + proc_operate_mode = writebuf[0]; + + switch (proc_operate_mode) { + case PROC_UPGRADE: + { + char upgrade_file_path[128]; + memset(upgrade_file_path, 0, sizeof(upgrade_file_path)); + sprintf(upgrade_file_path, "%s", writebuf + 1); + upgrade_file_path[buflen-1] = '\0'; + DBG("%s\n", upgrade_file_path); + disable_irq(client->irq); + + ret = fts_ctpm_fw_upgrade_with_app_file(client, upgrade_file_path); + + enable_irq(client->irq); + if (ret < 0) { + dev_err(&client->dev, "%s:upgrade failed.\n", __func__); + return ret; + } + } + break; + case PROC_READ_REGISTER: + writelen = 1; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + case PROC_WRITE_REGISTER: + writelen = 2; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + case PROC_AUTOCLB: + DBG("%s: autoclb\n", __func__); + fts_ctpm_auto_clb(client); + break; + case PROC_READ_DATA: + case PROC_WRITE_DATA: + writelen = len - 1; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + default: + break; + } + + + return len; +} + +/*interface of read proc*/ +static int ft6x06_debug_read( char *page, char **start, + off_t off, int count, int *eof, void *data ) +{ + struct i2c_client *client = (struct i2c_client *)ft6x06_proc_entry->data; + int ret = 0; + unsigned char buf[PAGE_SIZE]; + int num_read_chars = 0; + int readlen = 0; + u8 regvalue = 0x00, regaddr = 0x00; + + switch (proc_operate_mode) { + case PROC_UPGRADE: + /*after calling ft5x0x_debug_write to upgrade*/ + regaddr = 0xA6; + ret = ft6x06_read_reg(client, regaddr, ®value); + if (ret < 0) + num_read_chars = sprintf(buf, "%s", "get fw version failed.\n"); + else + num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue); + break; + case PROC_READ_REGISTER: + readlen = 1; + ret = ft6x06_i2c_Read(client, NULL, 0, buf, readlen); + if (ret < 0) { + dev_err(&client->dev, "%s:read iic error\n", __func__); + return ret; + } + num_read_chars = 1; + break; + case PROC_READ_DATA: + readlen = count; + ret = ft6x06_i2c_Read(client, NULL, 0, buf, readlen); + if (ret < 0) { + dev_err(&client->dev, "%s:read iic error\n", __func__); + return ret; + } + + num_read_chars = readlen; + break; + case PROC_WRITE_DATA: + break; + default: + break; + } + + memcpy(page, buf, num_read_chars); + return num_read_chars; +} +int ft6x06_create_apk_debug_channel(struct i2c_client * client) +{ + ft6x06_proc_entry = create_proc_entry(PROC_NAME, 0777, NULL); + if (NULL == ft6x06_proc_entry) { + dev_err(&client->dev, "Couldn't create proc entry!\n"); + return -ENOMEM; + } else { + dev_info(&client->dev, "Create proc entry success!\n"); + ft6x06_proc_entry->data = client; + ft6x06_proc_entry->write_proc = ft6x06_debug_write; + ft6x06_proc_entry->read_proc = ft6x06_debug_read; + } + return 0; +} + +void ft6x06_release_apk_debug_channel(void) +{ + if (ft6x06_proc_entry) + remove_proc_entry(PROC_NAME, NULL); +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h new file mode 100755 index 00000000..e25675c0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.h @@ -0,0 +1,79 @@ +#ifndef __LINUX_FT6X06_EX_FUN_H__
+#define __LINUX_FT6X06_EX_FUN_H__
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+
+#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+
+
+#define FT_UPGRADE_AA 0xAA
+#define FT_UPGRADE_55 0x55
+
+
+//upgrade config of FT6X06
+/*
+#define FT6X06_UPGRADE_AA_DELAY 100
+#define FT6X06_UPGRADE_55_DELAY 10
+#define FT6X06_UPGRADE_ID_1 0x79
+#define FT6X06_UPGRADE_ID_2 0x08
+#define FT6X06_UPGRADE_READID_DELAY 10
+#define FT6X06_UPGRADE_EARSE_DELAY 2000
+*/
+
+/*upgrade config of FT6X36*/
+#define FT6X06_UPGRADE_AA_DELAY 10
+#define FT6X06_UPGRADE_55_DELAY 10
+#define FT6X06_UPGRADE_ID_1 0x79
+#define FT6X06_UPGRADE_ID_2 0x18
+#define FT6X06_UPGRADE_READID_DELAY 10
+#define FT6X06_UPGRADE_EARSE_DELAY 2000
+
+#define FTS_PACKET_LENGTH 128
+#define FTS_SETTING_BUF_LEN 128
+
+#define FTS_UPGRADE_LOOP 20
+
+#define FTS_FACTORYMODE_VALUE 0x40
+#define FTS_WORKMODE_VALUE 0x00
+
+//#define AUTO_CLB
+#define FTS_DBG
+#ifdef FTS_DBG
+#define DBG(fmt, args...) printk("[FTS]" fmt, ## args)
+#else
+#define DBG(fmt, args...) do{}while(0)
+#endif
+
+/*create sysfs for debug*/
+int ft6x06_create_sysfs(struct i2c_client * client);
+
+void ft6x06_release_sysfs(struct i2c_client * client);
+
+int ft6x06_create_apk_debug_channel(struct i2c_client *client);
+
+void ft6x06_release_apk_debug_channel(void);
+
+/*
+*ft6x06_write_reg- write register
+*@client: handle of i2c
+*@regaddr: register address
+*@regvalue: register value
+*
+*/
+int ft6x06_write_reg(struct i2c_client * client,u8 regaddr, u8 regvalue);
+
+int ft6x06_read_reg(struct i2c_client * client,u8 regaddr, u8 *regvalue);
+
+#endif
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c new file mode 100755 index 00000000..56148177 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.c @@ -0,0 +1,511 @@ +/* drivers/input/touchscreen/ft5x06_ts.c + * + * FocalTech ft6x06 TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include "ft6x06_ts.h" +//#include <linux/earlysuspend.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <mach/irqs.h> +#include <linux/kernel.h> +#include <linux/semaphore.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/syscalls.h> +#include <linux/unistd.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/timer.h> + +//#define FTS_CTL_FACE_DETECT +#define FTS_CTL_IIC +#define SYSFS_DEBUG +#define FTS_APK_DEBUG +//#define FT6X06_DOWNLOAD + +#ifdef FTS_CTL_IIC +#include "focaltech_ctl.h" +#endif +#ifdef FTS_CTL_FACE_DETECT +#include "ft_psensor_drv.h" +#endif +#ifdef SYSFS_DEBUG +#include "ft6x06_ex_fun.h" +#endif + +#if 0 +struct ts_event { + u16 au16_x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */ + u16 au16_y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */ + u8 au8_touch_event[CFG_MAX_TOUCH_POINTS]; /*touch event: + 0 -- down; 1-- up; 2 -- contact */ + u8 au8_finger_id[CFG_MAX_TOUCH_POINTS]; /*touch ID */ + u16 pressure; + u8 touch_point; +}; + +struct ft6x06_ts_data { + unsigned int irq; + unsigned int x_max; + unsigned int y_max; + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + struct ft6x06_platform_data *pdata; +#ifdef CONFIG_PM + struct early_suspend *early_suspend; +#endif +}; + +#define FTS_POINT_UP 0x01 +#define FTS_POINT_DOWN 0x00 +#define FTS_POINT_CONTACT 0x02 +#endif + +/* +*ft6x06_i2c_Read-read data and write data by i2c +*@client: handle of i2c +*@writebuf: Data that will be written to the slave +*@writelen: How many bytes to write +*@readbuf: Where to store data read from slave +*@readlen: How many bytes to read +* +*Returns negative errno, else the number of messages executed +* +* +*/ +int ft6x06_i2c_Read(struct i2c_client *client, char *writebuf, + int writelen, char *readbuf, int readlen) +{ + int ret; + + if (writelen > 0) { + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + dev_err(&client->dev, "f%s: i2c read error.\n", + __func__); + } else { + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) + dev_err(&client->dev, "%s:i2c read error.\n", __func__); + } + return ret; +} +/*write data by i2c*/ +int ft6x06_i2c_Write(struct i2c_client *client, char *writebuf, int writelen) +{ + int ret; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + dev_err(&client->dev, "%s i2c write error.\n", __func__); + + return ret; +} + +#if 0 +/*Read touch point information when the interrupt is asserted.*/ +static int ft6x06_read_Touchdata(struct ft6x06_ts_data *data) +{ + struct ts_event *event = &data->event; + u8 buf[POINT_READ_BUF] = { 0 }; + int ret = -1; + int i = 0; + u8 pointid = FT_MAX_ID; + + ret = ft6x06_i2c_Read(data->client, buf, 1, buf, POINT_READ_BUF); + if (ret < 0) { + dev_err(&data->client->dev, "%s read touchdata failed.\n", + __func__); + return ret; + } + memset(event, 0, sizeof(struct ts_event)); + + //event->touch_point = buf[2] & 0x0F; + + //event->touch_point = 0; + + for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) + { + pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4; + if (pointid >= FT_MAX_ID) + break; + else + event->touch_point++; + event->au16_x[i] = + (s16) (buf[FT_TOUCH_X_H_POS + FT_TOUCH_STEP * i] & 0x0F) << + 8 | (s16) buf[FT_TOUCH_X_L_POS + FT_TOUCH_STEP * i]; + event->au16_y[i] = + (s16) (buf[FT_TOUCH_Y_H_POS + FT_TOUCH_STEP * i] & 0x0F) << + 8 | (s16) buf[FT_TOUCH_Y_L_POS + FT_TOUCH_STEP * i]; + event->au8_touch_event[i] = + buf[FT_TOUCH_EVENT_POS + FT_TOUCH_STEP * i] >> 6; + event->au8_finger_id[i] = + (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4; + } + + //event->pressure = FT_PRESS; + + return 0; +} + +/* +*report the point information +*/ +static void ft6x06_report_value(struct ft6x06_ts_data *data) +{ + struct ts_event *event = &data->event; + int i = 0; + int up_point = 0; + + for (i = 0; i < event->touch_point; i++) + { + input_mt_slot(data->input_dev, event->au8_finger_id[i]); + + if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2) + { + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, + true); + //input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, + //event->au8_finger_id[i]); + input_report_abs(data->input_dev, ABS_MT_PRESSURE, + 0x3f); + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, + 0x05); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, + event->au16_x[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, + event->au16_y[i]); + + } + else + { + up_point++; + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, + false); + } + + } + + if(event->touch_point == up_point) + input_report_key(data->input_dev, BTN_TOUCH, 0); + else + input_report_key(data->input_dev, BTN_TOUCH, 1); + + input_sync(data->input_dev); + +} + +/*The ft6x06 device will signal the host about TRIGGER_FALLING. +*Processed when the interrupt is asserted. +*/ +static irqreturn_t ft6x06_ts_interrupt(int irq, void *dev_id) +{ + struct ft6x06_ts_data *ft6x06_ts = dev_id; + int ret = 0; + disable_irq_nosync(ft6x06_ts->irq); + + ret = ft6x06_read_Touchdata(ft6x06_ts); + if (ret == 0) + ft6x06_report_value(ft6x06_ts); + + enable_irq(ft6x06_ts->irq); + + //printk(KERN_WARNING "interrupt \n"); + + return IRQ_HANDLED; +} + +static int ft6x06_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ft6x06_platform_data *pdata = + (struct ft6x06_platform_data *)client->dev.platform_data; + struct ft6x06_ts_data *ft6x06_ts; + struct input_dev *input_dev; + int err = 0; + unsigned char uc_reg_value; + unsigned char uc_reg_addr; + + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + err = -ENODEV; + goto exit_check_functionality_failed; + } + + ft6x06_ts = kzalloc(sizeof(struct ft6x06_ts_data), GFP_KERNEL); + + if (!ft6x06_ts) { + err = -ENOMEM; + goto exit_alloc_data_failed; + } + + i2c_set_clientdata(client, ft6x06_ts); + ft6x06_ts->irq = client->irq; + ft6x06_ts->client = client; + ft6x06_ts->pdata = pdata; + ft6x06_ts->x_max = pdata->x_max - 1; + ft6x06_ts->y_max = pdata->y_max - 1; + ft6x06_ts->pdata->irq = ft6x06_ts->irq; + client->irq = ft6x06_ts->irq; + pr_info("irq = %d\n", client->irq); + +#ifdef CONFIG_PM + #if 0 + err = gpio_request(pdata->reset, "ft6x06 reset"); + if (err < 0) { + dev_err(&client->dev, "%s:failed to set gpio reset.\n", + __func__); + goto exit_request_reset; + } + #endif +#endif + + err = request_threaded_irq(client->irq, NULL, ft6x06_ts_interrupt, + IRQF_TRIGGER_FALLING, client->dev.driver->name, + ft6x06_ts); + + if (err < 0) { + dev_err(&client->dev, "ft6x06_probe: request irq failed\n"); + goto exit_irq_request_failed; + } + disable_irq(client->irq); + + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + dev_err(&client->dev, "failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + ft6x06_ts->input_dev = input_dev; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + + input_mt_init_slots(input_dev, MT_MAX_TOUCH_POINTS); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, PRESS_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, ft6x06_ts->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, ft6x06_ts->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PRESSURE, + 0, PRESS_MAX, 0, 0); + + input_dev->name = FT6X06_NAME; + err = input_register_device(input_dev); + if (err) { + dev_err(&client->dev, + "ft6x06_ts_probe: failed to register input device: %s\n", + dev_name(&client->dev)); + goto exit_input_register_device_failed; + } + /*make sure CTP already finish startup process */ + msleep(150); + + /*get some register information */ + uc_reg_addr = FT6x06_REG_FW_VER; + ft6x06_i2c_Read(client, &uc_reg_addr, 1, &uc_reg_value, 1); + dev_dbg(&client->dev, "[FTS] Firmware version = 0x%x\n", uc_reg_value); + + uc_reg_addr = FT6x06_REG_POINT_RATE; + ft6x06_i2c_Read(client, &uc_reg_addr, 1, &uc_reg_value, 1); + dev_dbg(&client->dev, "[FTS] report rate is %dHz.\n", + uc_reg_value * 10); + + uc_reg_addr = FT6x06_REG_THGROUP; + ft6x06_i2c_Read(client, &uc_reg_addr, 1, &uc_reg_value, 1); + dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", + uc_reg_value * 4); + +#ifdef SYSFS_DEBUG + ft6x06_create_sysfs(client); +#endif + +#ifdef FTS_CTL_IIC + if (ft_rw_iic_drv_init(client) < 0) + dev_err(&client->dev, "%s:[FTS] create fts control iic driver failed\n", + __func__); +#endif + +#ifdef FTS_APK_DEBUG + ft6x06_create_apk_debug_channel(client); +#endif + +#ifdef FTS_CTL_FACE_DETECT + if (ft_psensor_drv_init(client) < 0) + dev_err(&client->dev, "%s:[FTS] create fts control psensor driver failed\n", + __func__); +#endif + + enable_irq(client->irq); + return 0; + +exit_input_register_device_failed: + input_free_device(input_dev); + +exit_input_dev_alloc_failed: + free_irq(client->irq, ft6x06_ts); +#ifdef CONFIG_PM +exit_request_reset: + gpio_free(ft6x06_ts->pdata->reset); +#endif + +exit_irq_request_failed: + i2c_set_clientdata(client, NULL); + kfree(ft6x06_ts); + +exit_alloc_data_failed: +exit_check_functionality_failed: + return err; +} + +#ifdef CONFIG_PM +static void ft6x06_ts_suspend(struct early_suspend *handler) +{ + struct ft6x06_ts_data *ts = container_of(handler, struct ft6x06_ts_data, + early_suspend); + + dev_dbg(&ts->client->dev, "[FTS]ft6x06 suspend\n"); + disable_irq(ts->pdata->irq); +} + +static void ft6x06_ts_resume(struct early_suspend *handler) +{ + struct ft6x06_ts_data *ts = container_of(handler, struct ft6x06_ts_data, + early_suspend); + + dev_dbg(&ts->client->dev, "[FTS]ft6x06 resume.\n"); + gpio_set_value(ts->pdata->reset, 0); + msleep(20); + gpio_set_value(ts->pdata->reset, 1); + enable_irq(ts->pdata->irq); +} +#else +#define ft6x06_ts_suspend NULL +#define ft6x06_ts_resume NULL +#endif + +static int __devexit ft6x06_ts_remove(struct i2c_client *client) +{ + struct ft6x06_ts_data *ft6x06_ts; + ft6x06_ts = i2c_get_clientdata(client); + input_unregister_device(ft6x06_ts->input_dev); + #ifdef CONFIG_PM + gpio_free(ft6x06_ts->pdata->reset); + #endif + + #ifdef SYSFS_DEBUG + ft6x06_release_sysfs(client); + #endif + #ifdef FTS_CTL_IIC + ft_rw_iic_drv_exit(); + #endif + #ifdef FTS_CTL_FACE_DETECT + ft_psensor_drv_exit(); + #endif + free_irq(client->irq, ft6x06_ts); + kfree(ft6x06_ts); + i2c_set_clientdata(client, NULL); + return 0; +} + +static const struct i2c_device_id ft6x06_ts_id[] = { + {FT6X06_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ft6x06_ts_id); + +static struct i2c_driver ft6x06_ts_driver = { + .probe = ft6x06_ts_probe, + .remove = __devexit_p(ft6x06_ts_remove), + .id_table = ft6x06_ts_id, + .suspend = ft6x06_ts_suspend, + .resume = ft6x06_ts_resume, + .driver = { + .name = FT6X06_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ft6x06_ts_init(void) +{ + int ret; + ret = i2c_add_driver(&ft6x06_ts_driver); + if (ret) { + printk(KERN_WARNING "Adding ft6x06 driver failed " + "(errno = %d)\n", ret); + } else { + pr_info("Successfully added driver %s\n", + ft6x06_ts_driver.driver.name); + } + return ret; +} + +static void __exit ft6x06_ts_exit(void) +{ + i2c_del_driver(&ft6x06_ts_driver); +} + +module_init(ft6x06_ts_init); +module_exit(ft6x06_ts_exit); + +MODULE_AUTHOR("<luowj>"); +MODULE_DESCRIPTION("FocalTech ft6x06 TouchScreen driver"); +MODULE_LICENSE("GPL"); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h new file mode 100755 index 00000000..83859c05 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ft6x06_ts.h @@ -0,0 +1,52 @@ +#ifndef __LINUX_FT6X06_TS_H__ +#define __LINUX_FT6X06_TS_H__ + +/* -- dirver configure -- */ +#define CFG_MAX_TOUCH_POINTS 2 +#define MT_MAX_TOUCH_POINTS 9 + +#define PRESS_MAX 0xFF +#define FT_PRESS 0x7F + +#define Proximity_Max 32 + +#define FT_FACE_DETECT_ON 0xc0 +#define FT_FACE_DETECT_OFF 0xe0 + +#define FT_FACE_DETECT_ENABLE 1 +#define FT_FACE_DETECT_DISABLE 0 +#define FT_FACE_DETECT_REG 0xB0 + +#define FT6X06_NAME "ft6x06_ts" + +#define FT_MAX_ID 0x0F +#define FT_TOUCH_STEP 6 +#define FT_FACE_DETECT_POS 1 +#define FT_TOUCH_X_H_POS 3 +#define FT_TOUCH_X_L_POS 4 +#define FT_TOUCH_Y_H_POS 5 +#define FT_TOUCH_Y_L_POS 6 +#define FT_TOUCH_EVENT_POS 3 +#define FT_TOUCH_ID_POS 5 + +#define POINT_READ_BUF (3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS) + +/*register address*/ +#define FT6x06_REG_FW_VER 0xA6 +#define FT6x06_REG_POINT_RATE 0x88 +#define FT6x06_REG_THGROUP 0x80 + +int ft6x06_i2c_Read(struct i2c_client *client, char *writebuf, int writelen, + char *readbuf, int readlen); +int ft6x06_i2c_Write(struct i2c_client *client, char *writebuf, int writelen); + +/* The platform data for the Focaltech ft6x06 touchscreen driver */ +struct ft6x06_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned long irqflags; + unsigned int irq; + unsigned int reset; +}; + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c new file mode 100755 index 00000000..a4f8dc38 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.c @@ -0,0 +1,406 @@ +#include <linux/string.h>
+#include <asm/unistd.h>
+#include <linux/slab.h> +
+#include "ini.h"
+
+
+char CFG_SSL = '['; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/
+char CFG_SSR = ']'; /* Ïî±êÖ¾·ûSection Symbol --¿É¸ù¾ÝÌØÊâÐèÒª½øÐж¨Òå¸ü¸Ä£¬Èç { }µÈ*/ +char CFG_NIS = ':'; /* name Óë index Ö®¼äµÄ·Ö¸ô·û */ +char CFG_NTS = '#'; /* ×¢ÊÍ·û*/ + +static char * ini_str_trim_r(char * buf);
+static char * ini_str_trim_l(char * buf);
+static int ini_file_get_line(char *filedata, char *buffer, int maxlen);
+static int ini_split_key_value(char *buf, char **key, char **val);
+static long atol(char *nptr);
+
+
+/*************************************************************
+Function: »ñµÃkeyµÄÖµ
+Input: char * filedata¡¡Îļþ£»char * section¡¡ÏîÖµ£»char * key¡¡¼üÖµ
+Output: char * value¡¡keyµÄÖµ
+Return: 0 SUCCESS
+ -1 δÕÒµ½section
+ -2 δÕÒµ½key
+ -10 Îļþ´ò¿ªÊ§°Ü
+ -12 ¶ÁÈ¡Îļþʧ°Ü
+ -14 Îļþ¸ñʽ´íÎó
+ -22 ³¬³ö»º³åÇø´óС
+Note:
+*************************************************************/
+int ini_get_key(char *filedata, char * section, char * key, char * value)
+{
+ //char buf1[MAX_CFG_BUF + 1], buf2[MAX_CFG_BUF + 1];
+ char *buf1, *buf2;
+ char *key_ptr, *val_ptr;
+ int n, ret;
+ int dataoff = 0;
+
+ *value='\0';
+
+ buf1 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf1){ + printk("buf1: mem alloc failed.\n"); + return -ENOMEM; + } + buf2 = kzalloc(MAX_CFG_BUF + 1, GFP_KERNEL); + if(!buf2){ + printk("buf2: mem alloc failed.\n"); + kfree(buf1); + return -ENOMEM; + } + + while(1) { /* ËÑÕÒÏîsection */
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto r_cfg_end;
+ ret = CFG_SECTION_NOT_FOUND;
+ if(n < 0)
+ goto r_cfg_end; /* Îļþβ£¬Î´·¢ÏÖ */
+
+ n = strlen(ini_str_trim_l(ini_str_trim_r(buf1)));
+ if(n == 0 || buf1[0] == CFG_NTS)
+ continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */
+
+ ret = CFG_ERR_FILE_FORMAT;
+ if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR)))
+ goto r_cfg_end;
+ if(buf1[0] == CFG_SSL) {
+ buf1[n-1] = 0x00;
+ if(strcmp(buf1+1, section) == 0)
+ break; /* ÕÒµ½Ïîsection */
+ }
+ }
+
+ while(1){ /* ËÑÕÒkey */
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto r_cfg_end;
+ ret = CFG_KEY_NOT_FOUND;
+ if(n < 0)
+ goto r_cfg_end;/* Îļþβ£¬Î´·¢ÏÖkey */
+
+ n = strlen(ini_str_trim_l(ini_str_trim_r(buf1)));
+ if(n == 0 || buf1[0] == CFG_NTS)
+ continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */
+ ret = CFG_KEY_NOT_FOUND;
+ if(buf1[0] == CFG_SSL)
+ goto r_cfg_end;
+ if(buf1[n-1] == '+') { /* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */
+ buf1[n-1] = 0x00;
+ while(1) {
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf2, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto r_cfg_end;
+ if(n < 0)
+ break;/* Îļþ½áÊø */
+
+ n = strlen(ini_str_trim_r(buf2));
+ ret = CFG_ERR_EXCEED_BUF_SIZE;
+ if(n > 0 && buf2[n-1] == '+'){/* Óö+ºÅ±íʾÏÂÒ»ÐмÌÐø */
+ buf2[n-1] = 0x00;
+ if( (strlen(buf1) + strlen(buf2)) > MAX_CFG_BUF)
+ goto r_cfg_end;
+ strcat(buf1, buf2);
+ continue;
+ }
+ if(strlen(buf1) + strlen(buf2) > MAX_CFG_BUF)
+ goto r_cfg_end;
+ strcat(buf1, buf2);
+ break;
+ }
+ }
+ ret = CFG_ERR_FILE_FORMAT;
+ if(ini_split_key_value(buf1, &key_ptr, &val_ptr) != 1)
+ goto r_cfg_end;
+ ini_str_trim_l(ini_str_trim_r(key_ptr));
+ if(strcmp(key_ptr, key) != 0)
+ continue; /* ºÍkeyÖµ²»Æ¥Åä */
+ strcpy(value, val_ptr);
+ break;
+ }
+ ret = CFG_OK;
+r_cfg_end:
+ //if(fp != NULL) fclose(fp);
+ kfree(buf1); + kfree(buf2); + return ret;
+}
+/*************************************************************
+Function: »ñµÃËùÓÐsection
+Input: char *filename¡¡Îļþ,int max ×î´ó¿É·µ»ØµÄsectionµÄ¸öÊý
+Output: char *sections[]¡¡´æ·ÅsectionÃû×Ö
+Return: ·µ»Øsection¸öÊý¡£Èô³ö´í£¬·µ»Ø¸ºÊý¡£
+ -10 Îļþ´ò¿ª³ö´í
+ -12 Îļþ¶ÁÈ¡´íÎó
+ -14 Îļþ¸ñʽ´íÎó
+Note:
+*************************************************************/
+int ini_get_sections(char *filedata, unsigned char * sections[], int max)
+{
+ //FILE *fp;
+ char buf1[MAX_CFG_BUF + 1];
+ int n, n_sections = 0, ret;
+ int dataoff = 0;
+
+// if((fp = fopen(filename, "rb")) == NULL)
+// return CFG_ERR_OPEN_FILE;
+
+ while(1) {/*ËÑÕÒÏîsection */
+ ret = CFG_ERR_READ_FILE;
+ n = ini_file_get_line(filedata+dataoff, buf1, MAX_CFG_BUF);
+ dataoff += n;
+ if(n < -1)
+ goto cfg_scts_end;
+ if(n < 0)
+ break;/* Îļþβ */
+ n = strlen(ini_str_trim_l(ini_str_trim_r(buf1)));
+ if(n == 0 || buf1[0] == CFG_NTS)
+ continue; /* ¿ÕÐÐ »ò ×¢ÊÍÐÐ */
+ ret = CFG_ERR_FILE_FORMAT;
+ if(n > 2 && ((buf1[0] == CFG_SSL && buf1[n-1] != CFG_SSR)))
+ goto cfg_scts_end;
+ if(buf1[0] == CFG_SSL) {
+ if (max!=0){
+ buf1[n-1] = 0x00;
+ strcpy((char *)sections[n_sections], buf1+1);
+ if (n_sections>=max)
+ break; /* ³¬¹ý¿É·µ»Ø×î´ó¸öÊý */
+ }
+ n_sections++;
+ }
+
+ }
+ ret = n_sections;
+cfg_scts_end:
+// if(fp != NULL)
+// fclose(fp);
+ return ret;
+}
+
+
+/*************************************************************
+Function: È¥³ý×Ö·û´®ÓұߵĿÕ×Ö·û
+Input: char * buf ×Ö·û´®Ö¸Õë
+Output:
+Return: ×Ö·û´®Ö¸Õë
+Note:
+*************************************************************/
+static char * ini_str_trim_r(char * buf)
+{
+ int len,i;
+ char tmp[128];
+
+ memset(tmp, 0, sizeof(tmp));
+ len = strlen(buf);
+// tmp = (char *)malloc(len);
+
+ memset(tmp,0x00,len);
+ for(i = 0;i < len;i++) {
+ if (buf[i] !=' ')
+ break;
+ }
+ if (i < len) {
+ strncpy(tmp,(buf+i),(len-i));
+ }
+ strncpy(buf,tmp,len);
+// free(tmp);
+ return buf;
+}
+
+/*************************************************************
+Function: È¥³ý×Ö·û´®×ó±ßµÄ¿Õ×Ö·û
+Input: char * buf ×Ö·û´®Ö¸Õë
+Output:
+Return: ×Ö·û´®Ö¸Õë
+Note:
+*************************************************************/
+static char * ini_str_trim_l(char * buf)
+{
+ int len,i;
+ char tmp[128];
+
+ memset(tmp, 0, sizeof(tmp));
+ len = strlen(buf);
+ //tmp = (char *)malloc(len);
+
+ memset(tmp,0x00,len);
+
+ for(i = 0;i < len;i++) {
+ if (buf[len-i-1] !=' ')
+ break;
+ }
+ if (i < len) {
+ strncpy(tmp,buf,len-i);
+ }
+ strncpy(buf,tmp,len);
+ //free(tmp);
+ return buf;
+}
+/*************************************************************
+Function: ´ÓÎļþÖжÁÈ¡Ò»ÐÐ
+Input: FILE *fp Îļþ¾ä±ú£»int maxlen »º³åÇø×î´ó³¤¶È
+Output: char *buffer Ò»ÐÐ×Ö·û´®
+Return: >0 ʵ¼Ê¶ÁµÄ³¤¶È
+ -1 Îļþ½áÊø
+ -2 ¶ÁÎļþ³ö´í
+Note:
+*************************************************************/
+static int ini_file_get_line(char *filedata, char *buffer, int maxlen)
+{
+ int i, j;
+ char ch1;
+
+ for(i=0, j=0; i<maxlen; j++) {
+ ch1 = filedata[j];
+ if(ch1 == '\n' || ch1 == 0x00)
+ break; /* »»ÐÐ */
+ if(ch1 == '\f' || ch1 == 0x1A) { /* '\f':»»Ò³·ûÒ²ËãÓÐЧ×Ö·û */
+ buffer[i++] = ch1;
+ break;
+ }
+ if(ch1 != '\r') buffer[i++] = ch1; /* ºöÂԻسµ·û */
+ }
+ buffer[i] = '\0';
+ return i+2;
+}
+/*************************************************************
+Function: ·ÖÀëkeyºÍvalue
+ key=val
+ jack = liaoyuewang
+ | | |
+ k1 k2 i
+Input: char *buf
+Output: char **key, char **val
+Return: 1 --- ok
+ 0 --- blank line
+ -1 --- no key, "= val"
+ -2 --- only key, no '='
+Note:
+*************************************************************/
+static int ini_split_key_value(char *buf, char **key, char **val)
+{
+ int i, k1, k2, n;
+
+ if((n = strlen((char *)buf)) < 1)
+ return 0;
+ for(i = 0; i < n; i++)
+ if(buf[i] != ' ' && buf[i] != '\t')
+ break;
+
+ if(i >= n)
+ return 0;
+
+ if(buf[i] == '=')
+ return -1;
+
+ k1 = i;
+ for(i++; i < n; i++)
+ if(buf[i] == '=')
+ break;
+
+ if(i >= n)
+ return -2;
+ k2 = i;
+
+ for(i++; i < n; i++)
+ if(buf[i] != ' ' && buf[i] != '\t')
+ break;
+
+ buf[k2] = '\0';
+
+ *key = buf + k1;
+ *val = buf + i;
+ return 1;
+}
+
+int my_atoi(const char *str)
+{
+ int result = 0;
+ int signal = 1; /* ĬÈÏΪÕýÊý */
+ if((*str>='0'&&*str<='9')||*str=='-'||*str=='+') {
+ if(*str=='-'||*str=='+') {
+ if(*str=='-')
+ signal = -1; /*ÊäÈ븺Êý*/
+ str++;
+ }
+ }
+ else
+ return 0;
+ /*¿ªÊ¼×ª»»*/
+ while(*str>='0' && *str<='9')
+ result = result*10 + (*str++ - '0' );
+
+ return signal*result;
+}
+
+int isspace(int x)
+{
+ if(x==' '||x=='\t'||x=='\n'||x=='\f'||x=='\b'||x=='\r')
+ return 1;
+ else
+ return 0;
+}
+
+int isdigit(int x)
+{
+ if(x<='9' && x>='0')
+ return 1;
+ else
+ return 0;
+
+}
+
+static long atol(char *nptr)
+{
+ int c; /* current char */
+ long total; /* current total */
+ int sign; /* if ''-'', then negative, otherwise positive */
+ /* skip whitespace */
+ while ( isspace((int)(unsigned char)*nptr) )
+ ++nptr;
+ c = (int)(unsigned char)*nptr++;
+ sign = c; /* save sign indication */
+ if (c == '-' || c == '+')
+ c = (int)(unsigned char)*nptr++; /* skip sign */
+ total = 0;
+ while (isdigit(c)) {
+ total = 10 * total + (c - '0'); /* accumulate digit */
+ c = (int)(unsigned char)*nptr++; /* get next char */
+ }
+ if (sign == '-')
+ return -total;
+ else
+ return total; /* return result, negated if necessary */
+}
+/***
+*int atoi(char *nptr) - Convert string to long
+*
+*Purpose:
+* Converts ASCII string pointed to by nptr to binary.
+* Overflow is not detected. Because of this, we can just use
+* atol().
+*
+*Entry:
+* nptr = ptr to string to convert
+*
+*Exit:
+* return int value of the string
+*
+*Exceptions:
+* None - overflow is not detected.
+*
+*******************************************************************************/
+int atoi(char *nptr)
+{
+ return (int)atol(nptr);
+}
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h new file mode 100755 index 00000000..72434b53 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ft6x0x/ini.h @@ -0,0 +1,43 @@ +#ifndef INI_H +#define INI_H + +#define MAX_CFG_BUF 512 +#define SUCCESS 0 +/* return value */ +#define CFG_OK SUCCESS +#define CFG_SECTION_NOT_FOUND -1 +#define CFG_KEY_NOT_FOUND -2 +#define CFG_ERR -10 + +#define CFG_ERR_OPEN_FILE -10 +#define CFG_ERR_CREATE_FILE -11 +#define CFG_ERR_READ_FILE -12 +#define CFG_ERR_WRITE_FILE -13 +#define CFG_ERR_FILE_FORMAT -14 + + +#define CFG_ERR_EXCEED_BUF_SIZE -22 + +#define COPYF_OK SUCCESS +#define COPYF_ERR_OPEN_FILE -10 +#define COPYF_ERR_CREATE_FILE -11 +#define COPYF_ERR_READ_FILE -12 +#define COPYF_ERR_WRITE_FILE -13 + + +struct ini_key_location { + int ini_section_line_no; + int ini_key_line_no; + int ini_key_lines; +}; + + +int ini_get_key(char *filedata, char * section, char * key, char * value); +int ini_get_sections(char *filedata, unsigned char * sections[], int max); + +int ini_split_section(char *section, char **name, char **index); +//int ini_join_section(char **section, char *name, char *index); + +int atoi(char *nptr); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig new file mode 100755 index 00000000..0f47c8bc --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Kconfig @@ -0,0 +1,16 @@ +# +# GSL1680 capacity touch screen driver configuration +# +config TOUCHSCREEN_GSL1680 + tristate "ilead GSL1680 I2C Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_gsl1680. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile new file mode 100755 index 00000000..372a0fce --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/Makefile @@ -0,0 +1,33 @@ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_gsl1680
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := gslX680.o wmt_ts.o gsl_point_id.b
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c new file mode 100755 index 00000000..bcb252a5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.c @@ -0,0 +1,1416 @@ +/* + * drivers/input/touchscreen/gslX680.c + * + * Copyright (c) 2012 Shanghai Basewin + * Guan Yuwei<guanyuwei@basewin.com> + * + * 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/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/delay.h> +//#include <mach/gpio.h> +//#include <mach/gpio_data.h> +#include <linux/jiffies.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> +#include <linux/pm_runtime.h> + +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include <linux/earlysuspend.h> +#endif +#include <linux/input/mt.h> + +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/async.h> +#include <linux/hrtimer.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/kthread.h> +#include <linux/wakelock.h> + + +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + + +//#include <asm/irq.h> +//#include <asm/io.h> + +//#include <mach/irqs.h> +//#include <mach/system.h> +//#include <mach/hardware.h> +#include "gslX680.h" +#include "wmt_ts.h" +#include "../../../video/backlight/wmt_bl.h" + +//#define GSL_DEBUG +//#define GSL_TIMER +//#define REPORT_DATA_ANDROID_4_0 + +#define HAVE_TOUCH_KEY + +#define SCREEN_MAX_X 480 +#define SCREEN_MAX_Y 800 + + +#define GSLX680_I2C_NAME "touch_gslX680" +#define GSLX680_I2C_ADDR 0x40 +#define IRQ_PORT INT_GPIO_0 + +#define GSL_DATA_REG 0x80 +#define GSL_STATUS_REG 0xe0 +#define GSL_PAGE_REG 0xf0 + +#define PRESS_MAX 255 +#define MAX_FINGERS 5 +#define MAX_CONTACTS 10 +#define DMA_TRANS_LEN 0x20 + +#ifdef GSL_NOID_VERSION +int gsl_noid_ver = 0; +unsigned int gsl_config_data_id[512] = {0}; +#endif + +#ifdef HAVE_TOUCH_KEY +static u16 key = 0; +static int key_state_flag = 0; +struct key_data { + u16 key; + u16 x_min; + u16 x_max; + u16 y_min; + u16 y_max; +}; + +const u16 key_array[]={ + KEY_BACK, + KEY_HOME, + KEY_MENU, + KEY_SEARCH, + }; +#define MAX_KEY_NUM (sizeof(key_array)/sizeof(key_array[0])) + +struct key_data gsl_key_data[MAX_KEY_NUM] = { + {KEY_BACK, 2048, 2048, 2048, 2048}, + {KEY_HOME, 2048, 2048, 2048, 2048}, + {KEY_MENU, 2048, 2048, 2048, 2048}, + {KEY_SEARCH, 2048, 2048, 2048, 2048}, +}; +#endif + +struct gsl_ts_data { + u8 x_index; + u8 y_index; + u8 z_index; + u8 id_index; + u8 touch_index; + u8 data_reg; + u8 status_reg; + u8 data_size; + u8 touch_bytes; + u8 update_data; + u8 touch_meta_data; + u8 finger_size; +}; + +static struct gsl_ts_data devices[] = { + { + .x_index = 6, + .y_index = 4, + .z_index = 5, + .id_index = 7, + .data_reg = GSL_DATA_REG, + .status_reg = GSL_STATUS_REG, + .update_data = 0x4, + .touch_bytes = 4, + .touch_meta_data = 4, + .finger_size = 70, + }, +}; + +struct gsl_ts { + struct i2c_client *client; + struct input_dev *input; + struct work_struct work; + struct workqueue_struct *wq; + struct gsl_ts_data *dd; + u8 *touch_data; + u8 device_id; + u8 prev_touches; + bool is_suspended; + bool int_pending; + struct mutex sus_lock; +// uint32_t gpio_irq; + int irq; +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +#ifdef GSL_TIMER + struct timer_list gsl_timer; +#endif + + struct workqueue_struct *timeout_queue; + struct delayed_work timeout_work; + struct mutex timeout_mutex; + int timeout_count; +}; + +#define DELAY_TIMEOUT 1000 +#define DELAY_TIMEOUT_MAX 3 + + + +struct gsl_ts *l_ts=NULL; + +static u32 id_sign[MAX_CONTACTS+1] = {0}; +static u8 id_state_flag[MAX_CONTACTS+1] = {0}; +static u8 id_state_old_flag[MAX_CONTACTS+1] = {0}; +static u16 x_old[MAX_CONTACTS+1] = {0}; +static u16 y_old[MAX_CONTACTS+1] = {0}; +static u16 x_new = 0; +static u16 y_new = 0; + +static struct fw_data* GSLX680_FW = NULL; +static int l_fwlen = 0; +static struct task_struct *resume_download_task; +static struct wake_lock downloadWakeLock; +static int is_delay = 0; + +extern int tp_led_gpio; +extern int tp_led_gpio_active; + +extern int sel_reg_bit; +extern int sel_reg_active; + + +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +//////////////////////////////////////////////////////////////////// +static int wmt_get_fwdata(void); + +//////////////////////////////////////////////////////////////////// +static int gslX680_chip_init(void) +{ + //gpio_set_status(PAD_GPIOA_6, gpio_status_out); + //gpio_out(PAD_GPIOA_6, 1); + // shutdown pin + wmt_rst_output(1); + // irq pin + //gpio_set_status(PAD_GPIOA_16, gpio_status_in); + //gpio_irq_set(PAD_GPIOA_16, GPIO_IRQ(INT_GPIO_0-INT_GPIO_0, GPIO_IRQ_RISING)); + wmt_set_gpirq(IRQ_TYPE_EDGE_RISING);//GIRQ_FALLING); + wmt_disable_gpirq(); + msleep(20); + return 0; +} + +static int gslX680_shutdown_low(void) +{ + //gpio_set_status(PAD_GPIOA_6, gpio_status_out); + //gpio_out(PAD_GPIOA_6, 0); + wmt_rst_output(0); + return 0; +} + +static int gslX680_shutdown_high(void) +{ + //gpio_set_status(PAD_GPIOA_6, gpio_status_out); + //gpio_out(PAD_GPIOA_6, 1); + wmt_rst_output(1); + return 0; +} + +static inline u16 join_bytes(u8 a, u8 b) +{ + u16 ab = 0; + ab = ab | a; + ab = ab << 8 | b; + return ab; +} + +#if 0 +static u32 gsl_read_interface(struct i2c_client *client, u8 reg, u8 *buf, u32 num) +{ + struct i2c_msg xfer_msg[2]; + + xfer_msg[0].addr = client->addr; + xfer_msg[0].len = 1; + xfer_msg[0].flags = client->flags & I2C_M_TEN; + xfer_msg[0].buf = ® + + xfer_msg[1].addr = client->addr; + xfer_msg[1].len = num; + xfer_msg[1].flags |= I2C_M_RD; + xfer_msg[1].buf = buf; + + if (reg < 0x80) { + i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)); + msleep(5); + } + + return i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)) == ARRAY_SIZE(xfer_msg) ? 0 : -EFAULT; +} +#endif + +static u32 gsl_write_interface(struct i2c_client *client, const u8 reg, u8 *buf, u32 num) +{ + struct i2c_msg xfer_msg[1]; + + buf[0] = reg; + + xfer_msg[0].addr = client->addr; + xfer_msg[0].len = num + 1; + xfer_msg[0].flags = client->flags & I2C_M_TEN; + xfer_msg[0].buf = buf; + + return i2c_transfer(client->adapter, xfer_msg, 1) == 1 ? 0 : -EFAULT; +} + +static __inline__ void fw2buf(u8 *buf, const u32 *fw) +{ + u32 *u32_buf = (int *)buf; + *u32_buf = *fw; +} + +static int wmt_get_fwdata(void) +{ + char fwname[128]; + + // get the firmware file name + memset(fwname,0,sizeof(fwname)); + wmt_ts_get_firmwfilename(fwname); + // load the data into GSLX680_FW + l_fwlen = read_firmwfile(fwname, &GSLX680_FW, gsl_config_data_id); + return ((l_fwlen>0)?0:-1); +} + +static void gsl_load_fw(struct i2c_client *client) +{ + u8 buf[DMA_TRANS_LEN*4 + 1] = {0}; + u8 send_flag = 1; + u8 *cur = buf + 1; + u32 source_line = 0; + u32 source_len = l_fwlen;//ARRAY_SIZE(GSLX680_FW); + + printk("=============gsl_load_fw start==============\n"); + + for (source_line = 0; source_line < source_len; source_line++) + { + /* init page trans, set the page val */ + if (GSL_PAGE_REG == GSLX680_FW[source_line].offset) + { + fw2buf(cur, &GSLX680_FW[source_line].val); + gsl_write_interface(client, GSL_PAGE_REG, buf, 4); + send_flag = 1; + } + else + { + if (1 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20)) + buf[0] = (u8)GSLX680_FW[source_line].offset; + + fw2buf(cur, &GSLX680_FW[source_line].val); + cur += 4; + + if (0 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20)) + { + gsl_write_interface(client, buf[0], buf, cur - buf - 1); + cur = buf + 1; + } + + send_flag++; + } + } + + printk("=============gsl_load_fw end==============\n"); + +} + + +static int gsl_ts_write(struct i2c_client *client, u8 addr, u8 *pdata, int datalen) +{ + int ret = 0; + u8 tmp_buf[128]; + unsigned int bytelen = 0; + if (datalen > 125) + { + dbg("%s too big datalen = %d!\n", __func__, datalen); + return -1; + } + + tmp_buf[0] = addr; + bytelen++; + + if (datalen != 0 && pdata != NULL) + { + memcpy(&tmp_buf[bytelen], pdata, datalen); + bytelen += datalen; + } + + ret = i2c_master_send(client, tmp_buf, bytelen); + return ret; +} + +static int gsl_ts_read(struct i2c_client *client, u8 addr, u8 *pdata, unsigned int datalen) +{ + int ret = 0; + + if (datalen > 126) + { + dbg("%s too big datalen = %d!\n", __func__, datalen); + return -1; + } + + ret = gsl_ts_write(client, addr, NULL, 0); + if (ret < 0) + { + dbg("%s set data address fail!\n", __func__); + return ret; + } + + return i2c_master_recv(client, pdata, datalen); +} + +#if 0 +static void test_i2c(struct i2c_client *client) +{ + u8 read_buf = 0; + u8 write_buf = 0x12; + int ret; + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if (ret < 0) + { + pr_info("I2C transfer error!\n"); + } + else + { + pr_info("I read reg 0xf0 is %x\n", read_buf); + } + msleep(10); + + ret = gsl_ts_write(client, 0xf0, &write_buf, sizeof(write_buf)); + if (ret < 0) + { + pr_info("I2C transfer error!\n"); + } + else + { + pr_info("I write reg 0xf0 0x12\n"); + } + msleep(10); + + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if (ret < 0 ) + { + pr_info("I2C transfer error!\n"); + } + else + { + pr_info("I read reg 0xf0 is 0x%x\n", read_buf); + } + msleep(10); + +} +#endif + +static int test_i2c(struct i2c_client *client) +{ + u8 read_buf = 0; + u8 write_buf = 0x12; + int ret, rc = 1; + + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if (ret < 0) + rc --; + else + dbg("I read reg 0xf0 is %x\n", read_buf); + + msleep(2); + ret = gsl_ts_write(client, 0xf0, &write_buf, sizeof(write_buf)); + if(ret >= 0 ) + dbg("I write reg 0xf0 0x12\n"); + + msleep(2); + ret = gsl_ts_read( client, 0xf0, &read_buf, sizeof(read_buf) ); + if(ret < 0 ) + rc --; + else + dbg("I read reg 0xf0 is 0x%x\n", read_buf); + + return rc; +} + +static void startup_chip(struct i2c_client *client) +{ + u8 tmp = 0x00; +#ifdef GSL_NOID_VERSION + if (gsl_noid_ver) + gsl_DataInit(gsl_config_data_id); +#endif + gsl_ts_write(client, 0xe0, &tmp, 1); + msleep(10); +} + +static void reset_chip(struct i2c_client *client) +{ + u8 buf[4] = {0x00}; + u8 tmp = 0x88; + gsl_ts_write(client, 0xe0, &tmp, sizeof(tmp)); + msleep(10); + + tmp = 0x04; + gsl_ts_write(client, 0xe4, &tmp, sizeof(tmp)); + msleep(10); + + gsl_ts_write(client, 0xbc, buf, sizeof(buf)); + msleep(10); +} + +static void clr_reg(struct i2c_client *client) +{ + u8 write_buf[4] = {0}; + + write_buf[0] = 0x88; + gsl_ts_write(client, 0xe0, &write_buf[0], 1); + msleep(20); + write_buf[0] = 0x03; + gsl_ts_write(client, 0x80, &write_buf[0], 1); + msleep(5); + write_buf[0] = 0x04; + gsl_ts_write(client, 0xe4, &write_buf[0], 1); + msleep(5); + write_buf[0] = 0x00; + gsl_ts_write(client, 0xe0, &write_buf[0], 1); + msleep(20); +} + +static void init_chip(struct i2c_client *client) +{ + int rc; + + gslX680_shutdown_low(); + msleep(20); + gslX680_shutdown_high(); + msleep(20); + rc = test_i2c(client); + if(rc < 0) + { + printk("------gslX680 test_i2c error------\n"); + return; + } + clr_reg(client); + reset_chip(client); + gsl_load_fw(client); + startup_chip(client); + reset_chip(client); + startup_chip(client); +} + +static void check_mem_data(struct i2c_client *client) +{ + /*char write_buf; + char read_buf[4] = {0}; + + msleep(30); + write_buf = 0x00; + gsl_ts_write(client,0xf0, &write_buf, sizeof(write_buf)); + gsl_ts_read(client,0x00, read_buf, sizeof(read_buf)); + gsl_ts_read(client,0x00, read_buf, sizeof(read_buf)); + if (read_buf[3] != 0x1 || read_buf[2] != 0 || read_buf[1] != 0 || read_buf[0] != 0) + { + dbg("!!!!!!!!!!!page: %x offset: %x val: %x %x %x %x\n",0x0, 0x0, read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + init_chip(client); + }*/ + + u8 read_buf[4] = {0}; + + msleep(30); + gsl_ts_read(client,0xb0, read_buf, sizeof(read_buf)); + + if (read_buf[3] != 0x5a || read_buf[2] != 0x5a || read_buf[1] != 0x5a || read_buf[0] != 0x5a) + { + printk("#########check mem read 0xb0 = %x %x %x %x #########\n", read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + init_chip(client); + } + +} + +static void record_point(u16 x, u16 y , u8 id) +{ + u16 x_err =0; + u16 y_err =0; + + id_sign[id]=id_sign[id]+1; + + if(id_sign[id]==1){ + x_old[id]=x; + y_old[id]=y; + } + + x = (x_old[id] + x)/2; + y = (y_old[id] + y)/2; + + if(x>x_old[id]){ + x_err=x -x_old[id]; + } + else{ + x_err=x_old[id]-x; + } + + if(y>y_old[id]){ + y_err=y -y_old[id]; + } + else{ + y_err=y_old[id]-y; + } + + if( (x_err > 3 && y_err > 1) || (x_err > 1 && y_err > 3) ){ + x_new = x; x_old[id] = x; + y_new = y; y_old[id] = y; + } + else{ + if(x_err > 3){ + x_new = x; x_old[id] = x; + } + else + x_new = x_old[id]; + if(y_err> 3){ + y_new = y; y_old[id] = y; + } + else + y_new = y_old[id]; + } + + if(id_sign[id]==1){ + x_new= x_old[id]; + y_new= y_old[id]; + } + +} + +void wmt_set_keypos(int index,int xmin,int xmax,int ymin,int ymax) +{ + gsl_key_data[index].x_min = xmin; + gsl_key_data[index].x_max = xmax; + gsl_key_data[index].y_min = ymin; + gsl_key_data[index].y_max = ymax; +} + +#ifdef HAVE_TOUCH_KEY +static void report_key(struct gsl_ts *ts, u16 x, u16 y) +{ + u16 i = 0; + + for(i = 0; i < MAX_KEY_NUM; i++) + { + if((gsl_key_data[i].x_min <= x) && (x <= gsl_key_data[i].x_max)&&(gsl_key_data[i].y_min <= y) && (y <= gsl_key_data[i].y_max)) + { + key = gsl_key_data[i].key; + input_report_key(ts->input, key, 1); + input_sync(ts->input); + key_state_flag = 1; + dbg("rport key:%d\n",key); + + if( tp_led_gpio >= 0 ){ + gpio_set_value(tp_led_gpio,tp_led_gpio_active); + + mutex_lock(&ts->timeout_mutex); + if( ts->timeout_count < 0 ){ + queue_delayed_work(ts->timeout_queue, &ts->timeout_work, msecs_to_jiffies(DELAY_TIMEOUT)); + } + ts->timeout_count = DELAY_TIMEOUT_MAX; + mutex_unlock(&ts->timeout_mutex); + } + break; + } + } +} +#endif + +static void report_data(struct gsl_ts *ts, u16 x, u16 y, u8 pressure, u8 id) +{ + //swap(x, y); + int tx,ty; + int keyx,keyy; + + dbg("#####id=%d,x=%d,y=%d######\n",id,x,y); + + + tx = x; + ty = y; + keyx = x; + keyy = y; + + if( (x>=wmt_ts_get_resolvX()&&x>=wmt_ts_get_resolvY()) + || (y>= wmt_ts_get_resolvX()&&y>= wmt_ts_get_resolvY())) + { + #ifdef HAVE_TOUCH_KEY + if (wmt_ts_if_tskey()) + { + report_key(ts,keyx,keyy); + } + #endif + return; + } + + + if (wmt_ts_get_xaxis()==1) + { + tx = y; + ty = x; + } + if (wmt_ts_get_xdir()==-1) + { + tx = wmt_ts_get_resolvX() - tx - 1; + } + if (wmt_ts_get_ydir()==-1) + { + ty = wmt_ts_get_resolvY() - ty - 1; + } + /*if ((tx < 0) || (tx >= wmt_ts_get_resolvX()) || + (ty < 0) || (ty >= wmt_ts_get_resolvY())) + { + dbg("Invalid point(%d,%d)\n"); + return; + }*/ + x = tx; + y = ty; + + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = x; + x = y; + y = wmt_ts_get_resolvX() - tmp; + } + + dbg("rpt%d(%d,%d)\n",id,x,y); +#ifdef REPORT_DATA_ANDROID_4_0 + input_mt_slot(ts->input, id); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, id); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure); + input_report_abs(ts->input, ABS_MT_POSITION_X, x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, y); + //input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1); +#else + //add for cross finger 2013-1-10 + input_report_key(ts->input, BTN_TOUCH, 1); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, id); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure); + input_report_abs(ts->input, ABS_MT_POSITION_X,x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, y); + //input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(ts->input); +#endif +} + +static void process_gslX680_data(struct gsl_ts *ts) +{ + u8 id, touches; + u16 x, y; + int i = 0; +#ifdef GSL_NOID_VERSION + u32 tmp1; + u8 buf[4] = {0}; + struct gsl_touch_info cinfo; +#endif + touches = ts->touch_data[ts->dd->touch_index]; + +#ifdef GSL_NOID_VERSION + if (gsl_noid_ver) { + cinfo.finger_num = touches; + dbg("tp-gsl finger_num = %d\n",cinfo.finger_num); + for(i = 0; i < (touches < MAX_CONTACTS ? touches : MAX_CONTACTS); i ++) { + cinfo.x[i] = join_bytes( ( ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf), + ts->touch_data[ts->dd->x_index + 4 * i]); + cinfo.y[i] = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1], + ts->touch_data[ts->dd->y_index + 4 * i ]); + cinfo.id[i] = ((ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf0)>>4); + dbg("tp-gsl x = %d y = %d \n",cinfo.x[i],cinfo.y[i]); + } + cinfo.finger_num=(ts->touch_data[3]<<24)|(ts->touch_data[2]<<16) + |(ts->touch_data[1]<<8)|(ts->touch_data[0]); + gsl_alg_id_main(&cinfo); + tmp1=gsl_mask_tiaoping(); + dbg("[tp-gsl] tmp1=%x\n",tmp1); + if(tmp1>0&&tmp1<0xffffffff) { + buf[0]=0xa;buf[1]=0;buf[2]=0;buf[3]=0; + gsl_ts_write(ts->client,0xf0,buf,4); + buf[0]=(u8)(tmp1 & 0xff); + buf[1]=(u8)((tmp1>>8) & 0xff); + buf[2]=(u8)((tmp1>>16) & 0xff); + buf[3]=(u8)((tmp1>>24) & 0xff); + dbg("tmp1=%08x,buf[0]=%02x,buf[1]=%02x,buf[2]=%02x,buf[3]=%02x\n", + tmp1,buf[0],buf[1],buf[2],buf[3]); + gsl_ts_write(ts->client,0x8,buf,4); + } + touches = cinfo.finger_num; + } +#endif + + for(i=1;i<=MAX_CONTACTS;i++) + { + if(touches == 0) + id_sign[i] = 0; + id_state_flag[i] = 0; + } + for(i= 0;i < (touches > MAX_FINGERS ? MAX_FINGERS : touches);i ++) + { + #ifdef GSL_NOID_VERSION + if (gsl_noid_ver) { + id = cinfo.id[i]; + x = cinfo.x[i]; + y = cinfo.y[i]; + } + else { + x = join_bytes( ( ts->touch_data[ts->dd->x_index + 4 * i + 1] & 0xf), + ts->touch_data[ts->dd->x_index + 4 * i]); + y = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1], + ts->touch_data[ts->dd->y_index + 4 * i ]); + id = ts->touch_data[ts->dd->id_index + 4 * i] >> 4; + } + #endif + + if(1 <=id && id <= MAX_CONTACTS) + { + dbg("raw%d(%d,%d)\n", id, x, y); + record_point(x, y , id); + dbg("new%d(%d,%d)\n", id, x_new, y_new); + report_data(ts, x_new, y_new, 10, id); + id_state_flag[id] = 1; + } + } + for(i=1;i<=MAX_CONTACTS;i++) + { + if( (0 == touches) || ((0 != id_state_old_flag[i]) && (0 == id_state_flag[i])) ) + { + #ifdef REPORT_DATA_ANDROID_4_0 + input_mt_slot(ts->input, i); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false); + #endif + id_sign[i]=0; + } + id_state_old_flag[i] = id_state_flag[i]; + } +#ifndef REPORT_DATA_ANDROID_4_0 + if(0 == touches) + { + //add 2013-1-10 cross fingers + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + input_report_key(ts->input, BTN_TOUCH, 0); + //********************** + input_mt_sync(ts->input); + #ifdef HAVE_TOUCH_KEY + if (wmt_ts_if_tskey()) + { + if(key_state_flag) + { + input_report_key(ts->input, key, 0); + input_sync(ts->input); + key_state_flag = 0; + } + } + #endif + } +#endif + input_sync(ts->input); + ts->prev_touches = touches; +} + + +static void gsl_ts_xy_worker(struct work_struct *work) +{ + int rc; + u8 read_buf[4] = {0}; + + struct gsl_ts *ts = container_of(work, struct gsl_ts,work); + + dbg("---gsl_ts_xy_worker---\n"); + + if (ts->is_suspended == true) { + dev_dbg(&ts->client->dev, "TS is supended\n"); + ts->int_pending = true; + goto schedule; + } + + /* read data from DATA_REG */ + rc = gsl_ts_read(ts->client, 0x80, ts->touch_data, ts->dd->data_size); + dbg("---touches: %d ---\n",ts->touch_data[0]); + + if (rc < 0) + { + dev_err(&ts->client->dev, "read failed\n"); + goto schedule; + } + + if (ts->touch_data[ts->dd->touch_index] == 0xff) { + goto schedule; + } + + rc = gsl_ts_read( ts->client, 0xbc, read_buf, sizeof(read_buf)); + if (rc < 0) + { + dev_err(&ts->client->dev, "read 0xbc failed\n"); + goto schedule; + } + dbg("//////// reg %x : %x %x %x %x\n",0xbc, read_buf[3], read_buf[2], read_buf[1], read_buf[0]); + + if (read_buf[3] == 0 && read_buf[2] == 0 && read_buf[1] == 0 && read_buf[0] == 0) + { + process_gslX680_data(ts); + } + else + { + reset_chip(ts->client); + startup_chip(ts->client); + } + +schedule: + //enable_irq(ts->irq); + wmt_enable_gpirq(); + +} + +static irqreturn_t gsl_ts_irq(int irq, void *dev_id) +{ + struct gsl_ts *ts = dev_id; + + if (wmt_is_tsint()) + { + wmt_clr_int(); + if (wmt_is_tsirq_enable() && ts->is_suspended == false) + { + wmt_disable_gpirq(); + dbg("begin..\n"); + //if (!work_pending(&l_tsdata.pen_event_work)) + { + queue_work(ts->wq, &ts->work); + } + } + return IRQ_HANDLED; + } + return IRQ_NONE; + + + /*disable_irq_nosync(ts->irq); + + if (!work_pending(&ts->work)) + { + queue_work(ts->wq, &ts->work); + } + + return IRQ_HANDLED;*/ + +} + +#ifdef GSL_TIMER +static void gsl_timer_handle(unsigned long data) +{ + struct gsl_ts *ts = (struct gsl_ts *)data; + +#ifdef GSL_DEBUG + dbg("----------------gsl_timer_handle-----------------\n"); +#endif + + disable_irq_nosync(ts->irq); + check_mem_data(ts->client); + ts->gsl_timer.expires = jiffies + 3 * HZ; + add_timer(&ts->gsl_timer); + enable_irq(ts->irq); + +} +#endif + +static int gsl_ts_init_ts(struct i2c_client *client, struct gsl_ts *ts) +{ + struct input_dev *input_device; + int i; + int rc = 0; + + dbg("[GSLX680] Enter %s\n", __func__); + + + ts->dd = &devices[ts->device_id]; + + if (ts->device_id == 0) { + ts->dd->data_size = MAX_FINGERS * ts->dd->touch_bytes + ts->dd->touch_meta_data; + ts->dd->touch_index = 0; + } + + ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL); + if (!ts->touch_data) { + pr_err("%s: Unable to allocate memory\n", __func__); + return -ENOMEM; + } + + ts->prev_touches = 0; + + input_device = input_allocate_device(); + if (!input_device) { + rc = -ENOMEM; + goto error_alloc_dev; + } + + ts->input = input_device; + input_device->name = GSLX680_I2C_NAME; + input_device->id.bustype = BUS_I2C; + input_device->dev.parent = &client->dev; + input_set_drvdata(input_device, ts); + +#ifdef REPORT_DATA_ANDROID_4_0 + __set_bit(EV_ABS, input_device->evbit); + __set_bit(EV_KEY, input_device->evbit); + __set_bit(EV_REP, input_device->evbit); + __set_bit(INPUT_PROP_DIRECT, input_device->propbit); + input_mt_init_slots(input_device, (MAX_CONTACTS+1)); +#else + //input_set_abs_params(input_device,ABS_MT_TRACKING_ID, 0, (MAX_CONTACTS+1), 0, 0); + set_bit(EV_ABS, input_device->evbit); + set_bit(EV_KEY, input_device->evbit); + __set_bit(INPUT_PROP_DIRECT, input_device->propbit); +#endif + + input_device->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +#ifdef HAVE_TOUCH_KEY + //input_device->evbit[0] = BIT_MASK(EV_KEY); + if (wmt_ts_if_tskey()) + { + for (i = 0; i < MAX_KEY_NUM; i++) + set_bit(key_array[i], input_device->keybit); + } +#endif + + set_bit(ABS_MT_POSITION_X, input_device->absbit); + set_bit(ABS_MT_POSITION_Y, input_device->absbit); + //set_bit(ABS_MT_TOUCH_MAJOR, input_device->absbit); + //set_bit(ABS_MT_WIDTH_MAJOR, input_device->absbit); + //****************add 2013-1-10 + set_bit(BTN_TOUCH, input_device->keybit); + set_bit(ABS_MT_TRACKING_ID, input_device->absbit); + + dbg("regsister:x=%d,y=%d\n",wmt_ts_get_resolvX(),wmt_ts_get_resolvY()); + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, wmt_ts_get_resolvY(), 0, 0); + input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvX(), 0, 0); + } else { + input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, wmt_ts_get_resolvX(), 0, 0); + input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvY(), 0, 0); + } + //input_set_abs_params(input_device,ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0); + //input_set_abs_params(input_device,ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0); + + //client->irq = IRQ_PORT, + //ts->irq = client->irq; + + ts->wq = create_singlethread_workqueue("kworkqueue_ts"); + if (!ts->wq) { + dev_err(&client->dev, "Could not create workqueue\n"); + goto error_wq_create; + } + flush_workqueue(ts->wq); + + INIT_WORK(&ts->work, gsl_ts_xy_worker); + + rc = input_register_device(input_device); + if (rc) + goto error_unreg_device; + + + + return 0; + +error_unreg_device: + destroy_workqueue(ts->wq); +error_wq_create: + input_free_device(input_device); +error_alloc_dev: + kfree(ts->touch_data); + return rc; +} + +static int gsl_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct gsl_ts *ts = l_ts; //dev_get_drvdata(dev); + //int rc = 0; + + printk("I'am in gsl_ts_suspend() start\n"); + ts->is_suspended = true; + +#ifdef GSL_TIMER + printk( "gsl_ts_suspend () : delete gsl_timer\n"); + + del_timer(&ts->gsl_timer); +#endif + //disable_irq_nosync(ts->irq); + wmt_disable_gpirq(); + + reset_chip(ts->client); + gslX680_shutdown_low(); + msleep(10); + + return 0; +} + +int resume_download_thread(void *arg) +{ + wake_lock(&downloadWakeLock); + gslX680_chip_init(); + gslX680_shutdown_high(); + msleep(20); + reset_chip(l_ts->client); + startup_chip(l_ts->client); + //check_mem_data(l_ts->client); + init_chip(l_ts->client); + + l_ts->is_suspended = false; + if (!earlysus_en) + wmt_enable_gpirq(); + wake_unlock(&downloadWakeLock); + return 0; +} + +static int gsl_ts_resume(struct platform_device *pdev) +{ + + gpio_direction_output(tp_led_gpio, !tp_led_gpio_active); +#ifdef GSL_TIMER + dbg( "gsl_ts_resume () : add gsl_timer\n"); + + init_timer(&ts->gsl_timer); + ts->gsl_timer.expires = jiffies + 3 * HZ; + ts->gsl_timer.function = &gsl_timer_handle; + ts->gsl_timer.data = (unsigned long)ts; + add_timer(&ts->gsl_timer); +#endif + if (is_delay) { + resume_download_task = kthread_create(resume_download_thread, NULL , "resume_download"); + if(IS_ERR(resume_download_task)) { + errlog("cread thread failed\n"); + } + wake_up_process(resume_download_task); + } else + resume_download_thread(NULL); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void gsl_ts_early_suspend(struct early_suspend *h) +{ + //struct gsl_ts *ts = container_of(h, struct gsl_ts, early_suspend); + dbg("[GSL1680] Enter %s\n", __func__); + //gsl_ts_suspend(&ts->client->dev); + wmt_disable_gpirq(); +} + +static void gsl_ts_late_resume(struct early_suspend *h) +{ + //struct gsl_ts *ts = container_of(h, struct gsl_ts, early_suspend); + dbg("[GSL1680] Enter %s\n", __func__); + //gsl_ts_resume(&ts->client->dev); + wmt_enable_gpirq(); +} +#endif + +static void check_Backlight_delay(void) +{ + int ret; + int len = 7; + char retval[8]; + + ret = wmt_getsyspara("wmt.backlight.delay", retval, &len); + if(ret) { + dbg("Read wmt.backlight.delay Failed.\n"); + is_delay = 0; + } else + is_delay = 1; +} + +static void timeout_func(struct work_struct *work){ + struct gsl_ts *ts = + container_of(work, struct gsl_ts, timeout_work.work); + int button_up = -1; + + mutex_lock(&ts->timeout_mutex); + button_up = --ts->timeout_count; + mutex_unlock(&ts->timeout_mutex); + + if( button_up < 0){ + gpio_set_value(tp_led_gpio,!tp_led_gpio_active); + }else{ + queue_delayed_work(ts->timeout_queue, &ts->timeout_work, msecs_to_jiffies(DELAY_TIMEOUT)); + } + +} + + +static int gsl_ts_probe(struct i2c_client *client) +{ + struct gsl_ts *ts; + int rc; + + dbg("GSLX680 Enter %s\n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "I2C functionality not supported\n"); + return -ENODEV; + } + if (wmt_get_fwdata()) + { + errlog("Failed to load the firmware data!\n"); + return -1; + } + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (!ts) { + rc = -ENOMEM; + goto error_kfree_fw; + } + dbg("==kzalloc success=\n"); + l_ts = ts; + + ts->client = client; + i2c_set_clientdata(client, ts); + ts->device_id = 0;//id->driver_data; + + ts->is_suspended = false; + ts->int_pending = false; + wake_lock_init(&downloadWakeLock, WAKE_LOCK_SUSPEND, "resume_download"); + mutex_init(&ts->sus_lock); + + rc = gsl_ts_init_ts(client, ts); + if (rc < 0) { + dev_err(&client->dev, "GSLX680 init failed\n"); + goto error_mutex_destroy; + } + + gslX680_chip_init(); + init_chip(ts->client); + check_mem_data(ts->client); + + ts->irq = wmt_get_tsirqnum(); + rc= request_irq(wmt_get_tsirqnum(), gsl_ts_irq, IRQF_SHARED, client->name, ts); + if (rc < 0) { + dbg( "gsl_probe: request irq failed\n"); + goto error_req_irq_fail; + } + + if( tp_led_gpio >= 0 ){ + if(gpio_request(tp_led_gpio, "tp_led_gpio") >= 0){ + wmt_gpio_setpull(tp_led_gpio, tp_led_gpio_active ? WMT_GPIO_PULL_UP : WMT_GPIO_PULL_DOWN); + gpio_direction_output(tp_led_gpio, !tp_led_gpio_active); + #if 0 + errlog("sel_reg_bit:%d sel_reg_active:%d\n",sel_reg_bit,sel_reg_active); + if(sel_reg_bit >= 0 && sel_reg_active >= 0){ + if(sel_reg_active == 0){ + REG32_VAL(__GPIO_BASE+PIN_SHARING_SEL_OFFSET) &= ~(1<<sel_reg_bit); + }else { + REG32_VAL(__GPIO_BASE+PIN_SHARING_SEL_OFFSET) |= (1<<sel_reg_bit); + } + } + #endif + }else{ + errlog(" touch panel led gpio request failed !! \n"); + goto error_req_irq_fail; + } + + mutex_init(&ts->timeout_mutex); + ts->timeout_count = -1; + ts->timeout_queue= create_singlethread_workqueue("timeout_queue"); + INIT_DELAYED_WORK(&ts->timeout_work,timeout_func); + + } + + + + +#ifdef GSL_TIMER + dbg( "gsl_ts_probe () : add gsl_timer\n"); + + init_timer(&ts->gsl_timer); + ts->gsl_timer.expires = jiffies + 3 * HZ; //¶¨Ê±3 ÃëÖÓ + ts->gsl_timer.function = &gsl_timer_handle; + ts->gsl_timer.data = (unsigned long)ts; + add_timer(&ts->gsl_timer); +#endif + + /* create debug attribute */ + //rc = device_create_file(&ts->input->dev, &dev_attr_debug_enable); + +#ifdef CONFIG_HAS_EARLYSUSPEND + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = gsl_ts_early_suspend; + ts->early_suspend.resume = gsl_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + dbg("[GSLX680] End %s\n", __func__); + wmt_enable_gpirq(); + + check_Backlight_delay(); + return 0; + + + +error_req_irq_fail: + free_irq(ts->irq, ts); + +error_mutex_destroy: + mutex_destroy(&ts->sus_lock); + wake_lock_destroy(&downloadWakeLock); + input_free_device(ts->input); + kfree(ts); +error_kfree_fw: + kfree(GSLX680_FW); + return rc; +} + +static int gsl_ts_remove(struct i2c_client *client) +{ + + + struct gsl_ts *ts = i2c_get_clientdata(client); + dbg("==gsl_ts_remove=\n"); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts->early_suspend); +#endif + + //device_init_wakeup(&client->dev, 0); + cancel_work_sync(&ts->work); + + if( tp_led_gpio >= 0 ){ + mutex_destroy(&ts->timeout_mutex); + gpio_free(tp_led_gpio); + tp_led_gpio = -1; + tp_led_gpio_active = -1; + } + + free_irq(ts->irq, ts); + destroy_workqueue(ts->wq); + input_unregister_device(ts->input); + mutex_destroy(&ts->sus_lock); + wake_lock_destroy(&downloadWakeLock); + + //device_remove_file(&ts->input->dev, &dev_attr_debug_enable); + + if(GSLX680_FW){ + kfree(GSLX680_FW); + GSLX680_FW = NULL; + } + + kfree(ts->touch_data); + kfree(ts); + + return 0; +} + +/* +static const struct i2c_device_id gsl_ts_id[] = { + {GSLX680_I2C_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, gsl_ts_id); + + +static struct i2c_driver gsl_ts_driver = { + .driver = { + .name = GSLX680_I2C_NAME, + .owner = THIS_MODULE, + }, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = gsl_ts_suspend, + .resume = gsl_ts_resume, +#endif + .probe = gsl_ts_probe, + .remove = __devexit_p(gsl_ts_remove), + .id_table = gsl_ts_id, +}; +*/ +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_ts->is_suspended = true; + //printk("\nclose backlight\n\n"); + //printk("disable irq\n\n"); + wmt_disable_gpirq(); + break; + case BL_OPEN: + l_ts->is_suspended = false; + //printk("\nopen backlight\n\n"); + //printk("enable irq\n\n"); + wmt_enable_gpirq(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int gsl_ts_init(void) +{ + int ret = 0; + ret = gsl_ts_probe(ts_get_i2c_client()); + if (ret) + { + dbg("Can't load gsl1680 ts driver!\n"); + } + //dbg("ret=%d\n",ret); + if (earlysus_en) + register_bl_notifier(&wmt_bl_notify); + return ret; +} +static void gsl_ts_exit(void) +{ + dbg("==gsl_ts_exit==\n"); + //i2c_del_driver(&gsl_ts_driver); + gsl_ts_remove(ts_get_i2c_client()); + if (earlysus_en) + unregister_bl_notifier(&wmt_bl_notify); + return; +} + +struct wmtts_device gslx680_tsdev = { + .driver_name = WMT_TS_I2C_NAME, + .ts_id = "GSL1680", + .init = gsl_ts_init, + .exit = gsl_ts_exit, + .suspend = gsl_ts_suspend, + .resume = gsl_ts_resume, +}; + + +//module_init(gsl_ts_init); +//module_exit(gsl_ts_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GSLX680 touchscreen controller driver"); +MODULE_AUTHOR("Guan Yuwei, guanyuwei@basewin.com"); +MODULE_ALIAS("platform:gsl_ts"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h new file mode 100755 index 00000000..c146127c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gslX680.h @@ -0,0 +1,35 @@ +#ifndef _GSLX680_H_
+#define _GSLX680_H_
+
+
+
+#define GSL_NOID_VERSION
+#ifdef GSL_NOID_VERSION
+struct gsl_touch_info
+{
+ int x[10];
+ int y[10];
+ int id[10];
+ int finger_num;
+};
+extern unsigned int gsl_mask_tiaoping(void);
+extern unsigned int gsl_version_id(void);
+extern void gsl_alg_id_main(struct gsl_touch_info *cinfo);
+extern void gsl_DataInit(int *ret);
+
+extern int gsl_noid_ver;
+extern unsigned int gsl_config_data_id[512];
+#endif
+
+struct fw_data
+{
+ //u32 offset : 8;
+ //u32 : 0;
+ u32 offset;
+ u32 val;
+};
+
+extern void wmt_set_keypos(int index,int xmin,int xmax,int ymin,int ymax);
+
+
+#endif
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b Binary files differnew file mode 100755 index 00000000..f25fccd3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/gsl_point_id.b diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c new file mode 100755 index 00000000..e0ddf9e7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.c @@ -0,0 +1,1102 @@ +#include <linux/unistd.h> +#include <linux/time.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +//#include <asm/semaphore.h> +#include <linux/proc_fs.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/suspend.h> +#include <linux/input.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <linux/i2c.h> +#include <linux/irq.h> + +#include <asm/uaccess.h> +#include <linux/fs.h> +#include <linux/syscalls.h> + +#include "gslX680.h" +#include "wmt_ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int irq_gpio; +static int rst_gpio; +static int panelres_x; +static int panelres_y; +static int lcd_exchg = 0; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static CALIBRATION_PARAMETER g_CalcParam; +static TS_EVENT g_evLast; +static struct mutex cal_mutex; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +extern struct wmtts_device gslx680_tsdev; +static struct wmtts_device* l_tsdev = &gslx680_tsdev; +struct proc_dir_entry* l_tsproc = NULL; +static struct i2c_client *l_client=NULL; +static int l_penup = 0; // 1-pen up,0-pen down +static int l_iftskey = -1; // 1:have ts key +int earlysus_en = 0; + +int tp_led_gpio; +int tp_led_gpio_active; + +int sel_reg_bit; +int sel_reg_active; + + +struct tp_infor +{ + //enum tp_type type; + char name[64]; + int i2caddr; + int xaxis; //0: x,1: x swap with y + int xdir; // 1: positive,-1: revert + int ydir; // 1: positive,-1: revert + int finger_num; +}; + +static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; + + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); +/////////////////////////////////////////////////////////////////////// +void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ) +{ + int x, y; + mutex_lock(&cal_mutex); + x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + + g_CalcParam.c2) / g_CalcParam.delta; + +//klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); + if ( x < 0 ) + x = 0; + + if ( y < 0 ) + y = 0; + if (x >= panelres_x) + x = panelres_x-1; + if (y >= panelres_y) + y = panelres_y-1; + + *pCalX = x; + *pCalY = y; + mutex_unlock(&cal_mutex); + return; +} + +int wmt_ts_if_tskey(void) +{ + return ((l_iftskey==1) ? 1: 0); +} + +int wmt_ts_get_firmwfilename(char* fname) +{ + sprintf(fname,"%s_fw.tpf",l_tpinfor[l_tpindex].name); + return 0; +} + + +static struct device* get_tp_device(void){ + if(l_client == NULL){ + errlog("l_client is NULL\n"); + } + return &l_client->dev; +} + + +unsigned int wmt_ts_get_xaxis(void) +{ + return l_tpinfor[l_tpindex].xaxis; +} + +unsigned int wmt_ts_get_xdir(void) +{ + return l_tpinfor[l_tpindex].xdir; +} + +unsigned int wmt_ts_get_ydir(void) +{ + return l_tpinfor[l_tpindex].ydir; +} + +static int parse_firmwarefile(const char* filedata, struct fw_data** firmarr, unsigned int* id_config) +{ + char endflag[]="/* End flag */"; + const char *p = filedata; + u32 val[2]; + int i = 0; + int j = 0; + int k = 0; + const char *s = NULL; + int hex = 0; + +#ifdef GSL_NOID_VERSION + if (gsl_noid_ver) { + while (*p != '{') p++; + p++; + s = p; + while (*s != '}') { + if (*s == '0' && *(s+1) == 'x') { + hex = 1; + break; + } + s++; + } + while (*p != '}') { + sscanf(p,hex ? "%x" : "%u,",&(id_config[k++])); + p = strchr(p,',');p++; + } + } +#endif + + // the first { + while (*p!='{') p++; + p++; + s = p; + // calculate the number of array + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + i++; + } + p++; + }; + dbg("the number of arry:0x%x\n", i); + // alloc the memory for array + *firmarr = kzalloc(sizeof(struct fw_data)*i, GFP_KERNEL); + // parse the value of array + p = s; + j = 0; + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + memset(val,0,sizeof(val)); + sscanf(p,"{%x,%x}",val,val+1); + (*firmarr)[j].offset = val[0]&0x00FF; + (*firmarr)[j].val= val[1]; + //dbg("data%x{%x,%x}\n",j,(*firmarr)[j].offset,(*firmarr)[j].val); + j++; + } + //p = strchr(p,'}'); + p++; + if (j>=i-2) + { + dbg("%s",p); + } + + }; + if (i != j) + { + errlog("Error parsing file(the number of arry not match)!\n"); + errlog("i=0x%x,j=0x%x\n", i,j); + kfree(*firmarr); + return -1; + }; + dbg("paring firmware file end.\n"); + return i; +} + + + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//id_config:config data for some ICs whitch have no id; +//return:the lengthen of firmware data,negative-parsing error. +int read_firmwfile(char* filepath, struct fw_data** firmdata, unsigned int* id_config) +{ + const u8 *data = NULL; + int i = 0; + int ret = -1; + const struct firmware* tpfirmware = NULL; + + klog("ts firmware file:%s\n",filepath); + ret = request_firmware(&tpfirmware, filepath, get_tp_device()); + if (ret < 0) { + errlog("Failed load tp firmware: %s ret=%d\n", filepath,ret); + goto err_end; + } + data = tpfirmware->data; + + i = parse_firmwarefile(data,firmdata,id_config); + + if (i <= 0){ + dbg("Failed to pare firmware file!\n"); + ret = -1; + goto error_parse_fw; + } + dbg("firmware arry len=0x%x\n", i); + ret = i; + dbg("success to read firmware file!\n");; +error_parse_fw: + if(tpfirmware){ + release_firmware(tpfirmware); + tpfirmware = NULL; + } +err_end: + return ret; +} + + + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +void wmt_tsreset_init(void) +{ + int num = rst_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num);//&= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<num); // out low + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //output enable + msleep(10); + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); // out high +} + +// enable:0-disable,1-enable +void wmt_enable_rst_pull(int enable) +{ + if (enable) + { + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<rst_gpio); //enable pull up/down + } else { + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<rst_gpio); //disable pull up/down + } +} + +// up:0-pull down,1-pull up +void wmt_set_rst_pull(int up) +{ + if (up) + { + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<rst_gpio); //pull up + } else { + REG32_VAL(__GPIO_BASE+0x04c0) &= ~(1<<rst_gpio); //pull down + } +} + +// high:0-low level,1-high level +void wmt_rst_output(int high) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + if (high) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<rst_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<rst_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<rst_gpio); //set output +} + +void wmt_rst_input(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<rst_gpio); //set input +} + +void wmt_set_intasgp(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio +} + +// val:1--high,0-low +void wmt_intgp_out(int val) +{ + if (val) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<irq_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<irq_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set output +} + +void wmt_ts_set_irqinput(void) +{ + int num = irq_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input +} + +unsigned int wmt_ts_irqinval(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<irq_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<irq_gpio); //set input + return REG32_VAL(__GPIO_BASE+0x0000)&(1<<irq_gpio); +} + +int wmt_set_gpirq(int type) +{ + int shift; + int offset; + unsigned long reg; + int num = irq_gpio; + + if(num >11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<num); //enable pull up/down + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + +int wmt_enable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + if (l_tsdev->suspend != NULL) + { + return l_tsdev->suspend(pdev, state); + } + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + if (l_tsdev->resume != NULL) + { + return l_tsdev->resume(pdev); + } + klog("...\n"); + return 0; +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_ts_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + klog("wmt ts driver opening...\n"); + + //ts_clear(); + //try_module_get(THIS_MODULE); + + return ret; +} + +static int wmt_ts_close(struct inode *inode, struct file *filp) +{ + klog("wmt ts driver closing...\n"); + //ts_clear(); + //module_put(THIS_MODULE); + + return 0; +} + +static unsigned int wmt_ts_poll(struct file *filp, struct poll_table_struct *wait) +{ +#if 0 + poll_wait(filp, &queue, wait); + if ( head != tail ) + return (POLLIN | POLLRDNORM); +#endif + return 0; +} + +static long wmt_ts_ioctl(/*struct inode * node,*/ struct file *dev, unsigned int cmd, unsigned long arg) +{ + int nBuff[7]; + char env_val[96]={0}; + //dbg("wmt_ts_ioctl(node=0x%p, dev=0x%p, cmd=0x%08x, arg=0x%08lx)\n", node, dev, cmd, arg); + + if (_IOC_TYPE(cmd) != TS_IOC_MAGIC){ + dbg("CMD ERROR!"); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > TS_IOC_MAXNR){ + dbg("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + + case TS_IOCTL_CAL_DONE: + klog("wmt_ts_ioctl: TS_IOCTL_CAL_DONE\n"); + copy_from_user(nBuff, (unsigned int*)arg, 7*sizeof(int)); + + mutex_lock(&cal_mutex); + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero + + mutex_unlock(&cal_mutex); + + sprintf(env_val,"%d %d %d %d %d %d %d",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + wmt_setsyspara("wmt.io.ts.2dcal", env_val); + klog("Tsc calibrate done data: [%s]\n",env_val); + + return 0; + + + case TS_IOCTL_GET_RAWDATA: + // wait for point up + dbg("test wait_penup\n"); + //l_tsdev->wait_penup(>811_tsdev); + klog("wmt_ts_ioctl: TS_IOCTL_GET_RAWDATA\n"); + wmt_ts_wait_penup(); + + nBuff[0] = g_evLast.x; + nBuff[1] = g_evLast.y; + copy_to_user((unsigned int*)arg, nBuff, 2*sizeof(int)); + klog("raw data: x=%d, y=%d\n", nBuff[0], nBuff[1]); + + return 0; + } + + return -EINVAL; +} + +static ssize_t wmt_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) +{ + // read firmware file + + return 0; +} + + +static struct file_operations wmt_ts_fops = { + .read = wmt_ts_read, + .poll = wmt_ts_poll, + .unlocked_ioctl = wmt_ts_ioctl, + .open = wmt_ts_open, + .release = wmt_ts_close, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "reset=%d\n", &val)) + { + + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127, i = 0; + char retval[128] = {0},*p=NULL,*s=NULL; + int Enable=0; + int keypos[4][4]; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(l_tpinfor,0,sizeof(l_tpinfor[0])); + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(l_tpinfor[0].name,p, (s-p)); + p = s+1; + dbg("ts_name=%s\n", l_tpinfor[0].name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tpinfor[0].xaxis),&(l_tpinfor[0].xdir),&(l_tpinfor[0].ydir), + &(l_tpinfor[0].finger_num), + &(l_tpinfor[0].i2caddr),&gsl_noid_ver); + if (ret < 9) + { + dbg("Wrong format ts u-boot param(%d)!\n",ret); + return -ENODEV; + } + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + /*if (strstr(l_tpinfor[0].name, l_tsdev->ts_id) == NULL) + { + dbg("Can't find %s!\n", l_tsdev->ts_id); + return -ENODEV; + }*/ + l_tpindex = 0; + + klog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,i2caddr=%d,gsl_noid_ver=%d\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_tpinfor[0].xaxis,l_tpinfor[0].xdir,l_tpinfor[0].ydir, + l_tpinfor[0].i2caddr, gsl_noid_ver); + + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskey", retval, &len); + if(ret) + { + l_iftskey = 0; + } else { + // get touch key + p = retval; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", \ + keypos[0],keypos[0]+1,keypos[0]+2,keypos[0]+3, \ + keypos[1],keypos[1]+1,keypos[1]+2,keypos[1]+3, \ + keypos[2],keypos[2]+1,keypos[2]+2,keypos[2]+3, \ + keypos[3],keypos[3]+1,keypos[3]+2,keypos[3]+3); + for (i = 0; i < 4; i++) + { + wmt_set_keypos(i,keypos[i][0],keypos[i][1],keypos[i][2],keypos[i][3]); + dbg("%d:%d,%d,%d,%d\n",i,keypos[i][0],keypos[i][1],keypos[i][2],keypos[i][3]); + }; + l_iftskey = 1; + } + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) { + p = retval; + sscanf(p, "%d", &earlysus_en); + } + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + + //wmt.tpkey.led 141:1 + tp_led_gpio = -1; + tp_led_gpio_active = -1; + sel_reg_bit = -1; + sel_reg_active = -1; + ret = wmt_getsyspara("wmt.tpkey.led", retval, &len); + + errlog("wmt.tpkey.led: %s \n",retval); + + if (!ret) { + int tmp[4] = {0}; + p = retval; + ret = sscanf(p, "%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3]); + if(ret == 2){ + tp_led_gpio = tmp[0]; + tp_led_gpio_active = tmp[1]; + } + if(ret == 4){ + tp_led_gpio = tmp[0]; + tp_led_gpio_active = tmp[1]; + sel_reg_bit = tmp[2]; + sel_reg_active = tmp[3]; + } + errlog("tp_led_gpio:%d tp_led_gpio_active:%d sel_reg_bit:%d sel_reg_active:%d \n" + ,tp_led_gpio,tp_led_gpio_active,sel_reg_bit,sel_reg_active); + } + +/* + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + errlog("Read env wmt.io.ts.2dcal Failed.\n "); + //return -EIO; + } + i = 0; + while(i < sizeof(retval)){ + if(retval[i]==' ' || retval[i]==',' || retval[i]==':') + retval[i] = '\0'; + i++; + } + + i = 0; + p = retval; + while(i<7 && p < (retval + sizeof(retval))){ + if(*p == '\0') + p++; + else{ + sscanf(p,"%d",&nBuff[i]); + //printk("%d\n",nBuff[i]); + p=p+strlen(p); + i++; + } + } + //sscanf(retval,"%d %d %d %d %d %d %d %d",&nBuff[0],&nBuff[1],&nBuff[2],&nBuff[3],&nBuff[4],&nBuff[5],&nBuff[6]); + printk("Tsc calibrate init data: [%d %d %d %d %d %d %d]\n",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero +*/ + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + //.addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + ts_i2c_board_info.addr = l_tpinfor[0].i2caddr; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + // Create device node + if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + unregister_chrdev(TS_MAJOR, TS_NAME); + class_destroy(l_dev_class); + mutex_destroy(&cal_mutex); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h new file mode 100755 index 00000000..ea764fd4 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gsl1680_ts/wmt_ts.h @@ -0,0 +1,117 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/suspend.h> +#include <linux/i2c.h> +#include <linux/firmware.h> +#include <mach/hardware.h> + + +//#define DEBUG_WMT_TS // kinseyli +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "gsl1680-ts" +//#define WMT_TS_I2C_ADDR 0x15 + +#define PIN_SHARING_SEL_OFFSET 0x200 + + +#define FW_BINARYFILE_SIZE 0x8000 + +extern int earlysus_en; + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern unsigned int wmt_ts_get_xaxis(void); +extern unsigned int wmt_ts_get_xdir(void); +extern unsigned int wmt_ts_get_ydir(void); +extern int wmt_ts_if_tskey(void); + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//return:the lengthen of firmware data,negative-parsing error. +extern int read_firmwfile(char* filepath, struct fw_data** firmdata, unsigned int* id_config); +extern int wmt_ts_get_firmwfilename(char* fname); + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig new file mode 100755 index 00000000..d5d6a394 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_GT9XX
+ tristate "GT9XX Capacity Touchscreen Device Support"
+ default y
+ depends on ARCH_WMT
+ ---help---
+ Say Y here if you have an WMT based board with touchscreen
+ attached to it.
+ If unsure, say N.
+ To compile this driver as a module, choose M here: the
+ module will be called gt9xx.
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile new file mode 100755 index 00000000..642b1271 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_gt9xx
+
+#obj-$(CONFIG_TOUCHSCREEN_FT5X0X) := $(MY_MODULE_NAME).o
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := gt9xx.o gt9xx_update.o goodix_tool.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c new file mode 100755 index 00000000..3dfe4e1d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/goodix_tool.c @@ -0,0 +1,615 @@ +/* drivers/input/touchscreen/goodix_tool.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Version:1.6
+ * V1.0:2012/05/01,create file.
+ * V1.2:2012/06/08,modify some warning.
+ * V1.4:2012/08/28,modified to support GT9XX
+ * V1.6:new proc name
+ */
+
+#include "gt9xx.h"
+
+#define DATA_LENGTH_UINT 512
+#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*))
+static char procname[20] = {0};
+
+#define UPDATE_FUNCTIONS
+
+#ifdef UPDATE_FUNCTIONS
+extern s32 gup_enter_update_mode(struct i2c_client *client);
+extern void gup_leave_update_mode(void);
+extern s32 gup_update_proc(void *dir);
+#endif
+
+extern void gtp_irq_disable(struct goodix_ts_data *);
+extern void gtp_irq_enable(struct goodix_ts_data *);
+
+#pragma pack(1)
+typedef struct{
+ u8 wr; //write read flag£¬0:R 1:W 2:PID 3:
+ u8 flag; //0:no need flag/int 1: need flag 2:need int
+ u8 flag_addr[2]; //flag address
+ u8 flag_val; //flag val
+ u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:<
+ u16 circle; //polling cycle
+ u8 times; //plling times
+ u8 retry; //I2C retry times
+ u16 delay; //delay befor read or after write
+ u16 data_len; //data length
+ u8 addr_len; //address length
+ u8 addr[2]; //address
+ u8 res[3]; //reserved
+ u8* data; //data pointer
+}st_cmd_head;
+#pragma pack()
+st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client = NULL;
+
+static struct proc_dir_entry *goodix_proc_entry;
+
+static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data);
+static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data );
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+#if GTP_ESD_PROTECT
+extern void gtp_esd_switch(struct i2c_client *, s32);
+#endif
+s32 DATA_LENGTH = 0;
+s8 IC_TYPE[16] = {0};
+
+static void tool_set_proc_name(char * procname)
+{
+ char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ char date[20] = {0};
+ char month[4] = {0};
+ int i = 0, n_month = 1, n_day = 0, n_year = 0;
+
+ sprintf(date, "%s", __DATE__);
+
+ //GTP_DEBUG("compile date: %s", date);
+
+ sscanf(date, "%s %d %d", month, &n_day, &n_year);
+
+ for (i = 0; i < 12; ++i)
+ {
+ if (!memcmp(months[i], month, 3))
+ {
+ n_month = i+1;
+ break;
+ }
+ }
+
+ sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day);
+
+ //GTP_DEBUG("procname = %s", procname);
+}
+
+
+static s32 tool_i2c_read_no_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msgs[2];
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = gt_client->addr;
+ msgs[0].len = cmd_head.addr_len;
+ msgs[0].buf = &buf[0];
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = gt_client->addr;
+ msgs[1].len = len;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+ for (i = 0; i < cmd_head.retry; i++)
+ {
+ ret=i2c_transfer(gt_client->adapter, msgs, 2);
+ if (ret > 0)
+ {
+ break;
+ }
+ }
+ return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msg;
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = gt_client->addr;
+ msg.len = len;
+ msg.buf = buf;
+
+ for (i = 0; i < cmd_head.retry; i++)
+ {
+ ret=i2c_transfer(gt_client->adapter, &msg, 1);
+ if (ret > 0)
+ {
+ break;
+ }
+ }
+ return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_read_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_write_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static void register_i2c_func(void)
+{
+// if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
+// || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
+// || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
+// || !strncmp(IC_TYPE, "GT813", 5))
+ if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
+ && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
+ && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
+ && strncmp(IC_TYPE, "GTxxx", 5))
+ {
+ tool_i2c_read = tool_i2c_read_with_extra;
+ tool_i2c_write = tool_i2c_write_with_extra;
+ GTP_DEBUG("I2C function: with pre and end cmd!");
+ }
+ else
+ {
+ tool_i2c_read = tool_i2c_read_no_extra;
+ tool_i2c_write = tool_i2c_write_no_extra;
+ GTP_INFO("I2C function: without pre and end cmd!");
+ }
+}
+
+static void unregister_i2c_func(void)
+{
+ tool_i2c_read = NULL;
+ tool_i2c_write = NULL;
+ GTP_INFO("I2C function: unregister i2c transfer function!");
+}
+
+
+s32 init_wr_node(struct i2c_client *client)
+{
+ s32 i;
+
+ gt_client = client;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.data = NULL;
+
+ i = 5;
+ while ((!cmd_head.data) && i)
+ {
+ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+ if (NULL != cmd_head.data)
+ {
+ break;
+ }
+ i--;
+ }
+ if (i)
+ {
+ DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+ GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+ }
+ else
+ {
+ GTP_ERROR("Apply for memory failed.");
+ return FAIL;
+ }
+
+ cmd_head.addr_len = 2;
+ cmd_head.retry = 5;
+
+ register_i2c_func();
+
+ tool_set_proc_name(procname);
+ goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+ if (goodix_proc_entry == NULL)
+ {
+ GTP_ERROR("Couldn't create proc entry!");
+ return FAIL;
+ }
+ else
+ {
+ GTP_INFO("Create proc entry success!");
+ goodix_proc_entry->write_proc = goodix_tool_write;
+ goodix_proc_entry->read_proc = goodix_tool_read;
+ }
+
+ return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+ kfree(cmd_head.data);
+ cmd_head.data = NULL;
+ unregister_i2c_func();
+ remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+ u8 ret = 0;
+
+ switch (rlt)
+ {
+ case 0:
+ ret = (src != dst) ? true : false;
+ break;
+
+ case 1:
+ ret = (src == dst) ? true : false;
+ GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32)ret);
+ break;
+
+ case 2:
+ ret = (src > dst) ? true : false;
+ break;
+
+ case 3:
+ ret = (src < dst) ? true : false;
+ break;
+
+ case 4:
+ ret = (src & dst) ? true : false;
+ break;
+
+ case 5:
+ ret = (!(src | dst)) ? true : false;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Comfirm function.
+Input:
+ None.
+Output:
+ Return write length.
+********************************************************/
+static u8 comfirm(void)
+{
+ s32 i = 0;
+ u8 buf[32];
+
+// memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len);
+// memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17
+ memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+ for (i = 0; i < cmd_head.times; i++)
+ {
+ if (tool_i2c_read(buf, 1) <= 0)
+ {
+ GTP_ERROR("Read flag data failed!");
+ return FAIL;
+ }
+ if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation))
+ {
+ GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);
+ GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+ break;
+ }
+
+ msleep(cmd_head.circle);
+ }
+
+ if (i >= cmd_head.times)
+ {
+ GTP_ERROR("Didn't get the flag to continue!");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+/*******************************************************
+Function:
+ Goodix tool write function.
+Input:
+ standard proc write function param.
+Output:
+ Return write length.
+********************************************************/
+static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
+{
+ s32 ret = 0;
+ GTP_DEBUG_FUNC();
+ GTP_DEBUG_ARRAY((u8*)buff, len);
+
+ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+ if(ret)
+ {
+ GTP_ERROR("copy_from_user failed.");
+ }
+
+ GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
+ GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
+ GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);
+ GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
+ GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
+ GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
+ GTP_DEBUG("times :%d.", (s32)cmd_head.times);
+ GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
+ GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
+ GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
+ GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
+ GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+ GTP_DEBUG("len:%d.", (s32)len);
+ GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+
+ if (1 == cmd_head.wr)
+ {
+ // copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ GTP_ERROR("copy_from_user failed.");
+ }
+ memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len);
+ GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+
+ if (1 == cmd_head.flag)
+ {
+ if (FAIL == comfirm())
+ {
+ GTP_ERROR("[WRITE]Comfirm fail!");
+ return FAIL;
+ }
+ }
+ else if (2 == cmd_head.flag)
+ {
+ //Need interrupt!
+ }
+ if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len) <= 0)
+ {
+ GTP_ERROR("[WRITE]Write data failed!");
+ return FAIL;
+ }
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len);
+ if (cmd_head.delay)
+ {
+ msleep(cmd_head.delay);
+ }
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ }
+ else if (3 == cmd_head.wr) //Write ic type
+ {
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ GTP_ERROR("copy_from_user failed.");
+ }
+ memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ register_i2c_func();
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ }
+ else if (5 == cmd_head.wr)
+ {
+ //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ }
+ else if (7 == cmd_head.wr)//disable irq!
+ {
+ gtp_irq_disable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_OFF);
+ #endif
+ return CMD_HEAD_LENGTH;
+ }
+ else if (9 == cmd_head.wr) //enable irq!
+ {
+ gtp_irq_enable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_ON);
+ #endif
+ return CMD_HEAD_LENGTH;
+ }
+ else if(17 == cmd_head.wr)
+ {
+ struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ GTP_DEBUG("copy_from_user failed.");
+ }
+ if(cmd_head.data[GTP_ADDR_LENGTH])
+ {
+ GTP_DEBUG("gtp enter rawdiff.");
+ ts->gtp_rawdiff_mode = true;
+ }
+ else
+ {
+ ts->gtp_rawdiff_mode = false;
+ GTP_DEBUG("gtp leave rawdiff.");
+ }
+ return CMD_HEAD_LENGTH;
+ }
+#ifdef UPDATE_FUNCTIONS
+ else if (11 == cmd_head.wr)//Enter update mode!
+ {
+ if (FAIL == gup_enter_update_mode(gt_client))
+ {
+ return FAIL;
+ }
+ }
+ else if (13 == cmd_head.wr)//Leave update mode!
+ {
+ gup_leave_update_mode();
+ }
+ else if (15 == cmd_head.wr) //Update firmware!
+ {
+ show_len = 0;
+ total_len = 0;
+ memset(cmd_head.data, 0, cmd_head.data_len + 1);
+ memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+
+ if (FAIL == gup_update_proc((void*)cmd_head.data))
+ {
+ return FAIL;
+ }
+ }
+#endif
+
+ return CMD_HEAD_LENGTH;
+}
+
+/*******************************************************
+Function:
+ Goodix tool read function.
+Input:
+ standard proc read function param.
+Output:
+ Return read length.
+********************************************************/
+static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )
+{
+ GTP_DEBUG_FUNC();
+
+ if (cmd_head.wr % 2)
+ {
+ return FAIL;
+ }
+ else if (!cmd_head.wr)
+ {
+ u16 len = 0;
+ s16 data_len = 0;
+ u16 loc = 0;
+
+ if (1 == cmd_head.flag)
+ {
+ if (FAIL == comfirm())
+ {
+ GTP_ERROR("[READ]Comfirm fail!");
+ return FAIL;
+ }
+ }
+ else if (2 == cmd_head.flag)
+ {
+ //Need interrupt!
+ }
+
+ memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]);
+ GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+
+ if (cmd_head.delay)
+ {
+ msleep(cmd_head.delay);
+ }
+
+ data_len = cmd_head.data_len;
+ while(data_len > 0)
+ {
+ if (data_len > DATA_LENGTH)
+ {
+ len = DATA_LENGTH;
+ }
+ else
+ {
+ len = data_len;
+ }
+ data_len -= DATA_LENGTH;
+
+ if (tool_i2c_read(cmd_head.data, len) <= 0)
+ {
+ GTP_ERROR("[READ]Read data failed!");
+ return FAIL;
+ }
+ memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);
+ loc += len;
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
+ GTP_DEBUG_ARRAY(page, len);
+ }
+ }
+ else if (2 == cmd_head.wr)
+ {
+ // memcpy(page, "gt8", cmd_head.data_len);
+ // memcpy(page, "GT818", 5);
+ // page[5] = 0;
+
+ GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len);
+ return cmd_head.data_len;
+ //return sizeof(IC_TYPE_NAME);
+ }
+ else if (4 == cmd_head.wr)
+ {
+ page[0] = show_len >> 8;
+ page[1] = show_len & 0xff;
+ page[2] = total_len >> 8;
+ page[3] = total_len & 0xff;
+
+ return cmd_head.data_len;
+ }
+ else if (6 == cmd_head.wr)
+ {
+ //Read error code!
+ }
+ else if (8 == cmd_head.wr) //Read driver version
+ {
+ // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION));
+ s32 tmp_len;
+ tmp_len = strlen(GTP_DRIVER_VERSION);
+ memcpy(page, GTP_DRIVER_VERSION, tmp_len);
+ page[tmp_len] = 0;
+ }
+
+ return cmd_head.data_len;
+}
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c new file mode 100755 index 00000000..cc02513e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.c @@ -0,0 +1,2163 @@ +/* drivers/input/touchscreen/gt9xx.c + * + * 2010 - 2013 Goodix Technology. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Version: 1.8 + * Authors: andrew@goodix.com, meta@goodix.com + * Release Date: 2013/04/25 + * Revision record: + * V1.0: + * first Release. By Andrew, 2012/08/31 + * V1.2: + * modify gtp_reset_guitar,slot report,tracking_id & 0x0F. By Andrew, 2012/10/15 + * V1.4: + * modify gt9xx_update.c. By Andrew, 2012/12/12 + * V1.6: + * 1. new heartbeat/esd_protect mechanism(add external watchdog) + * 2. doze mode, sliding wakeup + * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5) + * 3. config length verification + * 4. names & comments + * By Meta, 2013/03/11 + * V1.8: + * 1. pen/stylus identification + * 2. read double check & fixed config support + * 2. new esd & slide wakeup optimization + * By Meta, 2013/06/08 + */ + +#include <linux/irq.h> +#include <linux/firmware.h> +#include "gt9xx.h" + +#if GTP_ICS_SLOT_REPORT + #include <linux/input/mt.h> +#endif + +static const char *goodix_ts_name = "Goodix Capacitive TouchScreen"; +static struct workqueue_struct *goodix_wq; +struct goodix_ts_data *l_ts; +int l_suspend = 0; +struct i2c_client * i2c_connect_client = NULL; +u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH] + = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + +#if GTP_HAVE_TOUCH_KEY + static const u16 touch_key_array[] = GTP_KEY_TAB; + #define GTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0])) + +#if GTP_DEBUG_ON + static const int key_codes[] = {KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH}; + static const char *key_names[] = {"Key_Home", "Key_Back", "Key_Menu", "Key_Search"}; +#endif + +#endif + +static s8 gtp_i2c_test(struct i2c_client *client); +void gtp_reset_guitar(struct i2c_client *client, s32 ms); +void gtp_int_sync(s32 ms); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void goodix_ts_early_suspend(struct early_suspend *h); +static void goodix_ts_late_resume(struct early_suspend *h); +#endif + +#if GTP_CREATE_WR_NODE +extern s32 init_wr_node(struct i2c_client*); +extern void uninit_wr_node(void); +#endif + +#if GTP_AUTO_UPDATE +extern u8 gup_init_update_proc(struct goodix_ts_data *); +#endif + +#if GTP_ESD_PROTECT +static struct delayed_work gtp_esd_check_work; +static struct workqueue_struct * gtp_esd_check_workqueue = NULL; +static void gtp_esd_check_func(struct work_struct *); +static s32 gtp_init_ext_watchdog(struct i2c_client *client); +void gtp_esd_switch(struct goodix_ts_data *, s32); +#endif + + +#if GTP_SLIDE_WAKEUP +typedef enum +{ + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}DOZE_T; +static DOZE_T doze_status = DOZE_DISABLED; +static s8 gtp_enter_doze(struct goodix_ts_data *ts); +#endif + +static u8 chip_gt9xxs = 0; // true if ic is gt9xxs, like gt915s +u8 grp_cfg_version = 0; + +/******************************************************* +Function: + Read data from the i2c slave device. +Input: + client: i2c device. + buf[0~1]: read start address. + buf[2~len-1]: read data buffer. + len: GTP_ADDR_LENGTH + read bytes count +Output: + numbers of i2c_msgs to transfer: + 2: succeed, otherwise: failed +*********************************************************/ +s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len) +{ + struct i2c_msg msgs[2]; + s32 ret=-1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + //msgs[0].flags = !I2C_M_RD; + msgs[0].flags = 0 | I2C_M_NOSTART; + msgs[0].addr = client->addr; + msgs[0].len = GTP_ADDR_LENGTH; + msgs[0].buf = &buf[0]; + //msgs[0].scl_rate = 300 * 1000; // for Rockchip + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = client->addr; + msgs[1].len = len - GTP_ADDR_LENGTH; + msgs[1].buf = &buf[GTP_ADDR_LENGTH]; + //msgs[1].scl_rate = 300 * 1000; + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + if((retries >= 5)) + { + #if GTP_SLIDE_WAKEUP + // reset chip would quit doze mode + if (DOZE_ENABLED == doze_status) + { + return ret; + } + #endif + GTP_DEBUG("I2C communication timeout, resetting chip..."); + gtp_reset_guitar(client, 10); + } + return ret; +} + +/******************************************************* +Function: + Write data to the i2c slave device. +Input: + client: i2c device. + buf[0~1]: write start address. + buf[2~len-1]: data buffer + len: GTP_ADDR_LENGTH + write bytes count +Output: + numbers of i2c_msgs to transfer: + 1: succeed, otherwise: failed +*********************************************************/ +s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len) +{ + struct i2c_msg msg; + s32 ret = -1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = len; + msg.buf = buf; + //msg.scl_rate = 300 * 1000; // for Rockchip + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1)break; + retries++; + } + if((retries >= 5)) + { + #if GTP_SLIDE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + return ret; + } + #endif + GTP_DEBUG("I2C communication timeout, resetting chip..."); + gtp_reset_guitar(client, 10); + } + return ret; +} +/******************************************************* +Function: + i2c read twice, compare the results +Input: + client: i2c device + addr: operate address + rxbuf: read data to store, if compare successful + len: bytes to read +Output: + FAIL: read failed + SUCCESS: read successful +*********************************************************/ +s32 gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + while (retry++ < 3) + { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len+2)) + { + break; + } + } + if (retry < 3) + { + memcpy(rxbuf, confirm_buf+2, len); + return SUCCESS; + } + else + { + GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len); + return FAIL; + } +} + +/******************************************************* +Function: + Send config. +Input: + client: i2c device. +Output: + result of i2c write operation. + 1: succeed, otherwise: failed +*********************************************************/ +s32 gtp_send_cfg(struct goodix_ts_data * ts) +{ + s32 ret = 2; + +#if GTP_DRIVER_SEND_CFG + s32 retry = 0; + + if (ts->fixed_cfg) + { + GTP_INFO("Ic fixed config, no config sent!"); + return 2; + } + GTP_INFO("driver send config"); + for (retry = 0; retry < 5; retry++) + { + ret = gtp_i2c_write(ts->client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + if (ret > 0) + { + break; + } + } +#endif + + return ret; +} + +/******************************************************* +Function: + Disable irq function +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +void gtp_irq_disable(struct goodix_ts_data *ts) +{ + //unsigned long irqflags; + + GTP_DEBUG_FUNC(); + + //spin_lock_irqsave(&ts->irq_lock, irqflags); + if (!ts->irq_is_disable) + { + ts->irq_is_disable = 1; + //disable_irq_nosync(ts->client->irq); + wmt_gpio_mask_irq(ts->irq_gpio); + } + //spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} + +/******************************************************* +Function: + Enable irq function +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +void gtp_irq_enable(struct goodix_ts_data *ts) +{ + //unsigned long irqflags = 0; + + GTP_DEBUG_FUNC(); + + //spin_lock_irqsave(&ts->irq_lock, irqflags); + if (ts->irq_is_disable) + { + //enable_irq(ts->client->irq); + wmt_gpio_unmask_irq(ts->irq_gpio); + ts->irq_is_disable = 0; + } + //spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} + + +/******************************************************* +Function: + Report touch point event +Input: + ts: goodix i2c_client private data + id: trackId + x: input x coordinate + y: input y coordinate + w: input pressure +Output: + None. +*********************************************************/ +static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w) +{ + s32 px = 0, py = 0; +#if GTP_CHANGE_X2Y + GTP_SWAP(x, y); +#endif + + if (ts->swap) { + px = y; + py = x; + } else { + px = x; + py = y; + } + if (ts->xdir == -1) + px = ts->abs_x_max - px; + if (ts->ydir == -1) + py = ts->abs_y_max - py; + + if (ts->lcd_exchg) { + int tmp; + tmp = px; + px = py; + py = ts->abs_x_max - tmp; + } + +#if GTP_ICS_SLOT_REPORT + input_mt_slot(ts->input_dev, id); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); +#else + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, px); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, py); + //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + //input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id); + input_mt_sync(ts->input_dev); +#endif + + GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, px, py, w); +} + +/******************************************************* +Function: + Report touch release event +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +static void gtp_touch_up(struct goodix_ts_data* ts, s32 id) +{ +#if GTP_ICS_SLOT_REPORT + input_mt_slot(ts->input_dev, id); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + GTP_DEBUG("Touch id[%2d] release!", id); +#else + //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + //input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); + input_mt_sync(ts->input_dev); +#endif +} + + +/******************************************************* +Function: + Goodix touchscreen work function +Input: + work: work struct of goodix_workqueue +Output: + None. +*********************************************************/ +static void goodix_ts_work_func(struct work_struct *work) +{ + u8 end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0}; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF}; + u8 touch_num = 0; + u8 finger = 0; + static u16 pre_touch = 0; + static u8 pre_key = 0; +#if GTP_WITH_PEN + static u8 pre_pen = 0; +#endif + u8 key_value = 0; + u8* coor_data = NULL; + s32 input_x = 0; + s32 input_y = 0; + s32 input_w = 0; + s32 id = 0; + s32 i = 0; + s32 ret = -1; + struct goodix_ts_data *ts = NULL; + +#if GTP_SLIDE_WAKEUP + u8 doze_buf[3] = {0x81, 0x4B}; +#endif + + GTP_DEBUG_FUNC(); + ts = container_of(work, struct goodix_ts_data, work); + if (ts->enter_update) + { + return; + } +#if GTP_SLIDE_WAKEUP + if (DOZE_ENABLED == doze_status) + { + ret = gtp_i2c_read(i2c_connect_client, doze_buf, 3); + GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]); + if (ret > 0) + { + if (doze_buf[2] == 0xAA) + { + GTP_INFO("Slide(0xAA) To Light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c_connect_client, doze_buf, 3); + } + else if (doze_buf[2] == 0xBB) + { + GTP_INFO("Slide(0xBB) To Light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c_connect_client, doze_buf, 3); + } + else if (0xC0 == (doze_buf[2] & 0xC0)) + { + GTP_INFO("double click to light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + // clear 0x814B + doze_buf[2] = 0x00; + gtp_i2c_write(i2c_connect_client, doze_buf, 3); + } + else + { + gtp_enter_doze(ts); + } + } + if (ts->use_irq) + { + gtp_irq_enable(ts); + } + return; + } +#endif + + ret = gtp_i2c_read(ts->client, point_data, 12); + if (ret < 0) + { + GTP_ERROR("I2C transfer error. errno:%d\n ", ret); + goto exit_work_func; + } + + finger = point_data[GTP_ADDR_LENGTH]; + if((finger & 0x80) == 0) + { + goto exit_work_func; + } + + touch_num = finger & 0x0f; + if (touch_num > GTP_MAX_TOUCH) + { + goto exit_work_func; + } + + if (touch_num > 1) + { + u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff}; + + ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + +#if GTP_HAVE_TOUCH_KEY + key_value = point_data[3 + 8 * touch_num]; + + if(key_value || pre_key) + { + for (i = 0; i < GTP_MAX_KEY_NUM; i++) + { + #if GTP_DEBUG_ON + for (ret = 0; ret < 4; ++ret) + { + if (key_codes[ret] == touch_key_array[i]) + { + GTP_DEBUG("Key: %s %s", key_names[ret], (key_value & (0x01 << i)) ? "Down" : "Up"); + break; + } + } + #endif + input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<<i)); + } + touch_num = 0; + pre_touch = 0; + } +#endif + pre_key = key_value; + + GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger); + +#if GTP_ICS_SLOT_REPORT + +#if GTP_WITH_PEN + if (pre_pen && (touch_num == 0)) + { + GTP_DEBUG("Pen touch UP(Slot)!"); + input_report_key(ts->input_dev, BTN_TOOL_PEN, 0); + input_mt_slot(ts->input_dev, 5); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + pre_pen = 0; + } +#endif + if (pre_touch || touch_num) + { + s32 pos = 0; + u16 touch_index = 0; + + coor_data = &point_data[3]; + + if(touch_num) + { + id = coor_data[pos] & 0x0F; + + #if GTP_WITH_PEN + id = coor_data[pos]; + if ((id == 128)) + { + GTP_DEBUG("Pen touch DOWN(Slot)!"); + input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8); + input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8); + input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8); + + input_report_key(ts->input_dev, BTN_TOOL_PEN, 1); + input_mt_slot(ts->input_dev, 5); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 5); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); + GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]", input_x, input_y, input_w); + pre_pen = 1; + pre_touch = 0; + } + #endif + + touch_index |= (0x01<<id); + } + + GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",id, touch_index,pre_touch); + for (i = 0; i < GTP_MAX_TOUCH; i++) + { + #if GTP_WITH_PEN + if (pre_pen == 1) + { + break; + } + #endif + + if (touch_index & (0x01<<i)) + { + input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8); + input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8); + input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8); + + gtp_touch_down(ts, id, input_x, input_y, input_w); + pre_touch |= 0x01 << i; + + pos += 8; + id = coor_data[pos] & 0x0F; + touch_index |= (0x01<<id); + } + else + { + gtp_touch_up(ts, i); + pre_touch &= ~(0x01 << i); + } + } + } +#else + //input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value)); + if (touch_num) + { + for (i = 0; i < touch_num; i++) + { + coor_data = &point_data[i * 8 + 3]; + + id = coor_data[0]; // & 0x0F; + input_x = coor_data[1] | (coor_data[2] << 8); + input_y = coor_data[3] | (coor_data[4] << 8); + input_w = coor_data[5] | (coor_data[6] << 8); + + #if GTP_WITH_PEN + if (id == 128) + { + GTP_DEBUG("Pen touch DOWN!"); + input_report_key(ts->input_dev, BTN_TOOL_PEN, 1); + pre_pen = 1; + id = 0; + } + #endif + + gtp_touch_down(ts, id, input_x, input_y, input_w); + } + } + else if (pre_touch) + { + #if GTP_WITH_PEN + if (pre_pen == 1) + { + GTP_DEBUG("Pen touch UP!"); + input_report_key(ts->input_dev, BTN_TOOL_PEN, 0); + pre_pen = 0; + } + #endif + + GTP_DEBUG("Touch Release!"); + gtp_touch_up(ts, 0); + } + + pre_touch = touch_num; +#endif + + input_sync(ts->input_dev); + +exit_work_func: + if(!ts->gtp_rawdiff_mode) + { + ret = gtp_i2c_write(ts->client, end_cmd, 3); + if (ret < 0) + { + GTP_INFO("I2C write end_cmd error!"); + } + } + if (ts->use_irq) + { + gtp_irq_enable(ts); + } +} + +/******************************************************* +Function: + Timer interrupt service routine for polling mode. +Input: + timer: timer struct pointer +Output: + Timer work mode. + HRTIMER_NORESTART: no restart mode +*********************************************************/ +static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer) +{ + struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer); + + GTP_DEBUG_FUNC(); + + queue_work(goodix_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +/******************************************************* +Function: + External interrupt service routine for interrupt mode. +Input: + irq: interrupt number. + dev_id: private data pointer +Output: + Handle Result. + IRQ_HANDLED: interrupt handled successfully +*********************************************************/ +static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) +{ + struct goodix_ts_data *ts = dev_id; + + GTP_DEBUG_FUNC(); + + if (gpio_irqstatus(ts->irq_gpio)) + { + wmt_gpio_ack_irq(ts->irq_gpio); + if (is_gpio_irqenable(ts->irq_gpio) && l_suspend == 0) + { + gtp_irq_disable(ts); + queue_work(goodix_wq, &ts->work); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} +/******************************************************* +Function: + Synchronization. +Input: + ms: synchronization time in millisecond. +Output: + None. +*******************************************************/ +void gtp_int_sync(s32 ms) +{ + GTP_GPIO_OUTPUT(l_ts->irq_gpio, 0); + msleep(ms); + GTP_GPIO_AS_INPUT(l_ts->irq_gpio); + //GTP_GPIO_AS_INT(ts->irq_gpio); +} + +/******************************************************* +Function: + Reset chip. +Input: + ms: reset time in millisecond +Output: + None. +*******************************************************/ +void gtp_reset_guitar(struct i2c_client *client, s32 ms) +{ + GTP_DEBUG_FUNC(); + + GTP_GPIO_OUTPUT(l_ts->rst_gpio, 0); // begin select I2C slave addr + msleep(ms); // T2: > 10ms + // HIGH: 0x28/0x29, LOW: 0xBA/0xBB + GTP_GPIO_OUTPUT(l_ts->irq_gpio, client->addr == 0x14); + + msleep(2); // T3: > 100us + GTP_GPIO_OUTPUT(l_ts->rst_gpio, 1); + + msleep(6); // T4: > 5ms + + GTP_GPIO_AS_INPUT(l_ts->rst_gpio); // end select I2C slave addr + + gtp_int_sync(50); + +#if GTP_ESD_PROTECT + gtp_init_ext_watchdog(client); +#endif +} + +#if GTP_SLIDE_WAKEUP +/******************************************************* +Function: + Enter doze mode for sliding wakeup. +Input: + ts: goodix tp private data +Output: + 1: succeed, otherwise failed +*******************************************************/ +static s8 gtp_enter_doze(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8}; + + GTP_DEBUG_FUNC(); + +#if GTP_DBL_CLK_WAKEUP + i2c_control_buf[2] = 0x09; +#endif + + gtp_irq_disable(ts); + + GTP_DEBUG("entering doze mode..."); + while(retry++ < 5) + { + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x46; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret < 0) + { + GTP_DEBUG("failed to set doze flag into 0x8046, %d", retry); + continue; + } + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x40; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) + { + doze_status = DOZE_ENABLED; + GTP_INFO("GTP has been working in doze mode!"); + gtp_irq_enable(ts); + return ret; + } + msleep(10); + } + GTP_ERROR("GTP send doze cmd failed."); + gtp_irq_enable(ts); + return ret; +} +#else +/******************************************************* +Function: + Enter sleep mode. +Input: + ts: private data. +Output: + Executive outcomes. + 1: succeed, otherwise failed. +*******************************************************/ +#if 0 +static s8 gtp_enter_sleep(struct goodix_ts_data * ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5}; + + GTP_DEBUG_FUNC(); + + GTP_GPIO_OUTPUT(ts->irq_gpio, 0); + msleep(5); + + while(retry++ < 5) + { + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) + { + GTP_INFO("GTP enter sleep!"); + + return ret; + } + msleep(10); + } + GTP_ERROR("GTP send sleep cmd failed."); + return ret; +} +#endif +#endif +/******************************************************* +Function: + Wakeup from sleep. +Input: + ts: private data. +Output: + Executive outcomes. + >0: succeed, otherwise: failed. +*******************************************************/ +#if 0 +static s8 gtp_wakeup_sleep(struct goodix_ts_data * ts) +{ + u8 retry = 0; + s8 ret = -1; + + GTP_DEBUG_FUNC(); + +#if GTP_POWER_CTRL_SLEEP + while(retry++ < 5) + { + gtp_reset_guitar(ts->client, 20); + + ret = gtp_send_cfg(ts); + if (ret < 0) + { + GTP_INFO("Wakeup sleep send config failed!"); + continue; + } + GTP_INFO("GTP wakeup sleep"); + return 1; + } +#else + while(retry++ < 10) + { + #if GTP_SLIDE_WAKEUP + if (DOZE_WAKEUP != doze_status) // wakeup not by slide + { + gtp_reset_guitar(ts->client, 10); + } + else // wakeup by slide + { + doze_status = DOZE_DISABLED; + } + #else + if (chip_gt9xxs == 1) + { + gtp_reset_guitar(ts->client, 10); + } + else + { + GTP_GPIO_OUTPUT(ts->irq_gpio, 1); + msleep(5); + } + #endif + ret = gtp_i2c_test(ts->client); + if (ret > 0) + { + GTP_INFO("GTP wakeup sleep."); + + #if (!GTP_SLIDE_WAKEUP) + if (chip_gt9xxs == 0) + { + gtp_int_sync(25); + msleep(20); + #if GTP_ESD_PROTECT + gtp_init_ext_watchdog(ts->client); + #endif + } + #endif + return ret; + } + gtp_reset_guitar(ts->client, 20); + } +#endif + + GTP_ERROR("GTP wakeup sleep failed."); + return ret; +} +#endif + +static int wmt_ts_load_firmware(char* firmwarename, unsigned char* firmdata) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos; + long fsize; + int alloclen; + char filepath[64]; + + sprintf(filepath, "/system/etc/firmware/%s", firmwarename); + printk("ts firmware file:%s\n",filepath); + + fp = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp)) { + printk("create file error\n"); + return -1; + } + fs = get_fs(); + set_fs(KERNEL_DS); + alloclen = fp->f_op->llseek(fp, 0, SEEK_END); + printk("firmware file lengh:0x%x,\n", alloclen); + alloclen += alloclen%4; + + fp->f_op->llseek(fp,0,0); + pos = 0; + fsize = vfs_read(fp, firmdata, alloclen, &pos); + printk("filesize:0x%ld,alloclen:0x%d\n",fsize,alloclen); + if (fsize <= 0) + { + printk("alloc size is too small.\n"); + goto error_vfs_read; + } + filp_close(fp, NULL); + set_fs(fs); + printk("success to read firmware file!\n");; + + return 0; +error_vfs_read: + filp_close(fp, NULL); + set_fs(fs); + return -1; +} + +static int read_cfg(char* cfgname, u8* cfg, int len_max) +{ + char endflag[]="/* End flag */"; + unsigned char* p; + int val; + int i = 0; + unsigned char *rawdata; + + rawdata = kzalloc(1024, GFP_KERNEL); + if (rawdata == NULL) + { + printk("Error when alloc memory for firmware file!\n"); + return -ENOMEM; + } + + if (wmt_ts_load_firmware(cfgname, rawdata)) + return -1; + + p = rawdata; + while (*p!='{') p++; + p++; + + while (strncmp(p,endflag,strlen(endflag))) + { + if (!strncmp(p,"0x",strlen("0x"))) + { + sscanf(p,"%x,",&val); + *(cfg++) = val&0x00FF; + i++; + } + if (i == len_max) + break; + p++; + + }; + + kfree(rawdata); + + return i; +} + +/******************************************************* +Function: + Initialize gtp. +Input: + ts: goodix private data +Output: + Executive outcomes. + 0: succeed, otherwise: failed +*******************************************************/ +static s32 gtp_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = -1; + +#if GTP_DRIVER_SEND_CFG + s32 i; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + + u8 send_cfg_buf[256] = {0}; + char cfgname[32] = {0}; + + ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); + if (SUCCESS == ret) + { + if (opr_buf[0] != 0xBE) + { + ts->fw_error = 1; + GTP_ERROR("Firmware error, no config sent!"); + return -1; + } + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1); + if (SUCCESS == ret) + { + if (sensor_id >= 0x06) + { + //GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id); + //return -1; + GTP_ERROR("Invalid sensor_id(0x%02X), Force set id to 0!", sensor_id); + sensor_id = 0; + } + } + else + { + GTP_ERROR("Failed to get sensor_id, No config sent!"); + return -1; + } + GTP_DEBUG("Sensor_ID: %d", sensor_id); + + sprintf(cfgname, "%s_id%d.cfg", ts->fw_name, sensor_id); + GTP_INFO("config file name: %s.", cfgname); + ret = read_cfg(cfgname, send_cfg_buf, 256); + if (ret < 0) + return -1; + ts->gtp_cfg_len = ret; + + if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) + { + GTP_ERROR("INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!"); + return -1; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1); + + if (ret == SUCCESS) + { + GTP_DEBUG("Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", + send_cfg_buf[0], send_cfg_buf[0], opr_buf[0], opr_buf[0]); + + if (opr_buf[0] < 90) + { + grp_cfg_version = send_cfg_buf[0]; // backup group config version + send_cfg_buf[0] = 0x00; + ts->fixed_cfg = 0; + } + else // treated as fixed config, not send config + { + GTP_INFO("Ic fixed config with config version(%d, 0x%02X)", opr_buf[0], opr_buf[0]); + ts->fixed_cfg = 1; + } + } + else + { + GTP_ERROR("Failed to get ic config version!No config sent!"); + return -1; + } + + memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf, ts->gtp_cfg_len); + +#if GTP_CUSTOM_CFG + config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; + config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); + config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; + config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); + + if (GTP_INT_TRIGGER == 0) //RISING + { + config[TRIGGER_LOC] &= 0xfe; + } + else if (GTP_INT_TRIGGER == 1) //FALLING + { + config[TRIGGER_LOC] |= 0x01; + } +#endif // GTP_CUSTOM_CFG + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) + { + check_sum += config[i]; + } + config[ts->gtp_cfg_len] = (~check_sum) + 1; + +#else // DRIVER NOT SEND CONFIG + ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH); + if (ret < 0) + { + GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!"); + ts->abs_x_max = GTP_MAX_WIDTH; + ts->abs_y_max = GTP_MAX_HEIGHT; + ts->int_trigger_type = GTP_INT_TRIGGER; + } +#endif // GTP_DRIVER_SEND_CFG + + GTP_DEBUG_FUNC(); + if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) + { + ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC]; + ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2]; + ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; + } + + ret = gtp_send_cfg(ts); + if (ret < 0) + { + GTP_ERROR("Send config error."); + } + //GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + //ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type); + GTP_INFO("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x(%s).", + ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type, ts->int_trigger_type?"Falling":"Rising"); + + msleep(10); + return 0; +} + +/******************************************************* +Function: + Read chip version. +Input: + client: i2c device + version: buffer to keep ic firmware version +Output: + read operation return. + 2: succeed, otherwise: failed +*******************************************************/ +s32 gtp_read_version(struct i2c_client *client, u16* version) +{ + s32 ret = -1; + u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + GTP_DEBUG_FUNC(); + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) + { + GTP_ERROR("GTP read version failed"); + return ret; + } + + if (version) + { + *version = (buf[7] << 8) | buf[6]; + } + + if (buf[5] == 0x00) + { + GTP_INFO("IC Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]); + } + else + { + if (buf[5] == 'S' || buf[5] == 's') + { + chip_gt9xxs = 1; + } + GTP_INFO("IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + return ret; +} + +/******************************************************* +Function: + I2c test Function. +Input: + client:i2c client. +Output: + Executive outcomes. + 2: succeed, otherwise failed. +*******************************************************/ +static s8 gtp_i2c_test(struct i2c_client *client) +{ + u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + u8 retry = 0; + s8 ret = -1; + + GTP_DEBUG_FUNC(); + + while(retry++ < 5) + { + ret = gtp_i2c_read(client, test, 3); + if (ret > 0) + { + return ret; + } + GTP_ERROR("GTP i2c test failed time %d.",retry); + msleep(10); + } + return ret; +} + +/******************************************************* +Function: + Request gpio(INT & RST) ports. +Input: + ts: private data. +Output: + Executive outcomes. + >= 0: succeed, < 0: failed +*******************************************************/ +static s8 gtp_request_io_port(struct goodix_ts_data *ts) +{ + s32 ret = 0; + + ret = GTP_GPIO_REQUEST(ts->irq_gpio, "GTP_INT_IRQ"); + if (ret < 0) + { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32)ts->irq_gpio, ret); + ret = -ENODEV; + } + else + { + GTP_GPIO_AS_INPUT(ts->irq_gpio); + //GTP_GPIO_AS_INT(ts->irq_gpio); + //ts->client->irq = IRQ_GPIO; + } + + ret = GTP_GPIO_REQUEST(ts->rst_gpio, "GTP_RST_PORT"); + if (ret < 0) + { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)ts->rst_gpio,ret); + ret = -ENODEV; + } + + GTP_GPIO_AS_INPUT(ts->rst_gpio); + gtp_reset_guitar(ts->client, 20); + + + if(ret < 0) + { + GTP_GPIO_FREE(ts->rst_gpio); + GTP_GPIO_FREE(ts->irq_gpio); + } + + return ret; +} + +/******************************************************* +Function: + Request interrupt. +Input: + ts: private data. +Output: + Executive outcomes. + 0: succeed, -1: failed. +*******************************************************/ +static s8 gtp_request_irq(struct goodix_ts_data *ts) +{ + s32 ret = -1; + //const u8 irq_table[] = GTP_IRQ_TAB; + + GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type); + + ret = request_irq(ts->client->irq, + goodix_ts_irq_handler, + IRQF_SHARED, + ts->client->name, + ts); + if (ret) + { + GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret); + GTP_GPIO_AS_INPUT(ts->irq_gpio); + GTP_GPIO_FREE(ts->irq_gpio); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = goodix_ts_timer_handler; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + return -1; + } + else + { + gtp_irq_disable(ts); + ts->use_irq = 1; + return 0; + } +} + +/******************************************************* +Function: + Request input device Function. +Input: + ts:private data. +Output: + Executive outcomes. + 0: succeed, otherwise: failed. +*******************************************************/ +static s8 gtp_request_input_dev(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 phys[32]; +#if GTP_HAVE_TOUCH_KEY + u8 index = 0; +#endif + + GTP_DEBUG_FUNC(); + + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) + { + GTP_ERROR("Failed to allocate input device."); + return -ENOMEM; + } + + ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); +#if GTP_ICS_SLOT_REPORT + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + input_mt_init_slots(ts->input_dev, 10); // in case of "out of memory" +#else + //ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); +#endif + +#if GTP_HAVE_TOUCH_KEY + for (index = 0; index < GTP_MAX_KEY_NUM; index++) + { + input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]); + } +#endif + +#if GTP_SLIDE_WAKEUP + input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); +#endif + +#if GTP_WITH_PEN + // pen support + __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit); +#endif + +#if GTP_CHANGE_X2Y + GTP_SWAP(ts->abs_x_max, ts->abs_y_max); +#endif + + if (ts->swap) { + s32 temp; + temp = ts->abs_x_max; + ts->abs_x_max = ts->abs_y_max; + ts->abs_y_max = temp; + } + + if (ts->lcd_exchg) { + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_y_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_x_max, 0, 0); + } else { + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0); + } + //input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + //input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + sprintf(phys, "input/ts"); + ts->input_dev->name = goodix_ts_name; + ts->input_dev->phys = phys; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0xDEAD; + ts->input_dev->id.product = 0xBEEF; + ts->input_dev->id.version = 10427; + + ret = input_register_device(ts->input_dev); + if (ret) + { + GTP_ERROR("Register %s input device failed", ts->input_dev->name); + return -ENODEV; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = goodix_ts_early_suspend; + ts->early_suspend.resume = goodix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + return 0; +} + + +static int wmt_check_touch_env(struct goodix_ts_data *ts) +{ + int ret = 0; + int len = 127; + char retval[128] = {0},*p=NULL,*s=NULL; + int Enable=0; + int x,y; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + GTP_ERROR("Read wmt.io.touch Failed.\n"); + return -EIO; + } + + //check touch enable + p = retval; + sscanf(p,"%d:", &Enable); + if(Enable == 0){ + GTP_ERROR("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + //check touch IC name + p = strchr(p,':');p++; + if (strncmp(p, "gt9xx", strlen("gt9xx"))) { + GTP_ERROR("Can't find gt9xx!\n"); + return -ENODEV; + } + + //get firmware file name + s = strchr(p,':'); + //p = p + strlen(fw_name) + 1; + if (s > (p + strlen("gt9xx") + 1)) { + memset(ts->fw_name,0x00,sizeof(ts->fw_name)); + strncpy(ts->fw_name, p, (s-p)); + GTP_DEBUG("ts_fwname=%s\n", ts->fw_name); + } else + GTP_DEBUG("needn't firmware\n"); + + //get other needed args + p = s + 1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", + &ts->irq_gpio,&x,&y,&ts->rst_gpio, + &ts->swap,&ts->xdir,&ts->ydir, + &ts->max_touch_num, + &ts->i2c_addr); + if (ret != 9) + { + GTP_ERROR("Wrong format ts u-boot param(%d)!\n",ret); + return -ENODEV; + } + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + ts->lcd_exchg = 1; + } + + return 0; +} + +/******************************************************* +Function: + I2c probe. +Input: + client: i2c device struct. + id: device id. +Output: + Executive outcomes. + 0: succeed. +*******************************************************/ +static int goodix_ts_probe(struct platform_device *pdev) +{ + s32 ret = -1; + struct goodix_ts_data *ts; + u16 version_info; + + GTP_DEBUG_FUNC(); + + //do NOT remove these logs + GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION); + GTP_INFO("GTP Driver Built@%s, %s", __TIME__, __DATE__); + GTP_INFO("GTP I2C Address: 0x%02x", i2c_connect_client->addr); + + //i2c_connect_client = client; + + if (!i2c_check_functionality(i2c_connect_client->adapter, I2C_FUNC_I2C)) + { + GTP_ERROR("I2C check functionality failed."); + return -ENODEV; + } + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts == NULL) + { + GTP_ERROR("Alloc GFP_KERNEL memory failed."); + return -ENOMEM; + } + memset(ts, 0, sizeof(*ts)); + l_ts = ts; + + ret = wmt_check_touch_env(ts); + if (ret < 0) + { + GTP_ERROR("GTP get touch env failed."); + kfree(ts); + return ret; + } + + i2c_connect_client->addr = ts->i2c_addr; + INIT_WORK(&ts->work, goodix_ts_work_func); + ts->client = i2c_connect_client; + //spin_lock_init(&ts->irq_lock); // 2.6.39 later + // ts->irq_lock = SPIN_LOCK_UNLOCKED; // 2.6.39 & before + platform_set_drvdata(pdev, ts); + + ts->gtp_rawdiff_mode = 0; + + ret = gtp_request_io_port(ts); + if (ret < 0) + { + GTP_ERROR("GTP request IO port failed."); + kfree(ts); + return ret; + } + + ret = gtp_i2c_test(ts->client); + if (ret < 0) + { + GTP_ERROR("I2C communication ERROR!"); + } + +#if GTP_AUTO_UPDATE + ret = gup_init_update_proc(ts); + if (ret < 0) + { + GTP_ERROR("Create update thread error."); + } +#endif + + ret = gtp_init_panel(ts); + if (ret < 0) + { + GTP_ERROR("GTP init panel failed."); + ts->abs_x_max = GTP_MAX_WIDTH; + ts->abs_y_max = GTP_MAX_HEIGHT; + ts->int_trigger_type = GTP_INT_TRIGGER; + } + + ret = gtp_request_input_dev(ts); + if (ret < 0) + { + GTP_ERROR("GTP request input dev failed"); + } + GTP_GPIO_AS_INT(ts->irq_gpio,IRQ_TYPE_EDGE_FALLING); + ts->client->irq = IRQ_GPIO; + ret = gtp_request_irq(ts); + if (ret < 0) + { + GTP_INFO("GTP works in polling mode."); + } + else + { + GTP_INFO("GTP works in interrupt mode."); + } + + ret = gtp_read_version(ts->client, &version_info); + if (ret < 0) + { + GTP_ERROR("Read version failed."); + } + if (ts->use_irq) + { + gtp_irq_enable(ts); + } + +#if GTP_CREATE_WR_NODE + init_wr_node(ts->client); +#endif + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts, SWITCH_ON); +#endif + return 0; +} + + +/******************************************************* +Function: + Goodix touchscreen driver release function. +Input: + client: i2c device struct. +Output: + Executive outcomes. 0---succeed. +*******************************************************/ +static int goodix_ts_remove(struct platform_device *pdev) +{ + struct goodix_ts_data *ts = platform_get_drvdata(pdev); + + GTP_DEBUG_FUNC(); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts->early_suspend); +#endif + +#if GTP_CREATE_WR_NODE + uninit_wr_node(); +#endif + +#if GTP_ESD_PROTECT + destroy_workqueue(gtp_esd_check_workqueue); +#endif + + if (ts) + { + if (ts->use_irq) + { + GTP_GPIO_AS_INPUT(ts->irq_gpio); + GTP_GPIO_FREE(ts->irq_gpio); + free_irq(ts->client->irq, ts); + } + else + { + hrtimer_cancel(&ts->timer); + } + } + + GTP_GPIO_FREE(ts->rst_gpio); + GTP_INFO("GTP driver removing..."); + input_unregister_device(ts->input_dev); + kfree(ts); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +/******************************************************* +Function: + Early suspend function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static void goodix_ts_early_suspend(struct early_suspend *h) +{ + struct goodix_ts_data *ts; + s8 ret = -1; + ts = container_of(h, struct goodix_ts_data, early_suspend); + + GTP_DEBUG_FUNC(); + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 1; + gtp_esd_switch(ts, SWITCH_OFF); +#endif + +#if GTP_SLIDE_WAKEUP + ret = gtp_enter_doze(ts); +#else + if (ts->use_irq) + { + gtp_irq_disable(ts); + } + else + { + hrtimer_cancel(&ts->timer); + } + ret = gtp_enter_sleep(ts); +#endif + if (ret < 0) + { + GTP_ERROR("GTP early suspend failed."); + } + // to avoid waking up while not sleeping + // delay 48 + 10ms to ensure reliability + msleep(58); +} + +/******************************************************* +Function: + Late resume function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static void goodix_ts_late_resume(struct early_suspend *h) +{ + struct goodix_ts_data *ts; + s8 ret = -1; + ts = container_of(h, struct goodix_ts_data, early_suspend); + + GTP_DEBUG_FUNC(); + + ret = gtp_wakeup_sleep(ts); + +#if GTP_SLIDE_WAKEUP + doze_status = DOZE_DISABLED; +#endif + + if (ret < 0) + { + GTP_ERROR("GTP later resume failed."); + } + + if (ts->use_irq) + { + gtp_irq_enable(ts); + } + else + { + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 0; + gtp_esd_switch(ts, SWITCH_ON); +#endif +} +#endif + +#if 1 +/******************************************************* +Function: + Suspend function. +Input: + client: i2c_client struct. + mesg: pm_message_t struct. +Output: + None. +*******************************************************/ +static int goodix_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct goodix_ts_data *ts; + ts = dev_get_drvdata(&pdev->dev); + + GTP_DEBUG_FUNC(); + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 1; + gtp_esd_switch(ts, SWITCH_OFF); +#endif + +#if GTP_SLIDE_WAKEUP + ret = gtp_enter_doze(ts); +#else + if (ts->use_irq) + { + gtp_irq_disable(ts); + } + else + { + hrtimer_cancel(&ts->timer); + } +#endif + // to avoid waking up while not sleeping + // delay 48 + 10ms to ensure reliability + l_suspend = 1; + return 0; +} + + +/******************************************************* +Function: + Late resume function. +Input: + client: i2c_client struct. +Output: + None. +*******************************************************/ +static int goodix_ts_resume(struct platform_device *pdev) +{ + struct goodix_ts_data *ts; + s8 ret = -1; + ts = dev_get_drvdata(&pdev->dev); + + GTP_DEBUG_FUNC(); + + GTP_GPIO_AS_INPUT(ts->irq_gpio); + GTP_GPIO_AS_INPUT(ts->rst_gpio); + gtp_reset_guitar(ts->client, 20); + + ret = gtp_i2c_test(ts->client); + if (ret < 0) + { + GTP_ERROR("I2C communication ERROR!"); + } + +#if GTP_SLIDE_WAKEUP + doze_status = DOZE_DISABLED; +#endif + + if (ts->use_irq) + { + GTP_GPIO_AS_INT(ts->irq_gpio,IRQ_TYPE_EDGE_FALLING); + gtp_irq_enable(ts); + } + else + { + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + +#if GTP_ESD_PROTECT + ts->gtp_is_suspend = 0; + gtp_esd_switch(ts, SWITCH_ON); +#endif + l_suspend = 0; + return 0; +} +#endif + +#if GTP_ESD_PROTECT +/******************************************************* +Function: + switch on & off esd delayed work +Input: + client: i2c device + on: SWITCH_ON / SWITCH_OFF +Output: + void +*********************************************************/ +void gtp_esd_switch(struct goodix_ts_data * ts, s32 on) +{ + + if (SWITCH_ON == on) // switch on esd + { + if (!ts->esd_running) + { + ts->esd_running = 1; + GTP_INFO("Esd started"); + queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); + } + } + else // switch off esd + { + if (ts->esd_running) + { + ts->esd_running = 0; + GTP_INFO("Esd cancelled"); + cancel_delayed_work_sync(>p_esd_check_work); + } + } +} + +/******************************************************* +Function: + Initialize external watchdog for esd protect +Input: + client: i2c device. +Output: + result of i2c write operation. + 1: succeed, otherwise: failed +*********************************************************/ +static s32 gtp_init_ext_watchdog(struct i2c_client *client) +{ + u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA}; + + struct i2c_msg msg; // in case of recursively reset by calling gtp_i2c_write + s32 ret = -1; + s32 retries = 0; + + GTP_DEBUG("Init external watchdog..."); + GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = 4; + msg.buf = opr_buffer; + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + { + return 1; + } + retries++; + } + if (retries >= 5) + { + GTP_ERROR("init external watchdog failed!"); + } + return 0; +} + +/******************************************************* +Function: + Esd protect function. + Added external watchdog by meta, 2013/03/07 +Input: + work: delayed work +Output: + None. +*******************************************************/ +static void gtp_esd_check_func(struct work_struct *work) +{ + s32 i; + s32 ret = -1; + struct goodix_ts_data *ts = NULL; + u8 test[4] = {0x80, 0x40}; + + GTP_DEBUG_FUNC(); + + ts = container_of(work, struct goodix_ts_data, work); + + if (ts->gtp_is_suspend) + { + ts->esd_running = 0; + GTP_INFO("Esd terminated!"); + return; + } + + for (i = 0; i < 3; i++) + { + ret = gtp_i2c_read(ts->client, test, 4); + + GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]); + if ((ret < 0)) + { + // IIC communication problem + continue; + } + else + { + if ((test[2] == 0xAA) || (test[3] != 0xAA)) + { + // IC works abnormally.. + i = 3; + break; + } + else + { + // IC works normally, Write 0x8040 0xAA, feed the dog + test[2] = 0xAA; + gtp_i2c_write(ts->client, test, 3); + break; + } + } + } + if (i >= 3) + { + GTP_ERROR("IC Working ABNORMALLY, Resetting Guitar..."); + gtp_reset_guitar(ts->client, 50); + } + + if(!ts->gtp_is_suspend) + { + queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); + } + else + { + GTP_INFO("Esd terminated!"); + ts->esd_running = 0; + } + return; +} +#endif + +static void gt9xx_release(struct device *device) +{ + return; +} + + +static struct platform_device gt9xx_device = { + .name = GTP_I2C_NAME, + .id = 0, + .dev = {.release = gt9xx_release}, +}; + +static struct platform_driver gt9xx_driver = { + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, + }, + .probe = goodix_ts_probe, + .remove = goodix_ts_remove, + .suspend = goodix_ts_suspend, + .resume = goodix_ts_resume, +}; + + +struct i2c_board_info ts_i2c_board_info = { + .type = GTP_I2C_NAME, + .flags = 0x00, + .addr = GTP_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(0x01);/*in bus 1*/ + if (NULL == adapter) { + GTP_ERROR("can not get i2c adapter, client address error."); + return -1; + } + i2c_connect_client = i2c_new_device(adapter, ts_i2c_bi); + if (i2c_connect_client == NULL) { + GTP_ERROR("allocate i2c client failed."); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (i2c_connect_client != NULL) + { + i2c_unregister_device(i2c_connect_client); + i2c_connect_client = NULL; + } +} + +/******************************************************* +Function: + Driver Install function. +Input: + None. +Output: + Executive Outcomes. 0---succeed. +********************************************************/ +static int __devinit goodix_ts_init(void) +{ + s32 ret; + + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver installing..."); + goodix_wq = create_singlethread_workqueue("goodix_wq"); + if (!goodix_wq) + { + GTP_ERROR("Creat workqueue failed."); + return -ENOMEM; + } +#if GTP_ESD_PROTECT + INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func); + gtp_esd_check_workqueue = create_workqueue("gtp_esd_check"); +#endif + if (ts_i2c_register_device()<0) + { + destroy_workqueue(goodix_wq); + GTP_ERROR("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ret = platform_device_register(>9xx_device); + if(ret){ + GTP_ERROR("register platform drivver failed!\n"); + goto err_register_platdev; + } + + ret = platform_driver_register(>9xx_driver); + if(ret){ + GTP_ERROR("register platform device failed!\n"); + goto err_register_platdriver; + } + return 0; +err_register_platdriver: + platform_device_unregister(>9xx_device); +err_register_platdev: + destroy_workqueue(goodix_wq); + ts_i2c_unregister_device(); + + return ret; +} + +/******************************************************* +Function: + Driver uninstall function. +Input: + None. +Output: + Executive Outcomes. 0---succeed. +********************************************************/ +static void __exit goodix_ts_exit(void) +{ + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver exited."); + ts_i2c_unregister_device(); + platform_driver_unregister(>9xx_driver); + platform_device_unregister(>9xx_device); + if (goodix_wq) + { + destroy_workqueue(goodix_wq); + } +} + +late_initcall(goodix_ts_init); +module_exit(goodix_ts_exit); + +MODULE_DESCRIPTION("GTP Series Driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h new file mode 100755 index 00000000..c58b4800 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx.h @@ -0,0 +1,278 @@ +/* drivers/input/touchscreen/gt9xx.h + * + * 2010 - 2013 Goodix Technology. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef _GOODIX_GT9XX_H_ +#define _GOODIX_GT9XX_H_ + +#include <linux/kernel.h> +#include <linux/hrtimer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/proc_fs.h> +#include <linux/string.h> +#include <asm/uaccess.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <mach/gpio.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <linux/platform_device.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif + +struct goodix_ts_data { + //spinlock_t irq_lock; + struct i2c_client *client; + struct input_dev *input_dev; + struct hrtimer timer; + struct work_struct work; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + char fw_name[20]; + s32 i2c_addr; + s32 irq_is_disable; + s32 use_irq; + s32 irq_gpio; + s32 rst_gpio; + s32 abs_x_max; + s32 abs_y_max; + s32 max_touch_num; + u8 int_trigger_type; + s32 swap; + s32 xdir; + s32 ydir; + s32 lcd_exchg; + u8 green_wake_mode; + u8 chip_type; + u8 enter_update; + u8 gtp_is_suspend; + u8 gtp_rawdiff_mode; + u8 gtp_cfg_len; + u8 fixed_cfg; + u8 esd_running; + u8 fw_error; +}; + +extern u16 show_len; +extern u16 total_len; +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +//***************************PART1:ON/OFF define******************************* +#define GTP_CUSTOM_CFG 0 +#define GTP_CHANGE_X2Y 0 +#define GTP_DRIVER_SEND_CFG 1 +#define GTP_HAVE_TOUCH_KEY 0 +#define GTP_POWER_CTRL_SLEEP 0 +#define GTP_ICS_SLOT_REPORT 0 + +#define GTP_AUTO_UPDATE 1 // auto updated by .bin file as default +#define GTP_HEADER_FW_UPDATE 0 // auto updated by head_fw_array in gt9xx_firmware.h, function together with GTP_AUTO_UPDATE + +#define GTP_CREATE_WR_NODE 1 +#define GTP_ESD_PROTECT 0 +#define GTP_WITH_PEN 0 + +#define GTP_SLIDE_WAKEUP 0 +#define GTP_DBL_CLK_WAKEUP 0 // double-click wakeup, function together with GTP_SLIDE_WAKEUP + +#define GTP_DEBUG_ON 0 +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +//*************************** PART2:TODO define ********************************** +// STEP_1(REQUIRED): Define Configuration Information Group(s) +// Sensor_ID Map: +/* sensor_opt1 sensor_opt2 Sensor_ID + GND GND 0 + VDDIO GND 1 + NC GND 2 + GND NC/300K 3 + VDDIO NC/300K 4 + NC NC/300K 5 +*/ +// TODO: define your own default or for Sensor_ID == 0 config here. +// The predefined one is just a sample config, which is not suitable for your tp in most cases. +#define CTP_CFG_GROUP1 {\ + 0x42,0x00,0x03,0x00,0x04,0x0A,0x34,0x00,0x01,0x3F,\ + 0x28,0x0F,0x50,0x3C,0x03,0x05,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x16,0x18,0x1C,0x14,0x8B,0x2A,0x0E,\ + 0x2D,0x3D,0x12,0x0C,0x00,0x00,0x00,0x01,0x03,0x1D,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x20,0x3D,0x94,0xC5,0x02,0x08,0x00,0x00,0x04,\ + 0x9A,0x22,0x00,0x8F,0x26,0x00,0x81,0x2C,0x00,0x77,\ + 0x32,0x00,0x6E,0x39,0x00,0x6E,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x0A,0x08,0x06,0x04,0x02,0x0C,0x0E,0x10,\ + 0x12,0x14,0x16,0x18,0x1A,0x1C,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0F,\ + 0x10,0x12,0x13,0x16,0x18,0x1C,0x1D,0x1E,0x1F,0x20,\ + 0x21,0x22,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x9D,0x01\ + } + +/* +#define CTP_CFG_GROUP1 {\ + 0x00,0x00,0x03,0x00,0x04,0x0A,0x35,0x00,0x01,0x08,\ + 0x14,0x05,0x37,0x28,0x03,0x05,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x16,0x18,0x1A,0x14,0x8B,0x2A,0x0E,\ + 0x63,0x5E,0x31,0x0D,0x00,0x00,0x02,0xB9,0x02,0x2D,\ + 0x00,0x00,0x00,0x00,0x00,0x03,0x64,0x32,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x0A,0x08,0x06,0x04,0x02,0x0C,0x0E,0x10,\ + 0x12,0x14,0x16,0x18,0x1A,0x1C,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0F,\ + 0x10,0x12,0x13,0x16,0x18,0x1C,0x1D,0x1E,0x1F,0x20,\ + 0x21,0x22,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0x4A,0x01\ + } +*/ + +// TODO: define your config for Sensor_ID == 1 here, if needed +#define CTP_CFG_GROUP2 {\ + } +// TODO: define your config for Sensor_ID == 2 here, if needed +#define CTP_CFG_GROUP3 {\ + } + +// TODO: define your config for Sensor_ID == 3 here, if needed +#define CTP_CFG_GROUP4 {\ + } + +// TODO: define your config for Sensor_ID == 4 here, if needed +#define CTP_CFG_GROUP5 {\ + } + +// TODO: define your config for Sensor_ID == 5 here, if needed +#define CTP_CFG_GROUP6 {\ + } + +// STEP_2(REQUIRED): Customize your I/O ports & I/O operations +#define GTP_RST_PORT S5PV210_GPJ3(6) +#define GTP_INT_PORT S5PV210_GPH1(3) +#define GTP_INT_IRQ gpio_to_irq(GTP_INT_PORT) +#define GTP_INT_CFG S3C_GPIO_SFN(0xF) + +#define GTP_GPIO_AS_INPUT(pin) do{\ + gpio_direction_input(pin);\ + wmt_gpio_setpull(pin, WMT_GPIO_PULL_NONE);\ + }while(0) +#define GTP_GPIO_AS_INT(pin,type) do{\ + GTP_GPIO_AS_INPUT(pin);\ + wmt_gpio_set_irq_type(pin,type);\ + }while(0) +#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) +#define GTP_GPIO_OUTPUT(pin,level) gpio_direction_output(pin,level) +#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) +#define GTP_GPIO_FREE(pin) gpio_free(pin) +#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH} + +// STEP_3(optional): Specify your special config info if needed +#if GTP_CUSTOM_CFG + #define GTP_MAX_HEIGHT 800 + #define GTP_MAX_WIDTH 480 + #define GTP_INT_TRIGGER 0 // 0: Rising 1: Falling +#else + #define GTP_MAX_HEIGHT 4096 + #define GTP_MAX_WIDTH 4096 + #define GTP_INT_TRIGGER 1 +#endif +#define GTP_MAX_TOUCH 5 +#define GTP_ESD_CHECK_CIRCLE 2000 // jiffy: ms + +// STEP_4(optional): If keys are available and reported as keys, config your key info here +#if GTP_HAVE_TOUCH_KEY + #define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK} +#endif + +//***************************PART3:OTHER define********************************* +#define GTP_DRIVER_VERSION "V1.8<2013/06/08>" +#define GTP_I2C_NAME "Goodix-TS" +#define GTP_I2C_ADDR 0x5d +#define GTP_POLL_TIME 10 // jiffy: ms +#define GTP_ADDR_LENGTH 2 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 240 +#define FAIL 0 +#define SUCCESS 1 +#define SWITCH_OFF 0 +#define SWITCH_ON 1 + +// Registers define +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_SLEEP 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) +// Log define +#define GTP_INFO(fmt,arg...) printk("<<-GTP-INFO->> "fmt"\n",##arg) +#define GTP_ERROR(fmt,arg...) printk("<<-GTP-ERROR->> "fmt"\n",##arg) +#define GTP_DEBUG(fmt,arg...) do{\ + if(GTP_DEBUG_ON)\ + printk("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\ + }while(0) +#define GTP_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if(GTP_DEBUG_ARRAY_ON)\ + {\ + printk("<<-GTP-DEBUG-ARRAY->>\n");\ + for (i = 0; i < (num); i++)\ + {\ + printk("%02x ", (a)[i]);\ + if ((i + 1 ) %10 == 0)\ + {\ + printk("\n");\ + }\ + }\ + printk("\n");\ + }\ + }while(0) +#define GTP_DEBUG_FUNC() do{\ + if(GTP_DEBUG_FUNC_ON)\ + printk("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\ + }while(0) +#define GTP_SWAP(x, y) do{\ + typeof(x) z = x;\ + x = y;\ + y = z;\ + }while (0) + +//*****************************End of Part III******************************** + +#endif /* _GOODIX_GT9XX_H_ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h new file mode 100755 index 00000000..3998bf00 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_firmware.h @@ -0,0 +1,6 @@ +// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
+// define your own firmware array here
+const unsigned char header_fw_array[] =
+{
+
+};
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c new file mode 100755 index 00000000..88daf209 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/gt9xx_ts/gt9xx_update.c @@ -0,0 +1,1939 @@ +/* drivers/input/touchscreen/gt9xx_update.c + * + * 2010 - 2012 Goodix Technology. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Latest Version:1.6 + * Author: andrew@goodix.com + * Revision Record: + * V1.0: + * first release. By Andrew, 2012/08/31 + * V1.2: + * add force update,GT9110P pid map. By Andrew, 2012/10/15 + * V1.4: + * 1. add config auto update function; + * 2. modify enter_update_mode; + * 3. add update file cal checksum. + * By Andrew, 2012/12/12 + * V1.6: + * 1. replace guitar_client with i2c_connect_client; + * 2. support firmware header array update. + * By Meta, 2013/03/11 + */ +#include <linux/kthread.h> +#include "gt9xx.h" + +#if GTP_HEADER_FW_UPDATE +#include <linux/namei.h> +#include <linux/mount.h> +#include "gt9xx_firmware.h" +#endif + +#define GUP_REG_HW_INFO 0x4220 +#define GUP_REG_FW_MSG 0x41E4 +#define GUP_REG_PID_VID 0x8140 + +#define GUP_SEARCH_FILE_TIMES 2 +#define UPDATE_FILE_PATH_2 "/system/etc/firmware/_goodix_update_.bin" +#define UPDATE_FILE_PATH_1 "/extsdcard/_goodix_update_.bin" + +#define CONFIG_FILE_PATH_1 "/extsdcard/_goodix_config_.cfg" +#define CONFIG_FILE_PATH_2 "/system/etc/firmware/_goodix_config_.cfg" + +#define FW_HEAD_LENGTH 14 +#define FW_SECTION_LENGTH 0x2000 +#define FW_DSP_ISP_LENGTH 0x1000 +#define FW_DSP_LENGTH 0x1000 +#define FW_BOOT_LENGTH 0x800 + +#define PACK_SIZE 256 +#define MAX_FRAME_CHECK_TIME 5 + +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 + +#define FAIL 0 +#define SUCCESS 1 + +#pragma pack(1) +typedef struct +{ + u8 hw_info[4]; //hardware info// + u8 pid[8]; //product id // + u16 vid; //version id // +}st_fw_head; +#pragma pack() + +typedef struct +{ + u8 force_update; + u8 fw_flag; + struct file *file; + struct file *cfg_file; + st_fw_head ic_fw_msg; + mm_segment_t old_fs; +}st_update_msg; + +st_update_msg update_msg; +u16 show_len; +u16 total_len; +u8 got_file_flag = 0; +u8 searching_file = 0; +extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]; +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern s32 gtp_send_cfg(struct goodix_ts_data * ts); +extern struct i2c_client * i2c_connect_client; +extern struct goodix_ts_data *l_ts; +extern void gtp_irq_enable(struct goodix_ts_data *ts); +extern void gtp_irq_disable(struct goodix_ts_data *ts); +extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int); +#if GTP_ESD_PROTECT +extern void gtp_esd_switch(struct i2c_client *, s32); +#endif +/******************************************************* +Function: + Read data from the i2c slave device. +Input: + client: i2c device. + buf[0~1]: read start address. + buf[2~len-1]: read data buffer. + len: GTP_ADDR_LENGTH + read bytes count +Output: + numbers of i2c_msgs to transfer: + 2: succeed, otherwise: failed +*********************************************************/ +s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len) +{ + struct i2c_msg msgs[2]; + s32 ret=-1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + msgs[0].flags = !I2C_M_RD; + msgs[0].addr = client->addr; + msgs[0].len = GTP_ADDR_LENGTH; + msgs[0].buf = &buf[0]; + //msgs[0].scl_rate = 300 * 1000; // for Rockchip + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = client->addr; + msgs[1].len = len - GTP_ADDR_LENGTH; + msgs[1].buf = &buf[GTP_ADDR_LENGTH]; + //msgs[1].scl_rate = 300 * 1000; + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + return ret; +} + +/******************************************************* +Function: + Write data to the i2c slave device. +Input: + client: i2c device. + buf[0~1]: write start address. + buf[2~len-1]: data buffer + len: GTP_ADDR_LENGTH + write bytes count +Output: + numbers of i2c_msgs to transfer: + 1: succeed, otherwise: failed +*********************************************************/ +s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len) +{ + struct i2c_msg msg; + s32 ret=-1; + s32 retries = 0; + + GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = len; + msg.buf = buf; + //msg.scl_rate = 300 * 1000; // for Rockchip + + while(retries < 5) + { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1)break; + retries++; + } + + return ret; +} + +static s32 gup_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = 0; + s32 i = 0; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + + u8 cfg_info_group1[] = CTP_CFG_GROUP1; + u8 cfg_info_group2[] = CTP_CFG_GROUP2; + u8 cfg_info_group3[] = CTP_CFG_GROUP3; + u8 cfg_info_group4[] = CTP_CFG_GROUP4; + u8 cfg_info_group5[] = CTP_CFG_GROUP5; + u8 cfg_info_group6[] = CTP_CFG_GROUP6; + u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3, + cfg_info_group4, cfg_info_group5, cfg_info_group6}; + u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1), + CFG_GROUP_LEN(cfg_info_group2), + CFG_GROUP_LEN(cfg_info_group3), + CFG_GROUP_LEN(cfg_info_group4), + CFG_GROUP_LEN(cfg_info_group5), + CFG_GROUP_LEN(cfg_info_group6)}; + + if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && + (!cfg_info_len[3]) && (!cfg_info_len[4]) && + (!cfg_info_len[5])) + { + sensor_id = 0; + } + else + { + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1); + if (SUCCESS == ret) + { + if (sensor_id >= 0x06) + { + GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id); + return -1; + } + } + else + { + GTP_ERROR("Failed to get sensor_id, No config sent!"); + return -1; + } + } + + GTP_DEBUG("Sensor_ID: %d", sensor_id); + + ts->gtp_cfg_len = cfg_info_len[sensor_id]; + + if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) + { + GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id); + return -1; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1); + + if (ret == SUCCESS) + { + GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1, + send_cfg_buf[sensor_id][0], opr_buf[0]); + + send_cfg_buf[sensor_id][0] = opr_buf[0]; + ts->fixed_cfg = 0; + /* + if (opr_buf[0] < 90) + { + grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version + send_cfg_buf[sensor_id][0] = 0x00; + ts->fixed_cfg = 0; + } + else // treated as fixed config, not send config + { + GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]); + ts->fixed_cfg = 1; + }*/ + } + else + { + GTP_ERROR("Failed to get ic config version!No config sent!"); + return -1; + } + + memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len); + + GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type); + + config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; + config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); + config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; + config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); + + if (GTP_INT_TRIGGER == 0) //RISING + { + config[TRIGGER_LOC] &= 0xfe; + } + else if (GTP_INT_TRIGGER == 1) //FALLING + { + config[TRIGGER_LOC] |= 0x01; + } + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) + { + check_sum += config[i]; + } + config[ts->gtp_cfg_len] = (~check_sum) + 1; + + GTP_DEBUG_FUNC(); + ret = gtp_send_cfg(ts); + if (ret < 0) + { + GTP_ERROR("Send config error."); + } + + msleep(10); + return 0; +} + + +static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len) +{ + s32 i = 0; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + + for (i = 0; i < 5; i++) + { + if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) + { + break; + } + } + + if (i >= 5) + { + GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) +{ + s32 i = 0; + u8 msg[3]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = val; + + for (i = 0; i < 5; i++) + { + if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) + { + break; + } + } + + if (i >= 5) + { + GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_get_ic_fw_msg(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 buf[16]; + u8 i; + + // step1:get hardware info + ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4); + if (FAIL == ret) + { + GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit"); + return FAIL; + } + + // buf[2~5]: 00 06 90 00 + // hw_info: 00 90 06 00 + for(i=0; i<4; i++) + { + update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; + } + GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]); + // step2:get firmware message + for(retry=0; retry<2; retry++) + { + ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); + if(FAIL == ret) + { + GTP_ERROR("Read firmware message fail."); + return ret; + } + + update_msg.force_update = buf[GTP_ADDR_LENGTH]; + if((0xBE != update_msg.force_update)&&(!retry)) + { + GTP_INFO("The check sum in ic is error."); + GTP_INFO("The IC will be updated by force."); + continue; + } + break; + } + GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update); + + // step3:get pid & vid + ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6); + if (FAIL == ret) + { + GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit"); + return FAIL; + } + + memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); + memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); + GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid); + + //GT9XX PID MAPPING + /*|-----FLASH-----RAM-----| + |------918------918-----| + |------968------968-----| + |------913------913-----| + |------913P-----913P----| + |------927------927-----| + |------927P-----927P----| + |------9110-----9110----| + |------9110P----9111----|*/ + if(update_msg.ic_fw_msg.pid[0] != 0) + { + if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) + { + GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid); + memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); + } + } + + update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8); + GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid); + + return SUCCESS; +} + +s32 gup_enter_update_mode(struct goodix_ts_data *ts) +{ + s32 ret = -1; + s32 retry = 0; + u8 rd_buf[3]; + + //step1:RST output low last at least 2ms + GTP_GPIO_OUTPUT(ts->rst_gpio, 0); + msleep(2); + + //step2:select I2C slave addr,INT:0--0xBA;1--0x28. + GTP_GPIO_OUTPUT(ts->irq_gpio, (ts->client->addr == 0x14)); + msleep(2); + + //step3:RST output high reset guitar + GTP_GPIO_OUTPUT(ts->rst_gpio, 1); + + //20121211 modify start + msleep(5); + while(retry++ < 200) + { + //step4:Hold ss51 & dsp + ret = gup_set_ic_msg(ts->client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + + //step5:Confirm hold + ret = gup_get_ic_msg(ts->client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); + if(ret <= 0) + { + GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + if(0x0C == rd_buf[GTP_ADDR_LENGTH]) + { + GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS"); + break; + } + GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]); + } + if(retry >= 200) + { + GTP_ERROR("Enter update Hold ss51 failed."); + return FAIL; + } + + //step6:DSP_CK and DSP_ALU_CK PowerOn + ret = gup_set_ic_msg(ts->client, 0x4010, 0x00); + + //20121211 modify end + return ret; +} + +void gup_leave_update_mode(struct goodix_ts_data *ts) +{ + //GTP_GPIO_AS_INT(ts->irq_gpio,IRQ_TYPE_EDGE_FALLING); + + GTP_DEBUG("[leave_update_mode]reset chip."); + gtp_reset_guitar(i2c_connect_client, 20); +} + +// Get the correct nvram data +// The correct conditions: +// 1. the hardware info is the same +// 2. the product id is the same +// 3. the firmware version in update file is greater than the firmware version in ic +// or the check sum in ic is wrong +/* Update Conditions: + 1. Same hardware info + 2. Same PID + 3. File PID > IC PID + Force Update Conditions: + 1. Wrong ic firmware checksum + 2. INVALID IC PID or VID + 3. IC PID == 91XX || File PID == 91XX +*/ + +static u8 gup_enter_update_judge(st_fw_head *fw_head) +{ + u16 u16_tmp; + s32 i = 0; + + u16_tmp = fw_head->vid; + fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); + + GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]); + GTP_DEBUG("FILE PID:%s", fw_head->pid); + GTP_DEBUG("FILE VID:%04x", fw_head->vid); + + GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]); + GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid); + GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid); + + //First two conditions + if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info))) + { + GTP_DEBUG("Get the same hardware info."); + if( update_msg.force_update != 0xBE ) + { + GTP_INFO("FW chksum error,need enter update."); + return SUCCESS; + } + + // 20130523 start + if (strlen(update_msg.ic_fw_msg.pid) < 3) + { + GTP_INFO("Illegal IC pid, need enter update"); + return SUCCESS; + } + else + { + for (i = 0; i < 3; i++) + { + if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39)) + { + GTP_INFO("Illegal IC pid, out of bound, need enter update"); + return SUCCESS; + } + } + } + // 20130523 end + + + if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))|| + (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))|| + (!memcmp(fw_head->pid, "91XX", 4))) + { + if(!memcmp(fw_head->pid, "91XX", 4)) + { + GTP_DEBUG("Force none same pid update mode."); + } + else + { + GTP_DEBUG("Get the same pid."); + } + //The third condition + if (fw_head->vid > update_msg.ic_fw_msg.vid) + { + + GTP_INFO("Need enter update."); + return SUCCESS; + } + GTP_ERROR("Don't meet the third condition."); + GTP_ERROR("File VID <= Ic VID, update aborted!"); + } + else + { + GTP_ERROR("File PID != Ic PID, update aborted!"); + } + } + else + { + GTP_ERROR("Different Hardware, update aborted!"); + } + return FAIL; +} + +static u8 ascii2hex(u8 a) +{ + s8 value = 0; + + if(a >= '0' && a <= '9') + { + value = a - '0'; + } + else if(a >= 'A' && a <= 'F') + { + value = a - 'A' + 0x0A; + } + else if(a >= 'a' && a <= 'f') + { + value = a - 'a' + 0x0A; + } + else + { + value = 0xff; + } + + return value; +} + +static s8 gup_update_config(struct i2c_client *client) +{ + s32 file_len = 0; + s32 ret = 0; + s32 i = 0; + s32 file_cfg_len = 0; + s32 chip_cfg_len = 0; + s32 count = 0; + u8 *buf; + u8 *pre_buf; + u8 *file_config; + //u8 checksum = 0; + u8 pid[8]; + + if(NULL == update_msg.cfg_file) + { + GTP_ERROR("[update_cfg]No need to upgrade config!"); + return FAIL; + } + file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END); + + ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6); + if(FAIL == ret) + { + GTP_ERROR("[update_cfg]Read product id & version id fail."); + return FAIL; + } + pid[5] = '\0'; + GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]); + + chip_cfg_len = 186; + if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) || + !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) || + !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) + { + chip_cfg_len = 228; + } + GTP_DEBUG("[update_cfg]config file len:%d", file_len); + GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len); + if((file_len+5) < chip_cfg_len*5) + { + GTP_ERROR("Config length error"); + return -1; + } + + buf = (u8*)kzalloc(file_len, GFP_KERNEL); + pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL); + file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL); + update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET); + + GTP_DEBUG("[update_cfg]Read config from file."); + ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos); + if(ret<0) + { + GTP_ERROR("[update_cfg]Read config file failed."); + goto update_cfg_file_failed; + } + + GTP_DEBUG("[update_cfg]Delete illgal charactor."); + for(i=0,count=0; i<file_len; i++) + { + if (pre_buf[i] == ' ' || pre_buf[i] == '\r' || pre_buf[i] == '\n') + { + continue; + } + buf[count++] = pre_buf[i]; + } + + GTP_DEBUG("[update_cfg]Ascii to hex."); + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i<count; i+=5) + { + if((buf[i]=='0') && ((buf[i+1]=='x') || (buf[i+1]=='X'))) + { + u8 high,low; + high = ascii2hex(buf[i+2]); + low = ascii2hex(buf[i+3]); + + if((high == 0xFF) || (low == 0xFF)) + { + ret = 0; + GTP_ERROR("[update_cfg]Illegal config file."); + goto update_cfg_file_failed; + } + file_config[file_cfg_len++] = (high<<4) + low; + } + else + { + ret = 0; + GTP_ERROR("[update_cfg]Illegal config file."); + goto update_cfg_file_failed; + } + } + +// //cal checksum +// for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++) +// { +// checksum += file_config[i]; +// } +// file_config[chip_cfg_len] = (~checksum) + 1; +// file_config[chip_cfg_len+1] = 0x01; + + GTP_DEBUG("config:"); + GTP_DEBUG_ARRAY(file_config+2, file_cfg_len); + + i = 0; + while(i++ < 5) + { + ret = gup_i2c_write(client, file_config, file_cfg_len); + if(ret > 0) + { + GTP_INFO("[update_cfg]Send config SUCCESS."); + break; + } + GTP_ERROR("[update_cfg]Send config i2c error."); + } + +update_cfg_file_failed: + kfree(pre_buf); + kfree(buf); + kfree(file_config); + return ret; +} + +#if GTP_HEADER_FW_UPDATE +static u8 gup_check_fs_mounted(char *path_name) +{ + struct path root_path; + struct path path; + int err; + err = kern_path("/", LOOKUP_FOLLOW, &root_path); + + if (err) + { + GTP_DEBUG("\"/\" NOT Mounted: %d", err); + return FAIL; + } + err = kern_path(path_name, LOOKUP_FOLLOW, &path); + + if (err) + { + GTP_DEBUG("/data/ NOT Mounted: %d", err); + return FAIL; + } + + return SUCCESS; + + /* + if (path.mnt->mnt_sb == root_path.mnt->mnt_sb) + { + //-- not mounted + return FAIL; + } + else + { + return SUCCESS; + }*/ + +} +#endif +static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path) +{ + s32 ret = 0; + s32 i = 0; + s32 fw_checksum = 0; + u8 buf[FW_HEAD_LENGTH]; + + char fwname[64] = {0}; + struct goodix_ts_data *ts = l_ts; + sprintf(fwname, "/system/etc/firmware/%s.bin", ts->fw_name); + GTP_INFO("firmware file name: %s.", fwname); + if (path) + { + GTP_DEBUG("Update File path:%s, %d", path, strlen(path)); + update_msg.file = filp_open(path, O_RDONLY, 0); + + if (IS_ERR(update_msg.file)) + { + GTP_ERROR("Open update file(%s) error!", path); + return FAIL; + } + } + else + { +#if GTP_HEADER_FW_UPDATE + for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) + { + GTP_DEBUG("Waiting for /data mounted [%d]", i); + + if (gup_check_fs_mounted("/data") == SUCCESS) + { + GTP_DEBUG("/data Mounted!"); + break; + } + msleep(3000); + } + if (i >= (GUP_SEARCH_FILE_TIMES)) + { + GTP_ERROR("Wait for /data mounted timeout!"); + return FAIL; + } + + // update config + update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0); + if (IS_ERR(update_msg.cfg_file)) + { + GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1); + } + else + { + GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1); + ret = gup_update_config(client); + if(ret <= 0) + { + GTP_ERROR("Update config failed."); + } + filp_close(update_msg.cfg_file, NULL); + } + + if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH)) + { + GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!"); + return FAIL; + } + update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666); + if ((IS_ERR(update_msg.file))) + { + GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2); + return FAIL; + } + update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET); + update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos); + filp_close(update_msg.file, NULL); + update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0); +#else + //u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2)); + u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(fwname)); + u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2)); + u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL); + u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL); + //Begin to search update file,the config file & firmware file must be in the same path,single or double. + searching_file = 1; + for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) + { + if (searching_file == 0) + { + kfree(search_update_path); + kfree(search_cfg_path); + GTP_INFO(".bin/.cfg update file search forcely terminated!"); + return FAIL; + } + if(i%2) + { + memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1)); + memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1)); + } + else + { + //memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2)); + memcpy(search_update_path, fwname, sizeof(fwname)); + memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2)); + } + + if(!(got_file_flag&0x0F)) + { + update_msg.file = filp_open(search_update_path, O_RDONLY, 0); + if(!IS_ERR(update_msg.file)) + { + GTP_DEBUG("Find the bin file"); + got_file_flag |= 0x0F; + } + } + if(!(got_file_flag&0xF0)) + { + update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0); + if(!IS_ERR(update_msg.cfg_file)) + { + GTP_DEBUG("Find the cfg file"); + got_file_flag |= 0xF0; + } + } + + if(got_file_flag) + { + if(got_file_flag == 0xFF) + { + break; + } + else + { + i += 4; + } + } + GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg"); + //msleep(3000); + } + searching_file = 0; + kfree(search_update_path); + kfree(search_cfg_path); + + if(!got_file_flag) + { + GTP_ERROR("Can't find update file."); + goto load_failed; + } + + if(got_file_flag&0xF0) + { + GTP_DEBUG("Got the update config file."); + ret = gup_update_config(client); + if(ret <= 0) + { + GTP_ERROR("Update config failed."); + } + filp_close(update_msg.cfg_file, NULL); + msleep(500); //waiting config to be stored in FLASH. + } + if(got_file_flag&0x0F) + { + GTP_DEBUG("Got the update firmware file."); + } + else + { + GTP_ERROR("No need to upgrade firmware."); + goto load_failed; + } +#endif + } + + update_msg.old_fs = get_fs(); + set_fs(KERNEL_DS); + + update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET); + //update_msg.file->f_pos = 0; + + ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos); + if (ret < 0) + { + GTP_ERROR("Read firmware head in update file error."); + goto load_failed; + } + memcpy(fw_head, buf, FW_HEAD_LENGTH); + + //check firmware legality + fw_checksum = 0; + for(i=0; i<FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH; i+=2) + { + u16 temp; + ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos); + if (ret < 0) + { + GTP_ERROR("Read firmware file error."); + goto load_failed; + } + //GTP_DEBUG("BUF[0]:%x", buf[0]); + temp = (buf[0]<<8) + buf[1]; + fw_checksum += temp; + } + + GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF); + if(fw_checksum&0xFFFF) + { + GTP_ERROR("Illegal firmware file."); + goto load_failed; + } + + return SUCCESS; + +load_failed: + set_fs(update_msg.old_fs); + return FAIL; +} + +#if 0 +static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head) +{ + const u8* pos; + int i = 0; + u8 mask_num = 0; + s32 ret = 0; + + pos = HEADER_UPDATE_DATA; + + memcpy(fw_head, pos, FW_HEAD_LENGTH); + pos += FW_HEAD_LENGTH; + + ret = gup_enter_update_judge(fw_head); + if(SUCCESS == ret) + { + return SUCCESS; + } + return FAIL; +} +#endif + +static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length) +{ + s32 ret = 0; + u16 burn_addr = start_addr; + u16 frame_length = 0; + u16 burn_length = 0; + u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 retry = 0; + + GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr); + while(burn_length < total_length) + { + GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length); + frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length); + wr_buf[0] = (u8)(burn_addr>>8); + rd_buf[0] = wr_buf[0]; + wr_buf[1] = (u8)burn_addr; + rd_buf[1] = wr_buf[1]; + memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length); + + for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) + { + ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length); + if(ret <= 0) + { + GTP_ERROR("Write frame data i2c error."); + continue; + } + ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length); + if(ret <= 0) + { + GTP_ERROR("Read back frame data i2c error."); + continue; + } + + if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length)) + { + GTP_ERROR("Check frame data fail,not equal."); + GTP_DEBUG("write array:"); + GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length); + GTP_DEBUG("read array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + continue; + } + else + { + //GTP_DEBUG("Check frame data success."); + break; + } + } + if(retry >= MAX_FRAME_CHECK_TIME) + { + GTP_ERROR("Burn frame data time out,exit."); + return FAIL; + } + burn_length += frame_length; + burn_addr += frame_length; + } + return SUCCESS; +} + +static u8 gup_load_section_file(u8* buf, u16 offset, u16 length) +{ + s32 ret = 0; + + if(update_msg.file == NULL) + { + GTP_ERROR("cannot find update file,load section file fail."); + return FAIL; + } + update_msg.file->f_pos = FW_HEAD_LENGTH + offset; + + ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos); + if(ret < 0) + { + GTP_ERROR("Read update file fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + s32 ret = 0; + u16 recall_addr = start_rd_addr; + u16 recall_length = 0; + u16 frame_length = 0; + + while(recall_length < chk_length) + { + frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length); + ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); + if(ret <= 0) + { + GTP_ERROR("recall i2c error,exit"); + return FAIL; + } + + if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length)) + { + GTP_ERROR("Recall frame data fail,not equal."); + GTP_DEBUG("chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length); + GTP_DEBUG("recall array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + return FAIL; + } + + recall_length += frame_length; + recall_addr += frame_length; + } + GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024)); + + return SUCCESS; +} + +static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd ) +{ + s32 ret = 0; + u8 rd_buf[5]; + + //step1:hold ss51 & dsp + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail."); + return FAIL; + } + + //step2:set scramble + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]set scramble fail."); + return FAIL; + } + + //step3:select bank + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F); + return FAIL; + } + + //step4:enable accessing code + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + //step5:burn 8k fw section + ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_section]burn fw_section fail."); + return FAIL; + } + + //step6:hold ss51 & release dsp + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail."); + return FAIL; + } + //must delay + msleep(1); + + //step7:send burn cmd to move data to flash from sram + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]send burn cmd fail."); + return FAIL; + } + GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......"); + do{ + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]Get burn state fail"); + return FAIL; + } + msleep(10); + //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + }while(rd_buf[GTP_ADDR_LENGTH]); + + //step8:select bank + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F); + return FAIL; + } + + //step9:enable accessing code + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + //step10:recall 8k fw section + ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_section]recall check 8k firmware fail."); + return FAIL; + } + + //step11:disable accessing code + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_section]disable accessing code fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_dsp_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8* fw_dsp_isp = NULL; + u8 retry = 0; + + GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>"); + + //step1:alloc memory + GTP_DEBUG("[burn_dsp_isp]step1:alloc memory"); + while(retry++ < 5) + { + fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL); + if(fw_dsp_isp == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load dsp isp file data + GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data"); + ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + //step3:disable wdt,clear cache enable + GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]disable wdt fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]clear cache enable fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step4:hold ss51 & dsp + GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step5:set boot from sram + GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]set boot from sram fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step6:software reboot + GTP_DEBUG("[burn_dsp_isp]step6:software reboot"); + ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]software reboot fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step7:select bank2 + GTP_DEBUG("[burn_dsp_isp]step7:select bank2"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]select bank2 fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step8:enable accessing code + GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]enable accessing code fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + //step9:burn 4k dsp_isp + GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp"); + ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + //step10:set scramble + GTP_DEBUG("[burn_dsp_isp]step10:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_dsp_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = SUCCESS; + +exit_burn_dsp_isp: + kfree(fw_dsp_isp); + return ret; +} + +static u8 gup_burn_fw_ss51(struct i2c_client *client) +{ + u8* fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>"); + + //step1:alloc memory + GTP_DEBUG("[burn_fw_ss51]step1:alloc memory"); + while(retry++ < 5) + { + fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if(fw_ss51 == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load ss51 firmware section 1 file data + GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data"); + ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + //step3:clear control flag + GTP_DEBUG("[burn_fw_ss51]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_ss51]clear control flag fail."); + ret = FAIL; + goto exit_burn_fw_ss51; + } + + //step4:burn ss51 firmware section 1 + GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + //step5:load ss51 firmware section 2 file data + GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data"); + ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + //step6:burn ss51 firmware section 2 + GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + //step7:load ss51 firmware section 3 file data + GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data"); + ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + //step8:burn ss51 firmware section 3 + GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + //step9:load ss51 firmware section 4 file data + GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data"); + ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + //step10:burn ss51 firmware section 4 + GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + ret = SUCCESS; + +exit_burn_fw_ss51: + kfree(fw_ss51); + return ret; +} + +static u8 gup_burn_fw_dsp(struct i2c_client *client) +{ + s32 ret = 0; + u8* fw_dsp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>"); + //step1:alloc memory + GTP_DEBUG("[burn_fw_dsp]step1:alloc memory"); + while(retry++ < 5) + { + fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL); + if(fw_dsp == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load firmware dsp + GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp"); + ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_dsp]load firmware dsp fail."); + goto exit_burn_fw_dsp; + } + + //step3:select bank3 + GTP_DEBUG("[burn_fw_dsp]step3:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + //step4:hold ss51 & dsp + GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + //step5:set scramble + GTP_DEBUG("[burn_fw_dsp]step5:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + //step6:release ss51 & dsp + GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211 + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + //must delay + msleep(1); + + //step7:burn 4k dsp firmware + GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware"); + ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_dsp]burn fw_section fail."); + goto exit_burn_fw_dsp; + } + + //step8:send burn cmd to move data to flash from sram + GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]send burn cmd fail."); + goto exit_burn_fw_dsp; + } + GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......"); + do{ + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_dsp]Get burn state fail"); + goto exit_burn_fw_dsp; + } + msleep(10); + //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + }while(rd_buf[GTP_ADDR_LENGTH]); + + //step9:recall check 4k dsp firmware + GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware"); + ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail."); + goto exit_burn_fw_dsp; + } + + ret = SUCCESS; + +exit_burn_fw_dsp: + kfree(fw_dsp); + return ret; +} + +static u8 gup_burn_fw_boot(struct i2c_client *client) +{ + s32 ret = 0; + u8* fw_boot = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>"); + + //step1:Alloc memory + GTP_DEBUG("[burn_fw_boot]step1:Alloc memory"); + while(retry++ < 5) + { + fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL); + if(fw_boot == NULL) + { + continue; + } + else + { + GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024)); + break; + } + } + if(retry >= 5) + { + GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit."); + return FAIL; + } + + //step2:load firmware bootloader + GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader"); + ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_boot]load firmware dsp fail."); + goto exit_burn_fw_boot; + } + + //step3:hold ss51 & dsp + GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step4:set scramble + GTP_DEBUG("[burn_fw_boot]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step5:release ss51 & dsp + GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211 + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + //must delay + msleep(1); + + //step6:select bank3 + GTP_DEBUG("[burn_fw_boot]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step7:burn 2k bootloader firmware + GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_boot]burn fw_section fail."); + goto exit_burn_fw_boot; + } + + //step7:send burn cmd to move data to flash from sram + GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]send burn cmd fail."); + goto exit_burn_fw_boot; + } + GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......"); + do{ + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]Get burn state fail"); + goto exit_burn_fw_boot; + } + msleep(10); + //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + }while(rd_buf[GTP_ADDR_LENGTH]); + + //step8:recall check 2k bootloader firmware + GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if(FAIL == ret) + { + GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail."); + goto exit_burn_fw_boot; + } + + //step9:enable download DSP code + GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code "); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]enable download DSP code fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + //step10:release ss51 & hold dsp + GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); + if(ret <= 0) + { + GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + ret = SUCCESS; + +exit_burn_fw_boot: + kfree(fw_boot); + return ret; +} + +s32 gup_update_proc(void *dir) +{ + s32 ret = 0; + u8 retry = 0; + st_fw_head fw_head; + struct goodix_ts_data *ts = NULL; + + GTP_DEBUG("[update_proc]Begin update ......"); + + show_len = 1; + total_len = 100; + if(dir == NULL) + { + //msleep(3000); //wait main thread to be completed + } + + ts = l_ts; + + if (searching_file) + { + searching_file = 0; // exit .bin update file searching + GTP_INFO("Exiting searching .bin update file..."); + while ((show_len != 200) && (show_len != 100)) // wait for auto update quitted completely + { + msleep(100); + } + } + + update_msg.file = NULL; + ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir); //20121211 + if(FAIL == ret) + { + GTP_ERROR("[update_proc]check update file fail."); + goto file_fail; + } + + //gtp_reset_guitar(i2c_connect_client, 20); + ret = gup_get_ic_fw_msg(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]get ic message fail."); + goto file_fail; + } + + ret = gup_enter_update_judge(&fw_head); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]Check *.bin file fail."); + goto file_fail; + } + + ts->enter_update = 1; + gtp_irq_disable(ts); +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_OFF); +#endif + ret = gup_enter_update_mode(ts); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]enter update mode fail."); + goto update_fail; + } + + while(retry++ < 5) + { + show_len = 10; + total_len = 100; + ret = gup_burn_dsp_isp(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn dsp isp fail."); + continue; + } + + show_len += 10; + ret = gup_burn_fw_ss51(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn ss51 firmware fail."); + continue; + } + + show_len += 40; + ret = gup_burn_fw_dsp(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn dsp firmware fail."); + continue; + } + + show_len += 20; + ret = gup_burn_fw_boot(i2c_connect_client); + if(FAIL == ret) + { + GTP_ERROR("[update_proc]burn bootloader firmware fail."); + continue; + } + show_len += 10; + GTP_INFO("[update_proc]UPDATE SUCCESS."); + break; + } + if(retry >= 5) + { + GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL."); + goto update_fail; + } + + GTP_DEBUG("[update_proc]leave update mode."); + gup_leave_update_mode(ts); + + msleep(100); +// GTP_DEBUG("[update_proc]send config."); +// ret = gtp_send_cfg(i2c_connect_client); +// if(ret < 0) +// { +// GTP_ERROR("[update_proc]send config fail."); +// } + if (ts->fw_error) + { + GTP_INFO("firmware error auto update, resent config!"); + gup_init_panel(ts); + } + show_len = 100; + total_len = 100; + ts->enter_update = 0; + gtp_irq_enable(ts); + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + filp_close(update_msg.file, NULL); + return SUCCESS; + +update_fail: + ts->enter_update = 0; + gtp_irq_enable(ts); + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + +file_fail: + if(update_msg.file && !IS_ERR(update_msg.file)) + { + filp_close(update_msg.file, NULL); + } + show_len = 200; + total_len = 100; + return FAIL; +} + +#if GTP_AUTO_UPDATE +u8 gup_init_update_proc(struct goodix_ts_data *ts) +{ + //struct task_struct *thread = NULL; + + GTP_INFO("Ready to run update thread."); + if(!gup_update_proc(NULL)) + GTP_ERROR("fail to update."); + /*thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update"); + if (IS_ERR(thread)) + { + GTP_ERROR("Failed to create update thread.\n"); + return -1; + }*/ + + return 0; +} +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig new file mode 100755 index 00000000..dbd6a729 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Kconfig @@ -0,0 +1,16 @@ +# +# ICN83XX capacity touch screen driver configuration +# +config TOUCHSCREEN_ICN83XX + tristate "ICN83XX I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_icn83xx + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile new file mode 100755 index 00000000..e1070854 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_icn83xx
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := icn83xx.o flash.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c new file mode 100755 index 00000000..595545d8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/flash.c @@ -0,0 +1,973 @@ +/*++
+
+ Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved.
+ This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd.
+ and may contains trade secrets and/or other confidential information of ChipOne
+ Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party,
+ in whole or in part, without prior written consent of ChipOne.
+ THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS,
+ WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR
+ IMPLIED WARRANTIES.
+
+ File Name: flash.c
+ Abstract:
+ flash operation, read write etc.
+ Author: Zhimin Tian
+ Date : 10 30,2012
+ Version: 0.1[.revision]
+ History :
+ Change logs.
+ --*/
+#include "icn83xx.h"
+
+struct file *fp;
+int g_status = R_OK;
+static char fw_mode = 0;
+static int fw_size = 0;
+static unsigned char *fw_buf;
+
+void icn83xx_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 icn83xx_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 icn83xx_checksum(int sum, char *buf, unsigned int size)
+{
+ int i;
+ for(i=0; i<size; i++)
+ {
+ sum = sum + buf[i];
+ }
+ return sum;
+}
+
+
+int icn83xx_update_status(int status)
+{
+// flash_info("icn83xx_update_status: %d\n", status);
+ g_status = status;
+ return 0;
+}
+
+int icn83xx_get_status(void)
+{
+ return g_status;
+}
+
+void icn83xx_set_fw(int size, unsigned char *buf)
+{
+ fw_size = size;
+ fw_buf = buf;
+
+}
+
+/***********************************************************************************************
+Name : icn83xx_writeInfo
+Input : addr, value
+Output :
+function : write Flash Info
+***********************************************************************************************/
+
+int icn83xx_writeInfo(unsigned short addr, char value)
+{
+ int ret = -1;
+ char temp_buf[3];
+
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(230, temp_buf, 2);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(2);
+ temp_buf[0] = value;
+ ret = icn83xx_i2c_txdata(232, temp_buf, 1);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(5);
+ return 0;
+}
+/***********************************************************************************************
+Name : icn83xx_readInfo
+Input :
+Output :
+function : read Flash info
+***********************************************************************************************/
+
+int icn83xx_readInfo(unsigned short addr, char *value)
+{
+ int ret = -1;
+ char temp_buf[3];
+
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(230, temp_buf, 2);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(2);
+ ret = icn83xx_i2c_rxdata(232, value, 1);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(2);
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_writeReg
+Input : addr, value
+Output :
+function : write MCU xdata and reg
+***********************************************************************************************/
+
+int icn83xx_writeReg(unsigned short addr, char value)
+{
+ int ret = -1;
+ char temp_buf[3];
+
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(224, temp_buf, 2);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(2);
+ temp_buf[0] = value;
+ ret = icn83xx_i2c_txdata(226, temp_buf, 1);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(5);
+ return 0;
+}
+/***********************************************************************************************
+Name : icn83xx_readReg
+Input :
+Output :
+function : read MCU xdata and reg
+***********************************************************************************************/
+
+int icn83xx_readReg(unsigned short addr, char *value)
+{
+ int ret = -1;
+ char temp_buf[3];
+
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(224, temp_buf, 2);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(2);
+
+ ret = icn83xx_i2c_rxdata(226, value, 1);
+ if (ret < 0) {
+ op_error("%s failed! ret: %d\n", __func__, ret);
+ return -1;
+ }
+ mdelay(2);
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_open_fw
+Input : *fw
+
+Output : file size
+function : open the fw file, and return total size
+***********************************************************************************************/
+int icn83xx_open_fw( char *fw)
+{
+ int file_size;
+ mm_segment_t fs;
+ struct inode *inode = NULL;
+ if(strcmp(fw, "icn83xx_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)) {
+ flash_error("read fw file error\n");
+ return -1;
+ }
+ else
+ flash_info("open fw file ok\n");
+
+ inode = fp->f_dentry->d_inode;
+ file_size = inode->i_size;
+ flash_info("file size: %d\n", file_size);
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ return file_size;
+
+}
+
+/***********************************************************************************************
+Name : icn83xx_read_fw
+Input : offset
+ length, read length
+ buf, return buffer
+Output :
+function : read data to buffer
+***********************************************************************************************/
+int icn83xx_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);
+ }
+// icn83xx_memdump(buf, length);
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_close_fw
+Input :
+Output :
+function : close file
+***********************************************************************************************/
+int icn83xx_close_fw(void)
+{
+ if(fw_mode == 0)
+ {
+ filp_close(fp, NULL);
+ }
+
+ return 0;
+}
+/***********************************************************************************************
+Name : icn83xx_readVersion
+Input : void
+Output :
+function : return version
+***********************************************************************************************/
+int icn83xx_readVersion(void)
+{
+ int err = 0;
+ char tmp[2];
+ short CurVersion;
+ err = icn83xx_i2c_rxdata(12, tmp, 2);
+ if (err < 0) {
+ calib_error("%s failed: %d\n", __func__, err);
+ return err;
+ }
+ CurVersion = (tmp[0]<<8) | tmp[1];
+ return CurVersion;
+}
+
+/***********************************************************************************************
+Name : icn83xx_changemode
+Input : normal/factory/config
+Output :
+function : change work mode
+***********************************************************************************************/
+int icn83xx_changemode(char mode)
+{
+ char value = 0x0;
+ icn83xx_write_reg(0, mode);
+ mdelay(1);
+ icn83xx_read_reg(1, &value);
+ while(value != 0)
+ {
+ mdelay(1);
+ icn83xx_read_reg(1, &value);
+ }
+// calib_info("icn83xx_changemode ok\n");
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_readrawdata
+Input : rownum and length
+Output :
+function : read one row rawdata
+***********************************************************************************************/
+
+int icn83xx_readrawdata(char *buffer, char row, char length)
+{
+ int err = 0;
+ int i;
+// calib_info("readrawdata: %d, length: %d\n", row, length);
+ icn83xx_write_reg(3, row);
+ mdelay(1);
+ err = icn83xx_i2c_rxdata(160, buffer, length);
+ if (err < 0) {
+ calib_error("%s failed: %d\n", __func__, err);
+ return err;
+ }
+
+ for(i=0; i<length; i=i+2)
+ {
+ swap_ab(buffer[i], buffer[i+1]);
+ }
+ return err;
+}
+
+/***********************************************************************************************
+Name : icn83xx_scanTP
+Input :
+Output :
+function : scan one frame rawdata
+***********************************************************************************************/
+
+int icn83xx_scanTP(void)
+{
+ char value = 0;
+ icn83xx_write_reg(2, 0x0);
+ mdelay(1);
+ icn83xx_read_reg(2, &value);
+ while(value != 1)
+ {
+ mdelay(1);
+ icn83xx_read_reg(2, &value);
+ }
+// calib_info("icn83xx_scanTP ok\n");
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_readTP
+Input : rownum and columnnum
+Output :
+function : read one frame rawdata
+***********************************************************************************************/
+
+int icn83xx_readTP(char row_num, char column_num, char *buffer)
+{
+ int err = 0;
+ int i;
+// calib_info("icn83xx_readTP\n");
+ icn83xx_changemode(1);
+ icn83xx_scanTP();
+ for(i=0; i<row_num; i++)
+ {
+ icn83xx_readrawdata(&buffer[i*16*2], i, column_num*2);
+ }
+ icn83xx_changemode(0);
+ return err;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_goto_progmode
+Input :
+Output :
+function : change MCU to progmod
+***********************************************************************************************/
+int icn83xx_goto_progmode(void)
+{
+ int ret = -1;
+// char value[64];
+ char regValue = 0;
+
+ flash_info("icn83xx_goto_progmode\n");
+
+ ret = icn83xx_readReg(0x009, ®Value);
+ if(ret != 0)
+ return ret;
+ flash_info("[0x009]: 0x%x\n", regValue);
+
+// open clock
+ if(regValue != 0xDF)
+ {
+ icn83xx_changemode(2);
+ ret = icn83xx_writeReg(0x002, 0x00);
+ if(ret != 0)
+ return ret;
+ ret = icn83xx_writeReg(0x009, 0xDF);
+ if(ret != 0)
+ return ret;
+ ret = icn83xx_writeReg(0x010, 0x00);
+ if(ret != 0)
+ return ret;
+
+ }
+
+/*
+ addr = 0x0;
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(230, temp_buf, 2);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+
+ temp_buf[0] = 0xff;
+ ret = icn83xx_i2c_txdata(232, temp_buf, 1);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+*/
+ ret = icn83xx_writeInfo(0x0, 0xff);
+ if(ret != 0)
+ return ret;
+
+/*
+ addr = 0x1;
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(230, temp_buf, 2);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+
+ temp_buf[0] = 0xff;
+ ret = icn83xx_i2c_txdata(232, temp_buf, 1);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+*/
+ ret = icn83xx_writeInfo(0x1, 0xff);
+ if(ret != 0)
+ return ret;
+
+ ret = icn83xx_writeInfo(0x10, 0xff);
+ if(ret != 0)
+ return ret;
+
+ ret = icn83xx_writeInfo(0x11, 0xff);
+ if(ret != 0)
+ return ret;
+/*
+ addr = 0xf00;
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(224, temp_buf, 2);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+ temp_buf[0] = 0x1;
+ ret = icn83xx_i2c_txdata(226, temp_buf, 1);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+*/
+ ret = icn83xx_writeReg(0xf00, 1);
+ if(ret != 0)
+ return ret;
+ icn83xx_ts_reset();
+ //mdelay(100);
+ msleep(100);
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_check_progmod
+Input :
+Output :
+function : check if MCU at progmode or not
+***********************************************************************************************/
+int icn83xx_check_progmod(void)
+{
+ int ret;
+ unsigned char ucTemp = 0x0;
+ ret = icn83xx_prog_i2c_rxdata(0x0, &ucTemp, 1);
+ flash_info("icn83xx_check_progmod: 0x%x\n", ucTemp);
+ if(ret < 0)
+ {
+ flash_error("icn83xx_check_progmod error, ret: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_uu
+Input :
+Output :
+function : unlock flash
+***********************************************************************************************/
+int icn83xx_uu(void)
+{
+ unsigned char ucTemp = 0x0;
+ ucTemp = 0x1e;
+ icn83xx_prog_i2c_txdata(0x050a, &ucTemp, 1);
+ ucTemp = 0x10;
+ icn83xx_prog_i2c_txdata(0x050b, &ucTemp, 1);
+ return 0;
+}
+/***********************************************************************************************
+Name : icn83xx_ll
+Input :
+Output :
+function : lock flash
+***********************************************************************************************/
+void icn83xx_ll(void)
+{
+ unsigned char ucTemp = 0x0;
+ ucTemp = 0xcc;
+ icn83xx_prog_i2c_txdata(0x050a, &ucTemp, 1);
+ ucTemp = 0xcc;
+ icn83xx_prog_i2c_txdata(0x050b, &ucTemp, 1);
+}
+
+/***********************************************************************************************
+Name : icn83xx_op1
+Input :
+Output :
+function : erase flash
+***********************************************************************************************/
+
+int icn83xx_op1(char info, unsigned short offset, unsigned int size)
+{
+ int count = 0;
+ unsigned char ucTemp = 0x0;
+ unsigned short uiAddress = 0x0;
+ int i;
+
+ icn83xx_uu();
+ for(i=0; i<size; )
+ {
+ uiAddress = offset + i;
+// flash_info("uiAddress: 0x%x\n", uiAddress);
+ ucTemp = U16LOBYTE(uiAddress);
+ icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1);
+ ucTemp = U16HIBYTE(uiAddress);
+ icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1);
+
+ ucTemp = 0x02;
+ icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1);
+ ucTemp = 0x01;
+ count = 0;
+ while(ucTemp)
+ {
+ icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1);
+ count++;
+ if(count > 5000)
+ {
+ flash_error("op1 ucTemp: 0x%x\n", ucTemp);
+ return 1;
+ }
+ }
+ i = i+1024;
+ }
+ icn83xx_ll();
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_op2
+Input :
+Output :
+function : progm flash
+***********************************************************************************************/
+int icn83xx_op2(char info, unsigned short offset, unsigned char * buffer, unsigned int size)
+{
+ int count = 0;
+ unsigned int flash_size;
+ unsigned char ucTemp;
+ unsigned short uiAddress;
+ ucTemp = 0x00;
+ uiAddress = 0x1000;
+
+ icn83xx_prog_i2c_txdata(uiAddress, buffer, size);
+
+ icn83xx_uu();
+
+ ucTemp = U16LOBYTE(offset);
+ icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1);
+ ucTemp = U16HIBYTE(offset);
+ icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1);
+
+ icn83xx_prog_i2c_txdata(0x0504, (char *)&uiAddress, 2);
+
+
+//ensure size is even
+ if(size%2 != 0)
+ {
+ flash_info("write op size: %d\n", size);
+ flash_size = size+1;
+ }
+ else
+ flash_size = size;
+
+ ucTemp = U16LOBYTE(flash_size);
+ icn83xx_prog_i2c_txdata(0x0506, &ucTemp, 1);
+ ucTemp = U16HIBYTE(flash_size);
+ icn83xx_prog_i2c_txdata(0x0507, &ucTemp, 1);
+ ucTemp = 0x01;
+
+ if(info > 0)
+ ucTemp = 0x01 | (1<<3);
+
+ icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1); //
+ while(ucTemp)
+ {
+ icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1);
+ count++;
+ if(count > 5000)
+ {
+ flash_error("op2 ucTemp: 0x%x\n", ucTemp);
+ return 1;
+ }
+
+ }
+ icn83xx_ll();
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_op3
+Input :
+Output :
+function : read flash
+***********************************************************************************************/
+int icn83xx_op3(char info, unsigned short offset, unsigned char * buffer, unsigned int size)
+{
+ int count = 0;
+ unsigned int flash_size;
+ unsigned char ucTemp;
+ unsigned short uiAddress;
+ ucTemp = 0x00;
+ uiAddress = 0x1000;
+ icn83xx_uu();
+ ucTemp = U16LOBYTE(offset);
+ icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1);
+ ucTemp = U16HIBYTE(offset);
+ icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1);
+
+ icn83xx_prog_i2c_txdata(0x0504, (unsigned char*)&uiAddress, 2);
+
+//ensure size is even
+ if(size%2 != 0)
+ {
+ flash_info("read op size: %d\n", size);
+ flash_size = size+1;
+ }
+ else
+ flash_size = size;
+
+ ucTemp = U16LOBYTE(flash_size);
+ icn83xx_prog_i2c_txdata(0x0506, &ucTemp, 1);
+
+ ucTemp = U16HIBYTE(flash_size);
+ icn83xx_prog_i2c_txdata(0x0507, &ucTemp, 1);
+ ucTemp = 0x40;
+
+ if(info > 0)
+ ucTemp = 0x40 | (1<<3);
+
+ icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1);
+ ucTemp = 0x01;
+ while(ucTemp)
+ {
+ icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1);
+ count++;
+ if(count > 5000)
+ {
+ flash_error("op3 ucTemp: 0x%x\n", ucTemp);
+ return 1;
+ }
+
+ }
+ icn83xx_ll();
+ icn83xx_prog_i2c_rxdata(uiAddress, buffer, size);
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_goto_nomalmode
+Input :
+Output :
+function : when prog flash ok, change flash info flag
+***********************************************************************************************/
+int icn83xx_goto_nomalmode(void)
+{
+ int ret = -1;
+ //unsigned short addr = 0;
+ char temp_buf[3];
+
+ flash_info("icn83xx_goto_nomalmode\n");
+ temp_buf[0] = 0x03;
+ icn83xx_prog_i2c_txdata(0x0f00, temp_buf, 1);
+
+ msleep(100);
+/*
+ addr = 0;
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ temp_buf[2] = 0;
+ ret = icn83xx_i2c_txdata(230, temp_buf, 2);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+
+ icn83xx_i2c_rxdata(232, &temp_buf[2], 1);
+ flash_info("temp_buf[2]: 0x%x\n", temp_buf[2]);
+*/
+ ret = icn83xx_readInfo(0, &temp_buf[2]);
+ if(ret != 0)
+ return ret;
+ flash_info("temp_buf[2]: 0x%x\n", temp_buf[2]);
+ if(temp_buf[2] == 0xff)
+ {
+/*
+ addr = 0;
+ temp_buf[0] = U16HIBYTE(addr);
+ temp_buf[1] = U16LOBYTE(addr);
+ ret = icn83xx_i2c_txdata(230, temp_buf, 2);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+ temp_buf[0] = 0x11;
+ ret = icn83xx_i2c_txdata(232, temp_buf, 1);
+ if (ret < 0) {
+ pr_err("write reg failed! ret: %d\n", ret);
+ return -1;
+ }
+*/
+ ret = icn83xx_writeInfo(0, 0x11);
+ if(ret != 0)
+ return ret;
+
+ }
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_read_fw_Ver
+Input : fw
+Output :
+function : read fw version
+***********************************************************************************************/
+
+short icn83xx_read_fw_Ver(char *fw)
+{
+ short FWversion;
+ char tmp[2];
+ int file_size;
+ file_size = icn83xx_open_fw(fw);
+ if(file_size < 0)
+ {
+ return -1;
+ }
+ icn83xx_read_fw(0x4000, 2, &tmp[0]);
+
+ icn83xx_close_fw();
+ FWversion = (tmp[0]<<8)|tmp[1];
+// flash_info("FWversion: 0x%x\n", FWversion);
+ return FWversion;
+}
+
+
+
+
+/***********************************************************************************************
+Name : icn83xx_fw_update
+Input : fw
+Output :
+function : upgrade fw
+***********************************************************************************************/
+
+E_UPGRADE_ERR_TYPE icn83xx_fw_update(char *fw)
+{
+ int file_size, last_length;
+ int j, num;
+ int checksum_bak = 0;
+ int checksum = 0;
+ char temp_buf[B_SIZE];
+#ifdef ENABLE_BYTE_CHECK
+ char temp_buf1[B_SIZE];
+#endif
+
+ file_size = icn83xx_open_fw(fw);
+ if(file_size < 0)
+ {
+ icn83xx_update_status(R_FILE_ERR);
+ return R_FILE_ERR;
+ }
+
+ if(icn83xx_goto_progmode() != 0)
+ {
+ if(icn83xx_check_progmod() < 0)
+ {
+ icn83xx_update_status(R_STATE_ERR);
+ icn83xx_close_fw();
+ return R_STATE_ERR;
+ }
+ }
+// msleep(50);
+
+ if(icn83xx_op1(0, 0, file_size) != 0)
+ {
+ flash_error("icn83xx_op1 error\n");
+ icn83xx_update_status(R_ERASE_ERR);
+ icn83xx_close_fw();
+ return R_ERASE_ERR;
+ }
+ icn83xx_update_status(5);
+
+ num = file_size/B_SIZE;
+ for(j=0; j < num; j++)
+ {
+ icn83xx_read_fw(j*B_SIZE, B_SIZE, temp_buf);
+
+// icn83xx_op3(0, j*B_SIZE, temp_buf1, B_SIZE);
+// icn83xx_memdump(temp_buf1, B_SIZE);
+
+ if(icn83xx_op2(0, j*B_SIZE, temp_buf, B_SIZE) != 0)
+ {
+ icn83xx_update_status(R_PROGRAM_ERR);
+ icn83xx_close_fw();
+ return R_PROGRAM_ERR;
+ }
+ checksum_bak = icn83xx_checksum(checksum_bak, temp_buf, B_SIZE);
+
+ icn83xx_update_status(5+(int)(60*j/num));
+ }
+ last_length = file_size - B_SIZE*j;
+ if(last_length > 0)
+ {
+ icn83xx_read_fw(j*B_SIZE, last_length, temp_buf);
+
+// icn83xx_op3(0, j*B_SIZE, temp_buf1, B_SIZE);
+// icn83xx_memdump(temp_buf1, B_SIZE);
+
+ if(icn83xx_op2(0, j*B_SIZE, temp_buf, last_length) != 0)
+ {
+ icn83xx_update_status(R_PROGRAM_ERR);
+ icn83xx_close_fw();
+ return R_PROGRAM_ERR;
+ }
+ checksum_bak = icn83xx_checksum(checksum_bak, temp_buf, last_length);
+ }
+
+ icn83xx_close_fw();
+ icn83xx_update_status(65);
+
+#ifdef ENABLE_BYTE_CHECK
+ file_size = icn83xx_open_fw(fw);
+ num = file_size/B_SIZE;
+#endif
+
+ for(j=0; j < num; j++)
+ {
+
+#ifdef ENABLE_BYTE_CHECK
+ icn83xx_read_fw(j*B_SIZE, B_SIZE, temp_buf1);
+#endif
+ icn83xx_op3(0, j*B_SIZE, temp_buf, B_SIZE);
+ checksum = icn83xx_checksum(checksum, temp_buf, B_SIZE);
+
+#ifdef ENABLE_BYTE_CHECK
+ if(memcmp(temp_buf1, temp_buf, B_SIZE) != 0)
+ {
+ flash_error("cmp error, %d\n", j);
+ icn83xx_memdump(temp_buf1, B_SIZE);
+ icn83xx_memdump(temp_buf, B_SIZE);
+ icn83xx_update_status(R_VERIFY_ERR);
+#ifdef ENABLE_BYTE_CHECK
+ icn83xx_close_fw();
+#endif
+ return R_VERIFY_ERR;
+ //while(1);
+ }
+#endif
+ icn83xx_update_status(65+(int)(30*j/num));
+ }
+
+#ifdef ENABLE_BYTE_CHECK
+ last_length = file_size - B_SIZE*j;
+#endif
+ if(last_length > 0)
+ {
+#ifdef ENABLE_BYTE_CHECK
+ icn83xx_read_fw(j*B_SIZE, last_length, temp_buf1);
+#endif
+ icn83xx_op3(0, j*B_SIZE, temp_buf, last_length);
+ checksum = icn83xx_checksum(checksum, temp_buf, last_length);
+
+#ifdef ENABLE_BYTE_CHECK
+ if(memcmp(temp_buf1, temp_buf, last_length) != 0)
+ {
+ flash_error("cmp error, %d\n", j);
+ icn83xx_memdump(temp_buf1, last_length);
+ icn83xx_memdump(temp_buf, last_length);
+ icn83xx_update_status(R_VERIFY_ERR);
+#ifdef ENABLE_BYTE_CHECK
+ icn83xx_close_fw();
+#endif
+ return R_VERIFY_ERR;
+ //while(1);
+ }
+#endif
+
+ }
+
+#ifdef ENABLE_BYTE_CHECK
+ icn83xx_close_fw();
+#endif
+
+ flash_info("checksum_bak: 0x%x, checksum: 0x%x\n", checksum_bak, checksum);
+ if(checksum_bak != checksum)
+ {
+ flash_error("upgrade checksum error\n");
+ icn83xx_update_status(R_VERIFY_ERR);
+ return R_VERIFY_ERR;
+ }
+
+ if(icn83xx_goto_nomalmode() != 0)
+ {
+ flash_error("icn83xx_goto_nomalmode error\n");
+ icn83xx_update_status(R_STATE_ERR);
+ return R_STATE_ERR;
+ }
+
+ icn83xx_update_status(R_OK);
+ flash_info("upgrade ok\n");
+ return R_OK;
+}
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c new file mode 100755 index 00000000..60e42e50 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.c @@ -0,0 +1,2034 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn83xx.c +Abstract: +input driver. +Author: Zhimin Tian +Date : 01,17,2013 +Version: 1.0 +History : +2012,10,30, V0.1 first version +--*/ + +#include "icn83xx.h" + +#if COMPILE_FW_WITH_DRIVER +#include "icn83xx_fw.h" +#endif + +static struct touch_param g_param; +static struct i2c_client *this_client; +short log_rawdata[28][16];// = {0,}; +short log_diffdata[28][16];// = {0,}; +static int l_suspend = 0; // 1:suspend, 0:normal state + +#if SUPPORT_ROCKCHIP +//if file system not ready,you can use inner array +//static char firmware[128] = "icn83xx_firmware"; +#endif +static char firmware[128] = {"/system/etc/firmware/fw.bin"}; + +//static void icn_delayedwork_fun(struct work_struct *work); +extern int register_bl_notifier(struct notifier_block *nb); +extern int unregister_bl_notifier(struct notifier_block *nb); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +#define dbg(fmt, args...) do{if (g_param.dbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args);}while(0) + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "echo 1 > dbg : print debug message.\necho 0 > dbg : Do not print debug message.\n"); +} +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + g_param.dbg = simple_strtoul(buf, NULL, 10) ? 1 : 0; + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +#if SUPPORT_SYSFS +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer); +static ssize_t icn83xx_show_update(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len); +static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); + +static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn83xx_show_update, icn83xx_store_update); +static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn83xx_show_process, icn83xx_store_process); + +static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, "icn83xx process\n"); + ret = strlen(buf) + 1; + return ret; +} + +static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + unsigned long on_off = simple_strtoul(buf, NULL, 10); + if(on_off == 0) + { + icn83xx_ts->work_mode = on_off; + } + else if((on_off == 1) || (on_off == 2)) + { + if((icn83xx_ts->work_mode == 0) && (icn83xx_ts->use_irq == 1)) + { + hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn83xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + icn83xx_ts->work_mode = on_off; + } + return len; +} + +static ssize_t icn83xx_show_update(struct device* cd, + struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, "icn83xx firmware\n"); + ret = strlen(buf) + 1; + return ret; +} + +static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len) +{ + //int err=0; + //unsigned long on_off = simple_strtoul(buf, NULL, 10); + return len; +} + +static int icn83xx_create_sysfs(struct i2c_client *client) +{ + int err; + struct device *dev = &(client->dev); + icn83xx_trace("%s: \n",__func__); + err = device_create_file(dev, &dev_attr_update); + err = device_create_file(dev, &dev_attr_process); + return err; +} + +#endif + +#if SUPPORT_PROC_FS + +pack_head cmd_head; +static struct proc_dir_entry *icn83xx_proc_entry; +int DATA_LENGTH = 0; +static int icn83xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data) +{ + int ret = 0; + + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + proc_info("%s \n",__func__); + if(down_interruptible(&icn83xx_ts->sem)) + { + return -1; + } + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + else + { + ret = CMD_HEAD_LENGTH; + } + + proc_info("wr :0x%02x.\n", cmd_head.wr); + proc_info("flag:0x%02x.\n", cmd_head.flag); + proc_info("circle :%d.\n", (int)cmd_head.circle); + proc_info("times :%d.\n", (int)cmd_head.times); + proc_info("retry :%d.\n", (int)cmd_head.retry); + proc_info("data len:%d.\n", (int)cmd_head.data_len); + proc_info("addr len:%d.\n", (int)cmd_head.addr_len); + proc_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]); + proc_info("len:%d.\n", (int)len); + proc_info("data:0x%02x%02x.\n", buff[CMD_HEAD_LENGTH], buff[CMD_HEAD_LENGTH+1]); + if (1 == cmd_head.wr) // write iic + { + if(1 == cmd_head.addr_len) + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = icn83xx_i2c_txdata(cmd_head.addr[0], &cmd_head.data[0], cmd_head.data_len); + if (ret < 0) { + proc_error("write iic failed! ret: %d\n", ret); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto write_out; + } + } + else if(3 == cmd_head.wr) + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + memset(firmware, 0, 128); + memcpy(firmware, &cmd_head.data[0], cmd_head.data_len); + proc_info("firmware : %s\n", firmware); + } + else if(5 == cmd_head.wr) + { + icn83xx_update_status(1); + ret = kernel_thread((int (*)(void *))icn83xx_fw_update,firmware,CLONE_KERNEL); + icn83xx_trace("the kernel_thread result is:%d\n", ret); + } + else if(7 == cmd_head.wr) //write reg + { + if(2 == cmd_head.addr_len) + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = icn83xx_writeReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], cmd_head.data[0]); + if (ret < 0) { + proc_error("write reg failed! ret: %d\n", ret); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto write_out; + + } + } + +write_out: + up(&icn83xx_ts->sem); + return len; + +} +static int icn83xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int i; + int ret = 0; + int data_len = 0; + int len = 0; + int loc = 0; + char retvalue; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + if(down_interruptible(&icn83xx_ts->sem)) + { + return -1; + } + proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count, (int)off, cmd_head.data_len); + if (cmd_head.wr % 2) + { + ret = 0; + goto read_out; + } + else if (0 == cmd_head.wr) //read iic + { + if(1 == cmd_head.addr_len) + { + data_len = cmd_head.data_len; + if(cmd_head.addr[0] == 0xff) + { + page[0] = 83; + proc_info("read ic type: %d\n", page[0]); + } + else + { + while(data_len>0) + { + if (data_len > DATA_LENGTH) + { + len = DATA_LENGTH; + } + else + { + len = data_len; + } + data_len -= len; + memset(&cmd_head.data[0], 0, len+1); + ret = icn83xx_i2c_rxdata(cmd_head.addr[0]+loc, &cmd_head.data[0], len); + //proc_info("cmd_head.data[0]: 0x%02x\n", cmd_head.data[0]); + //proc_info("cmd_head.data[1]: 0x%02x\n", cmd_head.data[1]); + if(ret < 0) + { + icn83xx_error("read iic failed: %d\n", ret); + goto read_out; + } + else + { + //proc_info("iic read out %d bytes, loc: %d\n", len, loc); + memcpy(&page[loc], &cmd_head.data[0], len); + } + loc += len; + } + proc_info("page[0]: 0x%02x\n", page[0]); + proc_info("page[1]: 0x%02x\n", page[1]); + } + } + } + else if(2 == cmd_head.wr) //read rawdata + { + //scan tp rawdata + icn83xx_write_reg(4, 0x20); + mdelay(cmd_head.times); + icn83xx_read_reg(2, &retvalue); + while(retvalue != 1) + { + mdelay(cmd_head.times); + icn83xx_read_reg(2, &retvalue); + } + + if(2 == cmd_head.addr_len) + { + for(i=0; i<cmd_head.addr[1]; i++) + { + icn83xx_write_reg(3, i); + mdelay(cmd_head.times); + ret = icn83xx_i2c_rxdata(128, &cmd_head.data[0], cmd_head.addr[0]*2); + if (ret < 0) + { + icn83xx_error("read rawdata failed: %d\n", ret); + goto read_out; + } + else + { + //proc_info("read rawdata out %d bytes, loc: %d\n", cmd_head.addr[0]*2, loc); + memcpy(&page[loc], &cmd_head.data[0], cmd_head.addr[0]*2); + } + loc += cmd_head.addr[0]*2; + } + for(i=0; i<cmd_head.data_len; i=i+2) + { + swap_ab(page[i], page[i+1]); + } + //icn83xx_rawdatadump(&page[0], cmd_head.data_len/2, cmd_head.addr[0]); + } + + //finish scan tp rawdata + icn83xx_write_reg(2, 0x0); + + } + else if(4 == cmd_head.wr) //get update status + { + page[0] = icn83xx_get_status(); + } + else if(6 == cmd_head.wr) //read reg + { + if(2 == cmd_head.addr_len) + { + ret = icn83xx_readReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], &cmd_head.data[0]); + if (ret < 0) { + proc_error("reg reg failed! ret: %d\n", ret); + goto read_out; + } + page[0] = cmd_head.data[0]; + goto read_out; + } + } +read_out: + up(&icn83xx_ts->sem); + proc_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len); + return cmd_head.data_len; +} + +int init_proc_node(void) +{ + int i; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 5; + while ((!cmd_head.data) && i) + { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL != cmd_head.data) + { + break; + } + i--; + } + if (i) + { + //DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH; + DATA_LENGTH = i * DATA_LENGTH_UINT; + icn83xx_trace("alloc memory size:%d.\n", DATA_LENGTH); + } + else + { + proc_error("alloc for memory failed.\n"); + return 0; + } + + icn83xx_proc_entry = create_proc_entry(ICN83XX_ENTRY_NAME, 0666, NULL); + if (icn83xx_proc_entry == NULL) + { + proc_error("Couldn't create proc entry!\n"); + return 0; + } + else + { + icn83xx_trace("Create proc entry success!\n"); + icn83xx_proc_entry->write_proc = icn83xx_tool_write; + icn83xx_proc_entry->read_proc = icn83xx_tool_read; + } + + return 1; +} + +void uninit_proc_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + remove_proc_entry(ICN83XX_ENTRY_NAME, NULL); +} + +#endif + + +#if TOUCH_VIRTUAL_KEYS +static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":280:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":470:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":900:1030:50:60" + "\n"); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys.chipone-ts", + .mode = S_IRUGO, + }, + .show = &virtual_keys_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + +static void icn83xx_ts_virtual_keys_init(void) +{ + int ret = 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 + + +/* --------------------------------------------------------------------- + * + * Chipone panel related driver + * + * + ----------------------------------------------------------------------*/ +/*********************************************************************************************** +Name : icn83xx_ts_wakeup +Input : void +Output : ret +function : this function is used to wakeup tp + ***********************************************************************************************/ +void icn83xx_ts_wakeup(void) +{ + //#if def TOUCH_RESET_PIN + +} + +/*********************************************************************************************** +Name : icn83xx_ts_reset +Input : void +Output : ret +function : this function is used to reset tp, you should not delete it + ***********************************************************************************************/ +void icn83xx_ts_reset(void) +{ + int rst = g_param.rstgpio; + gpio_direction_output(rst, 0); + //mdelay(30); + msleep(50); + gpio_direction_output(rst, 1); + //mdelay(50); + msleep(50); + +} + +/*********************************************************************************************** +Name : icn83xx_irq_disable +Input : void +Output : ret +function : this function is used to disable irq + ***********************************************************************************************/ +void icn83xx_irq_disable(void) +{ + unsigned long irqflags; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags); + if (!icn83xx_ts->irq_is_disable) + { + icn83xx_ts->irq_is_disable = 1; + wmt_gpio_mask_irq(g_param.irqgpio); + //disable_irq_nosync(icn83xx_ts->irq); + //disable_irq(icn83xx_ts->irq); + } + spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags); +} + +/*********************************************************************************************** +Name : icn83xx_irq_enable +Input : void +Output : ret +function : this function is used to enable irq + ***********************************************************************************************/ +void icn83xx_irq_enable(void) +{ + unsigned long irqflags = 0; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags); + if (icn83xx_ts->irq_is_disable) + { + wmt_gpio_unmask_irq(g_param.irqgpio); + //enable_irq(icn83xx_ts->irq); + icn83xx_ts->irq_is_disable = 0; + } + spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags); + +} + +/*********************************************************************************************** +Name : icn83xx_prog_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn83xx, prog mode + ***********************************************************************************************/ +int icn83xx_prog_i2c_rxdata(unsigned short addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; +#if 0 + struct i2c_msg msgs[] = { + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + icn83xx_prog_i2c_txdata(addr, NULL, 0); + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 1); + if(ret == 1)break; + retries++; + } + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } +#else + unsigned char tmp_buf[2]; + struct i2c_msg msgs[] = { + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + tmp_buf[0] = U16HIBYTE(addr); + tmp_buf[1] = U16LOBYTE(addr); + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } +#endif + return ret; +} +/*********************************************************************************************** +Name : icn83xx_prog_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn83xx , prog mode + ***********************************************************************************************/ +int icn83xx_prog_i2c_txdata(unsigned short addr, char *txdata, int length) +{ + int ret = -1; + char tmp_buf[128]; + int retries = 0; + struct i2c_msg msg[] = { + { + .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = length + 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn83xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = U16HIBYTE(addr); + tmp_buf[1] = U16LOBYTE(addr); + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[2], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c write error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } + return ret; +} +/*********************************************************************************************** +Name : icn83xx_prog_write_reg +Input : addr -- address +para -- parameter +Output : +function : write register of icn83xx, prog mode + ***********************************************************************************************/ +int icn83xx_prog_write_reg(unsigned short addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn83xx_prog_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn83xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn83xx_prog_read_reg +Input : addr +pdata +Output : +function : read register of icn83xx, prog mode + ***********************************************************************************************/ +int icn83xx_prog_read_reg(unsigned short addr, char *pdata) +{ + int ret = -1; + ret = icn83xx_prog_i2c_rxdata(addr, pdata, 1); + return ret; +} + +/*********************************************************************************************** +Name : icn83xx_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn83xx, normal mode + ***********************************************************************************************/ +int icn83xx_i2c_rxdata(unsigned char addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; +#if 0 + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + icn83xx_i2c_txdata(addr, NULL, 0); + while(retries < IIC_RETRY_NUM) + { + + ret = i2c_transfer(this_client->adapter, msgs, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + // icn83xx_ts_reset(); + } + +#else + unsigned char tmp_buf[1]; + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = 1, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + tmp_buf[0] = addr; + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c read error: %d\n", __func__, ret); + icn83xx_ts_reset(); + } +#endif + + return ret; +} +/*********************************************************************************************** +Name : icn83xx_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn83xx , normal mode + ***********************************************************************************************/ +int icn83xx_i2c_txdata(unsigned char addr, char *txdata, int length) +{ + int ret = -1; + unsigned char tmp_buf[128]; + int retries = 0; + + struct i2c_msg msg[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = length + 1, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN83XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn83xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = addr; + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[1], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn83xx_error("%s i2c write error: %d\n", __func__, ret); + icn83xx_ts_reset(); + } + + return ret; +} + +/*********************************************************************************************** +Name : icn83xx_write_reg +Input : addr -- address +para -- parameter +Output : +function : write register of icn83xx, normal mode + ***********************************************************************************************/ +int icn83xx_write_reg(unsigned char addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn83xx_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn83xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn83xx_read_reg +Input : addr +pdata +Output : +function : read register of icn83xx, normal mode + ***********************************************************************************************/ +int icn83xx_read_reg(unsigned char addr, char *pdata) +{ + int ret = -1; + ret = icn83xx_i2c_rxdata(addr, pdata, 1); + return ret; +} + +#if SUPPORT_FW_UPDATE +/*********************************************************************************************** +Name : icn83xx_log +Input : 0: rawdata, 1: diff data +Output : err type +function : calibrate param + ***********************************************************************************************/ +void icn83xx_log(char diff) +{ + char row = 0; + char column = 0; + int i, j; + icn83xx_read_reg(160, &row); + icn83xx_read_reg(161, &column); + + if(diff == 1) + { + icn83xx_readTP(row, column, (char *)&log_diffdata[0][0]); + + for(i=0; i<row; i++) + { + for(j=0; j<column; j++) + { + log_diffdata[i][j] = log_diffdata[i][j] - log_rawdata[i][j]; + } + } + icn83xx_rawdatadump(&log_diffdata[0][0], row*16, 16); + } + else + { + icn83xx_readTP(row, column, (char *)&log_rawdata[0][0]); + icn83xx_rawdatadump(&log_rawdata[0][0], row*16, 16); + } +} +#endif + +/*********************************************************************************************** +Name : icn83xx_iic_test +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_iic_test(void) +{ + int ret = -1; + char value = 0; + int retry = 0; + while(retry++ < 3) + { + ret = icn83xx_read_reg(0, &value); + if(ret > 0) + { + return ret; + } + icn83xx_error("iic test error! %d\n", retry); + msleep(3); + } + return ret; +} + +/*********************************************************************************************** +Name : icn83xx_report_value_B +Input : void +Output : +function : reprot touch ponit + ***********************************************************************************************/ +#if CTP_REPORT_PROTOCOL +static int icn83xx_report_value_B(void) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + static unsigned char finger_last[POINT_NUM + 1]={0}; + unsigned char finger_current[POINT_NUM + 1] = {0}; + unsigned int position = 0; + int temp = 0; + int ret = -1; + int x,y; + icn83xx_info("==icn83xx_report_value_B ==\n"); + // icn83xx_trace("==icn83xx_report_value_B ==\n"); + ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ret; + } + + icn83xx_ts->point_num = buf[1]; + if (icn83xx_ts->point_num > 5) { + printk("error point_num : %d\n",icn83xx_ts->point_num); + return -1; + } + if(icn83xx_ts->point_num > 0) + { + for(position = 0; position<icn83xx_ts->point_num; position++) + { + temp = buf[2 + POINT_SIZE*position] + 1; + finger_current[temp] = 1; + icn83xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u16PosX = (buf[3 + POINT_SIZE*position]<<8) + buf[4 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u16PosY = (buf[5 + POINT_SIZE*position]<<8) + buf[6 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position]; + icn83xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position]; + + if(icn83xx_ts->point_info[temp].u8EventId == 4) + finger_current[temp] = 0; + + if(1 == icn83xx_ts->revert_x_flag) + { + icn83xx_ts->point_info[temp].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[temp].u16PosX; + } + if(1 == icn83xx_ts->revert_y_flag) + { + icn83xx_ts->point_info[temp].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[temp].u16PosY; + } + icn83xx_info("temp %d\n", temp); + icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[temp].u8ID); + icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[temp].u16PosX); + icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[temp].u16PosY); + icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure); + icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[temp].u8EventId); + //icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure*16); + } + } + else + { + for(position = 1; position < POINT_NUM+1; position++) + { + finger_current[position] = 0; + } + icn83xx_info("no touch\n"); + } + + for(position = 1; position < POINT_NUM + 1; position++) + { + if((finger_current[position] == 0) && (finger_last[position] != 0)) + { + input_mt_slot(icn83xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false); + icn83xx_point_info("one touch up: %d\n", position); + } + else if(finger_current[position]) + { + if (g_param.xyswap == 0) + { + x = icn83xx_ts->point_info[position].u16PosX; + y = icn83xx_ts->point_info[position].u16PosY; + } else { + y = icn83xx_ts->point_info[position].u16PosX; + x = icn83xx_ts->point_info[position].u16PosY; + } + if (g_param.xdir == -1) + { + x = g_param.panelres_x - x; + } + if (g_param.ydir == -1) + { + y = g_param.panelres_y - y; + } + + if (g_param.lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = g_param.panelres_x - tmp; + } + + input_mt_slot(icn83xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, true); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); + //input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, icn83xx_ts->point_info[position].u8Pressure); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, y); + icn83xx_point_info("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure); + // icn83xx_trace("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure); + dbg("raw%d(%d,%d), rpt%d(%d,%d)\n", position, icn83xx_ts->point_info[position].u16PosX, icn83xx_ts->point_info[position].u16PosY, position, x, y); + } + + } + input_sync(icn83xx_ts->input_dev); + + for(position = 1; position < POINT_NUM + 1; position++) + { + finger_last[position] = finger_current[position]; + } + return 0; +} + +#else + +/*********************************************************************************************** +Name : icn83xx_ts_release +Input : void +Output : +function : touch release + ***********************************************************************************************/ +static void icn83xx_ts_release(void) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + icn83xx_info("==icn83xx_ts_release ==\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_sync(icn83xx_ts->input_dev); +} + +/*********************************************************************************************** +Name : icn83xx_report_value_A +Input : void +Output : +function : reprot touch ponit + ***********************************************************************************************/ +static int icn83xx_report_value_A(void) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + int ret = -1; + int i; +#if TOUCH_VIRTUAL_KEYS + unsigned char button; + static unsigned char button_last; +#endif + icn83xx_info("==icn83xx_report_value_A ==\n"); + + ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ret; + } +#if TOUCH_VIRTUAL_KEYS + button = buf[0]; + icn83xx_info("%s: button=%d\n",__func__, button); + + if((button_last != 0) && (button == 0)) + { + icn83xx_ts_release(); + button_last = button; + return 1; + } + if(button != 0) + { + switch(button) + { + case ICN_VIRTUAL_BUTTON_HOME: + icn83xx_info("ICN_VIRTUAL_BUTTON_HOME down\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 280); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + input_sync(icn83xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_BACK: + icn83xx_info("ICN_VIRTUAL_BUTTON_BACK down\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 470); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + input_sync(icn83xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_MENU: + icn83xx_info("ICN_VIRTUAL_BUTTON_MENU down\n"); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 100); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + input_sync(icn83xx_ts->input_dev); + break; + default: + icn83xx_info("other gesture\n"); + break; + } + button_last = button; + return 1; + } +#endif + + icn83xx_ts->point_num = buf[1]; + if (icn83xx_ts->point_num == 0) { + icn83xx_ts_release(); + return 1; + } + for(i=0;i<icn83xx_ts->point_num;i++){ + if(buf[8 + POINT_SIZE*i] != 4) break ; + } + + if(i == icn83xx_ts->point_num) { + icn83xx_ts_release(); + return 1; + } + + for(i=0; i<icn83xx_ts->point_num; i++) + { + icn83xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u16PosX = (buf[3 + POINT_SIZE*i]<<8) + buf[4 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u16PosY = (buf[5 + POINT_SIZE*i]<<8) + buf[6 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u8Pressure = 200;//buf[7 + POINT_SIZE*i]; + icn83xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i]; + + if(1 == icn83xx_ts->revert_x_flag) + { + icn83xx_ts->point_info[i].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[i].u16PosX; + } + if(1 == icn83xx_ts->revert_y_flag) + { + icn83xx_ts->point_info[i].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[i].u16PosY; + } + + icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[i].u8ID); + icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[i].u16PosX); + icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[i].u16PosY); + icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[i].u8Pressure); + icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[i].u8EventId); + + + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, icn83xx_ts->point_info[i].u8ID); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn83xx_ts->point_info[i].u8Pressure); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, icn83xx_ts->point_info[i].u16PosX); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, icn83xx_ts->point_info[i].u16PosY); + input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn83xx_ts->input_dev); + icn83xx_point_info("point: %d ===x = %d,y = %d, press = %d ====\n",i, icn83xx_ts->point_info[i].u16PosX,icn83xx_ts->point_info[i].u16PosY, icn83xx_ts->point_info[i].u8Pressure); + } + + input_sync(icn83xx_ts->input_dev); + return 0; +} +#endif + +/*********************************************************************************************** +Name : icn83xx_ts_pen_irq_work +Input : void +Output : +function : work_struct + ***********************************************************************************************/ +static void icn83xx_ts_pen_irq_work(struct work_struct *work) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); +#if SUPPORT_PROC_FS + if(down_interruptible(&icn83xx_ts->sem)) + { + return; + } +#endif + + if(icn83xx_ts->work_mode == 0) + { +#if CTP_REPORT_PROTOCOL + icn83xx_report_value_B(); +#else + icn83xx_report_value_A(); +#endif + + } +#if SUPPORT_FW_UPDATE + else if(icn83xx_ts->work_mode == 1) + { + printk("log raw data\n"); + icn83xx_log(0); //raw data + } + else if(icn83xx_ts->work_mode == 2) + { + printk("log diff data\n"); + icn83xx_log(1); //diff data + } +#endif + +#if SUPPORT_PROC_FS + up(&icn83xx_ts->sem); +#endif + wmt_gpio_unmask_irq(g_param.irqgpio); + +} +/*********************************************************************************************** +Name : chipone_timer_func +Input : void +Output : +function : Timer interrupt service routine. + ***********************************************************************************************/ +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer) +{ + struct icn83xx_ts_data *icn83xx_ts = container_of(timer, struct icn83xx_ts_data, timer); + queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work); + + if(icn83xx_ts->use_irq == 1) + { + if((icn83xx_ts->work_mode == 1) || (icn83xx_ts->work_mode == 2)) + { + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + } + else + { + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + return HRTIMER_NORESTART; +} +/*********************************************************************************************** +Name : icn83xx_ts_interrupt +Input : void +Output : +function : interrupt service routine + ***********************************************************************************************/ +static irqreturn_t icn83xx_ts_interrupt(int irq, void *dev_id) +{ + struct icn83xx_ts_data *icn83xx_ts = dev_id; + int irqindex = g_param.irqgpio; + + icn83xx_info("==========------icn83xx_ts TS Interrupt-----============\n"); + if (gpio_irqstatus(irqindex)) { + wmt_gpio_ack_irq(irqindex); + if (is_gpio_irqenable(irqindex) && l_suspend == 0) { + wmt_gpio_mask_irq(irqindex); + if(icn83xx_ts->work_mode != 0) { + wmt_gpio_unmask_irq(irqindex); + return IRQ_HANDLED; + } + //icn83xx_irq_disable(); + if (!work_pending(&icn83xx_ts->pen_event_work)) { + //icn83xx_info("Enter work\n"); + queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work); + } + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + + +#ifdef CONFIG_HAS_EARLYSUSPEND +/*********************************************************************************************** +Name : icn83xx_ts_suspend +Input : void +Output : +function : tp enter sleep mode + ***********************************************************************************************/ +static void icn83xx_ts_early_suspend(struct early_suspend *handler) +{ + int retry = 0; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n"); + if (icn83xx_ts->use_irq) + { + icn83xx_irq_disable(); + icn83xx_trace("icn83xx_ts_suspend:disable irq .\n"); + } + else + { + hrtimer_cancel(&icn83xx_ts->timer); + } + for(retry = 0;retry <3; retry++ ) + { + icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE); + } +} + +/*********************************************************************************************** +Name : icn83xx_ts_resume +Input : void +Output : +function : wakeup tp or reset tp + ***********************************************************************************************/ +static void icn83xx_ts_late_resume(struct early_suspend *handler) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + int i; + printk("==icn83xx_ts_resume== \n"); + // icn83xx_ts_reset(); + //report touch release +#if CTP_REPORT_PROTOCOL + for(i = 0; i < POINT_NUM; i++) + { + input_mt_slot(icn83xx_ts->input_dev, i); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false); + } +#else + icn83xx_ts_release(); +#endif + icn83xx_ts_wakeup(); + icn83xx_ts_reset(); + if (icn83xx_ts->use_irq) + { + printk("icn83xx_irq_enable\n"); + icn83xx_irq_enable(); + } + else + { printk("icn83xx_ts_resume hrtimer_start\n"); + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + +} +#endif + +#ifdef CONFIG_PM +/*********************************************************************************************** +Name : icn83xx_ts_suspend +Input : void +Output : +function : tp enter sleep mode + ***********************************************************************************************/ +static int icn83xx_ts_suspend(struct device *pdev) +{ + //int retry = 0; + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n"); + if (icn83xx_ts->use_irq) + { + icn83xx_irq_disable(); + icn83xx_trace("icn83xx_ts_suspend:disable irq .\n"); + } + else + { + hrtimer_cancel(&icn83xx_ts->timer); + } + /*for(retry = 0;retry <3; retry++ ) + { + icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE); + } */ + l_suspend = 1; + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_ts_resume +Input : void +Output : +function : wakeup tp or reset tp + ***********************************************************************************************/ +static int icn83xx_ts_resume(struct device *pdev) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client); + int i; + printk("==icn83xx_ts_resume== \n"); + // icn83xx_ts_reset(); + //report touch release +#if CTP_REPORT_PROTOCOL + for(i = 0; i < POINT_NUM; i++) + { + input_mt_slot(icn83xx_ts->input_dev, i); + input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false); + } +#else + icn83xx_ts_release(); +#endif + //icn83xx_ts_wakeup(); + icn83xx_ts_reset(); + l_suspend = 0; + if (icn83xx_ts->use_irq) + { + printk("icn83xx_irq_enable\n"); + icn83xx_irq_enable(); + } + else + { printk("icn83xx_ts_resume hrtimer_start\n"); + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + return 0; +} +#else +#define icn83xx_ts_suspend NULL +#define icn83xx_ts_resume NULL +#endif + +/*********************************************************************************************** +Name : icn83xx_request_io_port +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_request_io_port(struct icn83xx_ts_data *icn83xx_ts) +{ +#if SUPPORT_ROCKCHIP + icn83xx_ts->screen_max_x = SCREEN_MAX_X; + icn83xx_ts->screen_max_y = SCREEN_MAX_Y; + icn83xx_ts->irq = CTP_IRQ_PORT; +#endif + icn83xx_ts->irq = IRQ_GPIO; + + if (gpio_request(g_param.rstgpio, "ts_rst") < 0) { + printk("gpio(%d) touchscreen reset request fail\n", g_param.rstgpio); + return -EIO; + } + gpio_direction_output(g_param.rstgpio, 1); + + if (gpio_request(g_param.irqgpio, "ts_irq") < 0) { + printk("gpio(%d) touchscreen interrupt request fail\n", g_param.irqgpio); + gpio_free(g_param.rstgpio); + return -EIO; + } + wmt_gpio_setpull(g_param.irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(g_param.irqgpio); + + return 0; +} + +/*********************************************************************************************** +Name : icn83xx_free_io_port +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static void icn83xx_free_io_port(void) +{ + gpio_free(g_param.rstgpio); + gpio_free(g_param.irqgpio); +} + +/*********************************************************************************************** +Name : icn83xx_request_irq +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_request_irq(struct icn83xx_ts_data *icn83xx_ts) +{ + int err = -1; + + /*err = gpio_request(icn83xx_ts->irq, "TS_INT"); //Request IO + if (err < 0) + { + icn83xx_error("Failed to request GPIO:%d, ERRNO:%d\n", (int)icn83xx_ts->irq, err); + return err; + } + gpio_direction_input(icn83xx_ts->irq);*/ + + wmt_gpio_set_irq_type(g_param.irqgpio, IRQ_TYPE_EDGE_FALLING); + err = request_irq(icn83xx_ts->irq, icn83xx_ts_interrupt, IRQF_SHARED, "icn83xx_ts", icn83xx_ts); + if (err < 0) + { + icn83xx_error("icn83xx_ts_probe: request irq failed\n"); + return err; + } + else + { + icn83xx_irq_disable(); + icn83xx_ts->use_irq = 1; + } + + return 0; +} + + +/*********************************************************************************************** +Name : icn83xx_free_irq +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static void icn83xx_free_irq(struct icn83xx_ts_data *icn83xx_ts) +{ + if (icn83xx_ts) + { + if (icn83xx_ts->use_irq) + { + free_irq(icn83xx_ts->irq, icn83xx_ts); + } + else + { + hrtimer_cancel(&icn83xx_ts->timer); + } + } +} + +/*********************************************************************************************** +Name : icn83xx_request_input_dev +Input : void +Output : +function : 0 success, + ***********************************************************************************************/ +static int icn83xx_request_input_dev(struct icn83xx_ts_data *icn83xx_ts) +{ + int ret = -1; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) { + icn83xx_error("failed to allocate input device\n"); + return -ENOMEM; + } + icn83xx_ts->input_dev = input_dev; + + icn83xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; +#if CTP_REPORT_PROTOCOL + __set_bit(INPUT_PROP_DIRECT, icn83xx_ts->input_dev->propbit); + input_mt_init_slots(icn83xx_ts->input_dev, 255); +#else + set_bit(ABS_MT_TOUCH_MAJOR, icn83xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_X, icn83xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, icn83xx_ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, icn83xx_ts->input_dev->absbit); +#endif + if (g_param.lcd_exchg) { + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_y, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_x, 0, 0); + } else { + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_x, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_y, 0, 0); + } + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + __set_bit(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) { + icn83xx_error("Register %s input device failed\n", input_dev->name); + input_free_device(input_dev); + return -ENODEV; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + icn83xx_trace("==register_early_suspend =\n"); + icn83xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + icn83xx_ts->early_suspend.suspend = icn83xx_ts_early_suspend; + icn83xx_ts->early_suspend.resume = icn83xx_ts_late_resume; + register_early_suspend(&icn83xx_ts->early_suspend); +#endif + + return 0; +} + +#if SUPPORT_DELAYED_WORK +static void icn_delayedwork_fun(struct work_struct *work) +{ + int retry; + short fwVersion = 0; + short curVersion = 0; + icn83xx_trace("====%s begin1111=====. \n", __func__); + +#if SUPPORT_FW_UPDATE + fwVersion = icn83xx_read_fw_Ver(firmware); + curVersion = icn83xx_readVersion(); + icn83xx_trace("fwVersion : 0x%x\n", fwVersion); + icn83xx_trace("current version: 0x%x\n", curVersion); + + +#if FORCE_UPDATA_FW + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } +#else + if(fwVersion > curVersion) + { + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } +#endif + +#endif + + + icn83xx_irq_enable(); + icn83xx_trace("====%s over1111=====. \n", __func__); +} +#endif + + +char FbCap[4][16]={ + {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, + {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}, + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, +}; + +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_suspend = 1; + //printk("\nclose backlight\n\n"); + //printk("disable irq\n\n"); + wmt_gpio_mask_irq(g_param.irqgpio); + break; + case BL_OPEN: + l_suspend = 0; + //printk("\nopen backlight\n\n"); + //printk("enable irq\n\n"); + wmt_gpio_unmask_irq(g_param.irqgpio); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int icn83xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct icn83xx_ts_data *icn83xx_ts; + short fwVersion = 0; + short curVersion = 0; + //int average; + int err = 0; + //char value; + int retry; + + icn83xx_trace("====%s begin=====. \n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + icn83xx_error("I2C check functionality failed.\n"); + return -ENODEV; + } + + icn83xx_ts = kzalloc(sizeof(*icn83xx_ts), GFP_KERNEL); + if (!icn83xx_ts) + { + icn83xx_error("Alloc icn83xx_ts memory failed.\n"); + return -ENOMEM; + } + + this_client = client; + i2c_set_clientdata(client, icn83xx_ts); + + icn83xx_ts->work_mode = 0; + spin_lock_init(&icn83xx_ts->irq_lock); + // icn83xx_ts->irq_lock = SPIN_LOCK_UNLOCKED; + + err = icn83xx_request_io_port(icn83xx_ts); + if (err != 0) { + icn83xx_error("icn83xx_request_io_port failed.\n"); + goto fail1; + } + + memset(firmware, 0, 128); + sprintf(firmware,"/system/etc/firmware/%s.bin",g_param.fw_name); + + icn83xx_ts_reset(); + err = icn83xx_iic_test(); + if (err < 0) + { + icn83xx_error("icn83xx_iic_test failed.\n"); +#if SUPPORT_FW_UPDATE + +#if COMPILE_FW_WITH_DRIVER + icn83xx_set_fw(sizeof(icn83xx_fw), &icn83xx_fw[0]); +#endif + if(icn83xx_check_progmod() == 0) + { + + retry = 5; + icn83xx_trace("in prog mode\n"); + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } + else // + { + icn83xx_error("I2C communication failed.\n"); + err = -1; + goto fail2; + } + +#endif + } + else + { + icn83xx_trace("iic communication ok\n"); + } + +#if SUPPORT_FW_UPDATE + fwVersion = icn83xx_read_fw_Ver(firmware); + curVersion = icn83xx_readVersion(); + icn83xx_trace("fwVersion : 0x%x\n", fwVersion); + icn83xx_trace("current version: 0x%x\n", curVersion); + + if (g_param.force_download) { + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } else { + if(fwVersion > curVersion) + { + retry = 5; + while(retry > 0) + { + if(R_OK == icn83xx_fw_update(firmware)) + { + break; + } + retry--; + icn83xx_error("icn83xx_fw_update failed.\n"); + } + } + } + +#endif + +#if SUPPORT_FW_CALIB + err = icn83xx_read_reg(0, &value); + if(err > 0) + { + //auto calib fw + average = icn83xx_calib(0, NULL); + //fix FbCap + // average = icn83xx_calib(0, FbCap[1]); + icn83xx_trace("average : %d\n", average); + icn83xx_setPeakGroup(250, 150); + icn83xx_setDownUp(400, 300); + } +#endif + + INIT_WORK(&icn83xx_ts->pen_event_work, icn83xx_ts_pen_irq_work); + icn83xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev)); + if (!icn83xx_ts->ts_workqueue) { + icn83xx_error("create_singlethread_workqueue failed.\n"); + err = -ESRCH; + goto fail3; + } + + err= icn83xx_request_input_dev(icn83xx_ts); + if (err < 0) + { + icn83xx_error("request input dev failed\n"); + goto fail4; + } + +#if TOUCH_VIRTUAL_KEYS + icn83xx_ts_virtual_keys_init(); +#endif + err = icn83xx_request_irq(icn83xx_ts); + if (err != 0) + { + printk("request irq error, use timer\n"); + icn83xx_ts->use_irq = 0; + hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn83xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } +#if SUPPORT_SYSFS + icn83xx_create_sysfs(client); +#endif + +#if SUPPORT_PROC_FS + sema_init(&icn83xx_ts->sem, 1); + init_proc_node(); +#endif + + err = device_create_file(&(client->dev), &dev_attr_dbg); + if (err) { + printk("Can't create attr file"); + } + if (g_param.earlysus_en) + register_bl_notifier(&wmt_bl_notify); + +#if SUPPORT_DELAYED_WORK + INIT_DELAYED_WORK(&icn83xx_ts->icn_delayed_work, icn_delayedwork_fun); + schedule_delayed_work(&icn83xx_ts->icn_delayed_work, msecs_to_jiffies(8000)); +#else + + icn83xx_irq_enable(); +#endif + icn83xx_trace("==%s over =\n", __func__); + return 0; + +fail4: + input_unregister_device(icn83xx_ts->input_dev); + input_free_device(icn83xx_ts->input_dev); +fail3: + cancel_work_sync(&icn83xx_ts->pen_event_work); +fail2: + icn83xx_free_io_port(); +fail1: + kfree(icn83xx_ts); + return err; +} + +static int __devexit icn83xx_ts_remove(struct i2c_client *client) +{ + struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(client); + icn83xx_trace("==icn83xx_ts_remove=\n"); + icn83xx_irq_disable(); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&icn83xx_ts->early_suspend); +#endif + + if (g_param.earlysus_en) + unregister_bl_notifier(&wmt_bl_notify); + +#if SUPPORT_PROC_FS + uninit_proc_node(); +#endif + + input_unregister_device(icn83xx_ts->input_dev); + input_free_device(icn83xx_ts->input_dev); + cancel_work_sync(&icn83xx_ts->pen_event_work); + destroy_workqueue(icn83xx_ts->ts_workqueue); + icn83xx_free_irq(icn83xx_ts); + icn83xx_free_io_port(); + kfree(icn83xx_ts); + i2c_set_clientdata(client, NULL); + return 0; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96; + char retval[200] = {0},*p=NULL,*s=NULL; + int Enable=0; + + // Get u-boot parameter + /*ret = wmt_getsyspara("wmt.io.zettouch", retval, &len); + if(ret){ + klog("Read wmt.io.zettouch Failed.\n"); + } else + goto paste;*/ + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + printk("Read wmt.io.touch Failed.\n"); + return -EIO; + } + +//paste: + p = retval; + Enable = (p[0] - '0' == 1) ? 1 : 0; + if(Enable == 0){ + printk("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(g_param.fw_name,p, (s-p)); + printk("ts_name=%s\n", g_param.fw_name); + if (strncmp(g_param.fw_name, "ICN83", 5)) { + printk("Wrong firmware name.\n"); + return -ENODEV; + } + + p = s+1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d", + &(g_param.irqgpio),&(g_param.panelres_x),&(g_param.panelres_y),&(g_param.rstgpio), + &(g_param.xyswap),&(g_param.xdir),&(g_param.ydir),&(g_param.force_download)); + + if (ret < 8) { + printk("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + printk("p.x = %d, p.y = %d, irqgpio=%d, rstgpio=%d,xyswap=%d,xdir=%d,ydir=%d,force_download=%d\n", + g_param.panelres_x,g_param.panelres_y,g_param.irqgpio,g_param.rstgpio, + g_param.xyswap,g_param.xdir,g_param.ydir,g_param.force_download); + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) + g_param.earlysus_en = (retval[0] - '0' == 1) ? 1 : 0; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + g_param.lcd_exchg = 1; + } + + return 0; +} + +static const struct dev_pm_ops icn83xx_pm_ops = { + .suspend = icn83xx_ts_suspend, + .resume = icn83xx_ts_resume, +}; + +static const struct i2c_device_id icn83xx_ts_id[] = { + { CTP_NAME, 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, icn83xx_ts_id); + +static struct i2c_driver icn83xx_ts_driver = { + .driver = { + .name = CTP_NAME, + .pm = &icn83xx_pm_ops, + }, + .probe = icn83xx_ts_probe, + .remove = __devexit_p(icn83xx_ts_remove), + .id_table = icn83xx_ts_id, +}; + +static struct i2c_board_info i2c_board_info = { + I2C_BOARD_INFO(CTP_NAME, ICN83XX_IIC_ADDR), +}; + +static int __init icn83xx_ts_init(void) +{ + struct i2c_client *client; + struct i2c_adapter *adap; + //u8 ts_data[8]; + + icn83xx_trace("===========================%s=====================\n", __func__); + if(wmt_check_touch_env()) + return -ENODEV; + {//register i2c device + adap = i2c_get_adapter(1); //i2c Bus 1 + if (!adap) + return -ENODEV; + client = i2c_new_device(adap, &i2c_board_info); + i2c_put_adapter(adap); + if (!client) { + printk("i2c_new_device error\n"); + return -ENODEV; + } + } + /*{ //check if IC exists + if (i2c_read_tsdata(client, ts_data, 8) <= 0) { + errlog("Can't find IC!\n"); + i2c_unregister_device(client); + return -ENODEV; + } + }*/ + return i2c_add_driver(&icn83xx_ts_driver); +} + +static void __exit icn83xx_ts_exit(void) +{ + icn83xx_trace("==icn83xx_ts_exit==\n"); + i2c_unregister_device(this_client); + return i2c_del_driver(&icn83xx_ts_driver); +} + +late_initcall(icn83xx_ts_init); +module_exit(icn83xx_ts_exit); + +MODULE_AUTHOR("<zmtian@chiponeic.com>"); +MODULE_DESCRIPTION("Chipone icn83xx TouchScreen driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h new file mode 100755 index 00000000..46a7cf21 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx.h @@ -0,0 +1,434 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn83xx.h + Abstract: + input driver. +Author: Zhimin Tian +Date : 01,17,2013 +Version: 1.0 +History : + 2012,10,30, V0.1 first version + + --*/ + +#ifndef __LINUX_ICN83XX_H__ +#define __LINUX_ICN83XX_H__ + +#include <linux/i2c.h> +#include <linux/input.h> +#ifdef CONFIG_HAS_EARLYSUSPEND + #include <linux/pm.h> + #include <linux/earlysuspend.h> +#endif +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/async.h> +#include <linux/hrtimer.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/hrtimer.h> +#include <linux/proc_fs.h> + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/fs.h> + #include <linux/semaphore.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/ioctl.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/spinlock_types.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include "../../../video/backlight/wmt_bl.h" + +//----------------------------------------------------------------------------- +// Pin Declarations +//----------------------------------------------------------------------------- + +#define SUPPORT_ROCKCHIP 0 + +#if SUPPORT_ROCKCHIP +#include <linux/irq.h> +#include <mach/irqs.h> +//#include <mach/system.h> +#include <mach/hardware.h> +//#include <mach/board.h> +#include <mach/gpio.h> + +#define CTP_IRQ_PORT RK30_PIN1_PB7 +#define CTP_IRQ_MODE 0 +#define CTP_RST_PORT RK30_PIN1_PA7 +#define CTP_WAKEUP_PORT 0 + //1: B protocol +#define SCREEN_MAX_X (800) +#define SCREEN_MAX_Y (480) +#define ICN83XX_I2C_SCL 400*1000 + +#endif + +#define CTP_REPORT_PROTOCOL 1 //0: A protocol + +//----------------------------------------------------------------------------- +// Global CONSTANTS +//----------------------------------------------------------------------------- + +#define TOUCH_VIRTUAL_KEYS 0 +#define SUPPORT_PROC_FS 1 +#define SUPPORT_SYSFS 1 +#define SUPPORT_FW_UPDATE 1 +#define COMPILE_FW_WITH_DRIVER 0 +#define FORCE_UPDATA_FW 0 +#define SUPPORT_FW_CALIB 0 +#define SUPPORT_DELAYED_WORK 0 + +#define ICN83XX_NAME "chipone-ts" +#define ICN83XX_PROG_IIC_ADDR (0x60>>1) +#define ICN83XX_IIC_ADDR (0x80>>1) +#define CTP_NAME ICN83XX_NAME + +#define CTP_RESET_LOW_PERIOD (5) +#define CTP_RESET_HIGH_PERIOD (100) +#define CTP_WAKEUP_LOW_PERIOD (20) +#define CTP_WAKEUP_HIGH_PERIOD (50) +#define CTP_POLL_TIMER (16) /* ms delay between samples */ +#define CTP_START_TIMER (100) /* ms delay between samples */ + +#define POINT_NUM 5 +#define POINT_SIZE 7 + +#define TS_KEY_HOME 102 +#define TS_KEY_MENU 139 +#define TS_KEY_BACK 158 +#define TS_KEY_SEARCH 217 + +#define ICN_VIRTUAL_BUTTON_HOME 0x02 +#define ICN_VIRTUAL_BUTTON_MENU 0x01 +#define ICN_VIRTUAL_BUTTON_BACK 0x04 +#define ICN_VIRTUAL_BUTTON_SEARCH 0x08 + +#define IIC_RETRY_NUM 3 + +//ICN83XX_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_HIBERNATE 0x02 + +#define B_SIZE 32 +#define ENABLE_BYTE_CHECK +//#define WAKE_PIN 1 +//----------------------------------------------------------------------------- +// Macro DEFINITIONS +//----------------------------------------------------------------------------- +#define DBG_ICN83XX_TRACE +//#define DBG_ICN83XX_POINT +//#define DBG_ICN83XX_INFO +#define DBG_ICN83XX_ERROR +#define DBG_FLASH_INFO +#define DBG_FLASH_ERROR +#define DBG_OP_INFO +#define DBG_OP_ERROR +#define DBG_CALIB_INFO +#define DBG_CALIB_ERROR +//#define DBG_PROC_INFO +#define DBG_PROC_ERROR + + +#ifdef DBG_ICN83XX_TRACE +#define icn83xx_trace(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_trace(fmt, args...) // +#endif + + +#ifdef DBG_ICN83XX_POINT +#define icn83xx_point_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_point_info(fmt, args...) // +#endif + +#ifdef DBG_ICN83XX_INFO +#define icn83xx_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_info(fmt, args...) // +#endif + +#ifdef DBG_ICN83XX_ERROR +#define icn83xx_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn83xx_error(fmt, args...) // +#endif + +#ifdef DBG_FLASH_INFO +#define flash_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_info(fmt, args...) // +#endif + +#ifdef DBG_FLASH_ERROR +#define flash_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_error(fmt, args...) // +#endif + + +#ifdef DBG_OP_INFO +#define op_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_info(fmt, args...) // +#endif +#ifdef DBG_OP_ERROR +#define op_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_error(fmt, args...) // +#endif + + +#ifdef DBG_CALIB_INFO +#define calib_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_info(fmt, args...) // +#endif + +#ifdef DBG_CALIB_ERROR +#define calib_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_error(fmt, args...) // +#endif + + +#ifdef DBG_PROC_INFO +#define proc_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_info(fmt, args...) // +#endif + +#ifdef DBG_PROC_ERROR +#define proc_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_error(fmt, args...) // +#endif + +#define swap_ab(a,b) {char temp;temp=a;a=b;b=temp;} +#define U16LOBYTE(var) (*(unsigned char *) &var) +#define U16HIBYTE(var) (*(unsigned char *)((unsigned char *) &var + 1)) + + + +//----------------------------------------------------------------------------- +// Struct, Union and Enum DEFINITIONS +//----------------------------------------------------------------------------- +typedef struct _POINT_INFO +{ + unsigned char u8ID; + unsigned short u16PosX; // coordinate X, plus 4 LSBs for precision extension + unsigned short u16PosY; // coordinate Y, plus 4 LSBs for precision extension + unsigned char u8Pressure; + unsigned char u8EventId; +}POINT_INFO; + +struct icn83xx_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct pen_event_work; + struct delayed_work icn_delayed_work; + struct workqueue_struct *ts_workqueue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct hrtimer timer; + spinlock_t irq_lock; + struct semaphore sem; + + POINT_INFO point_info[POINT_NUM+1]; + int point_num; + int irq; + int irq_is_disable; + int use_irq; + int work_mode; + int screen_max_x; + int screen_max_y; + int revert_x_flag; + int revert_y_flag; + int exchange_x_y_flag; + int (*init_wakeup_hw)(void); +}; + +struct touch_param { + char fw_name[32]; + int irqgpio; + int rstgpio; + int panelres_x; + int panelres_y; + int xyswap; + int xdir; + int ydir; + int max_finger_num; + int force_download; + int earlysus_en; + int dbg; + int lcd_exchg; +}; + +#pragma pack(1) +typedef struct{ + unsigned char wr; //write read flag£¬0:R 1:W + unsigned char flag; //0: + unsigned char circle; //polling cycle + unsigned char times; //plling times + unsigned char retry; //I2C retry times + unsigned int data_len; //data length + unsigned char addr_len; //address length + unsigned char addr[2]; //address + unsigned char* data; //data pointer +}pack_head; +#pragma pack() + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(pack_head) - sizeof(unsigned char *)) +#define ICN83XX_ENTRY_NAME "icn83xx_tool" +enum icn83xx_ts_regs { + ICN83XX_REG_PMODE = 0x04, /* Power Consume Mode */ +}; + +typedef enum +{ + R_OK = 100, + R_FILE_ERR, + R_STATE_ERR, + R_ERASE_ERR, + R_PROGRAM_ERR, + R_VERIFY_ERR, +}E_UPGRADE_ERR_TYPE; + +//----------------------------------------------------------------------------- +// Global VARIABLES +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Function PROTOTYPES +//----------------------------------------------------------------------------- + +void icn83xx_ts_reset(void); +int icn83xx_i2c_rxdata(unsigned char addr, char *rxdata, int length); +int icn83xx_i2c_txdata(unsigned char addr, char *txdata, int length); +int icn83xx_write_reg(unsigned char addr, char para); +int icn83xx_read_reg(unsigned char addr, char *pdata); +int icn83xx_prog_i2c_rxdata(unsigned short addr, char *rxdata, int length); +int icn83xx_prog_i2c_txdata(unsigned short addr, char *txdata, int length); +int icn83xx_prog_write_reg(unsigned short addr, char para); +int icn83xx_prog_read_reg(unsigned short addr, char *pdata); +#if SUPPORT_FW_UPDATE + +int icn83xx_writeInfo(unsigned short addr, char value); +int icn83xx_readInfo(unsigned short addr, char *value); +int icn83xx_writeReg(unsigned short addr, char value); +int icn83xx_readReg(unsigned short addr, char *value); +int icn83xx_readVersion(void); +int icn83xx_changemode(char mode); +int icn83xx_readrawdata(char *buffer, char row, char length); +int icn83xx_readTP(char row_num, char column_num, char *buffer); +int icn83xx_scanTP(void); +void icn83xx_rawdatadump(short *mem, int size, char br); +void icn83xx_set_fw(int size, unsigned char *buf); +void icn83xx_memdump(char *mem, int size); +int icn83xx_checksum(int sum, char *buf, unsigned int size); +int icn83xx_update_status(int status); +int icn83xx_get_status(void); +int icn83xx_open_fw( char *fw); +int icn83xx_read_fw(int offset, int length, char *buf); +int icn83xx_close_fw(void); +int icn83xx_goto_progmode(void); +int icn83xx_check_progmod(void); +int icn83xx_uu(void); +void icn83xx_ll(void); +int icn83xx_op1(char info, unsigned short offset, unsigned int size); +int icn83xx_op2(char info, unsigned short offset, unsigned char * buffer, unsigned int size); +int icn83xx_op3(char info, unsigned short offset, unsigned char * buffer, unsigned int size); +short icn83xx_read_fw_Ver(char *fw); +E_UPGRADE_ERR_TYPE icn83xx_fw_update(char *fw); +#endif + +#if SUPPORT_FW_CALIB + +int icn83xx_checkrawdata(short *data, char num); +int icn83xx_readpara(char *TxOrder, char row, char *RxOrder, char column); +int icn83xx_writepara(char *TxOrder, char row, char *RxOrder, char column); +int icn83xx_readFB(char *FB, char num); +int icn83xx_writeFB(char *FB, char num); +int icn83xx_readDC(char *DC, char num); +int icn83xx_writeDC(char *DC, char num); +int icn83xx_readPhaseDelay(char *PD, char row, char length); +int icn83xx_writePhaseDelay(char *PD, char row, char length); +int icn83xx_changeDCflag(char flag); +int icn83xx_readVkmode(char *vkmode, char *vknum); +int icn83xx_setTarget(short target); +int icn83xx_setPeakGroup(short peak, short group); +int icn83xx_setDownUp(short down, short up); +int icn83xx_average(short *data, char num); + +int icn83xx_calib(char index, char *FB); +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h new file mode 100755 index 00000000..572bf1f3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn83xx_ts/icn83xx_fw.h @@ -0,0 +1,3 @@ +static unsigned char icn83xx_fw[] = { + +};
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig new file mode 100755 index 00000000..593b379b --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Kconfig @@ -0,0 +1,16 @@ +# +# ICN85XX capacity touch screen driver configuration +# +config TOUCHSCREEN_ICN85XX + tristate "ICN85XX I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_icn85xx + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile new file mode 100755 index 00000000..4f2c65ce --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_icn85xx
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := icn85xx.o icn85xx_flash.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c new file mode 100755 index 00000000..371742fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.c @@ -0,0 +1,2431 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn85xx.c + Abstract: + input driver. + Author: Zhimin Tian + Date : 08,14,2013 + Version: 1.0 + History : + 2012,10,30, V0.1 first version + --*/ + +#include "icn85xx.h" +#include "icn85xx_fw.h" +//#include "icn85xx_00_ht_0528.h" +//#include "icn85xx_02_lh_0528.h" + +#if COMPILE_FW_WITH_DRIVER + static char firmware[128] = "icn85xx_firmware"; +#else + #if SUPPORT_SENSOR_ID + static char firmware[128] = {0}; + #else + //static char firmware[128] = {"/misc/modules/ICN8505.BIN"}; + //static char firmware[128] = {"/system/etc/firmware/ICN8505.bin"}; + static char firmware[128] = {"ICN8505.bin"}; + #endif +#endif + +#if SUPPORT_SENSOR_ID + char cursensor_id,tarsensor_id,id_match; + char invalid_id = 0; + + struct sensor_id { + char value; + const char bin_name[128]; + unsigned char *fw_name; + int size; + }; + +static struct sensor_id sensor_id_table[] = { + { 0x00, "/misc/modules/ICN8505_00_name1.BIN",fw_00_ht_0528,sizeof(fw_00_ht_0528)},//default bin or fw + { 0x02, "/misc/modules/ICN8505_02_name3.BIN",fw_02_lh_0528,sizeof(fw_02_lh_0528)}, + + // if you want support other sensor id value ,please add here + }; +#endif +struct i2c_client *this_client; +short log_basedata[COL_NUM][ROW_NUM] = {{0,0}}; +short log_rawdata[COL_NUM][ROW_NUM] = {{0,0}}; +short log_diffdata[COL_NUM][ROW_NUM] = {{0,0}}; +unsigned int log_on_off = 0; +static struct touch_param g_param; +static struct wake_lock downloadWakeLock; +static struct task_struct *resume_download_task; +static int bl_is_delay = 0; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + //yank added + void icn85xx_charge_mode(void) + { + printk("yank---%s\n",__func__); + icn85xx_write_reg(ICN85xx_REG_PMODE, 0x55); + } + EXPORT_SYMBOL(icn85xx_charge_mode); + + void icn85xx_discharge_mode(void) + { + printk("yank---%s\n",__func__); + icn85xx_write_reg(ICN85xx_REG_PMODE, 0x66); + } + EXPORT_SYMBOL(icn85xx_discharge_mode); + + +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer); +#if SUPPORT_SYSFS +static ssize_t icn85xx_show_update(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn85xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len); +static ssize_t icn85xx_show_process(struct device* cd,struct device_attribute *attr, char* buf); +static ssize_t icn85xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len); + +static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn85xx_show_update, icn85xx_store_update); +static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn85xx_show_process, icn85xx_store_process); + +static ssize_t icn85xx_show_process(struct device* cd,struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, "icn85xx process\n"); + ret = strlen(buf) + 1; + return ret; +} + +static ssize_t icn85xx_store_process(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + unsigned long on_off = simple_strtoul(buf, NULL, 10); + + log_on_off = on_off; + memset(&log_basedata[0][0], 0, COL_NUM*ROW_NUM*2); + if(on_off == 0) + { + icn85xx_ts->work_mode = 0; + } + else if((on_off == 1) || (on_off == 2) || (on_off == 3)) + { + if((icn85xx_ts->work_mode == 0) && (icn85xx_ts->use_irq == 1)) + { + hrtimer_init(&icn85xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn85xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + icn85xx_ts->work_mode = on_off; + } + else if(on_off == 10) + { + icn85xx_ts->work_mode = 4; + mdelay(10); + printk("update baseline\n"); + icn85xx_write_reg(4, 0x30); + icn85xx_ts->work_mode = 0; + } + else + { + icn85xx_ts->work_mode = 0; + } + + + return len; +} + +static ssize_t icn85xx_show_update(struct device* cd, + struct device_attribute *attr, char* buf) +{ + ssize_t ret = 0; + sprintf(buf, firmware); + ret = strlen(buf) + 1; + printk("firmware: %s, ret: %d\n", firmware, ret); + + return ret; +} + +static ssize_t icn85xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len) +{ + printk("len: %d, update: %s\n", len, buf); + memset(firmware, 0, 128); + memcpy(firmware, buf, len-1); + if(R_OK == icn85xx_fw_update(firmware)) + { + printk("update ok\n"); + } + else + { + printk("update error\n"); + } + return len; +} + +static int icn85xx_create_sysfs(struct i2c_client *client) +{ + int err; + struct device *dev = &(client->dev); + icn85xx_trace("%s: \n",__func__); + err = device_create_file(dev, &dev_attr_update); + err = device_create_file(dev, &dev_attr_process); + return err; +} + +static void icn85xx_remove_sysfs(struct i2c_client *client) +{ + struct device *dev = &(client->dev); + icn85xx_trace("%s: \n",__func__); + device_remove_file(dev, &dev_attr_update); + device_remove_file(dev, &dev_attr_process); +} +#endif + +#if SUPPORT_PROC_FS + +pack_head cmd_head; +static struct proc_dir_entry *icn85xx_proc_entry; +int DATA_LENGTH = 0; + +STRUCT_PANEL_PARA_H g_structPanelPara; + +static int icn85xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data) +{ + int ret = 0; + int i; + unsigned short addr; + char retvalue; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + proc_info("%s \n",__func__); + if(down_interruptible(&icn85xx_ts->sem)) + { + return -1; + } + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + else + { + ret = CMD_HEAD_LENGTH; + } + + proc_info("wr :0x%02x.\n", cmd_head.wr); + proc_info("flag:0x%02x.\n", cmd_head.flag); + proc_info("circle :%d.\n", (int)cmd_head.circle); + proc_info("times :%d.\n", (int)cmd_head.times); + proc_info("retry :%d.\n", (int)cmd_head.retry); + proc_info("data len:%d.\n", (int)cmd_head.data_len); + proc_info("addr len:%d.\n", (int)cmd_head.addr_len); + proc_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]); + proc_info("len:%d.\n", (int)len); + proc_info("data:0x%02x%02x.\n", buff[CMD_HEAD_LENGTH], buff[CMD_HEAD_LENGTH+1]); + if (1 == cmd_head.wr) // write para + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + //need copy to g_structPanelPara + + memcpy(&g_structPanelPara, &cmd_head.data[0], cmd_head.data_len); + //write para to tp + for(i=0; i<cmd_head.data_len; ) + { + 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) { + proc_error("write para failed!\n"); + goto write_out; + } + i = i + 64; + } + + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + icn85xx_ts->work_mode = 5; //reinit + printk("reinit tp\n"); + icn85xx_write_reg(0, 1); + mdelay(100); + icn85xx_write_reg(0, 0); + icn85xx_ts->work_mode = 0; + goto write_out; + + } + else if(3 == cmd_head.wr) //set update file + { + proc_info("cmd_head_.wr == 3 \n"); + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + memset(firmware, 0, 128); + memcpy(firmware, &cmd_head.data[0], cmd_head.data_len); + proc_info("firmware : %s\n", firmware); + } + else if(5 == cmd_head.wr) //start update + { + proc_info("cmd_head_.wr == 5 \n"); + icn85xx_update_status(1); + ret = kernel_thread(icn85xx_fw_update,firmware,CLONE_KERNEL); + icn85xx_trace("the kernel_thread result is:%d\n", ret); + } + else if(11 == cmd_head.wr) //write hostcomm + { + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if(ret) + { + proc_error("copy_from_user failed.\n"); + goto write_out; + } + addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0]; + icn85xx_write_reg(addr, cmd_head.data[0]); + } + else if(13 == cmd_head.wr) //adc enable + { + proc_info("cmd_head_.wr == 13 \n"); + icn85xx_ts->work_mode = 4; + mdelay(10); + //set col + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8ColNum), 1); + //u8RXOrder[0] = u8RXOrder[cmd_head.addr[0]]; + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8RXOrder[0]), g_structPanelPara.u8RXOrder[cmd_head.addr[0]]); + //set row + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8RowNum), 1); + //u8TXOrder[0] = u8TXOrder[cmd_head.addr[1]]; + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8TXOrder[0]), g_structPanelPara.u8TXOrder[cmd_head.addr[1]]); + //scan mode + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8ScanMode), 0); + //bit + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16BitFreq), 0xD0); + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16BitFreq)+1, 0x07); + //freq + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16FreqCycleNum[0]), 0x64); + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u16FreqCycleNum[0])+1, 0x00); + //pga + icn85xx_write_reg(0x8000+STRUCT_OFFSET(STRUCT_PANEL_PARA_H, u8PgaGain), 0x0); + + //config mode + icn85xx_write_reg(0, 0x2); + + mdelay(1); + icn85xx_read_reg(2, &retvalue); + printk("retvalue0: %d\n", retvalue); + while(retvalue != 1) + { + printk("retvalue: %d\n", retvalue); + mdelay(1); + icn85xx_read_reg(2, &retvalue); + } + + if(icn85xx_goto_progmode() != 0) + { + printk("icn85xx_goto_progmode() != 0 error\n"); + goto write_out; + } + + icn85xx_prog_write_reg(0x040870, 1); + + } + +write_out: + up(&icn85xx_ts->sem); + proc_info("icn85xx_tool_write write_out \n"); + return len; + +} + +static int icn85xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int i, j; + int ret = 0; + + char row, column, retvalue; + unsigned short addr; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + if(down_interruptible(&icn85xx_ts->sem)) + { + return -1; + } + proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count,(int)off,(int)cmd_head.data_len); + if (cmd_head.wr % 2) + { + ret = 0; + proc_info("cmd_head_.wr == 1111111 \n"); + goto read_out; + } + else if (0 == cmd_head.wr) //read para + { + //read para + proc_info("cmd_head_.wr == 0 \n"); + ret = icn85xx_i2c_rxdata(0x8000, &page[0], cmd_head.data_len); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + } + memcpy(&g_structPanelPara, &page[0], sizeof(g_structPanelPara)); + goto read_out; + + } + else if(2 == cmd_head.wr) //get update status + { + proc_info("cmd_head_.wr == 2 \n"); + page[0] = icn85xx_get_status(); + proc_info("status: %d\n", page[0]); + } + else if(4 == cmd_head.wr) //read rawdata + { + //icn85xx_read_reg(0x8004, &row); + //icn85xx_read_reg(0x8005, &column); + proc_info("cmd_head_.wr == 4 \n"); + row = cmd_head.addr[1]; + column = cmd_head.addr[0]; + //scan tp rawdata + icn85xx_write_reg(4, 0x20); + mdelay(1); + for(i=0; i<1000; i++) + { + mdelay(1); + icn85xx_read_reg(2, &retvalue); + if(retvalue == 1) + break; + } + + for(i=0; i<row; i++) + { + ret = icn85xx_i2c_rxdata(0x2000 + i*(COL_NUM)*2,(char *) &log_rawdata[i][0], column*2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + } + //icn85xx_rawdatadump(&log_rawdata[i][0], column, COL_NUM); + memcpy(&page[column*2*i], &log_rawdata[i][0], column*2); + + } + + //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 + { + proc_info("cmd_head_.wr == 6 \n"); + row = cmd_head.addr[1]; + column = cmd_head.addr[0]; + + //scan tp rawdata + icn85xx_write_reg(4, 0x20); + mdelay(1); + + for(i=0; i<1000; i++) + { + mdelay(1); + icn85xx_read_reg(2, &retvalue); + if(retvalue == 1) + break; + } + + for(i=0; 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) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + } + //icn85xx_rawdatadump(&log_diffdata[i][0], column, COL_NUM); + memcpy(&page[column*2*i], &log_diffdata[i][0], column*2); + } + //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 + { + proc_info("cmd_head_.wr == 8 \n"); + row = cmd_head.addr[1]; + column = cmd_head.addr[0]; + //scan tp rawdata + icn85xx_write_reg(4, 0x20); + mdelay(1); + for(i=0; i<1000; i++) + { + mdelay(1); + icn85xx_read_reg(2, &retvalue); + if(retvalue == 1) + break; + } + + for(i=0; i<row; i++) + { + ret = icn85xx_i2c_rxdata(0x2000 + i*(COL_NUM)*2,(char *) &log_rawdata[i][0], column*2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + } + + } + + //finish scan tp rawdata + 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*(COL_NUM)*2,(char *) &log_diffdata[i][0], column*2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + } + for(j=0; j<column; j++) + { + *(short *)&page[2*(column*i +j)] = log_rawdata[i][j] - log_diffdata[i][j]; + } + + } + + //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 + { + if(cmd_head.flag == 0) + { + icn85xx_prog_write_reg(0x040874, 0); + } + icn85xx_prog_i2c_rxdata(2500*cmd_head.flag ,&page[0], cmd_head.data_len); + //icn85xx_rawdatadump(&page[0], 1024, 16); + if(cmd_head.flag == 9) + { + //reload code + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_ts->code_loaded_flag = 1; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code ok\n"); + } + else + { + icn85xx_ts->code_loaded_flag = 0; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code error\n"); + } + } + else + { + icn85xx_bootfrom_flash(); + msleep(50); + } + icn85xx_ts->work_mode = 0; + } + } + else if(12 == cmd_head.wr) //read hostcomm + { + proc_info("cmd_head_.wr == 12 \n"); + addr = (cmd_head.addr[1]<<8) | cmd_head.addr[0]; + icn85xx_read_reg(addr, &retvalue); + page[0] = retvalue; + } + else if(14 == cmd_head.wr) //read adc status + { + proc_info("cmd_head_.wr == 14 \n"); + icn85xx_prog_read_reg(0x4085E, &retvalue); + page[0] = retvalue; + printk("0x4085E: 0x%x\n", retvalue); + } +read_out: + up(&icn85xx_ts->sem); + proc_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len); + return cmd_head.data_len; +} + +void init_proc_node(void) +{ + int i; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 5; + while ((!cmd_head.data) && i) + { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL != cmd_head.data) + { + break; + } + i--; + } + if (i) + { + //DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH; + DATA_LENGTH = i * DATA_LENGTH_UINT; + icn85xx_trace("alloc memory size:%d.\n", DATA_LENGTH); + } + else + { + proc_error("alloc for memory failed.\n"); + return ; + } + + icn85xx_proc_entry = create_proc_entry(ICN85xx_ENTRY_NAME, 0666, NULL); + if (icn85xx_proc_entry == NULL) + { + proc_error("Couldn't create proc entry!\n"); + return ; + } + else + { + icn85xx_trace("Create proc entry success!\n"); + icn85xx_proc_entry->write_proc = icn85xx_tool_write; + icn85xx_proc_entry->read_proc = icn85xx_tool_read; + } + + return ; +} + +void uninit_proc_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + remove_proc_entry(ICN85xx_ENTRY_NAME, NULL); +} + +#endif + + +#if TOUCH_VIRTUAL_KEYS +static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":280:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":470:1030:50:60" + ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":900:1030:50:60" + "\n"); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys.chipone-ts", + .mode = S_IRUGO, + }, + .show = &virtual_keys_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + +static void icn85xx_ts_virtual_keys_init(void) +{ + int ret; + struct kobject *properties_kobj; + properties_kobj = kobject_create_and_add("board_properties", NULL); + if (properties_kobj) + ret = sysfs_create_group(properties_kobj, + &properties_attr_group); + if (!properties_kobj || ret) + pr_err("failed to create board_properties\n"); +} +#endif + + + + +/* --------------------------------------------------------------------- +* +* Chipone panel related driver +* +* +----------------------------------------------------------------------*/ +/*********************************************************************************************** +Name : icn85xx_ts_wakeup +Input : void +Output : ret +function : this function is used to wakeup tp +***********************************************************************************************/ +void icn85xx_ts_wakeup(void) +{ + + + +} + +/*********************************************************************************************** +Name : icn85xx_ts_reset +Input : void +Output : ret +function : this function is used to reset tp, you should not delete it +***********************************************************************************************/ +void icn85xx_ts_reset(void) +{ + //set reset func + + int rst = g_param.rstgpio; + gpio_direction_output(rst,0); + msleep(50); + icn85xx_info("[%s]:>>>>>>>>>>>>>>>>>CTP_RST_PORT = %d;msleep(50);\n",__func__,gpio_get_value(rst)); + gpio_direction_output(rst,1); + msleep(70); + icn85xx_info("[%s]:>>>>>>>>>>>>>>>>>CTP_RST_PORT = %d;msleep(70);\n",__func__,gpio_get_value(rst)); + +} + +/*********************************************************************************************** +Name : icn85xx_irq_disable +Input : void +Output : ret +function : this function is used to disable irq +***********************************************************************************************/ +void icn85xx_irq_disable(void) +{ + unsigned long irqflags; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn85xx_ts->irq_lock, irqflags); + if (!icn85xx_ts->irq_is_disable) + { + icn85xx_ts->irq_is_disable = 1; + wmt_gpio_mask_irq(g_param.irqgpio); + //disable_irq_nosync(icn85xx_ts->irq); + //disable_irq(icn85xx_ts->irq); + } + spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags); + +} + +/*********************************************************************************************** +Name : icn85xx_irq_enable +Input : void +Output : ret +function : this function is used to enable irq +***********************************************************************************************/ +void icn85xx_irq_enable(void) +{ + unsigned long irqflags = 0; + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + + spin_lock_irqsave(&icn85xx_ts->irq_lock, irqflags); + if (icn85xx_ts->irq_is_disable) + { + wmt_gpio_unmask_irq(g_param.irqgpio); + //enable_irq(icn85xx_ts->irq); + icn85xx_ts->irq_is_disable = 0; + } + spin_unlock_irqrestore(&icn85xx_ts->irq_lock, irqflags); + +} + +/*********************************************************************************************** +Name : icn85xx_prog_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn85xx, prog mode +***********************************************************************************************/ +int icn85xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; +#if 0 + struct i2c_msg msgs[] = { + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + icn85xx_prog_i2c_txdata(addr, NULL, 0); + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 1); + if(ret == 1)break; + retries++; + } + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#else + unsigned char tmp_buf[3]; + struct i2c_msg msgs[] = { + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = 3, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + tmp_buf[0] = (unsigned char)(addr>>16); + tmp_buf[1] = (unsigned char)(addr>>8); + tmp_buf[2] = (unsigned char)(addr); + + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#endif + return ret; +} +/*********************************************************************************************** +Name : icn85xx_prog_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn85xx , prog mode +***********************************************************************************************/ +int icn85xx_prog_i2c_txdata(unsigned int addr, char *txdata, int length) +{ + int ret = -1; + char tmp_buf[128]; + int retries = 0; + struct i2c_msg msg[] = { + { + .addr = ICN85XX_PROG_IIC_ADDR,//this_client->addr, + .flags = 0, + .len = length + 3, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn85xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = (unsigned char)(addr>>16); + tmp_buf[1] = (unsigned char)(addr>>8); + tmp_buf[2] = (unsigned char)(addr); + + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[3], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c write error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } + return ret; +} +/*********************************************************************************************** +Name : icn85xx_prog_write_reg +Input : addr -- address + para -- parameter +Output : +function : write register of icn85xx, prog mode +***********************************************************************************************/ +int icn85xx_prog_write_reg(unsigned int addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn85xx_prog_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn85xx_error("%s write reg failed! %#x ret: %d\n", __func__, buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn85xx_prog_read_reg +Input : addr + pdata +Output : +function : read register of icn85xx, prog mode +***********************************************************************************************/ +int icn85xx_prog_read_reg(unsigned int addr, char *pdata) +{ + int ret = -1; + ret = icn85xx_prog_i2c_rxdata(addr, pdata, 1); + return ret; +} + +/*********************************************************************************************** +Name : icn85xx_i2c_rxdata +Input : addr + *rxdata + length +Output : ret +function : read data from icn85xx, normal mode +***********************************************************************************************/ +int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length) +{ + int ret = -1; + int retries = 0; + unsigned char tmp_buf[2]; +#if 0 + + struct i2c_msg msgs[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + { + .addr = this_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxdata, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + tmp_buf[0] = (unsigned char)(addr>>8); + tmp_buf[1] = (unsigned char)(addr); + + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msgs, 2); + if(ret == 2)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#else + + tmp_buf[0] = (unsigned char)(addr>>8); + tmp_buf[1] = (unsigned char)(addr); + + while(retries < IIC_RETRY_NUM) + { + // ret = i2c_transfer(this_client->adapter, msgs, 2); + ret = i2c_master_send(this_client, tmp_buf, 2); + if (ret < 0) + return ret; + ret = i2c_master_recv(this_client, rxdata, length); + if (ret < 0) + return ret; + if(ret == length)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c read error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } +#endif + + return ret; +} +/*********************************************************************************************** +Name : icn85xx_i2c_txdata +Input : addr + *rxdata + length +Output : ret +function : send data to icn85xx , normal mode +***********************************************************************************************/ +int icn85xx_i2c_txdata(unsigned short addr, char *txdata, int length) +{ + int ret = -1; + unsigned char tmp_buf[128]; + int retries = 0; + + struct i2c_msg msg[] = { + { + .addr = this_client->addr, + .flags = 0, + .len = length + 2, + .buf = tmp_buf, +#if SUPPORT_ROCKCHIP + .scl_rate = ICN85XX_I2C_SCL, +#endif + }, + }; + + if (length > 125) + { + icn85xx_error("%s too big datalen = %d!\n", __func__, length); + return -1; + } + + tmp_buf[0] = (unsigned char)(addr>>8); + tmp_buf[1] = (unsigned char)(addr); + + if (length != 0 && txdata != NULL) + { + memcpy(&tmp_buf[2], txdata, length); + } + + while(retries < IIC_RETRY_NUM) + { + ret = i2c_transfer(this_client->adapter, msg, 1); + if(ret == 1)break; + retries++; + } + + if (retries >= IIC_RETRY_NUM) + { + icn85xx_error("%s i2c write error: %d\n", __func__, ret); +// icn85xx_ts_reset(); + } + + return ret; +} + +/*********************************************************************************************** +Name : icn85xx_write_reg +Input : addr -- address + para -- parameter +Output : +function : write register of icn85xx, normal mode +***********************************************************************************************/ +int icn85xx_write_reg(unsigned short addr, char para) +{ + char buf[3]; + int ret = -1; + + buf[0] = para; + ret = icn85xx_i2c_txdata(addr, buf, 1); + if (ret < 0) { + icn85xx_error("write reg failed! %#x ret: %d\n", buf[0], ret); + return -1; + } + + return ret; +} + + +/*********************************************************************************************** +Name : icn85xx_read_reg +Input : addr + pdata +Output : +function : read register of icn85xx, normal mode +***********************************************************************************************/ +int icn85xx_read_reg(unsigned short addr, char *pdata) +{ + int ret = -1; + ret = icn85xx_i2c_rxdata(addr, pdata, 1); + if(ret < 0) + { + icn85xx_error("addr: 0x%x: 0x%x\n", addr, *pdata); + } + return ret; +} + + +/*********************************************************************************************** +Name : icn85xx_log +Input : 0: rawdata, 1: diff data +Output : err type +function : calibrate param +***********************************************************************************************/ +static void icn85xx_log(char diff) +{ + char row = 0; + char column = 0; + int i, j, ret; + char retvalue = 0; + + icn85xx_read_reg(0x8004, &row); + icn85xx_read_reg(0x8005, &column); + + //scan tp rawdata + icn85xx_write_reg(4, 0x20); + mdelay(1); + for(i=0; i<1000; i++) + { + mdelay(1); + icn85xx_read_reg(2, &retvalue); + if(retvalue == 1) + break; + } + if(diff == 0) + { + for(i=0; i<row; i++) + { + ret = icn85xx_i2c_rxdata(0x2000 + i*COL_NUM*2, (char *)&log_rawdata[i][0], column*2); + if (ret < 0) { + icn85xx_error("%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) { + icn85xx_error("%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) { + icn85xx_error("%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); +} + + +/*********************************************************************************************** +Name : icn85xx_iic_test +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_iic_test(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + int ret = -1; + char value = 0; + int retry = 0; + int flashid; + icn85xx_ts->ictype = 0; + icn85xx_trace("====%s begin=====. \n", __func__); + + while(retry++ < 3) + { + ret = icn85xx_read_reg(0xa, &value); + if(ret > 0) + { + if(value == 0x85) + { + icn85xx_ts->ictype = ICN85XX_WITH_FLASH; + return ret; + } + } + + icn85xx_info("iic test error! retry = %d\n", retry); + msleep(3); + } + icn85xx_goto_progmode(); + msleep(10); + retry = 0; + while(retry++ < 3) + { + ret = icn85xx_prog_i2c_rxdata(0x040002, &value, 1); + icn85xx_info("icn85xx_check_progmod: 0x%x\n", value); + if(ret > 0) + { + if(value == 0x85) + { + flashid = icn85xx_read_flashid(); + if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid) + ||(MD25D20_ID1 == flashid) || (MD25D20_ID1 == flashid) + ||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid)) + { + icn85xx_ts->ictype = ICN85XX_WITH_FLASH; + } + else + { + icn85xx_ts->ictype = ICN85XX_WITHOUT_FLASH; + } + return ret; + } + } + icn85xx_error("iic2 test error! %d\n", retry); + msleep(3); + } + + return ret; +} + +#if !CTP_REPORT_PROTOCOL +/*********************************************************************************************** +Name : icn85xx_ts_release +Input : void +Output : +function : touch release +***********************************************************************************************/ +static void icn85xx_ts_release(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + icn85xx_info("==icn85xx_ts_release ==\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_sync(icn85xx_ts->input_dev); +} + +/*********************************************************************************************** +Name : icn85xx_report_value_A +Input : void +Output : +function : reprot touch ponit +***********************************************************************************************/ +static void icn85xx_report_value_A(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + int ret = -1; + int i; +#if TOUCH_VIRTUAL_KEYS + unsigned char button; + static unsigned char button_last; +#endif + + icn85xx_info("==icn85xx_report_value_A ==\n"); + + ret = icn85xx_i2c_rxdata(0x1000, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ; + } +#if TOUCH_VIRTUAL_KEYS + button = buf[0]; + icn85xx_info("%s: button=%d\n",__func__, button); + + if((button_last != 0) && (button == 0)) + { + icn85xx_ts_release(); + button_last = button; + return ; + } + if(button != 0) + { + switch(button) + { + case ICN_VIRTUAL_BUTTON_HOME: + icn85xx_info("ICN_VIRTUAL_BUTTON_HOME down\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 280); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + input_sync(icn85xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_BACK: + icn85xx_info("ICN_VIRTUAL_BUTTON_BACK down\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 470); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + input_sync(icn85xx_ts->input_dev); + break; + case ICN_VIRTUAL_BUTTON_MENU: + icn85xx_info("ICN_VIRTUAL_BUTTON_MENU down\n"); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 100); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 1030); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + input_sync(icn85xx_ts->input_dev); + break; + default: + icn85xx_info("other gesture\n"); + break; + } + button_last = button; + return ; + } +#endif + + icn85xx_ts->point_num = buf[1]; + if (icn85xx_ts->point_num == 0) { + icn85xx_ts_release(); + return ; + } + for(i=0;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++) + { + icn85xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u16PosX = (buf[4 + POINT_SIZE*i]<<8) + buf[3 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u16PosY = (buf[6 + POINT_SIZE*i]<<8) + buf[5 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u8Pressure = 20;//buf[7 + POINT_SIZE*i]; + icn85xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i]; + + if(1 == icn85xx_ts->revert_x_flag) + { + icn85xx_ts->point_info[i].u16PosX = icn85xx_ts->screen_max_x- icn85xx_ts->point_info[i].u16PosX; + } + if(1 == icn85xx_ts->revert_y_flag) + { + icn85xx_ts->point_info[i].u16PosY = icn85xx_ts->screen_max_y- icn85xx_ts->point_info[i].u16PosY; + } + + icn85xx_info("u8ID %d\n", icn85xx_ts->point_info[i].u8ID); + icn85xx_info("u16PosX %d\n", icn85xx_ts->point_info[i].u16PosX); + icn85xx_info("u16PosY %d\n", icn85xx_ts->point_info[i].u16PosY); + icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[i].u8Pressure); + icn85xx_info("u8EventId %d\n", icn85xx_ts->point_info[i].u8EventId); + + + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, icn85xx_ts->point_info[i].u8ID); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn85xx_ts->point_info[i].u8Pressure); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, icn85xx_ts->point_info[i].u16PosX); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, icn85xx_ts->point_info[i].u16PosY); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1); + input_mt_sync(icn85xx_ts->input_dev); + icn85xx_point_info("point: %d ===x = %d,y = %d, press = %d ====\n",i, icn85xx_ts->point_info[i].u16PosX,icn85xx_ts->point_info[i].u16PosY, icn85xx_ts->point_info[i].u8Pressure); + } + + input_sync(icn85xx_ts->input_dev); + +} +#endif +/*********************************************************************************************** +Name : icn85xx_report_value_B +Input : void +Output : +function : reprot touch ponit +***********************************************************************************************/ +#if CTP_REPORT_PROTOCOL +static void icn85xx_report_value_B(void) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); + char buf[POINT_NUM*POINT_SIZE+3]={0}; + static unsigned char finger_last[POINT_NUM + 1]={0}; + unsigned char finger_current[POINT_NUM + 1] = {0}; + unsigned int position = 0; + int temp = 0; + int ret = -1; + int x,y; + icn85xx_info("==icn85xx_report_value_B ==\n"); + + + + ret = icn85xx_i2c_rxdata(0x1000, buf, POINT_NUM*POINT_SIZE+2); + if (ret < 0) { + icn85xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret); + return ; + } + icn85xx_ts->point_num = buf[1]; + if (icn85xx_ts->point_num > POINT_NUM) + { + return ; + } + + if(icn85xx_ts->point_num > 0) + { + for(position = 0; position<icn85xx_ts->point_num; position++) + { + temp = buf[2 + POINT_SIZE*position] + 1; + finger_current[temp] = 1; + icn85xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u16PosX = (buf[4 + POINT_SIZE*position]<<8) + buf[3 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u16PosY = (buf[6 + POINT_SIZE*position]<<8) + buf[5 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position]; + icn85xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position]; + + if(icn85xx_ts->point_info[temp].u8EventId == 4) + finger_current[temp] = 0; + + if(1 == icn85xx_ts->revert_x_flag) + { + icn85xx_ts->point_info[temp].u16PosX = icn85xx_ts->screen_max_x- icn85xx_ts->point_info[temp].u16PosX; + } + if(1 == icn85xx_ts->revert_y_flag) + { + icn85xx_ts->point_info[temp].u16PosY = icn85xx_ts->screen_max_y- icn85xx_ts->point_info[temp].u16PosY; + } + icn85xx_info("temp %d\n", temp); + icn85xx_info("u8ID %d\n", icn85xx_ts->point_info[temp].u8ID); + icn85xx_info("u16PosX %d\n", icn85xx_ts->point_info[temp].u16PosX); + icn85xx_info("u16PosY %d\n", icn85xx_ts->point_info[temp].u16PosY); + icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure); + icn85xx_info("u8EventId %d\n", icn85xx_ts->point_info[temp].u8EventId); + //icn85xx_info("u8Pressure %d\n", icn85xx_ts->point_info[temp].u8Pressure*16); + } + } + else + { + for(position = 1; position < POINT_NUM+1; position++) + { + finger_current[position] = 0; + } + icn85xx_info("no touch\n"); + } + + for(position = 1; position < POINT_NUM + 1; position++) + { + if((finger_current[position] == 0) && (finger_last[position] != 0)) + { + input_mt_slot(icn85xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, false); + icn85xx_point_info("one touch up: %d\n", position); + } + else if(finger_current[position]) + { + if (g_param.xyswap == 0) + { + x = icn85xx_ts->point_info[position].u16PosX; + y = icn85xx_ts->point_info[position].u16PosY; + } else { + y = icn85xx_ts->point_info[position].u16PosX; + x = icn85xx_ts->point_info[position].u16PosY; + } + if (g_param.xdir == -1) + { + x = g_param.panelres_x - x; + } + if (g_param.ydir == -1) + { + y = g_param.panelres_y - y; + } + + if (g_param.lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = g_param.panelres_x - tmp; + } + + input_mt_slot(icn85xx_ts->input_dev, position-1); + input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, true); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); + //input_report_abs(icn85xx_ts->input_dev, ABS_MT_PRESSURE, icn85xx_ts->point_info[position].u8Pressure); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_PRESSURE, 200); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, y); + //icn85xx_point_info("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn85xx_ts->point_info[position].u16PosX,icn85xx_ts->point_info[position].u16PosY, icn85xx_ts->point_info[position].u8Pressure); + icn85xx_point_info("raw%d(%d,%d), rpt%d(%d,%d)\n", position, icn85xx_ts->point_info[position].u16PosX, icn85xx_ts->point_info[position].u16PosY, position, x, y); + } + + } + input_sync(icn85xx_ts->input_dev); + + for(position = 1; position < POINT_NUM + 1; position++) + { + finger_last[position] = finger_current[position]; + } + +} +#endif + +/*********************************************************************************************** +Name : icn85xx_ts_pen_irq_work +Input : void +Output : +function : work_struct +***********************************************************************************************/ +static void icn85xx_ts_pen_irq_work(struct work_struct *work) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(this_client); +#if SUPPORT_PROC_FS + if(down_interruptible(&icn85xx_ts->sem)) + { + return ; + } +#endif + + if(icn85xx_ts->work_mode == 0) + { +#if CTP_REPORT_PROTOCOL + icn85xx_report_value_B(); +#else + icn85xx_report_value_A(); +#endif + + + if(icn85xx_ts->use_irq) + { + icn85xx_irq_enable(); + } + if(log_on_off == 4) + { + printk("normal raw data\n"); + icn85xx_log(0); //raw data + } + else if(log_on_off == 5) + { + printk("normal diff data\n"); + icn85xx_log(1); //diff data + } + else if(log_on_off == 6) + { + printk("normal raw2diff\n"); + icn85xx_log(2); //diff data + } + + } + else if(icn85xx_ts->work_mode == 1) + { + printk("raw data\n"); + icn85xx_log(0); //raw data + } + else if(icn85xx_ts->work_mode == 2) + { + printk("diff data\n"); + icn85xx_log(1); //diff data + } + else if(icn85xx_ts->work_mode == 3) + { + printk("raw2diff data\n"); + icn85xx_log(2); //diff data + } + else if(icn85xx_ts->work_mode == 4) //idle + { + ; + } + else if(icn85xx_ts->work_mode == 5)//write para, reinit + { + printk("reinit tp\n"); + icn85xx_write_reg(0, 1); + mdelay(100); + icn85xx_write_reg(0, 0); + icn85xx_ts->work_mode = 0; + } + +#if SUPPORT_PROC_FS + up(&icn85xx_ts->sem); +#endif + + +} +/*********************************************************************************************** +Name : chipone_timer_func +Input : void +Output : +function : Timer interrupt service routine. +***********************************************************************************************/ +static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer) +{ + struct icn85xx_ts_data *icn85xx_ts = container_of(timer, struct icn85xx_ts_data, timer); + queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); + //icn85xx_info("chipone_timer_func\n"); + if(icn85xx_ts->use_irq == 1) + { + if((icn85xx_ts->work_mode == 1) || (icn85xx_ts->work_mode == 2) || (icn85xx_ts->work_mode == 3)) + { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + } + else + { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + return HRTIMER_NORESTART; +} +/*********************************************************************************************** +Name : icn85xx_ts_interrupt +Input : void +Output : +function : interrupt service routine +***********************************************************************************************/ +static irqreturn_t icn85xx_ts_interrupt(int irq, void *dev_id) +{ + struct icn85xx_ts_data *icn85xx_ts = dev_id; + int irqindex = g_param.irqgpio; + + icn85xx_info("==========------icn85xx_ts TS Interrupt-----============\n"); + + if (gpio_irqstatus(irqindex)) { + wmt_gpio_ack_irq(irqindex); + if (is_gpio_irqenable(irqindex)) { + icn85xx_irq_disable(); + if(icn85xx_ts->work_mode != 0) { + icn85xx_irq_enable(); + return IRQ_HANDLED; + } + if (!work_pending(&icn85xx_ts->pen_event_work)) { + icn85xx_info("Enter work\n"); + queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); + } + } + return IRQ_HANDLED; + } + return IRQ_NONE; + + /*if(icn85xx_ts->use_irq) + icn85xx_irq_disable(); + if (!work_pending(&icn85xx_ts->pen_event_work)) + { + queue_work(icn85xx_ts->ts_workqueue, &icn85xx_ts->pen_event_work); + + } + + return IRQ_HANDLED;*/ +} + +/*********************************************************************************************** +Name : icn85xx_ts_suspend +Input : void +Output : +function : tp enter sleep mode +***********************************************************************************************/ +static int icn85xx_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); + icn85xx_trace("icn85xx_ts_suspend\n"); + if (icn85xx_ts->use_irq) { + icn85xx_irq_disable(); + } else { + hrtimer_cancel(&icn85xx_ts->timer); + } + cancel_work_sync(&icn85xx_ts->pen_event_work); + flush_workqueue(icn85xx_ts->ts_workqueue); + //} + + //reset flag if ic is flashless when power off + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) + { + //icn85xx_ts->code_loaded_flag = 0; + } +#if SUSPEND_POWER_OFF + +#else + icn85xx_write_reg(ICN85xx_REG_PMODE, PMODE_HIBERNATE); +#endif + + return 0; + +} + +int resume_download_thread(void *arg) +{ + int retry = 1; + int need_update_fw = false; + int ret = -1; + unsigned char value; + struct icn85xx_ts_data *icn85xx_ts = (struct icn85xx_ts_data*)arg; + wake_lock(&downloadWakeLock); + while (retry-- && !need_update_fw) { + icn85xx_ts_reset(); + icn85xx_bootfrom_sram(); + msleep(50); + ret = icn85xx_read_reg(0xa, &value); + if (ret > 0) { + need_update_fw = false; + break; + } + } + if (retry < 0) need_update_fw = true; + + if (need_update_fw) { + if(R_OK == icn85xx_fw_update(firmware)) { + icn85xx_ts->code_loaded_flag = 1; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code ok\n"); + } + else { + icn85xx_ts->code_loaded_flag = 0; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, reload code error\n"); + } + } + + if (icn85xx_ts->use_irq) { + icn85xx_irq_enable(); + } else { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, \ + (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + wake_unlock(&downloadWakeLock); + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_ts_resume +Input : void +Output : +function : wakeup tp or reset tp +***********************************************************************************************/ +static int icn85xx_ts_resume(struct i2c_client *client) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); + int i; + icn85xx_trace("==icn85xx_ts_resume== \n"); + + //report touch release +#if CTP_REPORT_PROTOCOL + for(i = 0; i < POINT_NUM; i++) + { + input_mt_slot(icn85xx_ts->input_dev, i); + input_mt_report_slot_state(icn85xx_ts->input_dev, MT_TOOL_FINGER, false); + } +#else + icn85xx_ts_release(); +#endif + + + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) { + if (bl_is_delay) { + resume_download_task = kthread_create(resume_download_thread, icn85xx_ts, "resume_download"); + if(IS_ERR(resume_download_task)) { + icn85xx_error("cread thread failed\n"); + } + wake_up_process(resume_download_task); + } else + resume_download_thread(icn85xx_ts); + } else { + icn85xx_write_reg(ICN85xx_REG_PMODE, 0xff); + icn85xx_ts_reset(); + if (icn85xx_ts->use_irq) { + icn85xx_irq_enable(); + } else { + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, \ + (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } + } + + // icn85xx_write_reg(ICN85xx_REG_PMODE, 0x00); + return 0; +} + +/*********************************************************************************************** +Name : icn85xx_request_io_port +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_request_io_port(struct icn85xx_ts_data *icn85xx_ts) +{ + +#if SUPPORT_ROCKCHIP + icn85xx_ts->screen_max_x = SCREEN_MAX_X; + icn85xx_ts->screen_max_y = SCREEN_MAX_Y; + icn85xx_ts->irq = CTP_IRQ_PORT; //maybe need changed +#endif + icn85xx_ts->irq = IRQ_GPIO; + + if (gpio_request(g_param.rstgpio, "ts_rst") < 0) { + printk("gpio(%d) touchscreen reset request fail\n", g_param.rstgpio); + return -EIO; + } + gpio_direction_output(g_param.rstgpio, 1); + + if (gpio_request(g_param.irqgpio, "ts_irq") < 0) { + printk("gpio(%d) touchscreen interrupt request fail\n", g_param.irqgpio); + gpio_free(g_param.rstgpio); + return -EIO; + } + wmt_gpio_setpull(g_param.irqgpio, WMT_GPIO_PULL_UP); + gpio_direction_input(g_param.irqgpio); + + + return 0; + +} + +/*********************************************************************************************** +Name : icn85xx_free_io_port +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static void icn85xx_free_io_port(void) +{ + gpio_free(g_param.rstgpio); + gpio_free(g_param.irqgpio); + return; +} + +/*********************************************************************************************** +Name : icn85xx_request_irq +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_request_irq(struct icn85xx_ts_data *icn85xx_ts) +{ + int err = -1; + + + wmt_gpio_set_irq_type(g_param.irqgpio, IRQ_TYPE_EDGE_FALLING); + err = request_irq(icn85xx_ts->irq, icn85xx_ts_interrupt, IRQF_SHARED, "icn85xx_ts", icn85xx_ts); + if (err < 0) + { + icn85xx_error("icn85xx_ts_probe: request irq failed\n"); + return err; + } + else + { + icn85xx_irq_disable(); + icn85xx_ts->use_irq = 1; + } + +#if SUPPORT_ROCKCHIP + err = gpio_request(icn85xx_ts->irq, "TS_INT"); //Request IO + if (err < 0) + { + icn85xx_error("Failed to request GPIO:%d, ERRNO:%d\n", (int)icn85xx_ts->irq, err); + return err; + } + gpio_direction_input(icn85xx_ts->irq); + err = request_irq(icn85xx_ts->irq, icn85xx_ts_interrupt, IRQ_TYPE_EDGE_FALLING, "icn85xx_ts", icn85xx_ts); + if (err < 0) + { + icn85xx_ts->use_irq = 0; + icn85xx_error("icn85xx_ts_probe: request irq failed\n"); + return err; + } + else + { + icn85xx_irq_disable(); + icn85xx_ts->use_irq = 1; + } +#endif + + return 0; +} + + +/*********************************************************************************************** +Name : icn85xx_free_irq +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static void icn85xx_free_irq(struct icn85xx_ts_data *icn85xx_ts) +{ + if (icn85xx_ts) + { + if (icn85xx_ts->use_irq) + { + free_irq(icn85xx_ts->irq, icn85xx_ts); + } + else + { + hrtimer_cancel(&icn85xx_ts->timer); + } + } + +} + +/*********************************************************************************************** +Name : icn85xx_request_input_dev +Input : void +Output : +function : 0 success, +***********************************************************************************************/ +static int icn85xx_request_input_dev(struct icn85xx_ts_data *icn85xx_ts) +{ + int ret = -1; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) { + icn85xx_error("failed to allocate input device\n"); + return -ENOMEM; + } + icn85xx_ts->input_dev = input_dev; + + icn85xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; +#if CTP_REPORT_PROTOCOL + __set_bit(INPUT_PROP_DIRECT, icn85xx_ts->input_dev->propbit); + input_mt_init_slots(icn85xx_ts->input_dev, POINT_NUM*2); +#else + set_bit(ABS_MT_TOUCH_MAJOR, icn85xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_X, icn85xx_ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, icn85xx_ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, icn85xx_ts->input_dev->absbit); +#endif + if (g_param.lcd_exchg) { + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_y, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_x, 0, 0); + } else { + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_x, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_y, 0, 0); + } + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(icn85xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, POINT_NUM*2, 0, 0); + + __set_bit(KEY_MENU, input_dev->keybit); + __set_bit(KEY_BACK, input_dev->keybit); + __set_bit(KEY_HOME, input_dev->keybit); + __set_bit(KEY_SEARCH, input_dev->keybit); + + input_dev->name = CTP_NAME; + ret = input_register_device(input_dev); + if (ret) { + icn85xx_error("Register %s input device failed\n", input_dev->name); + input_free_device(input_dev); + return -ENODEV; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + icn85xx_trace("==register_early_suspend =\n"); + icn85xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + icn85xx_ts->early_suspend.suspend = icn85xx_ts_suspend; + icn85xx_ts->early_suspend.resume = icn85xx_ts_resume; + register_early_suspend(&icn85xx_ts->early_suspend); +#endif + + return 0; +} +#if SUPPORT_SENSOR_ID +static void read_sensor_id(void) +{ + int i,ret; + //icn85xx_trace("scan sensor id value begin sensor_id_num = %d\n",(sizeof(sensor_id_table)/sizeof(sensor_id_table[0]))); + ret = icn85xx_read_reg(0x10, &cursensor_id); + if(ret > 0) + { + icn85xx_trace("cursensor_id= 0x%x\n", cursensor_id); + } + else + { + icn85xx_error("icn85xx read cursensor_id failed.\n"); + cursensor_id = -1; + } + + ret = icn85xx_read_reg(0x1e, &tarsensor_id); + if(ret > 0) + { + icn85xx_trace("tarsensor_id= 0x%x\n", tarsensor_id); + tarsensor_id = -1; + } + else + { + icn85xx_error("icn85xx read tarsensor_id failed.\n"); + } + ret = icn85xx_read_reg(0x1f, &id_match); + if(ret > 0) + { + icn85xx_trace("match_flag= 0x%x\n", id_match); // 1: match; 0:not match + } + else + { + icn85xx_error("icn85xx read id_match failed.\n"); + id_match = -1; + } + // scan sensor id value + icn85xx_trace("begin to scan id table,find correct fw or bin. sensor_id_num = %d\n",(sizeof(sensor_id_table)/sizeof(sensor_id_table[0]))); + + for(i = 0;i < (sizeof(sensor_id_table)/sizeof(sensor_id_table[0])); i++) // not change tp + { + if (cursensor_id == sensor_id_table[i].value) + { + #if COMPILE_FW_WITH_DRIVER + icn85xx_set_fw(sensor_id_table[i].size, sensor_id_table[i].fw_name); + #else + strcpy(firmware,sensor_id_table[i].bin_name); + icn85xx_trace("icn85xx matched firmware = %s\n", firmware); + #endif + icn85xx_trace("icn85xx matched id = 0x%x\n", sensor_id_table[i].value); + invalid_id = 1; + break; + } + else + { + invalid_id = 0; + icn85xx_trace("icn85xx not matched id%d= 0x%x\n", i,sensor_id_table[i].value); + //icn85xx_trace("not match sensor_id_table[%d].value= 0x%x,bin_name = %s\n",i,sensor_id_table[i].value,sensor_id_table[i].bin_name); + } + } + +} +static void compare_sensor_id(void) +{ + int retry = 5; + + read_sensor_id(); // select sensor id + + if(0 == invalid_id) //not compare sensor id,update default fw or bin + { + icn85xx_trace("not compare sensor id table,update default: invalid_id= %d, cursensor_id= %d\n", invalid_id,cursensor_id); + #if COMPILE_FW_WITH_DRIVER + icn85xx_set_fw(sensor_id_table[0].size, sensor_id_table[0].fw_name); + #else + strcpy(firmware,sensor_id_table[0].bin_name); + icn85xx_trace("match default firmware = %s\n", firmware); + #endif + + while(retry > 0) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_trace("icn85xx upgrade default firmware ok\n"); + break; + } + retry--; + icn85xx_error("icn85xx_fw_update default firmware failed.\n"); + } + } + + if ((1 == invalid_id)&&(0 == id_match)) // tp is changed,update current fw or bin + { + icn85xx_trace("icn85xx detect tp is changed!!! invalid_id= %d,id_match= %d,\n", invalid_id,id_match); + while(retry > 0) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_trace("icn85xx upgrade cursensor id firmware ok\n"); + break; + } + retry--; + icn85xx_error("icn85xx_fw_update current id firmware failed.\n"); + } + } +} +#endif + +static void icn85xx_update(struct icn85xx_ts_data *icn85xx_ts) +{ + short fwVersion = 0; + short curVersion = 0; + int retry = 0; + + if(icn85xx_ts->ictype == ICN85XX_WITHOUT_FLASH) + { + #if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID) + icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]); + #endif + + #if SUPPORT_SENSOR_ID + while(0 == invalid_id ) //reselect sensor id + { + compare_sensor_id(); // select sensor id + icn85xx_trace("invalid_id= %d\n", invalid_id); + } + #else + if(R_OK == icn85xx_fw_update(firmware)) + { + icn85xx_ts->code_loaded_flag = 1; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, update default fw ok\n"); + } + else + { + icn85xx_ts->code_loaded_flag = 0; + icn85xx_trace("ICN85XX_WITHOUT_FLASH, update error\n"); + } + #endif + + } + else if(icn85xx_ts->ictype == ICN85XX_WITH_FLASH) + { + #if (COMPILE_FW_WITH_DRIVER && !SUPPORT_SENSOR_ID) + icn85xx_set_fw(sizeof(icn85xx_fw), &icn85xx_fw[0]); + #endif + + #if SUPPORT_SENSOR_ID + while(0 == invalid_id ) //reselect sensor id + { + compare_sensor_id(); // select sensor id + if( 1 == invalid_id) + { + icn85xx_trace("select sensor id ok. begin compare fwVersion with curversion\n"); + } + } + #endif + + fwVersion = icn85xx_read_fw_Ver(firmware); + curVersion = icn85xx_readVersion(); + icn85xx_trace("fwVersion : 0x%x\n", fwVersion); + icn85xx_trace("current version: 0x%x\n", curVersion); + + #if FORCE_UPDATA_FW + retry = 5; + while(retry > 0) + { + if(icn85xx_goto_progmode() != 0) + { + printk("icn85xx_goto_progmode() != 0 error\n"); + return -1; + } + icn85xx_read_flashid(); + if(R_OK == icn85xx_fw_update(firmware)) + { + break; + } + retry--; + icn85xx_error("icn85xx_fw_update failed.\n"); + } + + #else + if(fwVersion > curVersion) + { + retry = 5; + while(retry > 0) + { + if(R_OK == icn85xx_fw_update(firmware)) + { + break; + } + retry--; + icn85xx_error("icn85xx_fw_update failed.\n"); + } + } + #endif + } +} +static int icn85xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct icn85xx_ts_data *icn85xx_ts; + int err = 0; + + icn85xx_trace("====%s begin=====. \n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + icn85xx_error("I2C check functionality failed.\n"); + return -ENODEV; + } + + icn85xx_ts = kzalloc(sizeof(*icn85xx_ts), GFP_KERNEL); + if (!icn85xx_ts) + { + icn85xx_error("Alloc icn85xx_ts memory failed.\n"); + return -ENOMEM; + } + memset(icn85xx_ts, 0, sizeof(*icn85xx_ts)); + + this_client = client; + this_client->addr = client->addr; + i2c_set_clientdata(client, icn85xx_ts); + + icn85xx_ts->work_mode = 0; + spin_lock_init(&icn85xx_ts->irq_lock); +// icn85xx_ts->irq_lock = SPIN_LOCK_UNLOCKED; + + icn85xx_request_io_port(icn85xx_ts); + if (err != 0) { + icn85xx_error("icn85xx_request_io_port failed.\n"); + goto fail1; + } + memset(firmware, 0, 128); + sprintf(firmware,"%s.bin",g_param.fw_name); + + icn85xx_ts_reset(); + + err = icn85xx_iic_test(); + if (err <= 0) + { + icn85xx_error("icn85xx_iic_test failed.\n"); + goto fail2; + + } + else + { + icn85xx_trace("iic communication ok: 0x%x\n", icn85xx_ts->ictype); + } + + icn85xx_update(icn85xx_ts); + + err= icn85xx_request_input_dev(icn85xx_ts); + if (err < 0) + { + icn85xx_error("request input dev failed\n"); + goto fail3; + } + + + +#if TOUCH_VIRTUAL_KEYS + icn85xx_ts_virtual_keys_init(); +#endif + err = icn85xx_request_irq(icn85xx_ts); + if (err != 0) + { + icn85xx_error("request irq error, use timer\n"); + icn85xx_ts->use_irq = 0; + hrtimer_init(&icn85xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + icn85xx_ts->timer.function = chipone_timer_func; + hrtimer_start(&icn85xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL); + } +#if SUPPORT_SYSFS + icn85xx_create_sysfs(client); +#endif + +#if SUPPORT_PROC_FS + sema_init(&icn85xx_ts->sem, 1); + init_proc_node(); +#endif + + INIT_WORK(&icn85xx_ts->pen_event_work, icn85xx_ts_pen_irq_work); + icn85xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev)); + if (!icn85xx_ts->ts_workqueue) { + icn85xx_error("create_singlethread_workqueue failed.\n"); + err = -ESRCH; + goto fail4; + } + + if(icn85xx_ts->use_irq) + icn85xx_irq_enable(); + icn85xx_trace("==%s over =\n", __func__); + return 0; +fail4: + cancel_work_sync(&icn85xx_ts->pen_event_work); +fail3: + input_unregister_device(icn85xx_ts->input_dev); + input_free_device(icn85xx_ts->input_dev); +fail2: + icn85xx_free_io_port(); +fail1: + kfree(icn85xx_ts); + icn85xx_free_fw(); + return err; +} + +static int __devexit icn85xx_ts_remove(struct i2c_client *client) +{ + struct icn85xx_ts_data *icn85xx_ts = i2c_get_clientdata(client); + icn85xx_trace("==icn85xx_ts_remove=\n"); + if(icn85xx_ts->use_irq) + icn85xx_irq_disable(); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&icn85xx_ts->early_suspend); +#endif + +#if SUPPORT_PROC_FS + uninit_proc_node(); +#endif + +#if SUPPORT_SYSFS + icn85xx_remove_sysfs(client); +#endif + input_unregister_device(icn85xx_ts->input_dev); + input_free_device(icn85xx_ts->input_dev); + cancel_work_sync(&icn85xx_ts->pen_event_work); + destroy_workqueue(icn85xx_ts->ts_workqueue); + icn85xx_free_irq(icn85xx_ts); + icn85xx_free_io_port(); + icn85xx_free_fw(); + kfree(icn85xx_ts); + i2c_set_clientdata(client, NULL); + return 0; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96; + char retval[200] = {0},*p=NULL,*s=NULL; + int Enable=0; + + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + printk("Read wmt.io.touch Failed.\n"); + return -EIO; + } + +//paste: + p = retval; + Enable = (p[0] - '0' == 1) ? 1 : 0; + if(Enable == 0){ + printk("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(g_param.fw_name,p, (s-p)); + printk("ts_name=%s\n", g_param.fw_name); + if (strncmp(g_param.fw_name, "ICN85", 5)) { + printk("Wrong firmware name.\n"); + return -ENODEV; + } + + p = s+1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d", + &(g_param.irqgpio),&(g_param.panelres_x),&(g_param.panelres_y),&(g_param.rstgpio), + &(g_param.xyswap),&(g_param.xdir),&(g_param.ydir)); + + if (ret < 7) { + printk("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + printk("p.x = %d, p.y = %d, irqgpio=%d, rstgpio=%d,xyswap=%d,xdir=%d,ydir=%d\n", + g_param.panelres_x,g_param.panelres_y,g_param.irqgpio,g_param.rstgpio, + g_param.xyswap,g_param.xdir,g_param.ydir); + + /*memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) + g_param.earlysus_en = (retval[0] - '0' == 1) ? 1 : 0;*/ + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + g_param.lcd_exchg = 1; + } + + ret = wmt_getsyspara("wmt.backlight.delay", retval, &len); + if(ret) { + bl_is_delay = 0; + } else + bl_is_delay = 1; + + return 0; +} + +static const struct i2c_device_id icn85xx_ts_id[] = { + { CTP_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, icn85xx_ts_id); + +static struct i2c_driver icn85xx_ts_driver = { + .probe = icn85xx_ts_probe, + .remove = __devexit_p(icn85xx_ts_remove), +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = icn85xx_ts_suspend, + .resume = icn85xx_ts_resume, +#endif + .id_table = icn85xx_ts_id, + .driver = { + .name = CTP_NAME, + .owner = THIS_MODULE, + }, + +}; + + +static struct i2c_board_info i2c_board_info = { + I2C_BOARD_INFO(CTP_NAME, ICN85XX_IIC_ADDR), +}; + + +static int __init icn85xx_ts_init(void) +{ + struct i2c_client *client; + struct i2c_adapter *adap; + icn85xx_trace("===========================%s=====================\n", __func__); + + if(wmt_check_touch_env()) + return -ENODEV; + + {//register i2c device + adap = i2c_get_adapter(1); //i2c Bus 1 + if (!adap) + return -ENODEV; + client = i2c_new_device(adap, &i2c_board_info); + i2c_put_adapter(adap); + if (!client) { + printk("i2c_new_device error\n"); + return -ENODEV; + } + } + + return i2c_add_driver(&icn85xx_ts_driver); +} + +static void __exit icn85xx_ts_exit(void) +{ + icn85xx_trace("==icn85xx_ts_exit==\n"); + i2c_unregister_device(this_client); + i2c_del_driver(&icn85xx_ts_driver); +} +late_initcall(icn85xx_ts_init); +//module_init(icn85xx_ts_init); +module_exit(icn85xx_ts_exit); + +MODULE_AUTHOR("<zmtian@chiponeic.com>"); +MODULE_DESCRIPTION("Chipone icn85xx TouchScreen driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h new file mode 100755 index 00000000..262b76fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx.h @@ -0,0 +1,500 @@ +/*++ + + Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. + This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. + and may contains trade secrets and/or other confidential information of ChipOne + Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, + in whole or in part, without prior written consent of ChipOne. + THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR + IMPLIED WARRANTIES. + + File Name: icn85xx.h + Abstract: + input driver. +Author: Zhimin Tian +Date : 08,14,2013 +Version: 1.0 +History : + 2012,10,30, V0.1 first version + + --*/ + +#ifndef __LINUX_ICN85XX_H__ +#define __LINUX_ICN85XX_H__ + +#include <linux/i2c.h> +#include <linux/input.h> +#ifdef CONFIG_HAS_EARLYSUSPEND + #include <linux/pm.h> + #include <linux/earlysuspend.h> +#endif +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/async.h> +#include <linux/hrtimer.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/hrtimer.h> +#include <linux/proc_fs.h> + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/fs.h> + #include <linux/semaphore.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/ioctl.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/spinlock_types.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <linux/kthread.h> +#include <linux/wakelock.h> +#include <linux/firmware.h> + + +//----------------------------------------------------------------------------- +// Pin Declarations +//----------------------------------------------------------------------------- + +#define SUPPORT_ALLWINNER_A13 0 +#define SUPPORT_ROCKCHIP 0 +#define SUPPORT_SPREADTRUM 0 + + + + +#if SUPPORT_ROCKCHIP +#include <linux/irq.h> +#include <mach/irqs.h> +#include <mach/system.h> +#include <mach/hardware.h> +#include <mach/board.h> +#include <mach/gpio.h> + + +#define CTP_IRQ_MODE 0 + + + #define CTP_RST_PORT RK30_PIN2_PB1//RK30_PIN1_PB1 + #define CTP_IRQ_PORT RK30_PIN1_PA1 + + + +#define CTP_WAKEUP_PORT 0 +#define CTP_REPORT_PROTOCOL 1 //0: A protocol + //1: B protocol +#define SCREEN_MAX_X (600) +#define SCREEN_MAX_Y (1024) +//#define SCREEN_MAX_X (480) +//#define SCREEN_MAX_Y (800) +#define ICN85XX_I2C_SCL 400*1000 + +#endif + + +#include <linux/irq.h> +#include <mach/irqs.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#define CTP_RST_PORT 4//RK30_PIN1_PB1 +#define CTP_IRQ_PORT 7 +#define CTP_REPORT_PROTOCOL 1 //0: A protocol +#define SCREEN_MAX_X (1024) +#define SCREEN_MAX_Y (600) +#define ICN85XX_IIC_ADDR (0x90>>1) + +//----------------------------------------------------------------------------- +// Global CONSTANTS +//----------------------------------------------------------------------------- +#define COL_NUM 24 +#define ROW_NUM 36 + +#define MD25D40_ID1 0x514013 +#define MD25D40_ID2 0xC84013 +#define MD25D20_ID1 0x514012 +#define MD25D20_ID2 0xC84012 +#define GD25Q10_ID 0xC84011 +#define MX25L512E_ID 0xC22010 + +#define ICN85XX_WITHOUT_FLASH 0x11 +#define ICN85XX_WITH_FLASH 0x22 + +#define FLASH_TOTAL_SIZE 0x00010000 +#define FLASH_PAGE_SIZE 0x1000 +#define FLASH_AHB_BASE_ADDR 0x00100000 +#define FLASH_PATCH_PARA_BASE_ADDR (FLASH_TOTAL_SIZE - FLASH_PAGE_SIZE) // allocate 1 page for patch para, 0xff00 +#define FLASH_CODE_INFO_BASE_ADDR (FLASH_PATCH_PARA_BASE_ADDR - FLASH_PAGE_SIZE) // 0xfe00,allocate 1 page for system para +#define FLASH_CRC_ADDR (FLASH_AHB_BASE_ADDR + FLASH_CODE_INFO_BASE_ADDR + 0x00) // 0xfe00 +#define FLASH_CODE_LENGTH_ADDR (FLASH_AHB_BASE_ADDR + FLASH_CODE_INFO_BASE_ADDR + 0x04) // 0xfe04 + + +//tp config +#define TOUCH_VIRTUAL_KEYS 0 +#define SUPPORT_PROC_FS 1 +#define SUPPORT_SYSFS 1 +#define COMPILE_FW_WITH_DRIVER 0 +#define FORCE_UPDATA_FW 0 +#define SUSPEND_POWER_OFF 1 +#define SUPPORT_SENSOR_ID 0 + +#define ICN85XX_NAME "icn85xx" +#define ICN85XX_PROG_IIC_ADDR (0x30) +#define CTP_NAME ICN85XX_NAME + +#define CTP_RESET_LOW_PERIOD (5) +#define CTP_RESET_HIGH_PERIOD (100) +#define CTP_WAKEUP_LOW_PERIOD (20) +#define CTP_WAKEUP_HIGH_PERIOD (50) +#define CTP_POLL_TIMER (16) /* ms delay between samples */ +#define CTP_START_TIMER (100) /* ms delay between samples */ + +#define POINT_NUM 5 +#define POINT_SIZE 7 + +#define TS_KEY_HOME 102 +#define TS_KEY_MENU 139 +#define TS_KEY_BACK 158 +#define TS_KEY_SEARCH 217 + +#define ICN_VIRTUAL_BUTTON_HOME 0x02 +#define ICN_VIRTUAL_BUTTON_MENU 0x01 +#define ICN_VIRTUAL_BUTTON_BACK 0x04 +#define ICN_VIRTUAL_BUTTON_SEARCH 0x08 + +#define IIC_RETRY_NUM 3 + +//ICN85xx_REG_PMODE +#define PMODE_ACTIVE 0x00 +#define PMODE_MONITOR 0x01 +#define PMODE_HIBERNATE 0x02 + +#define B_SIZE 32 +//#define ENABLE_BYTE_CHECK + +//----------------------------------------------------------------------------- +// Macro DEFINITIONS +//----------------------------------------------------------------------------- +#define DBG_ICN85xx_TRACE +//#define DBG_ICN85xx_POINT +//#define DBG_ICN85xx_INFO +#define DBG_ICN85xx_ERROR +//#define DBG_FLASH_INFO +#define DBG_FLASH_ERROR +#define DBG_OP_INFO +#define DBG_OP_ERROR +#define DBG_CALIB_INFO +#define DBG_CALIB_ERROR +//#define DBG_PROC_INFO +#define DBG_PROC_ERROR + + +#ifdef DBG_ICN85xx_TRACE +#define icn85xx_trace(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_trace(fmt, args...) // +#endif + + +#ifdef DBG_ICN85xx_POINT +#define icn85xx_point_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_point_info(fmt, args...) // +#endif + +#ifdef DBG_ICN85xx_INFO +#define icn85xx_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_info(fmt, args...) // +#endif + +#ifdef DBG_ICN85xx_ERROR +#define icn85xx_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define icn85xx_error(fmt, args...) // +#endif + +#ifdef DBG_FLASH_INFO +#define flash_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_info(fmt, args...) // +#endif + +#ifdef DBG_FLASH_ERROR +#define flash_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define flash_error(fmt, args...) // +#endif + + +#ifdef DBG_OP_INFO +#define op_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_info(fmt, args...) // +#endif +#ifdef DBG_OP_ERROR +#define op_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define op_error(fmt, args...) // +#endif + + +#ifdef DBG_CALIB_INFO +#define calib_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_info(fmt, args...) // +#endif + +#ifdef DBG_CALIB_ERROR +#define calib_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define calib_error(fmt, args...) // +#endif + + +#ifdef DBG_PROC_INFO +#define proc_info(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_info(fmt, args...) // +#endif + +#ifdef DBG_PROC_ERROR +#define proc_error(fmt, args...) \ + do{ \ + printk(fmt, ##args); \ + }while(0) +#else +#define proc_error(fmt, args...) // +#endif + +#define swap_ab(a,b) {char temp;temp=a;a=b;b=temp;} +#define U16LOBYTE(var) (*(unsigned char *) &var) +#define U16HIBYTE(var) (*(unsigned char *)((unsigned char *) &var + 1)) + +#define STRUCT_OFFSET(StructName,MemberName) ((int)(&(((StructName*)0)->MemberName))) + + +//----------------------------------------------------------------------------- +// Struct, Union and Enum DEFINITIONS +//----------------------------------------------------------------------------- +typedef struct _POINT_INFO +{ + unsigned char u8ID; + unsigned short u16PosX; // coordinate X, plus 4 LSBs for precision extension + unsigned short u16PosY; // coordinate Y, plus 4 LSBs for precision extension + unsigned char u8Pressure; + unsigned char u8EventId; +}POINT_INFO; + +struct icn85xx_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct work_struct pen_event_work; + struct workqueue_struct *ts_workqueue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct hrtimer timer; + spinlock_t irq_lock; + struct semaphore sem; + int ictype; + int code_loaded_flag; + POINT_INFO point_info[POINT_NUM+1]; + int point_num; + int irq; + int irq_is_disable; + int use_irq; + int work_mode; + int screen_max_x; + int screen_max_y; + int revert_x_flag; + int revert_y_flag; + int exchange_x_y_flag; +}; + +struct touch_param { + char fw_name[32]; + int irqgpio; + int rstgpio; + int panelres_x; + int panelres_y; + int xyswap; + int xdir; + int ydir; + int max_finger_num; + int force_download; + int earlysus_en; + int dbg; + int lcd_exchg; +}; + +#pragma pack(1) +typedef struct{ + unsigned char wr; //write read flag£¬0:R 1:W + unsigned char flag; //0: + unsigned char circle; //polling cycle + unsigned char times; //plling times + unsigned char retry; //I2C retry times + unsigned int data_len; //data length + unsigned char addr_len; //address length + unsigned char addr[2]; //address + unsigned char* data; //data pointer +}pack_head; + +typedef struct _STRUCT_PANEL_PARA +{ + unsigned short u16ResX; // Row of resolution + unsigned short u16ResY; // Col of resolution + + unsigned char u8RowNum; // Row total number (Tp + vk) + unsigned char u8ColNum; // Column total number (Tp + vk) + unsigned char u8TXOrder[36]; // TX Order, start from zero + unsigned char u8RXOrder[24]; // TX Order, start from zero + + unsigned char u8NumVKey; // Virtual Key setting + unsigned char u8VKeyMode; + unsigned char u8TpVkOrder[4]; + unsigned char u8VKDownThreshold; + unsigned char u8VKUpThreshold; + + unsigned char u8MaxTouchNum; // max touch support + + unsigned char u8ScanMode; // scan mode + unsigned short u16BitFreq; + unsigned short u16FreqCycleNum[2]; + unsigned char u8MultiDrvNum; + unsigned char u8WindowType; + + unsigned char u8FreHopMode; // freq hopping + unsigned short u16FreHopBitFreq[5]; // Bit Freq + unsigned short u16FreqHopCycleNum[5]; // Cycle Num + unsigned short u16FreHopThreshold; // Threshold of Freq Hop + + unsigned char u8ShiftNum; // rawdata level + unsigned char u8DrvOutPutR; + unsigned char u8PgaC; + unsigned char u8RxVcmi; + unsigned char u8DacGain; + unsigned char u8PgaGain; + unsigned char u8PgaR; + unsigned char u8SpaceHolder[200]; +}STRUCT_PANEL_PARA_H; + +#pragma pack() + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(pack_head) - sizeof(unsigned char *)) +#define ICN85xx_ENTRY_NAME "icn85xx_tool" + + +enum icn85xx_ts_regs { + ICN85xx_REG_PMODE = 0x04, /* Power Consume Mode */ +}; + +typedef enum +{ + R_OK = 100, + R_FILE_ERR, + R_STATE_ERR, + R_ERASE_ERR, + R_PROGRAM_ERR, + R_VERIFY_ERR, +}E_UPGRADE_ERR_TYPE; + +//----------------------------------------------------------------------------- +// Global VARIABLES +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Function PROTOTYPES +//----------------------------------------------------------------------------- + +void icn85xx_ts_reset(void); +int icn85xx_i2c_rxdata(unsigned short addr, char *rxdata, int length); +int icn85xx_i2c_txdata(unsigned short addr, char *txdata, int length); +int icn85xx_write_reg(unsigned short addr, char para); +int icn85xx_read_reg(unsigned short addr, char *pdata); +int icn85xx_prog_i2c_rxdata(unsigned int addr, char *rxdata, int length); +int icn85xx_prog_i2c_txdata(unsigned int addr, char *txdata, int length); +int icn85xx_prog_write_reg(unsigned int addr, char para); +int icn85xx_prog_read_reg(unsigned int addr, char *pdata); + +int icn85xx_readVersion(void); +void icn85xx_rawdatadump(short *mem, int size, char br); +void icn85xx_set_fw(int size, unsigned char *buf); +void icn85xx_memdump(char *mem, int size); +int icn85xx_checksum(int sum, char *buf, unsigned int size); +int icn85xx_update_status(int status); +int icn85xx_get_status(void); +int icn85xx_open_fw( char *fw); +void icn85xx_free_fw(void); +int icn85xx_read_fw(int offset, int length, char *buf); +int icn85xx_close_fw(void); +int icn85xx_goto_progmode(void); +int icn85xx_check_progmod(void); +int icn85xx_read_flashid(void); +int icn85xx_erase_flash(void); +int icn85xx_prog_buffer(unsigned int flash_addr,unsigned int sram_addr,unsigned int copy_length,unsigned char program_type); +int icn85xx_prog_data(unsigned int flash_addr, unsigned int data); +void icn85xx_read_flash(unsigned int sram_address,unsigned int flash_address,unsigned long copy_length,unsigned char i2c_wire_num); +int icn85xx_fw_download(unsigned int offset, unsigned char * buffer, unsigned int size); +int icn85xx_bootfrom_flash(void); +int icn85xx_bootfrom_sram(void); +int icn85xx_crc_enable(unsigned char enable); +unsigned int icn85xx_crc_calc(unsigned crc_in, char *buf, int len); + +short icn85xx_read_fw_Ver(char *fw); +//E_UPGRADE_ERR_TYPE icn85xx_fw_update(char *fw); +int icn85xx_fw_update(void *arg); +#endif + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c new file mode 100755 index 00000000..a17cf176 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_flash.c @@ -0,0 +1,1050 @@ +/*++
+
+ Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved.
+ This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd.
+ and may contains trade secrets and/or other confidential information of ChipOne
+ Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party,
+ in whole or in part, without prior written consent of ChipOne.
+ THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS,
+ WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR
+ IMPLIED WARRANTIES.
+
+ File Name: icn85xx_flash.c
+ Abstract:
+ flash operation, read write etc.
+ Author: Zhimin Tian
+ Date : 08 14,2013
+ Version: 0.1[.revision]
+ History :
+ Change logs.
+ --*/
+#include "icn85xx.h"
+
+unsigned char* firmdata = NULL;
+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_WITH_FLASH;
+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)
+{
+// flash_info("icn85xx_update_status: %d\n", 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;
+
+}
+
+/***********************************************************************************************
+Name : icn85xx_open_fw
+Input : *fw
+
+Output : file size
+function : open the fw file, and return total size
+***********************************************************************************************/
+extern struct i2c_client *this_client;
+int icn85xx_open_fw( char *fw)
+{
+ static int file_size = 0;
+ const struct firmware *fw_entry;
+
+ if (firmdata)
+ return file_size;
+
+ if(request_firmware(&fw_entry, fw, &(this_client->dev))!=0) {
+ flash_error(KERN_ERR "cat't request firmware\n");
+ return -1;
+ }
+ if (fw_entry->size <= 0) {
+ flash_error(KERN_ERR "load firmware error\n");
+ release_firmware(fw_entry);
+ return -1;
+ }
+
+ firmdata = kzalloc(fw_entry->size + 1, GFP_KERNEL);
+ memcpy(firmdata, fw_entry->data, fw_entry->size);
+ file_size = fw_entry->size;
+ release_firmware(fw_entry);
+ return file_size;
+}
+
+void icn85xx_free_fw(void)
+{
+ if (firmdata) {
+ kfree(firmdata);
+ firmdata = NULL;
+ }
+}
+
+/***********************************************************************************************
+Name : icn85xx_read_fw
+Input : offset
+ length, read length
+ buf, return buffer
+Output :
+function : read data to buffer
+***********************************************************************************************/
+int icn85xx_read_fw(int offset, int length, char *buf)
+{
+ if(fw_mode == 1)
+ {
+ memcpy(buf, fw_buf+offset, length);
+ }
+ else
+ {
+ memcpy(buf, firmdata + offset, length);
+ }
+// icn85xx_memdump(buf, length);
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn85xx_close_fw
+Input :
+Output :
+function : close file
+***********************************************************************************************/
+int icn85xx_close_fw(void)
+{
+ if(fw_mode == 0)
+ {
+ //filp_close(fp, NULL);
+ }
+
+ return 0;
+}
+/***********************************************************************************************
+Name : icn85xx_readVersion
+Input : void
+Output :
+function : return version
+***********************************************************************************************/
+int icn85xx_readVersion(void)
+{
+ int err = 0;
+ char tmp[2];
+ short CurVersion;
+ err = icn85xx_i2c_rxdata(0x000c, tmp, 2);
+ if (err < 0) {
+ flash_error("%s failed: %d\n", __func__, err);
+ return 0;
+ }
+ CurVersion = (tmp[0]<<8) | tmp[1];
+ return CurVersion;
+}
+
+
+/***********************************************************************************************
+Name : icn85xx_goto_progmode
+Input :
+Output :
+function : change MCU to progmod
+***********************************************************************************************/
+int icn85xx_goto_progmode(void)
+{
+ int ret = -1;
+ int retry = 3;
+ unsigned char ucTemp;
+
+// flash_info("icn85xx_goto_progmode\n");
+ while(retry > 0)
+ {
+ ucTemp = 0x5a;
+ ret = icn85xx_prog_i2c_txdata(0xcc3355, &ucTemp,1);
+ mdelay(2);
+ ucTemp = 01;
+ ret = icn85xx_prog_i2c_txdata(0x040400, &ucTemp,1);
+ mdelay(2);
+ ret = icn85xx_check_progmod();
+ if(ret == 0)
+ return ret;
+
+ retry--;
+ mdelay(2);
+ }
+ printk("icn85xx_goto_progmode over\n");
+ if(retry == 0)
+ return -1;
+
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn85xx_check_progmod
+Input :
+Output :
+function : check if MCU at progmode or not
+***********************************************************************************************/
+int icn85xx_check_progmod(void)
+{
+ int ret;
+ unsigned char ucTemp = 0x0;
+ ret = icn85xx_prog_i2c_rxdata(0x040002, &ucTemp, 1);
+// flash_info("icn85xx_check_progmod: 0x%x\n", ucTemp);
+ if(ret < 0)
+ {
+ flash_error("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;
+
+ if((MD25D40_ID1 == flashid) || (MD25D40_ID2 == flashid)
+ ||(MD25D20_ID1 == flashid) || (MD25D20_ID1 == flashid)
+ ||(GD25Q10_ID == flashid) || (MX25L512E_ID == flashid))
+ {
+ boot_mode = ICN85XX_WITH_FLASH;
+ //printk("ICN85XX_WITH_FLASH\n");
+ }
+ else
+ {
+ boot_mode = ICN85XX_WITHOUT_FLASH;
+ //printk("ICN85XX_WITHOUT_FLASH\n");
+ }
+
+ printk("flashid: 0x%x\n", flashid);
+ return flashid;
+}
+
+
+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();
+ ////////////////////////////write comd to flash
+ 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);
+ }
+
+}
+
+/***********************************************************************************************
+Name : icn85xx_erase_flash
+Input :
+Output :
+function : erase flash
+***********************************************************************************************/
+int icn85xx_erase_flash(void)
+{
+ ClearFlashState();
+ while(FlashState(0)&0x01);
+ FlashWriteEnable();
+ EarseFlash(1,0);
+ while((FlashState(0)&0x01));
+ FlashWriteEnable();
+ EarseFlash(3,0x8000); //?which block
+ while((FlashState(0)&0x01));
+ FlashWriteEnable();
+ EarseFlash(3,0x9000);
+ while((FlashState(0)&0x01));
+ FlashWriteEnable();
+ EarseFlash(3,0xe000);
+ while((FlashState(0)&0x01));
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn85xx_prog_buffer
+Input :
+Output :
+function : progm flash
+***********************************************************************************************/
+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;
+}
+
+/***********************************************************************************************
+Name : icn85xx_prog_data
+Input :
+Output :
+function : write int data to flash
+***********************************************************************************************/
+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(0x7f00, ucTemp,4);
+ icn85xx_prog_buffer(flash_addr , 0x7f00, 0x04, 0);
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn85xx_read_flash
+Input :
+Output :
+function : read data from flash to sram
+***********************************************************************************************/
+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);
+ }
+
+}
+
+/***********************************************************************************************
+Name : icn85xx_read_fw_Ver
+Input : fw
+Output :
+function : read fw version
+***********************************************************************************************/
+
+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];
+// flash_info("FWversion: 0x%x\n", FWversion);
+ return FWversion;
+
+
+}
+
+/***********************************************************************************************
+Name : icn85xx_fw_download
+Input :
+Output :
+function : download code to sram
+***********************************************************************************************/
+int icn85xx_fw_download(unsigned int offset, unsigned char * buffer, unsigned int size)
+{
+#ifdef ENABLE_BYTE_CHECK
+ int i;
+ 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])
+ {
+ flash_error("buffer[%d]:%x testb[%d]:%x\n",i,buffer[i],i,testb[i]);
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn85xx_bootfrom_flash
+Input :
+Output :
+function :
+***********************************************************************************************/
+int icn85xx_bootfrom_flash(void)
+{
+ int ret = -1;
+ unsigned char ucTemp = 0x00;
+ flash_info("icn85xx_bootfrom_flash\n");
+
+ ucTemp=0x00;
+ ret = icn85xx_prog_i2c_txdata(0x40004, &ucTemp, 1 ); //nend flash sfcontrol clear
+ if (ret < 0) {
+ flash_error("%s failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+/***********************************************************************************************
+Name : icn85xx_bootfrom_sram
+Input :
+Output :
+function :
+***********************************************************************************************/
+int icn85xx_bootfrom_sram(void)
+{
+ int ret = -1;
+ unsigned char ucTemp = 0x03;
+ unsigned long addr = 0x40400;
+ flash_info("icn85xx_bootfrom_sram\n");
+ ret = icn85xx_prog_i2c_txdata(addr, &ucTemp, 1 ); //change bootmode from sram
+ return ret;
+}
+/***********************************************************************************************
+Name : icn85xx_crc_calc
+Input :
+Output :
+function :
+***********************************************************************************************/
+/*
+unsigned int icn85xx_crc_calc(unsigned crc_in, char *buf, int len)
+{
+ int pos;
+ unsigned int crc_result;
+ unsigned char in_data_8b;
+ unsigned int crc_reg_32b;
+ unsigned char i;
+ unsigned char xor_flag;
+
+ crc_result = crc_in;
+ for(pos=0;pos<len;pos++)
+ {
+ in_data_8b = *(buf+pos);
+ crc_reg_32b = crc_result ;
+ for(i=0; i<32; i++)
+ {
+ if(crc_reg_32b & 0x00000001)
+ {
+ crc_reg_32b ^= 0x04C11DB7;
+ crc_reg_32b >>= 1;
+ crc_reg_32b |= 0x80000000;
+ }
+ else
+ {
+ crc_reg_32b >>= 1;
+ }
+ }
+
+ for(i=0; i<40; i++)
+ {
+ xor_flag = (crc_reg_32b>>31);
+ crc_reg_32b = (crc_reg_32b<<1) + (in_data_8b>>7);
+ in_data_8b = (in_data_8b<<1);
+ if(xor_flag)
+ {
+ crc_reg_32b = crc_reg_32b ^ 0x04C11DB7;
+ }
+ }
+ crc_result = crc_reg_32b;
+ }
+ return crc_result;
+}
+*/
+
+
+/*
+ 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;
+}
+
+
+/***********************************************************************************************
+Name : icn85xx_crc_enable
+Input :
+Output :
+function :control crc control
+***********************************************************************************************/
+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;
+}
+/***********************************************************************************************
+Name : icn85xx_crc_check
+Input :
+Output :
+function :chec crc right or not
+***********************************************************************************************/
+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];
+// flash_info("crc_result: 0x%x\n", crc_result);
+
+ ret = icn85xx_prog_i2c_rxdata(0x40034, ucTemp, 2);
+ crc_len = ucTemp[1] << 8 | ucTemp[0];
+// flash_info("crc_len: %d\n", crc_len);
+
+ if((crc_result == crc) && (crc_len == len))
+ return 0;
+ else
+ {
+ flash_info("crc_fw: 0x%x\n", crc);
+ flash_info("crc_result: 0x%x\n", crc_result);
+ flash_info("crc_len: %d\n", crc_len);
+ return -1;
+ }
+
+}
+
+
+/***********************************************************************************************
+Name : icn85xx_fw_update
+Input : fw
+Output :
+function : upgrade fw
+***********************************************************************************************/
+int icn85xx_fw_update(void *arg)
+{
+ int file_size, last_length;
+ int j, num;
+ char temp_buf[B_SIZE];
+ unsigned int crc_fw;
+ char *fw = (char *)arg;
+
+ 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)
+ {
+ flash_error("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)
+ {
+ flash_error("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)
+ {
+ flash_error("error last length\n");
+ icn85xx_update_status(R_PROGRAM_ERR);
+ icn85xx_close_fw();
+ return R_PROGRAM_ERR;
+ }
+ }
+ icn85xx_close_fw();
+ icn85xx_update_status(65);
+// flash_info("crc_fw: 0x%x\n", crc_fw);
+// msleep(1);
+ icn85xx_crc_enable(0);
+ if(icn85xx_crc_check(crc_fw, file_size) != 0)
+ {
+ flash_info("down fw error, crc error\n");
+ return R_PROGRAM_ERR;
+ }
+ else
+ {
+ //flash_info("downoad fw ok, crc ok\n");
+ }
+ icn85xx_update_status(70);
+
+ if(ICN85XX_WITH_FLASH == boot_mode)
+ {
+ icn85xx_erase_flash();
+ // return R_PROGRAM_ERR;
+ 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)
+ {
+ flash_info("read flash data error, crc error\n");
+ return R_PROGRAM_ERR;
+ }
+ else
+ {
+ flash_info("read flash data ok, crc ok\n");
+ }
+ while((FlashState(0)&0x01));
+ icn85xx_update_status(95);
+
+ //if(icn85xx_bootfrom_flash() == 0)
+ if(icn85xx_bootfrom_sram() == 0) //code already in ram
+ {
+ flash_error("icn85xx_bootfrom_flash error\n");
+ icn85xx_update_status(R_STATE_ERR);
+ return R_STATE_ERR;
+ }
+ }
+ else if(ICN85XX_WITHOUT_FLASH == boot_mode)
+ {
+ if(icn85xx_bootfrom_sram() == 0)
+ {
+ flash_error("icn85xx_bootfrom_sram error\n");
+ icn85xx_update_status(R_STATE_ERR);
+ return R_STATE_ERR;
+ }
+ }
+ msleep(50);
+ icn85xx_update_status(R_OK);
+ flash_info("icn85xx upgrade ok\n");
+ return R_OK;
+}
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h new file mode 100755 index 00000000..757408c2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/icn85xx_ts/icn85xx_fw.h @@ -0,0 +1,2517 @@ +const unsigned char icn85xx_fw[40235] = {
+ 0xb0,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0x36,0x16,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xda,0x15,0x00,0x00,0xf0,0x13,0x00,0x00,0x6e,0x13,0x00,0x00,0xc4,0x14,0x00,0x00,
+ 0xfc,0x13,0x00,0x00,0xb8,0x12,0x00,0x00,0x98,0x11,0x00,0x00,0x96,0x10,0x00,0x00,
+ 0xfc,0x14,0x00,0x00,0xd0,0x14,0x00,0x00,0x82,0x15,0x00,0x00,0x28,0x15,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0x38,0x16,0x00,0x00,0x3a,0x16,0x00,0x00,
+ 0x3e,0x16,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0x3c,0x16,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,
+ 0xe4,0x07,0x00,0x00,0xe4,0x07,0x00,0x00,0x40,0x16,0x00,0x00,0x56,0x16,0x00,0x00,
+ 0x00,0x27,0x00,0x00,0x22,0x00,0x00,0x00,0x01,0x00,0x05,0x00,0x08,0x00,0x0c,0x00,
+ 0x0f,0x00,0x13,0x00,0x17,0x00,0x1a,0x00,0x1e,0x00,0x22,0x00,0x26,0x00,0x2a,0x00,
+ 0x2e,0x00,0x32,0x00,0x37,0x00,0x3c,0x00,0x40,0x00,0x46,0x00,0x4b,0x00,0x50,0x00,
+ 0x56,0x00,0x5d,0x00,0x63,0x00,0x6b,0x00,0x73,0x00,0x7b,0x00,0x84,0x00,0x8e,0x00,
+ 0x99,0x00,0xa6,0x00,0xb4,0x00,0xc4,0x00,0xd6,0x00,0xeb,0x00,0x04,0x01,0x22,0x01,
+ 0x47,0x01,0x75,0x01,0xb1,0x01,0x02,0x02,0x77,0x02,0x2e,0x03,0x77,0x04,0x74,0x07,
+ 0x60,0x16,0x00,0x00,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7e,0x7e,0x7e,0x7e,
+ 0x7e,0x7d,0x7d,0x7d,0x7d,0x7c,0x7c,0x7c,0x7b,0x7b,0x7a,0x7a,0x79,0x79,0x78,0x78,
+ 0x77,0x77,0x76,0x76,0x75,0x75,0x74,0x73,0x73,0x72,0x71,0x71,0x70,0x6f,0x6e,0x6d,
+ 0x6d,0x6c,0x6b,0x6a,0x69,0x68,0x67,0x67,0x66,0x65,0x64,0x63,0x62,0x61,0x60,0x5f,
+ 0x5e,0x5d,0x5b,0x5a,0x59,0x58,0x57,0x56,0x55,0x53,0x52,0x51,0x50,0x4f,0x4d,0x4c,
+ 0x4b,0x4a,0x48,0x47,0x46,0x44,0x43,0x42,0x40,0x3f,0x3e,0x3c,0x3b,0x3a,0x38,0x37,
+ 0x35,0x34,0x32,0x31,0x30,0x2e,0x2d,0x2b,0x2a,0x28,0x27,0x25,0x24,0x22,0x21,0x1f,
+ 0x1e,0x1c,0x1b,0x19,0x17,0x16,0x14,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x09,0x08,0x06,
+ 0x05,0x03,0x02,0x00,0xaa,0xa5,0x55,0x5a,0x5a,0xa5,0x66,0x6a,0x58,0x02,0x00,0x04,
+ 0x10,0x0a,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x0f,0x0d,0x0b,0x09,0x07,0x05,
+ 0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x14,0x0e,0x0c,0x0a,0x08,0x06,0x04,0x02,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x16,0x00,0x00,0x00,0x1e,0x14,0x05,0x01,0xa0,0x0f,0x28,0x00,0x96,0x00,0x09,0x01,
+ 0x00,0x34,0x21,0x40,0x1f,0x58,0x1b,0xa8,0x16,0x88,0x13,0x3a,0x00,0x32,0x00,0x2d,
+ 0x00,0x2a,0x00,0x14,0x00,0x58,0x02,0x03,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x14,
+ 0x28,0x3c,0x50,0xc8,0x00,0x03,0x01,0x00,0x01,0x01,0x10,0x01,0x14,0x00,0x28,0x00,
+ 0x58,0x02,0x00,0xea,0x00,0x01,0x06,0x1e,0x0a,0x00,0x10,0x27,0x00,0x00,0x00,0x80,
+ 0x01,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,
+ 0x00,0x02,0x01,0x00,0x02,0x80,0x01,0x06,0x00,0x02,0x00,0x01,0x01,0x0a,0x10,0x20,
+ 0x03,0xc4,0xff,0x3c,0x00,0x64,0x01,0x01,0x01,0x00,0x1e,0x00,0x64,0x01,0x00,0x01,
+ 0x00,0x00,0x64,0x0a,0x00,0x01,0x14,0x01,0x07,0x00,0xd0,0x07,0x14,0x14,0x14,0x14,
+ 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,
+ 0x14,0x14,0x14,0x14,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x32,0x00,0x05,0x01,0x00,0x00,0x01,0x03,
+ 0x05,0x07,0x46,0x46,0x0f,0x01,0x00,0x00,0x01,0x32,0xe8,0x03,0x00,0x03,0x00,0x00,
+ 0x00,0x40,0x00,0x20,0x00,0x20,0x00,0xe0,0x00,0xe0,0x00,0x00,0x00,0xf0,0x00,0xf0,
+ 0x00,0xf0,0x00,0x10,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe8,
+ 0x00,0xf8,0x00,0x08,0x00,0xf8,0x00,0x08,0x00,0xf8,0x00,0xf0,0x00,0xf0,0x00,0x00,
+ 0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0xf0,0xab,0xfa,0x00,0xf0,0xab,0xfa,0x55,0x05,
+ 0x55,0x05,0x00,0xf0,0x55,0x05,0xab,0xfa,0xd8,0xf0,0x94,0xf7,0x36,0xf4,0xe5,0xf5,
+ 0x0d,0x05,0x79,0xed,0x43,0xf9,0x5e,0x03,0x51,0xfe,0x74,0xf9,0x2f,0xf2,0x46,0xff,
+ 0xe9,0xfa,0x5d,0xfc,0x8c,0x06,0xd1,0xed,0xba,0x00,0x17,0x05,0xa3,0x03,0xde,0xf4,
+ 0x37,0xfd,0x4d,0xef,0xd3,0xfb,0xf4,0x06,0xbd,0xe9,0x6f,0xfa,0x9b,0xfe,0xa6,0xf7,
+ 0xe9,0x0d,0x7a,0xf3,0x9a,0xf9,0x33,0xf7,0x66,0xfa,0xcd,0xf4,0x9a,0x05,0x33,0xf7,
+ 0x66,0x06,0xcd,0x00,0x9a,0xfd,0x33,0xfb,0x66,0x02,0xcd,0x00,0x55,0xf5,0x55,0xf5,
+ 0x55,0xf5,0x55,0xf5,0x00,0x00,0xff,0xff,0x55,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x55,0xf5,0x00,0x00,0x00,0x00,0x2a,0x05,0x81,0xfa,0x9e,0xf8,0x66,0xf8,0x97,0xf8,
+ 0xb7,0x03,0xe6,0xf9,0x8f,0x02,0x27,0xf7,0x74,0xfd,0x30,0x03,0xe4,0x01,0x64,0xfd,
+ 0x7b,0xff,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,
+ 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0xf8,
+ 0x51,0x01,0xad,0xfc,0xaa,0xf9,0x2b,0xfb,0x6a,0xfa,0xcb,0xfa,0xf0,0xff,0xb3,0x02,
+ 0xa7,0xf6,0xad,0xfc,0x54,0x04,0x2b,0xfb,0x15,0x05,0xcb,0xfa,0xf0,0xff,0xb3,0x02,
+ 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xf8,
+ 0x00,0xf8,0x5b,0xff,0xf2,0xfa,0xbb,0xfb,0x07,0xf8,0x31,0xf9,0xc4,0x01,0x90,0xfa,
+ 0x59,0xfa,0x20,0x00,0xd1,0x02,0xcf,0xfb,0xf3,0x03,0x15,0xfe,0xb5,0x02,0x25,0xfc,
+ 0x28,0xfd,0xff,0x02,0x4a,0x02,0x9a,0xf9,0x9a,0xf9,0x00,0x00,0x9a,0xf9,0x00,0x00,
+ 0x9a,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9a,0xf9,0x9a,0xf9,0x00,0x00,
+ 0x9a,0xf9,0x9a,0xf9,0x00,0x00,0x00,0x00,0x9a,0xf9,0x9a,0xf9,0x13,0xfe,0x0f,0xfc,
+ 0xd8,0xfa,0x7b,0xfb,0xb4,0xfc,0x50,0x02,0x2b,0xfb,0x14,0x02,0xc4,0xf9,0xf4,0x01,
+ 0x89,0x03,0x34,0x00,0xa9,0x00,0x41,0xfa,0x08,0xfd,0xe5,0x01,0xee,0xfc,0xb0,0xf9,
+ 0xf4,0x01,0x68,0x01,0x01,0x01,0x01,0xff,0xff,0x01,0xff,0xff,0xff,0x01,0xff,0xff,
+ 0x01,0x01,0xff,0xff,0xff,0x01,0xff,0x01,0xff,0xff,0xff,0x01,0x01,0xff,0x01,0xff,
+ 0xff,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0x01,
+ 0x01,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0x01,0x01,0x01,0xff,0xff,0xff,0x01,
+ 0xff,0xff,0x01,0x01,0x01,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0x01,0xff,0xff,
+ 0x01,0x01,0xff,0xff,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0xff,0x01,0x01,0x01,
+ 0xff,0xff,0xff,0xff,0x01,0xff,0x01,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0xff,0x01,
+ 0x01,0x01,0xff,0x01,0x01,0xff,0xff,0x01,0xff,0x01,0xff,0xff,0x01,0xff,0xff,0xff,
+ 0xff,0xff,0x01,0x01,0xff,0xff,0x01,0xff,0x01,0xff,0x01,0x01,0xff,0xff,0xff,0x01,
+ 0xff,0x01,0x01,0x01,0xff,0xff,0x01,0x01,0x01,0xff,0x01,0xff,0xff,0x01,0xff,0xff,
+ 0xff,0xff,0x01,0xff,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0xff,0xff,0x01,0x01,0xff,
+ 0xff,0x01,0xff,0x01,0xff,0x01,0x01,0x01,0x01,0xff,0xff,0x01,0xff,0xff,0x01,0x01,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xff,0x01,0xff,0x01,0x01,0x01,0x01,0xff,
+ 0xff,0x01,0xff,0xff,0x01,0x01,0x00,0x00,0x01,0x02,0x04,0x08,0x00,0x01,0x02,0x02,
+ 0x03,0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05,
+ 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,
+ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
+ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,
+ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
+ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
+ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
+ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x45,0x6e,0x74,0x65,
+ 0x72,0x20,0x44,0x75,0x6d,0x6d,0x79,0x20,0x45,0x78,0x63,0x65,0x70,0x74,0x69,0x6f,
+ 0x6e,0x20,0x48,0x61,0x6e,0x64,0x6c,0x65,0x72,0x21,0x20,0x00,0x6d,0x65,0x6d,0x6f,
+ 0x72,0x79,0x20,0x64,0x75,0x6d,0x70,0x3a,0x25,0x78,0x2c,0x25,0x64,0x0a,0x00,0x00,
+ 0x0a,0x00,0x00,0x00,0x25,0x78,0x20,0x00,0x25,0x32,0x64,0x3a,0x25,0x34,0x64,0x2c,
+ 0x25,0x34,0x64,0x2c,0x25,0x32,0x64,0x2c,0x25,0x32,0x64,0x7c,0x00,0x00,0x00,0x00,
+ 0x0a,0x00,0x00,0x00,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,
+ 0x43,0x44,0x45,0x46,0x00,0x00,0x00,0x00,0x41,0x64,0x64,0x72,0x3a,0x30,0x78,0x25,
+ 0x78,0x0a,0x00,0x00,0x25,0x35,0x64,0x2c,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,
+ 0x52,0x61,0x77,0x3a,0x54,0x78,0x3a,0x25,0x32,0x64,0x2c,0x52,0x78,0x3a,0x25,0x32,
+ 0x64,0x0a,0x00,0x00,0x42,0x61,0x73,0x65,0x3a,0x54,0x78,0x3a,0x25,0x32,0x64,0x2c,
+ 0x52,0x78,0x3a,0x25,0x32,0x64,0x0a,0x00,0x62,0x65,0x66,0x6f,0x72,0x65,0x20,0x64,
+ 0x63,0x0a,0x00,0x00,0x44,0x69,0x66,0x3a,0x54,0x78,0x3a,0x25,0x32,0x64,0x2c,0x52,
+ 0x78,0x3a,0x25,0x32,0x64,0x0a,0x00,0x00,0x61,0x66,0x74,0x65,0x72,0x20,0x64,0x63,
+ 0x66,0x69,0x6c,0x74,0x65,0x72,0x0a,0x00,0x54,0x6f,0x74,0x61,0x6c,0x20,0x4e,0x75,
+ 0x6d,0x3a,0x25,0x32,0x64,0x0a,0x00,0x00,0x30,0x78,0x25,0x34,0x78,0x2c,0x30,0x78,
+ 0x25,0x34,0x78,0x2c,0x25,0x64,0x2c,0x25,0x64,0x7c,0x00,0x00,0x75,0x38,0x50,0x6c,
+ 0x61,0x6d,0x53,0x75,0x6d,0x3a,0x25,0x64,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xb0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x0a,0x71,0x10,0x12,0x02,0x60,0x03,0x60,0x01,0x60,0x04,0x60,0x05,0x60,0x06,0x60,
+ 0x07,0x60,0x08,0x60,0x09,0x60,0x0a,0x60,0x0b,0x60,0x0c,0x60,0x0d,0x60,0x0e,0x60,
+ 0x0f,0x60,0x02,0x7f,0x03,0x7f,0xff,0xf7,0xfc,0xaf,0x00,0x00,0xf2,0x07,0x00,0x00,
+ 0xec,0x88,0x00,0x00,0x70,0x24,0x00,0x9f,0x0d,0x72,0x0d,0x7f,0x00,0x8f,0x70,0x20,
+ 0xcf,0x00,0x70,0x24,0x00,0x9f,0x0b,0x77,0x0c,0x73,0x37,0x0f,0x04,0xe8,0x72,0x12,
+ 0x0b,0x74,0x74,0x05,0x0b,0x7f,0x0b,0x74,0x0c,0x77,0x74,0x0f,0x04,0xe8,0x72,0x12,
+ 0x03,0x60,0x74,0x05,0x0a,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x8c,0x06,0x00,0x00,
+ 0x7a,0x25,0x00,0x00,0x00,0x9e,0x00,0x00,0x60,0x89,0x00,0x00,0x04,0x9e,0x00,0x00,
+ 0x8c,0x82,0x00,0x00,0x52,0xaa,0x00,0x00,0x10,0x9e,0x00,0x00,0x22,0x83,0x00,0x00,
+ 0x70,0x24,0x00,0x9f,0x12,0x60,0x69,0x7f,0x6a,0x77,0x07,0xa7,0x07,0x2a,0x29,0xe0,
+ 0x69,0x76,0x06,0x84,0x69,0x76,0x06,0x83,0x69,0x75,0x05,0x86,0xc6,0x30,0xd6,0x30,
+ 0x05,0x96,0x67,0x75,0x68,0x76,0x06,0x95,0x36,0x60,0x67,0x75,0x05,0xb6,0x67,0x75,
+ 0x05,0x97,0x67,0x75,0x05,0x97,0x35,0x12,0x65,0x01,0x66,0x77,0x07,0xd5,0x66,0x77,
+ 0x07,0xb6,0x66,0x77,0x07,0x94,0x16,0x60,0x66,0x77,0x07,0xb6,0x66,0x77,0x07,0xb6,
+ 0x76,0x12,0x06,0xa7,0x07,0x2a,0xfd,0xe7,0x62,0x76,0x06,0xb7,0x36,0x60,0x54,0x77,
+ 0x07,0xb6,0x00,0x8f,0x70,0x20,0xcf,0x00,0xcf,0x00,0x46,0x60,0x5f,0x77,0x07,0x96,
+ 0x26,0x60,0x5e,0x77,0x07,0xb6,0xcf,0x00,0x70,0x24,0x00,0x9f,0x23,0x12,0x43,0x01,
+ 0x5c,0x77,0x07,0xa7,0x07,0x2a,0x0e,0xe0,0x03,0x2a,0x5a,0x77,0x05,0xe8,0x07,0xa3,
+ 0x32,0x60,0x03,0x2a,0x05,0xe0,0x05,0xf0,0x07,0xa7,0x32,0x60,0x07,0x2a,0x01,0xe0,
+ 0x13,0x60,0x55,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x54,0x76,0x06,0x87,0x07,0x34,
+ 0x17,0x34,0x06,0x97,0x53,0x76,0x06,0x87,0xe7,0x35,0x06,0x97,0xcf,0x00,0x4f,0x76,
+ 0x06,0x87,0x07,0x30,0x17,0x30,0x06,0x97,0x4e,0x76,0x06,0x87,0xe7,0x31,0x06,0x97,
+ 0xcf,0x00,0x70,0x24,0x00,0x9f,0x4b,0x77,0x07,0xa2,0x4b,0x77,0x72,0x03,0x4b,0x73,
+ 0x4c,0x7f,0x4c,0x77,0x07,0x92,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,
+ 0x23,0x12,0x43,0x01,0x36,0x12,0x36,0x25,0x46,0x01,0x47,0x77,0x67,0x0c,0x01,0xe0,
+ 0x03,0x65,0x42,0x72,0x46,0x7f,0x40,0x77,0x72,0x03,0x40,0x73,0x41,0x7f,0x44,0x77,
+ 0x07,0x92,0x00,0x8f,0x70,0x20,0xcf,0x00,0x43,0x76,0x06,0x87,0x07,0x34,0x17,0x34,
+ 0x06,0x97,0x37,0x76,0x06,0x87,0x40,0x75,0x57,0x1e,0x06,0x97,0x16,0x60,0x3f,0x77,
+ 0x37,0xb6,0xcf,0x00,0x3c,0x76,0x06,0x87,0x07,0x30,0x17,0x30,0x06,0x97,0x30,0x76,
+ 0x06,0x87,0xf7,0x31,0x06,0x97,0xcf,0x00,0x70,0x24,0x00,0x9f,0x39,0x77,0x07,0xa2,
+ 0x39,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,0x02,0x60,0x36,0x7f,
+ 0x32,0x60,0x36,0x7f,0x32,0x60,0x13,0x60,0x36,0x7f,0x02,0x60,0x36,0x7f,0x36,0x7f,
+ 0x37,0x7f,0x37,0x7f,0x06,0x60,0x37,0x77,0x07,0xd6,0x37,0x7f,0x38,0x7f,0x00,0x8f,
+ 0x70,0x20,0xcf,0x00,0x03,0x01,0x07,0x60,0x02,0xf0,0x06,0xb1,0x07,0x20,0x26,0x12,
+ 0x76,0x1c,0x47,0x0f,0xfa,0xe7,0xcf,0x00,0x63,0x01,0x07,0x60,0x03,0xf0,0x02,0xd3,
+ 0x07,0x20,0x12,0x20,0x47,0x0f,0xfb,0xe7,0xcf,0x00,0x00,0x00,0xbc,0x1d,0x00,0x00,
+ 0x00,0x04,0x04,0x00,0x00,0xe0,0x10,0x00,0x04,0xe0,0x10,0x00,0x00,0x06,0x04,0x00,
+ 0x00,0x13,0x18,0x00,0x2c,0x06,0x04,0x00,0x30,0x06,0x04,0x00,0x34,0x06,0x04,0x00,
+ 0x3c,0x06,0x04,0x00,0x40,0x06,0x04,0x00,0x2a,0x00,0x04,0x00,0x30,0x00,0x04,0x00,
+ 0x28,0x00,0x04,0x00,0x44,0x06,0x04,0x00,0x0c,0x00,0x04,0x00,0x60,0x01,0x04,0x00,
+ 0x3b,0xaa,0x00,0x00,0xc2,0x9c,0x00,0x00,0x0c,0x21,0x00,0x00,0x00,0x02,0x04,0x00,
+ 0x10,0x00,0x00,0xe0,0xc3,0x9c,0x00,0x00,0x80,0xc3,0xc9,0x01,0xe8,0x03,0x00,0x00,
+ 0xd0,0x83,0x00,0x00,0x04,0x02,0x04,0x00,0xb4,0x00,0x00,0x00,0x3e,0x84,0x00,0x00,
+ 0x14,0x02,0x04,0x00,0x10,0x02,0x04,0x00,0x00,0x00,0x00,0x80,0xb0,0xa8,0x00,0x00,
+ 0xc6,0x9c,0x00,0x00,0x2c,0x09,0x00,0x00,0xa8,0x20,0x00,0x00,0xc2,0x20,0x00,0x00,
+ 0xec,0x20,0x00,0x00,0xb8,0x08,0x00,0x00,0x2c,0x10,0x00,0x00,0x12,0x09,0x00,0x00,
+ 0x88,0x09,0x00,0x00,0x10,0x9e,0x00,0x00,0x34,0x16,0x00,0x00,0x7e,0x23,0x00,0x00,
+ 0x70,0x25,0x7a,0x00,0x2c,0x12,0x3b,0x12,0x4a,0x12,0x4a,0x01,0x6e,0x72,0xc3,0x12,
+ 0xb4,0x12,0x6d,0x7f,0x0d,0x60,0x0b,0xf0,0xd2,0x12,0xa3,0x12,0x6c,0x7f,0x02,0x2a,
+ 0x02,0xe0,0x6b,0x72,0x69,0x7f,0x6b,0x72,0x0e,0xa3,0x67,0x7f,0x0d,0x20,0xce,0x12,
+ 0xde,0x1c,0xbd,0x0f,0xf1,0xe7,0x66,0x72,0x64,0x7f,0x6a,0x00,0x70,0x21,0xcf,0x00,
+ 0x07,0x60,0x02,0xf0,0x00,0x12,0x07,0x20,0x27,0x0f,0xfc,0xe7,0xcf,0x00,0xf0,0x25,
+ 0x78,0x00,0x70,0x24,0x61,0x77,0x07,0xa6,0x61,0x75,0x55,0xa7,0x06,0x2a,0x05,0xe0,
+ 0x07,0x2a,0x4a,0xe8,0x55,0xb6,0x55,0xa7,0x47,0xf0,0x07,0x2a,0x16,0xe0,0x5c,0x75,
+ 0x05,0xa7,0x07,0x2a,0x5c,0x77,0x0f,0xe0,0x25,0xa5,0x05,0x2a,0x0c,0xe0,0x07,0xc5,
+ 0x05,0x20,0x65,0x01,0x07,0xd5,0x35,0x3e,0x56,0x0c,0x36,0xe0,0x17,0x60,0x53,0x76,
+ 0x56,0xb7,0x56,0xa7,0x31,0xf0,0x06,0x60,0x2e,0xf0,0x50,0x75,0x55,0xa7,0x17,0x2a,
+ 0x0e,0xe0,0x4f,0x77,0x07,0xa6,0x06,0x2a,0x03,0xe0,0x27,0xa7,0x07,0x2a,0x24,0xe8,
+ 0x06,0x60,0x4c,0x77,0x07,0xd6,0x49,0x77,0x57,0xb6,0x57,0xa7,0x1d,0xf0,0x47,0x76,
+ 0x56,0xa7,0x27,0x2a,0x19,0xe0,0x48,0x7e,0x0e,0xca,0x48,0x7d,0x0d,0xc9,0x48,0x7c,
+ 0x0c,0xc8,0x48,0x7b,0x0b,0xc7,0x00,0x97,0x02,0x60,0x47,0x7f,0x42,0x66,0x47,0x7f,
+ 0x0e,0xda,0x0d,0xd9,0x0c,0xd8,0x00,0x85,0x0b,0xd5,0x45,0x7f,0x07,0x60,0x3b,0x76,
+ 0x56,0xb7,0x06,0x60,0x3c,0x77,0x07,0xd6,0x70,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00,
+ 0xe2,0x01,0x95,0x2c,0x52,0x16,0x3f,0x77,0x27,0x0c,0x3f,0x77,0x07,0xe0,0x72,0x14,
+ 0x97,0x32,0x72,0x1c,0x02,0xa2,0xf5,0x67,0x52,0x1c,0x17,0xf0,0x86,0x2c,0x26,0x0c,
+ 0x07,0xe0,0x72,0x1c,0x3a,0x77,0x72,0x1c,0x02,0xa7,0xf2,0x67,0x72,0x05,0x0d,0xf0,
+ 0xf6,0x67,0x26,0x0c,0x06,0xe0,0x27,0x05,0x85,0x32,0x57,0x1c,0x07,0xa2,0x62,0x14,
+ 0x04,0xf0,0x72,0x1c,0x02,0xa2,0xf7,0x67,0x72,0x1c,0x42,0x01,0xcf,0x00,0xf0,0x24,
+ 0x7d,0x00,0x2d,0x12,0x6d,0x01,0x63,0x01,0x0d,0x2a,0x3e,0x12,0x7e,0x01,0x26,0xe8,
+ 0xe7,0x12,0xe7,0x1c,0xe7,0x1c,0x72,0x12,0x52,0x3c,0x72,0x1c,0x7d,0x01,0xe2,0x1c,
+ 0xd3,0x12,0x27,0x7f,0x25,0x12,0xe5,0x01,0x27,0x77,0x02,0x60,0xd6,0x62,0x07,0xc4,
+ 0x45,0x0d,0x05,0xe0,0x02,0x20,0x42,0x01,0x17,0x20,0x62,0x0f,0xf8,0xe7,0x0d,0x22,
+ 0x04,0xe0,0x0e,0x22,0x13,0xe8,0x20,0x77,0x03,0xf0,0xa7,0x65,0x0e,0x22,0x03,0xe0,
+ 0x27,0x05,0x72,0x12,0x01,0xf0,0x72,0x1c,0x42,0x01,0x08,0xf0,0xd2,0x62,0x0e,0x22,
+ 0x05,0xe8,0x03,0x2a,0x02,0xe8,0x19,0x72,0x01,0xf0,0x32,0x12,0x6d,0x00,0xf0,0x20,
+ 0xcf,0x00,0x00,0x00,0xac,0x06,0x00,0x00,0x7a,0x25,0x00,0x00,0x08,0x84,0x00,0x00,
+ 0xc0,0x06,0x00,0x00,0xc4,0x06,0x00,0x00,0xc7,0x9c,0x00,0x00,0x20,0xaa,0x00,0x00,
+ 0x70,0xa8,0x00,0x00,0x10,0x9e,0x00,0x00,0x1c,0x04,0x04,0x00,0x20,0x04,0x04,0x00,
+ 0x40,0x04,0x04,0x00,0x44,0x04,0x04,0x00,0x68,0x23,0x00,0x00,0xe0,0x0a,0x00,0x00,
+ 0x60,0x26,0x00,0x00,0x7f,0x01,0x00,0x00,0x64,0x01,0x00,0x00,0x00,0xff,0xff,0xff,
+ 0x3e,0x84,0x00,0x00,0x08,0x01,0x00,0x00,0xb4,0xff,0xff,0xff,0x87,0x00,0x00,0x00,
+ 0x72,0x01,0x22,0x03,0x73,0x01,0x33,0x03,0x23,0x1c,0xf5,0x32,0x02,0x60,0xf6,0x60,
+ 0x04,0x2d,0x17,0x60,0x37,0x0c,0x03,0xe8,0x32,0x12,0x62,0x01,0x0e,0xf0,0x27,0x12,
+ 0x27,0x1c,0x57,0x1c,0x67,0x1b,0x06,0x24,0x66,0x01,0x73,0x0c,0x03,0xe8,0x52,0x1c,
+ 0x62,0x01,0x73,0x05,0x15,0x3e,0x46,0x0f,0xf2,0xe7,0xcf,0x00,0x70,0x24,0x00,0x9f,
+ 0x28,0x77,0x07,0xa6,0x16,0x2e,0x06,0x2a,0x2f,0xe8,0x07,0xa6,0x26,0x75,0x56,0x16,
+ 0x07,0xb6,0x32,0x60,0x25,0x73,0x25,0x7f,0x32,0x60,0x25,0x73,0x24,0x7f,0x25,0x7f,
+ 0x87,0x2c,0x27,0x16,0x25,0x76,0x06,0xa5,0x06,0xb7,0x12,0x01,0x24,0x77,0x07,0xa5,
+ 0x07,0xb1,0x22,0x01,0x23,0x73,0x03,0xa5,0x03,0xb1,0x82,0x3f,0x22,0x74,0x04,0xa5,
+ 0x04,0xb2,0x06,0xa6,0x07,0xa5,0x85,0x3c,0x65,0x1e,0x03,0xa7,0x07,0x3d,0x57,0x1e,
+ 0x04,0xa3,0x83,0x3d,0x17,0x72,0x73,0x1e,0x1c,0x74,0x05,0x60,0x1c,0x7f,0x12,0x72,
+ 0x1c,0x73,0x44,0x60,0x05,0x60,0x19,0x7f,0x0e,0x77,0x07,0xa6,0x16,0x36,0x14,0xe8,
+ 0x07,0xa6,0x18,0x75,0x56,0x16,0x07,0xb6,0x32,0x60,0x17,0x73,0x0c,0x7f,0x32,0x60,
+ 0x17,0x73,0x0a,0x7f,0x16,0x72,0x16,0x73,0x17,0x74,0x05,0x60,0x10,0x7f,0x12,0x72,
+ 0x16,0x73,0x44,0x60,0x05,0x60,0x0d,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x00,0x00,
+ 0x3c,0xaa,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0xb0,0x00,0x00,0x3c,0x1f,0x00,0x00,
+ 0x00,0xa0,0x00,0x00,0x96,0x3b,0x00,0x00,0x33,0xaa,0x00,0x00,0x34,0xaa,0x00,0x00,
+ 0x35,0xaa,0x00,0x00,0x36,0xaa,0x00,0x00,0xc0,0x06,0x00,0x00,0x20,0x20,0x00,0x00,
+ 0xe4,0x01,0x00,0x00,0xfd,0x00,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0xc0,0x00,0x00,
+ 0x00,0x9c,0x00,0x00,0x23,0x01,0x00,0x00,0xe8,0x01,0x00,0x00,0x70,0x24,0x7e,0x00,
+ 0x0b,0x7e,0xe2,0x12,0x03,0x60,0x64,0x60,0x0a,0x7f,0x16,0x60,0x0e,0xb6,0xa7,0x60,
+ 0x2e,0xb7,0x07,0x60,0x1e,0xb7,0x3e,0xb6,0x5e,0xb7,0x06,0x72,0x03,0x60,0x04,0x64,
+ 0x04,0x7f,0x05,0x7f,0x06,0x7f,0x6e,0x00,0x70,0x20,0xcf,0x00,0xb0,0xa8,0x00,0x00,
+ 0xc4,0x09,0x00,0x00,0x70,0xa8,0x00,0x00,0xf8,0x16,0x00,0x00,0xf8,0x1a,0x00,0x00,
+ 0xf0,0x25,0x78,0x00,0x6d,0x75,0x55,0xa7,0x27,0x2a,0xd2,0xe8,0x85,0xa7,0x07,0x2a,
+ 0x0c,0xe8,0x6a,0x77,0x16,0x60,0x17,0xb6,0x06,0x60,0x07,0xb6,0x67,0xb6,0x77,0xb6,
+ 0x47,0xb6,0x57,0xb6,0x44,0x60,0x97,0xb4,0x85,0xb6,0x64,0x77,0x07,0xa6,0x06,0x2a,
+ 0x13,0xe0,0x17,0xa6,0x06,0x2a,0x10,0xe0,0x27,0xa6,0x06,0x2a,0x0d,0xe0,0x37,0xa2,
+ 0x02,0x2a,0x0a,0xe0,0x5f,0x7e,0x1e,0xb2,0x5f,0x7f,0x3e,0xa7,0x07,0x2a,0xfd,0xef,
+ 0x06,0x60,0x5b,0x77,0x37,0xb6,0xac,0xf0,0x5a,0x77,0x27,0xa6,0x07,0xa7,0xa6,0x2a,
+ 0x06,0xe0,0x17,0x2a,0x02,0xe0,0x58,0x7f,0x07,0xf0,0x58,0x7f,0x05,0xf0,0x17,0x2a,
+ 0x02,0xe0,0x57,0x7f,0x01,0xf0,0x57,0x7f,0x2b,0x12,0x51,0x77,0x07,0xa6,0x16,0x2a,
+ 0x02,0xe8,0x16,0x60,0x07,0xb6,0x07,0xa7,0x0a,0x60,0x17,0x2a,0x51,0xe0,0x4b,0x78,
+ 0x28,0xa7,0x0b,0xb7,0xbd,0x12,0x1d,0x20,0x50,0x7c,0xae,0x12,0xa9,0x12,0x0e,0x01,
+ 0x0c,0xa7,0x07,0x2a,0x38,0xe8,0x09,0x20,0x49,0x01,0xe6,0x12,0xe6,0x1c,0xe6,0x1c,
+ 0x66,0x1c,0x86,0x1c,0x65,0x12,0x0d,0xb1,0x46,0xa6,0x1d,0xb6,0x55,0xa6,0x2d,0xb6,
+ 0x65,0xa6,0x3d,0xb6,0x75,0xa6,0x4d,0xb6,0xc6,0x12,0x06,0x24,0x06,0xa6,0x5d,0xb6,
+ 0x6d,0xb7,0x6d,0x20,0x17,0x2a,0x03,0xe8,0x47,0x2a,0x04,0xe0,0x02,0xf0,0x7a,0x12,
+ 0x01,0xf0,0x1a,0x60,0x3e,0x75,0x55,0xa6,0x05,0x64,0x56,0x16,0x06,0x2a,0x13,0xe8,
+ 0xe6,0x12,0xe6,0x1c,0xe6,0x1c,0x66,0x1c,0x86,0x1c,0x46,0xaf,0x56,0xa4,0x84,0x3c,
+ 0x66,0xa1,0x76,0xa5,0x85,0x3c,0xc6,0x12,0x06,0x24,0x35,0x72,0xe3,0x12,0xf4,0x1e,
+ 0x15,0x1e,0x06,0xa6,0x34,0x7f,0x0e,0x20,0x5c,0x20,0x5e,0x2a,0xc0,0xe7,0x2f,0x77,
+ 0x57,0xa7,0x06,0x64,0x67,0x16,0x07,0x2a,0x02,0xe8,0x2f,0x72,0x2e,0x7f,0x1b,0xb9,
+ 0x23,0x77,0x27,0xa6,0x37,0xb6,0x22,0x77,0x22,0x7d,0x37,0xa6,0x06,0x2a,0xfc,0xef,
+ 0x07,0x60,0x3d,0xb7,0x4e,0x66,0x29,0x72,0x2a,0x7f,0x5d,0xa7,0x07,0x2a,0x04,0xe8,
+ 0x0e,0x24,0x4e,0x01,0x0e,0x2a,0xf7,0xe7,0x1a,0x77,0x27,0xa6,0xa6,0x2a,0x02,0xe0,
+ 0xb6,0x60,0x01,0xf0,0xa6,0x60,0x27,0xb6,0x16,0x7d,0x17,0x60,0x1d,0xb7,0x1a,0x2a,
+ 0x1c,0xe0,0x0d,0xa7,0x3e,0x60,0x0c,0x60,0x4d,0xbc,0x12,0x60,0x12,0x7f,0x1d,0x7f,
+ 0x03,0xf0,0x1d,0xa7,0x07,0x2a,0x0b,0xe8,0x4d,0xa7,0x07,0x2a,0xfa,0xef,0x02,0x60,
+ 0x0d,0x7f,0x16,0x72,0x17,0x7f,0x0e,0x24,0x4e,0x01,0x0e,0x2a,0xed,0xe7,0x02,0x60,
+ 0x09,0x7f,0x06,0x60,0x15,0x77,0x07,0x96,0x03,0xf0,0x12,0x60,0x06,0x7f,0x11,0x7f,
+ 0x68,0x00,0xf0,0x21,0xcf,0x00,0x00,0x00,0x20,0xaa,0x00,0x00,0x70,0xa8,0x00,0x00,
+ 0xb0,0xa8,0x00,0x00,0xb8,0x08,0x00,0x00,0xc2,0x17,0x00,0x00,0x06,0x1b,0x00,0x00,
+ 0xbe,0x17,0x00,0x00,0xfa,0x1a,0x00,0x00,0x79,0xa8,0x00,0x00,0x44,0xaa,0x00,0x00,
+ 0xc8,0x06,0x00,0x00,0x7a,0x25,0x00,0x00,0xe0,0x06,0x00,0x00,0xc8,0x00,0x00,0x00,
+ 0xe0,0x0a,0x00,0x00,0xea,0x08,0x00,0x00,0x18,0x02,0x04,0x00,0x89,0x76,0x06,0x87,
+ 0x57,0x30,0x07,0x31,0x06,0x97,0x36,0x60,0x87,0x77,0x07,0xb6,0x87,0x76,0x87,0x77,
+ 0x07,0xd6,0x87,0x76,0x88,0x77,0x07,0xd6,0x17,0x60,0x87,0x76,0x06,0xb7,0x87,0x76,
+ 0x06,0xb7,0x87,0x77,0x07,0xa6,0x35,0x60,0x56,0x1e,0x07,0xb6,0x54,0x60,0x85,0x76,
+ 0x06,0xb4,0x85,0x76,0x06,0xb5,0x07,0xa6,0x85,0x75,0x56,0x16,0x07,0xb6,0x84,0x76,
+ 0x85,0x77,0x07,0xd6,0x85,0x76,0x06,0x87,0x07,0x34,0x06,0x97,0x84,0x77,0x05,0x60,
+ 0x07,0xb5,0x17,0xb5,0x24,0x60,0x37,0xb4,0x27,0xb5,0x47,0xb5,0x06,0x87,0x80,0x75,
+ 0x57,0x1e,0x06,0x97,0xcf,0x00,0xf0,0x24,0x7c,0x00,0x7e,0x77,0x13,0x60,0x57,0xb3,
+ 0x7e,0x75,0x05,0xa5,0x05,0x2a,0x64,0xe8,0x7d,0x74,0x04,0xa6,0x16,0x2e,0x06,0x2a,
+ 0x03,0xe8,0x07,0xb3,0x26,0x60,0x05,0xf0,0x04,0xa4,0x14,0x36,0x04,0xe8,0x26,0x60,
+ 0x07,0xb6,0x72,0x77,0x37,0xb6,0x71,0x76,0x07,0x60,0x26,0xb7,0x36,0xa7,0x57,0x0f,
+ 0x4f,0xe0,0x04,0x60,0x73,0x7d,0x0d,0xa2,0x26,0xa3,0x53,0x0c,0x0f,0xe0,0x03,0x2a,
+ 0x03,0xe0,0x06,0xb2,0x07,0x60,0x09,0xf0,0x06,0xae,0x16,0xa7,0x87,0x3c,0xe7,0x1e,
+ 0x87,0x3c,0x27,0x1c,0x67,0x01,0x06,0xb7,0x87,0x3e,0x16,0xb7,0x64,0x7e,0x37,0x12,
+ 0x07,0x20,0x26,0xb7,0x04,0x20,0x44,0x01,0x54,0x0f,0xe5,0xe7,0x07,0x60,0x4e,0xb7,
+ 0x16,0x60,0x56,0x77,0x07,0xb6,0x5f,0x77,0x07,0xa7,0x8d,0x60,0x62,0x7c,0x17,0x2a,
+ 0x14,0xe0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x5f,0x7f,0x0c,0xb2,0x0e,0xa6,
+ 0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,
+ 0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,0x13,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,
+ 0x72,0x1e,0x56,0x7f,0x0c,0xb2,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,
+ 0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,
+ 0x47,0x77,0x47,0xa6,0x06,0x2a,0x04,0xe8,0x06,0x60,0x3c,0x75,0x05,0xb6,0x47,0xb6,
+ 0x0e,0x60,0x27,0xbe,0x02,0x60,0x4a,0x7f,0x43,0x77,0x17,0xa6,0x06,0x2a,0x01,0xe8,
+ 0x17,0xbe,0x6c,0x00,0xf0,0x20,0xcf,0x00,0x70,0x25,0x7b,0x00,0x3e,0x76,0x07,0x60,
+ 0x56,0xb7,0x3a,0x7e,0x17,0x60,0x4e,0xb7,0x06,0xb7,0x26,0x60,0x3e,0xb6,0x3a,0x7c,
+ 0x0c,0xac,0x0c,0x2a,0x28,0xe8,0x0d,0x60,0x3a,0x7b,0x0b,0xa3,0x2e,0xa7,0x3e,0xa6,
+ 0x67,0x0c,0x0b,0xe0,0x07,0x2a,0x02,0xe0,0x0e,0xb3,0x14,0xf0,0x0e,0xa6,0x1e,0xa7,
+ 0x87,0x3c,0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,
+ 0x72,0x1e,0x34,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,
+ 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x2e,0xa7,0x07,0x20,0x2e,0xb7,0x0d,0x20,0x4d,0x01,
+ 0xcd,0x0f,0xdb,0xe7,0x02,0xf0,0x19,0x76,0x06,0xb7,0x20,0x7e,0x2e,0xa6,0x3e,0xa7,
+ 0x76,0x0f,0x1a,0xe0,0x07,0x60,0x4e,0xb7,0x16,0x60,0x14,0x77,0x07,0xb6,0x8d,0x60,
+ 0x21,0x7c,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x1f,0x7f,0x0c,0xb2,0x0e,0xa6,
+ 0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,
+ 0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,0x6b,0x00,0x70,0x21,0xcf,0x00,0x00,0x00,
+ 0x08,0x00,0x04,0x00,0x14,0x00,0x04,0x00,0x78,0x01,0x00,0x00,0x20,0x0e,0x04,0x00,
+ 0x48,0x01,0x00,0x00,0x24,0x0e,0x04,0x00,0x19,0x0e,0x04,0x00,0x1d,0x0e,0x04,0x00,
+ 0x00,0x0e,0x04,0x00,0x2c,0x0e,0x04,0x00,0x30,0x0e,0x04,0x00,0xfb,0x00,0x00,0x00,
+ 0x88,0x03,0x00,0x00,0x34,0x0e,0x04,0x00,0x10,0x00,0x00,0xe0,0x12,0x9e,0x00,0x00,
+ 0xfe,0x00,0x00,0x00,0xb0,0xa8,0x00,0x00,0x18,0x0e,0x04,0x00,0x0c,0x0e,0x04,0x00,
+ 0x14,0x0e,0x04,0x00,0x10,0x0e,0x04,0x00,0xc6,0x17,0x00,0x00,0x12,0x1b,0x00,0x00,
+ 0xb8,0x08,0x00,0x00,0x9a,0x18,0x00,0x00,0x70,0x25,0x7b,0x00,0x75,0x75,0x07,0x60,
+ 0x55,0xb7,0x74,0x7e,0x17,0x60,0x4e,0xb7,0x26,0x60,0x05,0xb6,0x3e,0xb6,0x72,0x7c,
+ 0x0c,0xac,0x0c,0x2a,0x28,0xe8,0x0d,0x60,0x71,0x7b,0x0b,0xa3,0x2e,0xa7,0x3e,0xa6,
+ 0x67,0x0c,0x0b,0xe0,0x07,0x2a,0x02,0xe0,0x0e,0xb3,0x14,0xf0,0x0e,0xa6,0x1e,0xa7,
+ 0x87,0x3c,0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,
+ 0x72,0x1e,0x67,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,
+ 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x2e,0xa7,0x07,0x20,0x2e,0xb7,0x0d,0x20,0x4d,0x01,
+ 0xcd,0x0f,0xdb,0xe7,0x02,0xf0,0x5f,0x76,0x06,0xb7,0x5a,0x7e,0x2e,0xa6,0x3e,0xa7,
+ 0x76,0x0f,0x1a,0xe0,0x07,0x60,0x4e,0xb7,0x16,0x60,0x5a,0x77,0x07,0xb6,0x8d,0x60,
+ 0x5a,0x7c,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x58,0x7f,0x0c,0xb2,0x0e,0xa6,
+ 0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,
+ 0x0d,0x24,0x4d,0x01,0x0d,0x2a,0xed,0xe7,0x6b,0x00,0x70,0x21,0xcf,0x00,0x70,0x25,
+ 0x7b,0x00,0x4f,0x77,0x07,0xac,0x8c,0x28,0x4c,0x01,0x45,0x77,0x07,0xa6,0x16,0x2a,
+ 0x19,0xe0,0x12,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x4a,0x7f,0x0b,0xb2,
+ 0x0d,0x20,0x4d,0x01,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,
+ 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x03,0xf0,0x0d,0x60,0x3a,0x7e,0x3f,0x7b,0xcd,0x0f,
+ 0xe9,0xe7,0x1b,0xf0,0x07,0xa7,0x27,0x2a,0x18,0xe0,0x12,0xf0,0x0e,0xa2,0x1e,0xa7,
+ 0x87,0x3c,0x72,0x1e,0x3a,0x7f,0x0b,0xb2,0x0d,0x20,0x4d,0x01,0x0e,0xa6,0x1e,0xa7,
+ 0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x03,0xf0,
+ 0x0d,0x60,0x2c,0x7e,0x31,0x7b,0xcd,0x0f,0xe9,0xe7,0x6b,0x00,0x70,0x21,0xcf,0x00,
+ 0x70,0x24,0x00,0x9f,0x31,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x25,0x7a,0x00,
+ 0x2f,0x76,0x06,0xa7,0x17,0x2e,0x07,0x2a,0x07,0xe8,0x16,0x60,0x21,0x77,0x07,0xb6,
+ 0x26,0x60,0x20,0x77,0x37,0xb6,0x08,0xf0,0x06,0xa6,0x16,0x36,0x05,0xe8,0x27,0x60,
+ 0x1c,0x76,0x06,0xb7,0x1c,0x76,0x36,0xb7,0x1c,0x7c,0x0c,0xac,0x0d,0x60,0x1b,0x7b,
+ 0x19,0x7e,0x17,0x7a,0x28,0xf0,0x0b,0xa3,0x2e,0xa7,0x3e,0xa6,0x67,0x0c,0x0b,0xe0,
+ 0x07,0x2a,0x02,0xe0,0x0e,0xb3,0x19,0xf0,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,
+ 0x87,0x3c,0x37,0x1c,0x0f,0xf0,0x0a,0xa7,0x17,0x2a,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,
+ 0x72,0x1e,0x02,0xe0,0x17,0x7f,0x01,0xf0,0x0e,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x2e,0xa7,0x07,0x20,
+ 0x2e,0xb7,0x0d,0x20,0x4d,0x01,0xcd,0x0f,0xd6,0xe7,0x6a,0x00,0x70,0x21,0xcf,0x00,
+ 0xb0,0xa8,0x00,0x00,0x12,0x9e,0x00,0x00,0x18,0x0e,0x04,0x00,0x14,0x0e,0x04,0x00,
+ 0x20,0x1b,0x00,0x00,0x1d,0x0e,0x04,0x00,0x10,0x0e,0x04,0x00,0x12,0x1b,0x00,0x00,
+ 0x1c,0x0e,0x04,0x00,0xc6,0x17,0x00,0x00,0x6e,0x13,0x00,0x00,0x0c,0x0e,0x04,0x00,
+ 0x9a,0x18,0x00,0x00,0x70,0x24,0x00,0x9f,0x4f,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,
+ 0x70,0x24,0x7e,0x00,0x4d,0x7e,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x4b,0x7f,
+ 0x4c,0x77,0x07,0xb2,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,
+ 0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,
+ 0x42,0x7e,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x42,0x7f,0x41,0x77,0x07,0xb2,
+ 0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,
+ 0x1e,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x16,0x60,0x3a,0x77,
+ 0x07,0xb6,0x35,0x7e,0x27,0x60,0x3e,0xb7,0x39,0x73,0x03,0xa3,0x2e,0xa5,0x16,0x60,
+ 0x56,0x0c,0x0e,0xe8,0x05,0x2a,0x04,0xe0,0x2e,0xb6,0x0e,0xb3,0x07,0x60,0x15,0xf0,
+ 0x2e,0xb7,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,
+ 0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,0x2e,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,0x87,0x3e,0x1e,0xb7,0x6e,0x00,0x70,0x20,
+ 0xcf,0x00,0x70,0x24,0x7e,0x00,0x27,0x60,0x24,0x76,0x06,0xb7,0x1f,0x7e,0x3e,0xb7,
+ 0x23,0x73,0x03,0xa3,0x2e,0xa5,0x16,0x60,0x56,0x0c,0x0e,0xe8,0x05,0x2a,0x04,0xe0,
+ 0x2e,0xb6,0x0e,0xb3,0x07,0x60,0x15,0xf0,0x2e,0xb7,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x87,0x3c,0x37,0x1c,0x0a,0xf0,0x0e,0xa2,0x1e,0xa7,0x87,0x3c,0x72,0x1e,
+ 0x19,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x20,0x67,0x01,0x0e,0xb7,
+ 0x87,0x3e,0x1e,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,0x12,0x77,
+ 0x07,0xa6,0x12,0x75,0x56,0x16,0x07,0xb6,0x07,0xa6,0x16,0x34,0x07,0xb6,0x10,0x7f,
+ 0x00,0x8f,0x70,0x20,0xcf,0x00,0x62,0x01,0x04,0x77,0x07,0xb2,0x82,0x3e,0x17,0xb2,
+ 0xcf,0x00,0x00,0x00,0xfc,0x13,0x00,0x00,0x12,0x9e,0x00,0x00,0xc6,0x17,0x00,0x00,
+ 0x10,0x0e,0x04,0x00,0x12,0x1b,0x00,0x00,0xb0,0xa8,0x00,0x00,0x14,0x0e,0x04,0x00,
+ 0x9a,0x18,0x00,0x00,0x20,0x1b,0x00,0x00,0x04,0x00,0x04,0x00,0xfd,0x00,0x00,0x00,
+ 0x2c,0x10,0x00,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,0xcf,0x00,
+ 0x70,0x24,0x00,0x9f,0x22,0x7f,0x02,0x60,0x22,0x7f,0x16,0x60,0x22,0x77,0x47,0xb6,
+ 0x00,0x8f,0x70,0x20,0xcf,0x00,0x16,0x60,0x1f,0x77,0x37,0xb6,0x1f,0x77,0x07,0xa6,
+ 0x06,0x20,0x46,0x01,0x07,0xb6,0x1d,0x75,0x05,0xa5,0x56,0x0c,0x1e,0xe8,0x06,0x60,
+ 0x07,0xb6,0x1b,0x72,0x02,0xa6,0x1b,0x74,0x04,0xa7,0x87,0x3c,0x67,0x1e,0x1a,0x75,
+ 0x05,0xa3,0x03,0x3d,0x73,0x1e,0x19,0x76,0x06,0xa7,0x87,0x3d,0x37,0x1e,0x07,0x20,
+ 0x83,0x2c,0x73,0x16,0x02,0xa1,0x02,0xb3,0x17,0x01,0x04,0xa3,0x04,0xb1,0x27,0x01,
+ 0x05,0xa4,0x05,0xb1,0x87,0x3f,0x06,0xa5,0x06,0xb7,0x11,0x75,0x05,0xa4,0x11,0x76,
+ 0x06,0xa7,0x87,0x3c,0x47,0x1e,0x07,0x20,0x67,0x01,0x84,0x2c,0x74,0x16,0x05,0xa3,
+ 0x05,0xb4,0x87,0x3e,0x06,0xa5,0x06,0xb7,0xcf,0x00,0x00,0x00,0xfe,0x08,0x00,0x00,
+ 0xb8,0x08,0x00,0x00,0xb0,0xa8,0x00,0x00,0x17,0x9e,0x00,0x00,0xc6,0x9c,0x00,0x00,
+ 0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,
+ 0x40,0xaa,0x00,0x00,0x41,0xaa,0x00,0x00,0xf0,0x24,0x7d,0x00,0x91,0x7e,0xe2,0x12,
+ 0x03,0x60,0x24,0x62,0x90,0x7f,0x90,0x72,0x03,0x60,0x90,0x74,0x8e,0x7f,0x90,0x72,
+ 0x03,0x60,0x64,0x60,0x8c,0x7f,0x76,0x62,0x9e,0xb6,0x8e,0x77,0xae,0xb7,0x47,0x60,
+ 0xbe,0xb7,0xce,0xb6,0xee,0xb7,0x02,0x60,0x8c,0x7f,0x2e,0x12,0x42,0x60,0x8a,0x7f,
+ 0x2d,0x12,0x27,0x12,0x47,0x3c,0xe7,0x1e,0x47,0x01,0x88,0x76,0x06,0xb7,0x02,0x2a,
+ 0x05,0xe0,0x42,0x60,0x87,0x7f,0x42,0x60,0xd3,0x12,0x86,0x7f,0x7d,0x77,0x0e,0x60,
+ 0x67,0xbe,0x77,0xbe,0x1d,0x60,0x87,0xbd,0x84,0x7f,0x86,0x2c,0x26,0x16,0x83,0x77,
+ 0x07,0xa5,0x07,0xb6,0x12,0x01,0x82,0x77,0x07,0xa6,0x07,0xb1,0x22,0x01,0x81,0x77,
+ 0x07,0xa6,0x07,0xb1,0x82,0x3f,0x80,0x77,0x07,0xa6,0x07,0xb2,0x80,0x77,0x07,0xa6,
+ 0x07,0xbe,0x7f,0x77,0x07,0xa6,0x07,0xbe,0x7f,0x77,0x07,0xa6,0x07,0xbe,0x7e,0x77,
+ 0x07,0xa6,0x07,0xbe,0x7e,0x77,0x07,0xbe,0x7e,0x77,0x07,0xbe,0x6d,0x77,0x57,0xbe,
+ 0x26,0x62,0x7c,0x77,0x07,0xb6,0x6d,0x76,0x06,0xa6,0x27,0x62,0x76,0x0f,0x7a,0x77,
+ 0x02,0xe0,0x07,0xbd,0x01,0xf0,0x07,0xbe,0x6d,0x00,0xf0,0x20,0xcf,0x00,0x62,0x72,
+ 0xcf,0x00,0x76,0x72,0xcf,0x00,0x27,0x12,0x67,0x01,0xc6,0x2c,0x76,0x0c,0x06,0xe8,
+ 0x82,0x2c,0x16,0x62,0x76,0x0c,0x60,0xe8,0x5a,0x76,0x0f,0xf0,0xd6,0x2c,0x76,0x0c,
+ 0x14,0xe8,0x6f,0x75,0x57,0x1c,0x67,0x01,0x82,0x2c,0x6e,0x76,0x76,0x0c,0x54,0xe8,
+ 0x6e,0x76,0x26,0xa5,0xa5,0x2a,0x04,0xe0,0x54,0x76,0x76,0x1c,0x06,0xa2,0x4c,0xf0,
+ 0x26,0xa6,0xb6,0x2a,0x49,0xe0,0x65,0x76,0xf8,0xf7,0x68,0x76,0x76,0x0c,0x12,0xe8,
+ 0x57,0x75,0x05,0xa5,0x57,0x76,0x06,0xa6,0x86,0x3c,0x56,0x1e,0x56,0x75,0x05,0xa5,
+ 0x05,0x3d,0x65,0x1e,0x55,0x76,0x06,0xa6,0x86,0x3d,0x56,0x1e,0x61,0x75,0x57,0x1c,
+ 0x67,0x01,0xe3,0xf7,0xe6,0x2c,0x76,0x0c,0x06,0xe8,0x5e,0x76,0x67,0x1c,0x67,0x01,
+ 0x5e,0x75,0x57,0x1c,0x28,0xf0,0x76,0x12,0x76,0x01,0x82,0x2c,0xf6,0x37,0x24,0xe8,
+ 0x5b,0x76,0x76,0x0c,0x05,0xe8,0x5a,0x76,0x67,0x1c,0x67,0x01,0x5a,0x76,0x1a,0xf0,
+ 0x5a,0x76,0x76,0x0c,0x19,0xe0,0xc5,0x32,0x57,0x1c,0x67,0x01,0x47,0x2a,0x38,0x76,
+ 0x11,0xe0,0x06,0xa5,0x16,0xa7,0x87,0x3c,0x57,0x1e,0x26,0xa5,0x05,0x3d,0x75,0x1e,
+ 0x36,0xa7,0x87,0x3d,0x57,0x1e,0x51,0x76,0x67,0x0f,0x05,0xe0,0x15,0x60,0x50,0x76,
+ 0x06,0xb5,0x01,0xf0,0x67,0x1c,0x07,0xa2,0xcf,0x00,0x70,0x24,0x7e,0x00,0x62,0x01,
+ 0x3e,0x12,0x4e,0x01,0xc7,0x2c,0x27,0x0c,0xda,0xe8,0x17,0x62,0x27,0x0c,0xff,0xe8,
+ 0x22,0x2a,0x0b,0xe8,0x42,0x2a,0x0c,0xe8,0x02,0x2a,0xf9,0xe0,0x21,0x77,0x07,0xa6,
+ 0xe6,0x0f,0xf5,0xe8,0x16,0x60,0x17,0xb6,0xee,0xf0,0x1d,0x77,0x27,0xbe,0xef,0xf0,
+ 0x1e,0x2a,0x02,0xe0,0x40,0x7f,0xc1,0xf0,0x2e,0x2a,0x03,0xe0,0x19,0x77,0x57,0xbe,
+ 0xbc,0xf0,0x4e,0x2a,0x08,0xe0,0x3c,0x77,0x07,0xa7,0x37,0x2a,0xb6,0xe0,0x28,0x76,
+ 0x06,0xa7,0x17,0x34,0x86,0xf0,0xe6,0x12,0xf6,0x24,0x46,0x01,0x67,0x60,0x67,0x0c,
+ 0x03,0xe8,0xe2,0x12,0x36,0x7f,0xa9,0xf0,0x07,0x62,0x7e,0x0f,0x07,0xe0,0x16,0x60,
+ 0x34,0x77,0x07,0xb6,0x06,0x60,0x0a,0x77,0x27,0xb6,0x9f,0xf0,0x07,0x63,0x7e,0x0f,
+ 0x03,0xe0,0x16,0x60,0x2b,0x77,0x98,0xf0,0x57,0x65,0x16,0x60,0x7e,0x0f,0x04,0xe8,
+ 0x67,0x66,0x7e,0x0f,0x57,0xe0,0x06,0x60,0x02,0x77,0x77,0xb6,0x8e,0xf0,0x00,0x00,
+ 0x20,0xaa,0x00,0x00,0x22,0x83,0x00,0x00,0xc0,0xa8,0x00,0x00,0x60,0x01,0x00,0x00,
+ 0x44,0xaa,0x00,0x00,0x85,0xff,0xff,0xff,0xa4,0x21,0x00,0x00,0x30,0xaa,0x00,0x00,
+ 0xc2,0x20,0x00,0x00,0xec,0x20,0x00,0x00,0x96,0x3b,0x00,0x00,0x33,0xaa,0x00,0x00,
+ 0x34,0xaa,0x00,0x00,0x35,0xaa,0x00,0x00,0x36,0xaa,0x00,0x00,0x37,0xaa,0x00,0x00,
+ 0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,0x3b,0xaa,0x00,0x00,
+ 0x3c,0xaa,0x00,0x00,0x3e,0xaa,0x00,0x00,0x3f,0xaa,0x00,0x00,0x30,0xa9,0x00,0x00,
+ 0x00,0xf0,0xff,0xff,0xb0,0x00,0x00,0x00,0xb0,0xa8,0x00,0x00,0xff,0x2f,0x00,0x00,
+ 0x00,0xe0,0xff,0xff,0x00,0xd0,0xff,0xff,0x00,0xe0,0x02,0x00,0xff,0x8f,0x00,0x00,
+ 0x00,0x80,0xff,0xff,0x00,0x9c,0x00,0x00,0xff,0xef,0x00,0x00,0xff,0xff,0x04,0x00,
+ 0x31,0xaa,0x00,0x00,0x60,0x26,0x00,0x00,0x18,0x9e,0x00,0x00,0x72,0x2d,0x00,0x00,
+ 0x32,0xaa,0x00,0x00,0x17,0x62,0x7e,0x0f,0x06,0xe0,0x07,0x60,0x32,0x76,0x06,0xb7,
+ 0x32,0x76,0x26,0xb7,0x32,0xf0,0x07,0x67,0x7e,0x0f,0x05,0xe0,0x30,0x76,0x06,0xa7,
+ 0x07,0x34,0x06,0xb7,0x2a,0xf0,0x2e,0x77,0x26,0x60,0x7e,0x0f,0x04,0xe8,0x2d,0x77,
+ 0x7e,0x0f,0x03,0xe0,0x06,0x60,0x2c,0x77,0x1f,0xf0,0x2c,0x77,0x16,0x60,0x7e,0x0f,
+ 0x04,0xe8,0x2b,0x77,0x7e,0x0f,0x03,0xe0,0x06,0x60,0x2a,0x77,0x15,0xf0,0x5e,0x2a,
+ 0x06,0xe0,0x16,0x60,0x29,0x77,0x07,0xb6,0x32,0x60,0x13,0x60,0x07,0xf0,0x6e,0x2a,
+ 0x07,0xe0,0x16,0x60,0x25,0x77,0x07,0xb6,0x32,0x60,0x03,0x60,0x24,0x7f,0x05,0xf0,
+ 0x7e,0x2a,0x03,0xe0,0x06,0x60,0x20,0x77,0x07,0xb6,0x21,0x77,0x24,0xf0,0xd7,0x2c,
+ 0x27,0x0c,0x25,0xe0,0xe7,0x2c,0x27,0x0c,0x22,0xe0,0x27,0x12,0xf7,0x36,0x1f,0xe8,
+ 0x1d,0x77,0x27,0x0c,0x05,0xe8,0x1c,0x77,0x72,0x1c,0x62,0x01,0x1c,0x77,0x15,0xf0,
+ 0x1c,0x77,0x27,0x0c,0x14,0xe0,0xc7,0x32,0x72,0x1c,0x62,0x01,0x42,0x2a,0x19,0x77,
+ 0x0c,0xe0,0x07,0xa6,0x17,0xa5,0x85,0x3c,0x65,0x1e,0x27,0xa6,0x06,0x3d,0x56,0x1e,
+ 0x37,0xa7,0x87,0x3d,0x67,0x1e,0x07,0xbe,0x02,0xf0,0x72,0x1c,0x02,0xbe,0x6e,0x00,
+ 0x70,0x20,0xcf,0x00,0x32,0xaa,0x00,0x00,0x20,0xaa,0x00,0x00,0x3c,0xaa,0x00,0x00,
+ 0x90,0x00,0x00,0x00,0x91,0x00,0x00,0x00,0x72,0x9c,0x00,0x00,0xa0,0x00,0x00,0x00,
+ 0xa1,0x00,0x00,0x00,0x11,0x9d,0x00,0x00,0x3b,0xaa,0x00,0x00,0x0c,0x21,0x00,0x00,
+ 0x18,0x9e,0x00,0x00,0xff,0x8f,0x00,0x00,0x00,0x80,0xff,0xff,0x00,0x9c,0x00,0x00,
+ 0xff,0xef,0x00,0x00,0x44,0xaa,0x00,0x00,0xcf,0x00,0x70,0x24,0x00,0x9f,0x0c,0x7f,
+ 0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,0x0a,0x7f,0x00,0x8f,0x70,0x20,
+ 0xcf,0x00,0x70,0x24,0x00,0x9f,0x62,0x01,0x08,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,
+ 0x70,0x24,0x00,0x9f,0x62,0x01,0x43,0x01,0x05,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,
+ 0xbe,0x17,0x00,0x00,0xc2,0x17,0x00,0x00,0xc6,0x17,0x00,0x00,0x9a,0x18,0x00,0x00,
+ 0x70,0x24,0x00,0x9f,0x09,0x77,0x07,0x86,0x09,0x77,0x09,0x72,0x76,0x0f,0x05,0xe0,
+ 0x09,0x73,0x09,0x74,0x15,0x60,0x09,0x7f,0x03,0xf0,0x09,0x73,0x07,0x74,0x09,0x7f,
+ 0x00,0x8f,0x70,0x20,0xcf,0x00,0x00,0x00,0x00,0xd0,0x10,0x00,0x5a,0xa5,0x66,0x6a,
+ 0x00,0x9c,0x00,0x00,0x00,0xc0,0x00,0x00,0x23,0x01,0x00,0x00,0xf6,0x1e,0x00,0x00,
+ 0xec,0x01,0x00,0x00,0x8c,0x82,0x00,0x00,0xf0,0x25,0x79,0x00,0x24,0x76,0x07,0x60,
+ 0x16,0xb7,0x56,0xb7,0x23,0x75,0x05,0xb7,0x26,0xb7,0x22,0x7f,0x23,0x72,0x23,0x7f,
+ 0x24,0x7f,0x24,0x7f,0x25,0x7f,0x25,0x7f,0x02,0x2a,0xfb,0xe7,0x25,0x7f,0x1b,0x7e,
+ 0x1c,0x79,0x24,0x7d,0x25,0x7c,0x25,0x7b,0x26,0x7a,0x26,0xf0,0x26,0x7f,0x26,0x7f,
+ 0x1d,0x7f,0x1d,0x7f,0x1e,0x7f,0x02,0x2a,0xfb,0xe7,0x24,0x7f,0x25,0x7f,0x09,0xa7,
+ 0x07,0x2a,0x13,0xe8,0x24,0x7f,0x87,0x2c,0x27,0x16,0x0d,0xa6,0x0d,0xb7,0x12,0x01,
+ 0x0c,0xa7,0x0c,0xb1,0x22,0x01,0x0b,0xa7,0x0b,0xb1,0x82,0x3f,0x0a,0xa7,0x0a,0xb2,
+ 0x17,0x60,0x2e,0xb7,0x2e,0xa7,0x07,0x2a,0xfd,0xe7,0x1b,0x7f,0x1c,0x7f,0x1c,0x7f,
+ 0x1d,0x72,0x1d,0x7f,0x1e,0x7f,0x1e,0x7f,0x0e,0xa7,0x07,0x2a,0xd7,0xef,0x1d,0x7f,
+ 0x16,0x60,0x02,0x77,0x17,0xb6,0x69,0x00,0xf0,0x21,0xcf,0x00,0x20,0xaa,0x00,0x00,
+ 0x32,0xaa,0x00,0x00,0x58,0x09,0x00,0x00,0x00,0x9c,0x00,0x00,0x8e,0x31,0x00,0x00,
+ 0x94,0x3b,0x00,0x00,0xd0,0x3c,0x00,0x00,0xea,0x3c,0x00,0x00,0x16,0x3c,0x00,0x00,
+ 0x7c,0x3c,0x00,0x00,0x33,0xaa,0x00,0x00,0x34,0xaa,0x00,0x00,0x35,0xaa,0x00,0x00,
+ 0x36,0xaa,0x00,0x00,0x8e,0x23,0x00,0x00,0x5e,0x31,0x00,0x00,0x70,0x3b,0x00,0x00,
+ 0xfc,0x0c,0x00,0x00,0x96,0x3b,0x00,0x00,0xf4,0x3c,0x00,0x00,0x5c,0x4f,0x00,0x00,
+ 0xf6,0x63,0x00,0x00,0x70,0xa8,0x00,0x00,0x3a,0x48,0x00,0x00,0x30,0x0e,0x00,0x00,
+ 0xee,0x0a,0x00,0x00,0x74,0x09,0x00,0x00,0xf0,0x25,0x79,0x00,0x02,0x60,0x34,0x7f,
+ 0x35,0x7e,0x0d,0x60,0x2e,0xbd,0x5e,0xbd,0x34,0x72,0x34,0x7f,0x1e,0xbd,0x34,0x7d,
+ 0x35,0x7c,0x35,0x7b,0x36,0x7a,0x19,0x60,0x20,0xf0,0x35,0x7f,0x36,0x7f,0x36,0x7f,
+ 0x37,0x7f,0x37,0x7f,0x02,0x2a,0xfb,0xe7,0x37,0x7f,0x37,0x7f,0x38,0x7f,0x87,0x2c,
+ 0x27,0x16,0x0d,0xa6,0x0d,0xb7,0x12,0x01,0x0c,0xa7,0x0c,0xb1,0x22,0x01,0x0b,0xa7,
+ 0x0b,0xb1,0x82,0x3f,0x0a,0xa7,0x0a,0xb2,0x2e,0xb9,0x04,0xf0,0x29,0x7f,0x0e,0xa7,
+ 0x17,0x2a,0x03,0xe0,0x2e,0xa7,0x07,0x2a,0xf9,0xe7,0x0e,0xa7,0x17,0x2a,0xdd,0xef,
+ 0x06,0x60,0x1c,0x77,0x27,0xb6,0x69,0x00,0xf0,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,
+ 0x02,0x60,0x17,0x7f,0x18,0x7e,0x0d,0x60,0x2e,0xbd,0x5e,0xbd,0x17,0x72,0x17,0x7f,
+ 0x1e,0xbd,0xed,0x12,0x23,0x7c,0x23,0x7b,0x24,0x7a,0x24,0x79,0x25,0x78,0x17,0xf0,
+ 0x18,0x7f,0x0c,0xbe,0x0b,0xa7,0x17,0x3e,0x47,0x34,0x0a,0xb7,0x09,0xbe,0x07,0x60,
+ 0x08,0xd7,0x20,0x76,0x21,0x77,0x07,0xd6,0x17,0x60,0x2d,0xb7,0x04,0xf0,0x10,0x7f,
+ 0x0d,0xa7,0x27,0x2a,0x03,0xe0,0x2d,0xa7,0x07,0x2a,0xf9,0xe7,0x13,0x7f,0x0d,0xae,
+ 0x2e,0x2a,0xe6,0xef,0x06,0x60,0x03,0x77,0x27,0xb6,0x68,0x00,0xf0,0x21,0xcf,0x00,
+ 0xa8,0x08,0x00,0x00,0x20,0xaa,0x00,0x00,0x00,0x9c,0x00,0x00,0x8e,0x31,0x00,0x00,
+ 0x33,0xaa,0x00,0x00,0x34,0xaa,0x00,0x00,0x35,0xaa,0x00,0x00,0x36,0xaa,0x00,0x00,
+ 0x8e,0x23,0x00,0x00,0x5e,0x31,0x00,0x00,0xd0,0x3c,0x00,0x00,0xea,0x3c,0x00,0x00,
+ 0x16,0x3c,0x00,0x00,0x70,0x3b,0x00,0x00,0xfc,0x0c,0x00,0x00,0x96,0x3b,0x00,0x00,
+ 0x5c,0x08,0x04,0x00,0x2a,0x9c,0x00,0x00,0x5d,0x08,0x04,0x00,0x74,0x08,0x04,0x00,
+ 0xa8,0x08,0x04,0x00,0xfc,0x7f,0x00,0x00,0xaa,0x08,0x04,0x00,0x02,0x01,0x78,0x76,
+ 0x06,0x87,0x78,0x74,0x47,0x1e,0x06,0x97,0x11,0x2a,0x77,0x77,0x07,0xa6,0x1a,0xe0,
+ 0x77,0x75,0x56,0x16,0x07,0xb6,0x76,0x76,0x06,0xa7,0x57,0x16,0x06,0xb7,0x75,0x76,
+ 0x06,0xa7,0x57,0x16,0x06,0xb7,0x74,0x77,0x07,0xb1,0x36,0x60,0x74,0x77,0x07,0xb6,
+ 0x74,0x75,0x05,0xa7,0x6e,0x74,0x47,0x16,0x05,0xb7,0x72,0x75,0x05,0xa7,0x47,0x16,
+ 0x05,0xb7,0x32,0xf0,0x21,0x2a,0x1a,0xe0,0x69,0x75,0x56,0x16,0x07,0xb6,0x68,0x76,
+ 0x06,0xa7,0x07,0x34,0x06,0xb7,0x67,0x76,0x06,0xa7,0x57,0x16,0x06,0xb7,0x16,0x60,
+ 0x66,0x77,0x07,0xb6,0x35,0x60,0x65,0x77,0x07,0xb5,0x65,0x75,0x05,0xa7,0x5f,0x74,
+ 0x47,0x16,0x05,0xb7,0x64,0x77,0x07,0xb6,0xb6,0x63,0x16,0xf0,0x41,0x2a,0x0d,0xe0,
+ 0x5b,0x75,0x56,0x16,0x07,0xb6,0x5a,0x77,0x07,0xa7,0x07,0x34,0x5a,0x76,0x06,0xb7,
+ 0x16,0x60,0x5c,0x77,0x07,0xb6,0xb6,0x66,0x07,0xf0,0x54,0x74,0x46,0x16,0x07,0xb6,
+ 0x16,0x60,0x58,0x77,0x07,0xb6,0xb6,0x60,0x58,0x77,0x07,0xb6,0x16,0x60,0x57,0x77,
+ 0x07,0x96,0xcf,0x00,0xc6,0x32,0x56,0x77,0x07,0x96,0x66,0x60,0x56,0x77,0x07,0xb6,
+ 0x06,0x60,0x55,0x77,0x07,0x96,0x55,0x77,0x16,0x60,0x07,0xb6,0x07,0xa6,0x06,0x2a,
+ 0xfd,0xe7,0xcf,0x00,0x02,0x01,0x52,0x76,0x4e,0x77,0x07,0x96,0x57,0x63,0x01,0x2a,
+ 0x01,0xe0,0x57,0x60,0x4c,0x76,0x06,0xb7,0x16,0x60,0x4b,0x77,0x07,0x96,0x4b,0x77,
+ 0x07,0xb6,0x07,0xa6,0x06,0x2a,0xfd,0xe7,0x4b,0x72,0x02,0xa2,0xcf,0x00,0x70,0x24,
+ 0x00,0x9f,0x49,0x7f,0x4a,0x76,0x42,0x77,0x07,0x96,0x16,0x60,0x42,0x77,0x07,0xb6,
+ 0x05,0x60,0x41,0x77,0x07,0x95,0x46,0x75,0x47,0x77,0x07,0xd5,0x40,0x77,0x07,0xb6,
+ 0x07,0xa6,0x06,0x2a,0xfd,0xe7,0x02,0x60,0x44,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7,
+ 0x00,0x8f,0x70,0x20,0xcf,0x00,0x05,0x01,0x11,0x2a,0x07,0xe8,0x21,0x2a,0x08,0xe8,
+ 0x41,0x2a,0x09,0xe0,0x3e,0x76,0xb7,0x66,0x08,0xf0,0x3d,0x76,0x37,0x60,0x05,0xf0,
+ 0x3d,0x76,0xb7,0x63,0x02,0xf0,0x3c,0x76,0xb7,0x60,0x2d,0x75,0x05,0x96,0x2d,0x76,
+ 0x06,0xb7,0x3a,0x77,0x07,0x93,0x3a,0x77,0x07,0x92,0x2b,0x77,0x07,0x94,0x2b,0x77,
+ 0x16,0x60,0x07,0xb6,0x07,0xa6,0x06,0x2a,0xfd,0xe7,0xcf,0x00,0xf0,0x24,0x7d,0x00,
+ 0x3d,0x12,0x2e,0x12,0x4e,0x01,0x28,0x7f,0x0e,0x2a,0x22,0x77,0x06,0xe0,0x31,0x76,
+ 0x07,0xb6,0xc6,0x32,0x1f,0x77,0x07,0x96,0x12,0xf0,0x1e,0x2a,0x06,0xe0,0x26,0x65,
+ 0x07,0xb6,0x2d,0x76,0x1b,0x77,0x07,0x96,0x08,0xf0,0x04,0x62,0x2e,0x2a,0x18,0x76,
+ 0x2a,0x75,0x01,0xe0,0x2a,0x74,0x07,0xb4,0x06,0x95,0x24,0x77,0x07,0x9d,0x06,0x60,
+ 0x16,0x77,0x07,0x96,0x16,0x77,0x16,0x60,0x07,0xb6,0x07,0xa6,0x06,0x2a,0xfd,0xe7,
+ 0x02,0x60,0x19,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7,0x6d,0x00,0xf0,0x20,0xcf,0x00,
+ 0x00,0x06,0x04,0x00,0x00,0x00,0x00,0x15,0x04,0x06,0x04,0x00,0xfe,0x00,0x00,0x00,
+ 0x08,0x06,0x04,0x00,0x0c,0x06,0x04,0x00,0x10,0x06,0x04,0x00,0x14,0x06,0x04,0x00,
+ 0x18,0x06,0x04,0x00,0x1c,0x06,0x04,0x00,0x20,0x06,0x04,0x00,0x28,0x06,0x04,0x00,
+ 0x2c,0x06,0x04,0x00,0x30,0x06,0x04,0x00,0x40,0x06,0x04,0x00,0x44,0x06,0x04,0x00,
+ 0x00,0x10,0x08,0x00,0x48,0x06,0x04,0x00,0x74,0x1e,0x00,0x00,0x20,0x10,0x00,0x00,
+ 0x02,0x02,0x00,0x00,0x38,0x06,0x04,0x00,0x94,0x1e,0x00,0x00,0x01,0x1d,0x18,0x00,
+ 0x00,0x13,0x18,0x00,0x01,0x1d,0x1a,0x00,0x01,0x13,0x18,0x00,0x34,0x06,0x04,0x00,
+ 0x3c,0x06,0x04,0x00,0xc7,0xff,0xff,0xff,0x00,0x13,0x00,0x00,0xd8,0xff,0xff,0xff,
+ 0xf0,0x25,0x78,0x00,0x70,0x24,0x38,0x12,0x4c,0x12,0x05,0x01,0x2a,0x60,0x01,0x2a,
+ 0x03,0xe8,0x11,0x2a,0x01,0xe0,0x74,0x7a,0x2b,0x12,0x0e,0x60,0x74,0x79,0x24,0xf0,
+ 0x02,0x60,0x73,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7,0x72,0x7f,0x73,0x77,0x73,0x76,
+ 0x06,0x97,0x73,0x76,0x06,0x9b,0x00,0x86,0x73,0x77,0x07,0x96,0x87,0x32,0xd7,0x1c,
+ 0x7c,0x0c,0x03,0xe8,0x87,0x32,0x09,0xd7,0x03,0xf0,0xcd,0x14,0x6d,0x01,0x09,0xdd,
+ 0x6e,0x77,0x07,0xba,0x6e,0x77,0x16,0x60,0x07,0xb6,0x86,0x32,0x6b,0x1c,0x07,0xa6,
+ 0x06,0x2a,0xfd,0xe7,0x87,0x32,0x7e,0x1c,0xe6,0x12,0x86,0x1c,0x00,0x96,0xed,0x12,
+ 0x6d,0x01,0xcd,0x0c,0xd5,0xef,0x02,0x60,0x5e,0x7f,0x12,0x2e,0x02,0x2a,0xfb,0xe7,
+ 0x70,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00,0x02,0x01,0x01,0x2a,0x61,0x76,0x06,0xa7,
+ 0x04,0xe0,0x07,0x30,0x17,0x30,0x07,0x34,0x02,0xf0,0x5e,0x75,0x57,0x16,0x06,0xb7,
+ 0xcf,0x00,0x02,0x01,0x87,0x60,0x17,0x0c,0x06,0xe8,0x5b,0x77,0x07,0xc6,0x11,0x13,
+ 0x61,0x1e,0x61,0x01,0x07,0xd1,0xcf,0x00,0x02,0x01,0x87,0x60,0x17,0x0c,0x05,0xe8,
+ 0x56,0x76,0x06,0xc7,0x11,0x13,0x17,0x1f,0x06,0xd7,0xcf,0x00,0x02,0x01,0x43,0x01,
+ 0x87,0x60,0x17,0x0c,0x0a,0xe8,0x03,0x2a,0x51,0x77,0x11,0x13,0x07,0xc6,0x03,0xe8,
+ 0x16,0x1e,0x66,0x01,0x01,0xf0,0x16,0x1f,0x07,0xd6,0xcf,0x00,0x02,0x01,0x43,0x01,
+ 0x87,0x60,0x17,0x0c,0x0a,0xe8,0x03,0x2a,0x4a,0x77,0x11,0x13,0x07,0xc6,0x03,0xe8,
+ 0x16,0x1e,0x66,0x01,0x01,0xf0,0x16,0x1f,0x07,0xd6,0xcf,0x00,0x02,0x01,0x43,0x01,
+ 0x87,0x60,0x17,0x0c,0x0a,0xe8,0x03,0x2a,0x43,0x77,0x11,0x13,0x07,0xc6,0x03,0xe8,
+ 0x16,0x1e,0x66,0x01,0x01,0xf0,0x16,0x1f,0x07,0xd6,0xcf,0x00,0x02,0x01,0x82,0x2c,
+ 0x87,0x60,0x17,0x0c,0x08,0xe8,0x3c,0x76,0x06,0xc6,0x17,0x13,0x67,0x16,0x47,0x01,
+ 0x17,0x1a,0x72,0x12,0x42,0x01,0xcf,0x00,0x02,0x01,0x77,0x60,0x17,0x0c,0x0a,0xe8,
+ 0x37,0x76,0x06,0xc7,0x11,0x13,0x17,0x1f,0x06,0xd7,0x35,0x76,0x06,0xc7,0x17,0x1e,
+ 0x67,0x01,0x06,0xd7,0xcf,0x00,0x02,0x01,0x77,0x60,0x17,0x0c,0x0a,0xe8,0x30,0x76,
+ 0x06,0xc7,0x11,0x13,0x17,0x1f,0x06,0xd7,0x2d,0x76,0x06,0xc7,0x17,0x1e,0x67,0x01,
+ 0x06,0xd7,0xcf,0x00,0x70,0x25,0x7a,0x00,0x2e,0x12,0x4e,0x01,0x82,0x2c,0x77,0x60,
+ 0xe7,0x0c,0x26,0xe8,0x21,0x7d,0x0d,0xcd,0x21,0x7c,0x0c,0xcc,0x24,0x7b,0x0b,0xcb,
+ 0x24,0x7a,0x0a,0xca,0xe2,0x12,0x23,0x7f,0xe2,0x12,0x03,0x60,0x23,0x7f,0xe2,0x12,
+ 0x23,0x7f,0x42,0x66,0x23,0x7f,0xe2,0x12,0x23,0x7f,0x02,0x2a,0x09,0xe8,0xe2,0x12,
+ 0x22,0x7f,0x42,0x66,0x1f,0x7f,0xe2,0x12,0x1f,0x7f,0x02,0x2a,0x32,0x00,0x02,0x20,
+ 0x12,0x77,0x07,0xdd,0x12,0x77,0x07,0xdc,0x15,0x77,0x07,0xdb,0x15,0x77,0x07,0xda,
+ 0x6a,0x00,0x70,0x21,0xcf,0x00,0x00,0x00,0xf2,0x00,0x00,0x00,0x40,0x06,0x04,0x00,
+ 0x94,0x1e,0x00,0x00,0x74,0x1e,0x00,0x00,0x00,0x13,0x00,0x00,0x2c,0x06,0x04,0x00,
+ 0x34,0x06,0x04,0x00,0x3c,0x06,0x04,0x00,0x30,0x06,0x04,0x00,0x44,0x06,0x04,0x00,
+ 0x58,0x01,0x04,0x00,0xfc,0x00,0x00,0x00,0x1c,0x04,0x04,0x00,0x20,0x04,0x04,0x00,
+ 0x24,0x04,0x04,0x00,0x08,0x04,0x04,0x00,0x28,0x04,0x04,0x00,0x38,0x04,0x04,0x00,
+ 0x3c,0x04,0x04,0x00,0xc2,0x20,0x00,0x00,0xec,0x20,0x00,0x00,0x68,0x21,0x00,0x00,
+ 0xe0,0x0a,0x00,0x00,0x4c,0x21,0x00,0x00,0x86,0x21,0x00,0x00,0xf0,0x24,0x7d,0x00,
+ 0x2e,0x12,0x4e,0x01,0x3d,0x12,0x4d,0x01,0x87,0x60,0xe7,0x0c,0x12,0xe8,0xe2,0x12,
+ 0x03,0x60,0x5f,0x7f,0x60,0x76,0x06,0xc7,0xee,0x13,0xe5,0x12,0x65,0x01,0x57,0x1e,
+ 0x06,0xd7,0x0d,0x2a,0x5d,0x77,0x07,0xc6,0x02,0xe8,0x56,0x1e,0x01,0xf0,0xe6,0x1f,
+ 0x07,0xd6,0x6d,0x00,0xf0,0x20,0xcf,0x00,0x02,0x01,0x21,0x2a,0x08,0xe0,0x57,0x76,
+ 0x06,0xa7,0x17,0x34,0x06,0xb7,0x56,0x76,0x06,0xa7,0x17,0x34,0x06,0xb7,0x55,0x76,
+ 0x06,0xa7,0x55,0x75,0x57,0x1e,0x06,0xb7,0x55,0x76,0x06,0xa7,0x57,0x1e,0x06,0xb7,
+ 0x54,0x76,0x06,0xa7,0x57,0x1e,0x06,0xb7,0x66,0x60,0x52,0x77,0x07,0xb6,0x52,0x76,
+ 0x06,0x87,0xa7,0x34,0x06,0x97,0x16,0x60,0x51,0x77,0x07,0xb6,0x51,0x76,0x06,0xa7,
+ 0x07,0x34,0x06,0xb7,0x50,0x76,0x06,0x87,0x50,0x75,0x57,0x1e,0x06,0x97,0x4f,0x76,
+ 0x06,0x87,0x4f,0x75,0x57,0x1e,0x06,0x97,0x4f,0x77,0x07,0xa6,0x16,0x34,0x07,0xb6,
+ 0x07,0xa6,0x06,0x34,0x07,0xb6,0xcf,0x00,0x02,0x01,0x4a,0x77,0x07,0xa6,0x4a,0x75,
+ 0x56,0x16,0x07,0xb6,0x07,0xa6,0x49,0x75,0x56,0x16,0x07,0xb6,0x06,0x60,0x3f,0x77,
+ 0x07,0xb6,0x40,0x76,0x06,0x87,0x46,0x75,0x57,0x16,0x06,0x97,0x40,0x76,0x06,0x87,
+ 0x45,0x75,0x57,0x16,0x06,0x97,0x3a,0x76,0x06,0xa7,0x3f,0x75,0x57,0x16,0x06,0xb7,
+ 0x21,0x2a,0x09,0xe0,0x2e,0x76,0x06,0xa7,0x3d,0x75,0x57,0x16,0x06,0xb7,0x2c,0x76,
+ 0x06,0xa7,0x57,0x16,0x06,0xb7,0xcf,0x00,0x70,0x24,0x7e,0x00,0x2e,0x12,0x4e,0x01,
+ 0xe2,0x12,0x39,0x7f,0xe2,0x12,0x39,0x7f,0x6e,0x00,0x70,0x20,0xcf,0x00,0x38,0x76,
+ 0x39,0x77,0x07,0xd6,0xcf,0x00,0x06,0x60,0x37,0x77,0x07,0xd6,0xcf,0x00,0x36,0x77,
+ 0x16,0x60,0x07,0xb6,0x36,0x76,0x07,0xb6,0xcf,0x00,0xf0,0x24,0x7d,0x00,0x2d,0x12,
+ 0x3e,0x12,0x4e,0x01,0x32,0x60,0x0e,0x2a,0x0b,0xe8,0x52,0x60,0x4e,0x2a,0x08,0xe8,
+ 0x5e,0x2a,0x03,0xe0,0x12,0x60,0x23,0x12,0x04,0xf0,0x7e,0x2a,0x14,0xe0,0x22,0x60,
+ 0x13,0x60,0x2b,0x7f,0xe2,0x12,0x2b,0x7f,0xd2,0x12,0x2b,0x73,0x2c,0x7f,0x62,0x01,
+ 0x2c,0x77,0x07,0xd2,0x2c,0x77,0x07,0xd2,0x16,0x61,0x2b,0x77,0x07,0xb6,0x2b,0x76,
+ 0x06,0xa7,0x07,0x34,0x06,0xb7,0x6d,0x00,0xf0,0x20,0xcf,0x00,0x02,0x01,0x28,0x77,
+ 0x07,0xb1,0x28,0x76,0x06,0xa7,0x17,0x2e,0x07,0x2a,0xfc,0xe7,0xcf,0x00,0x00,0x00,
+ 0xec,0x20,0x00,0x00,0x40,0x04,0x04,0x00,0x44,0x04,0x04,0x00,0x21,0x0e,0x04,0x00,
+ 0x25,0x0e,0x04,0x00,0x1c,0x04,0x04,0x00,0xa7,0x00,0x00,0x00,0x20,0x04,0x04,0x00,
+ 0x38,0x04,0x04,0x00,0x61,0x01,0x04,0x00,0x04,0x00,0x04,0x00,0x40,0x01,0x04,0x00,
+ 0x0b,0x00,0x04,0x00,0x0c,0x01,0x04,0x00,0x00,0x00,0x0f,0x00,0x04,0x01,0x04,0x00,
+ 0x03,0x20,0x00,0x00,0x44,0x01,0x04,0x00,0xfe,0x00,0x00,0x00,0xfd,0x00,0x00,0x00,
+ 0xff,0xff,0xf0,0xff,0xfc,0xdf,0xff,0xff,0xa8,0x22,0x00,0x00,0x18,0x23,0x00,0x00,
+ 0x10,0x02,0x00,0x00,0x24,0x00,0x04,0x00,0x26,0x00,0x04,0x00,0xfe,0xff,0xff,0xff,
+ 0x2c,0x21,0x00,0x00,0xd8,0x20,0x00,0x00,0x00,0xc2,0x01,0x00,0xd0,0x83,0x00,0x00,
+ 0x22,0x02,0x04,0x00,0x32,0x02,0x04,0x00,0x30,0x02,0x04,0x00,0x20,0x02,0x04,0x00,
+ 0x24,0x02,0x04,0x00,0x28,0x02,0x04,0x00,0xf0,0x25,0x78,0x00,0x01,0x63,0x10,0x05,
+ 0x3c,0x12,0x4a,0x12,0x4a,0x01,0x59,0x12,0x49,0x01,0x09,0x2a,0x27,0x00,0xa0,0x97,
+ 0xa6,0x12,0x06,0x24,0x46,0x01,0xf7,0x60,0x67,0x0c,0x07,0xe0,0xa7,0x62,0x03,0xb7,
+ 0x07,0x60,0x13,0xb7,0x32,0x12,0x12,0x20,0x4d,0xf0,0x0b,0x60,0xf2,0x37,0x03,0xe8,
+ 0xaa,0x2a,0x4d,0xe8,0x2b,0x60,0x2d,0x12,0x2b,0x2a,0x4c,0xe0,0x5a,0x77,0x26,0x12,
+ 0xf6,0x2e,0x67,0x1c,0x07,0xa7,0x00,0xb7,0x4d,0x3e,0x1e,0x60,0x08,0x12,0xe8,0x1c,
+ 0x13,0xf0,0xd2,0x12,0xa3,0x12,0x54,0x7f,0x53,0x77,0x72,0x1c,0x02,0xa7,0x08,0xb7,
+ 0x08,0x20,0x0e,0x20,0x4e,0x01,0xd2,0x12,0xa3,0x12,0x50,0x7f,0x2d,0x12,0xa0,0x87,
+ 0x07,0x2a,0x02,0xe8,0x9e,0x0c,0x04,0xe0,0x0d,0x2a,0xeb,0xe7,0x08,0x0f,0xe9,0xef,
+ 0x1b,0x2a,0x05,0xe0,0xd7,0x62,0x08,0xb7,0x08,0x20,0x0e,0x20,0x4e,0x01,0xa0,0x87,
+ 0x07,0x2a,0x06,0xe8,0x08,0xf0,0x08,0xb7,0x08,0x20,0x0e,0x20,0x4e,0x01,0x04,0xf0,
+ 0x86,0x12,0xc7,0x12,0x08,0xf0,0x07,0x62,0x9e,0x0c,0xf5,0xef,0xf9,0xf7,0x06,0x24,
+ 0x06,0xa5,0x07,0xb5,0x07,0x20,0x06,0x0f,0xfa,0xe7,0x82,0x12,0x02,0x05,0xc2,0x1c,
+ 0x07,0x60,0x02,0xb7,0x01,0x63,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x2d,0x12,
+ 0x0d,0x28,0x1b,0x60,0x0e,0x60,0x08,0x12,0xcf,0xf7,0x81,0x63,0x10,0x05,0xd0,0x97,
+ 0xc0,0x96,0xb0,0x95,0xa0,0x94,0x90,0x93,0x80,0x92,0x78,0x00,0xf0,0x25,0x07,0x64,
+ 0x07,0x1c,0x07,0x8e,0x4d,0x64,0x0d,0x1c,0x0c,0x60,0x59,0x62,0x4a,0x64,0x4a,0xf0,
+ 0x97,0x0f,0x0a,0xe8,0x0c,0x2a,0x08,0xe0,0xa7,0x2a,0x02,0xe0,0xd2,0x60,0x28,0x7f,
+ 0x0e,0xa2,0x0e,0x20,0x27,0x7f,0x3e,0xf0,0x1e,0xa2,0xa2,0x0f,0x18,0xe8,0x2a,0x0c,
+ 0x06,0xe8,0x24,0x76,0x26,0x1c,0x87,0x60,0x67,0x0c,0x2f,0xe8,0x0a,0xf0,0x47,0x66,
+ 0x72,0x0f,0x0d,0xe8,0x87,0x67,0x72,0x0f,0x19,0xe8,0x87,0x65,0x72,0x0f,0x25,0xe0,
+ 0x15,0xf0,0x0e,0x20,0x1d,0x77,0x72,0x1c,0x2c,0x12,0x4c,0x01,0x23,0xf0,0xdb,0x12,
+ 0x3b,0x20,0x0d,0x82,0x03,0x12,0xa4,0x60,0xc5,0x12,0x18,0x7f,0x08,0x12,0x02,0xf0,
+ 0x14,0x7f,0x08,0x20,0x08,0xa2,0x02,0x2a,0xfb,0xe7,0x11,0xf0,0xdb,0x12,0x3b,0x20,
+ 0x0d,0x82,0x03,0x12,0x04,0x61,0xc5,0x12,0x11,0x7f,0x08,0x12,0x02,0xf0,0x0c,0x7f,
+ 0x08,0x20,0x08,0xa2,0x02,0x2a,0xfb,0xe7,0x02,0xf0,0x09,0x7f,0xdb,0x12,0x1e,0x20,
+ 0xbd,0x12,0x0c,0x60,0x0e,0xa7,0x07,0x2a,0xb3,0xe7,0xf0,0x21,0x68,0x00,0x81,0x63,
+ 0x10,0x1c,0xcf,0x00,0xe4,0x06,0x00,0x00,0x08,0x84,0x00,0x00,0xd0,0x83,0x00,0x00,
+ 0xec,0x23,0x00,0x00,0xcf,0xff,0xff,0xff,0xd0,0xff,0xff,0xff,0x98,0x24,0x00,0x00,
+ 0x10,0x76,0x06,0xa7,0x10,0x75,0x57,0x16,0x06,0xb7,0xcf,0x00,0x0f,0x75,0x05,0xc5,
+ 0x45,0x01,0xf7,0x61,0x57,0x0c,0x12,0xe8,0x0d,0x77,0x07,0xc7,0xf7,0x01,0x47,0x01,
+ 0x75,0x0f,0x0c,0xe0,0x07,0xf0,0x07,0x84,0x47,0xa3,0x04,0xb3,0x06,0x20,0x46,0x01,
+ 0x77,0x20,0x02,0xf0,0x07,0x77,0x06,0x60,0x56,0x0c,0xf5,0xef,0xcf,0x00,0x00,0x00,
+ 0x04,0x00,0x04,0x00,0xfe,0x00,0x00,0x00,0x00,0xf0,0x10,0x00,0x02,0xf0,0x10,0x00,
+ 0x04,0xf0,0x10,0x00,0x70,0x24,0x7e,0x00,0xb2,0x71,0x01,0x8f,0xff,0x34,0x01,0x9f,
+ 0xb1,0x71,0x01,0x8f,0x1f,0x34,0x01,0x9f,0xb0,0x7e,0x0e,0xb2,0xb0,0x72,0x02,0xb3,
+ 0xb0,0x73,0x03,0x95,0xb0,0x75,0x05,0x96,0xb0,0x76,0x06,0x97,0xb0,0x77,0x20,0x86,
+ 0x07,0x96,0xaf,0x77,0x07,0xb4,0x01,0x87,0x07,0x34,0x01,0x97,0xae,0x76,0x06,0x87,
+ 0x17,0x2e,0x07,0x2a,0xfc,0xe7,0xa2,0x76,0x06,0x87,0xf7,0x34,0x06,0x97,0xa1,0x76,
+ 0x06,0x87,0x17,0x30,0x06,0x97,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,
+ 0x2e,0x12,0x32,0x12,0xf2,0x3c,0x03,0x60,0x35,0x12,0xa3,0x7f,0xa4,0x74,0x05,0x60,
+ 0xa4,0x7f,0x62,0x01,0x0e,0x2a,0x02,0xe0,0xa3,0x77,0x13,0xf0,0x1e,0x2a,0x04,0xe8,
+ 0x2e,0x2a,0x04,0xe0,0xa0,0x77,0x07,0xd2,0xa0,0x77,0x0b,0xf0,0x3e,0x2a,0x02,0xe0,
+ 0x9f,0x77,0x07,0xf0,0x4e,0x2a,0x04,0xe8,0x5e,0x2a,0x04,0xe0,0x9c,0x77,0x07,0xd2,
+ 0x9c,0x77,0x07,0xd2,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x2e,0x12,
+ 0x99,0x72,0x99,0x7f,0x0e,0x2a,0x03,0xe0,0x62,0x01,0x98,0x77,0x09,0xf0,0x1e,0x2a,
+ 0x03,0xe0,0x62,0x01,0x97,0x77,0x04,0xf0,0x2e,0x2a,0x03,0xe0,0x62,0x01,0x95,0x77,
+ 0x07,0xd2,0x6e,0x00,0x70,0x20,0xcf,0x00,0x94,0x75,0x95,0xa6,0x06,0x2a,0x93,0x77,
+ 0x01,0xe8,0x16,0x60,0x07,0xb6,0x05,0xa6,0x15,0xa7,0x87,0x3c,0x67,0x1e,0x25,0xa6,
+ 0x06,0x3d,0x76,0x1e,0x35,0xa7,0x87,0x3d,0x67,0x1e,0x8d,0x76,0x67,0x0f,0x02,0xe0,
+ 0x8d,0x76,0x04,0xf0,0x8d,0x76,0x67,0x0f,0x03,0xe0,0x8c,0x76,0x8d,0x77,0x07,0xd6,
+ 0x86,0x77,0xa7,0xa6,0xb7,0xa7,0x87,0x3c,0x67,0x1e,0x8a,0x76,0x06,0xd7,0x6c,0x76,
+ 0x06,0x87,0xf7,0x34,0x06,0x97,0x88,0x77,0x07,0x86,0x16,0x34,0x07,0x96,0x07,0x86,
+ 0x06,0x34,0x07,0x96,0x70,0x76,0x06,0x87,0x87,0x2e,0x07,0x2a,0xfc,0xe7,0x64,0x76,
+ 0x06,0x87,0xf7,0x34,0x06,0x97,0x80,0x76,0x06,0x87,0x17,0x30,0x06,0x97,0xcf,0x00,
+ 0x70,0x25,0x7a,0x00,0x75,0x77,0x0d,0x60,0x97,0xbd,0x7c,0x7e,0x07,0xbe,0x1e,0x01,
+ 0x17,0xb1,0x2e,0x01,0x27,0xb1,0xe6,0x12,0x86,0x3f,0x37,0xb6,0x79,0x76,0x26,0xac,
+ 0x8b,0x2c,0xcb,0x16,0xa7,0xbb,0x06,0x60,0xb7,0xb6,0x76,0x7f,0x77,0x74,0x04,0xa6,
+ 0x14,0xa7,0x87,0x3c,0x67,0x1e,0x75,0x76,0x06,0xb7,0x87,0x3e,0x16,0xb7,0x74,0x77,
+ 0x07,0xbd,0x74,0x77,0x07,0xbd,0x74,0x77,0x07,0xad,0x74,0x77,0x07,0xa3,0x02,0x60,
+ 0x25,0x12,0x6f,0x12,0xa1,0x61,0x19,0xf0,0x57,0x12,0x57,0x1c,0x46,0x12,0x76,0x1c,
+ 0x26,0xaa,0xf7,0x1c,0x27,0xba,0x36,0xaa,0x37,0xba,0x26,0xa7,0x36,0xaa,0xf1,0x11,
+ 0x17,0x03,0xf9,0x11,0xa7,0x1c,0x77,0x1c,0xe7,0x1c,0x07,0xc7,0x72,0x0c,0x03,0xe0,
+ 0x26,0xad,0x36,0xa3,0x72,0x12,0x05,0x20,0x65,0x01,0x04,0xa6,0x14,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x75,0x0c,0xe1,0xef,0x87,0x2c,0x27,0x16,0x5d,0x76,0x06,0xb7,0x82,0x3e,
+ 0x5d,0x76,0x06,0xb2,0x5d,0x76,0x06,0xbd,0x5d,0x76,0x06,0xb3,0x42,0x01,0x82,0x3c,
+ 0x72,0x1e,0x5b,0x77,0x07,0x8e,0x5b,0x77,0xe7,0x1c,0x07,0xa7,0xf1,0x11,0x72,0x03,
+ 0xf9,0x11,0x43,0x66,0x41,0x7f,0x2c,0x0c,0x58,0x77,0x06,0xe0,0x62,0x01,0x07,0xb2,
+ 0x82,0x3e,0x56,0x77,0x07,0xb2,0x04,0xf0,0x07,0xbb,0x54,0x77,0x06,0x60,0x07,0xb6,
+ 0x3e,0x76,0x17,0x60,0x96,0xb7,0x52,0x77,0xe7,0x1c,0x07,0xa5,0x52,0x77,0x7e,0x1c,
+ 0x0e,0xa7,0x87,0x3c,0x57,0x1e,0x07,0x3d,0x07,0x3b,0xe7,0x01,0x67,0x01,0x0e,0x60,
+ 0xa6,0xb7,0x87,0x3e,0xb6,0xb7,0x3f,0x7f,0x40,0x74,0x04,0xa6,0x14,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x49,0x76,0x06,0xb7,0x87,0x3e,0x49,0x76,0x06,0xb7,0x49,0x77,0x07,0xbe,
+ 0x49,0x77,0x07,0xbe,0xe6,0x12,0x39,0x7d,0x35,0x72,0xa3,0x61,0x1b,0xf0,0x65,0x12,
+ 0x65,0x1c,0x45,0x1c,0x25,0xaf,0x07,0x67,0x67,0x1c,0x77,0x1c,0xd7,0x1c,0x27,0xbf,
+ 0x35,0xaf,0x37,0xbf,0x25,0xa7,0x35,0xa5,0xf1,0x11,0x37,0x03,0xf9,0x11,0x57,0x1c,
+ 0x77,0x1c,0x27,0x1c,0x07,0xc7,0x77,0x01,0xe7,0x01,0x67,0x01,0x7e,0x0c,0x7e,0x0a,
+ 0x06,0x20,0x66,0x01,0x04,0xa5,0x14,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0c,0xdf,0xef,
+ 0x34,0x77,0x07,0xbe,0x8e,0x3e,0x33,0x77,0x07,0xbe,0x6a,0x00,0x70,0x21,0xcf,0x00,
+ 0x08,0x00,0x04,0x00,0x30,0x0a,0x04,0x00,0x00,0x0a,0x04,0x00,0x01,0x0a,0x04,0x00,
+ 0x24,0x0a,0x04,0x00,0x28,0x0a,0x04,0x00,0x20,0x0a,0x04,0x00,0x2c,0x0a,0x04,0x00,
+ 0x02,0x0a,0x04,0x00,0x3c,0x0a,0x04,0x00,0xd2,0x84,0x00,0x00,0x80,0xc3,0xc9,0x01,
+ 0x34,0x85,0x00,0x00,0x50,0x08,0x04,0x00,0x52,0x08,0x04,0x00,0x6c,0x08,0x04,0x00,
+ 0x6e,0x08,0x04,0x00,0xa0,0x25,0x26,0x00,0xd0,0x83,0x00,0x00,0x9a,0x08,0x04,0x00,
+ 0x9e,0x08,0x04,0x00,0x96,0x08,0x04,0x00,0x7a,0x9e,0x00,0x00,0x47,0x0a,0x04,0x00,
+ 0x00,0xe0,0x02,0x00,0x36,0x50,0x00,0x00,0x00,0x00,0x03,0x00,0x36,0x60,0x00,0x00,
+ 0x40,0x0a,0x04,0x00,0x48,0x0a,0x04,0x00,0x50,0x0a,0x04,0x00,0x00,0xe0,0x02,0x00,
+ 0x86,0x9e,0x00,0x00,0x88,0x27,0x00,0x00,0x00,0x08,0x03,0x00,0x8a,0x9e,0x00,0x00,
+ 0x3e,0xa4,0x00,0x00,0x3f,0xa4,0x00,0x00,0x40,0xa4,0x00,0x00,0x41,0xa4,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0xc0,0x00,0x00,0x00,0x44,0xa4,0x00,0x00,0x45,0xa4,0x00,0x00,
+ 0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x6a,0x9f,0x00,0x00,0x6b,0x9f,0x00,0x00,
+ 0x42,0xa4,0x00,0x00,0x43,0xa4,0x00,0x00,0xf0,0x25,0x78,0x00,0x81,0x62,0x10,0x05,
+ 0x29,0x12,0x3c,0x12,0x58,0x12,0x58,0x1c,0x4d,0x12,0x0b,0x60,0xa0,0xf0,0x02,0x12,
+ 0x03,0x60,0x04,0x61,0x52,0x7f,0x06,0x12,0xf6,0x20,0x07,0x60,0x73,0x12,0x04,0x61,
+ 0x1e,0xf0,0x75,0x12,0x75,0x1c,0xd5,0x1c,0x05,0xc5,0x75,0x01,0x4d,0x72,0x52,0x0d,
+ 0x02,0xe8,0x06,0xb4,0x0c,0xf0,0x4b,0x72,0x25,0x0d,0x02,0xe8,0x06,0xb3,0x07,0xf0,
+ 0xf5,0x37,0x02,0xe8,0xf2,0x63,0x25,0x1c,0x65,0x3a,0x75,0x20,0x06,0xb5,0x06,0xa5,
+ 0x55,0x01,0x05,0x1c,0x05,0xa2,0x02,0x20,0x05,0xb2,0x07,0x20,0x06,0x20,0x07,0x01,
+ 0xc1,0x0c,0xdf,0xef,0x07,0x60,0x76,0x12,0x75,0x12,0x07,0x01,0x04,0x12,0x74,0x1c,
+ 0x04,0xa4,0x45,0x0c,0x16,0x0a,0x45,0x0a,0x07,0x20,0x07,0x2b,0xf6,0xe7,0x07,0x60,
+ 0x7a,0x12,0x75,0x12,0x07,0x01,0x04,0x12,0x74,0x1c,0x04,0xa4,0x45,0x0c,0x03,0xe0,
+ 0x61,0x0f,0x1a,0x02,0x45,0x02,0x07,0x20,0x07,0x2b,0xf4,0xe7,0x07,0x60,0x72,0x12,
+ 0x73,0x12,0x10,0xf0,0x05,0x61,0x05,0x1c,0x75,0x1c,0x05,0xa5,0x55,0x01,0x65,0x0f,
+ 0x08,0xe0,0x75,0x12,0x75,0x1c,0xd5,0x1c,0x05,0xc5,0x75,0x01,0x52,0x1c,0x03,0x20,
+ 0x43,0x01,0x07,0x20,0x07,0x01,0xc1,0x0c,0xed,0xef,0x03,0x2a,0x03,0xe8,0x26,0x7f,
+ 0x2e,0x12,0x01,0xf0,0x3e,0x12,0x25,0x76,0x06,0x87,0x62,0x67,0x27,0x1c,0x07,0xa6,
+ 0x07,0x60,0x72,0x12,0x73,0x12,0xe6,0x0d,0x11,0xe0,0x18,0xf0,0x06,0x61,0x06,0x1c,
+ 0x76,0x1c,0x06,0xa6,0x56,0x01,0xa6,0x0f,0x08,0xe0,0x76,0x12,0x76,0x1c,0xd6,0x1c,
+ 0x06,0xc6,0x76,0x01,0x62,0x1c,0x03,0x20,0x43,0x01,0x07,0x20,0x07,0x01,0xc1,0x0c,
+ 0xed,0xef,0x03,0x2a,0x03,0xe8,0x14,0x7f,0x2e,0x0d,0x2e,0x0a,0xd7,0x12,0x06,0x60,
+ 0x63,0x12,0x10,0xf0,0x07,0xc5,0x54,0x12,0x74,0x01,0xf4,0x37,0x02,0xe0,0x4e,0x0d,
+ 0x01,0xf0,0xe4,0x0d,0x03,0xe8,0xe5,0x05,0x07,0xd5,0x01,0xf0,0x07,0xd3,0x06,0x20,
+ 0x46,0x01,0x17,0x20,0xc6,0x0f,0xee,0xe7,0x0b,0x20,0x4b,0x01,0x8d,0x1c,0x9b,0x0f,
+ 0x5e,0xe7,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x22,0x83,0x00,0x00,
+ 0xc0,0x01,0x00,0x00,0x40,0xfe,0xff,0xff,0x3e,0x84,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0xf0,0x25,0x79,0x00,0x2a,0x12,0x39,0x12,0x83,0x7f,0x83,0x72,0xa3,0x12,0x83,0x7f,
+ 0x0d,0x60,0x83,0x7c,0x17,0xf0,0x9e,0x12,0xf1,0x11,0xde,0x03,0xf9,0x11,0xee,0x1c,
+ 0xae,0x1c,0x0b,0x60,0x07,0xf0,0x0e,0xc3,0x1e,0x20,0x7e,0x72,0x73,0x01,0x7b,0x7f,
+ 0x0b,0x20,0x6b,0x01,0x0c,0x87,0x57,0xa7,0x7b,0x0c,0xf5,0xef,0x7b,0x72,0x77,0x7f,
+ 0x0d,0x20,0x6d,0x01,0x0c,0x87,0x47,0xa7,0x7d,0x0c,0xe5,0xef,0x69,0x00,0xf0,0x21,
+ 0xcf,0x00,0xf0,0x25,0x79,0x00,0x70,0x24,0xc6,0x60,0x74,0x77,0x07,0xb6,0x0e,0x60,
+ 0xed,0x12,0x73,0x7b,0x74,0x7a,0x74,0x79,0x6e,0x7c,0x19,0xf0,0xe6,0x12,0xe6,0x1c,
+ 0xe6,0x1c,0x46,0x3c,0x09,0xa2,0x0c,0x87,0x57,0xa3,0x70,0x77,0x67,0x1e,0x00,0x97,
+ 0xf4,0x60,0x6f,0x75,0x70,0x77,0x76,0x1e,0x07,0x60,0x6f,0x7f,0xb7,0x12,0xd7,0x1c,
+ 0x26,0x62,0x67,0x1c,0x07,0xa7,0x7e,0x1c,0x4e,0x01,0x0d,0x20,0x4d,0x01,0x0a,0xa7,
+ 0x7d,0x0c,0xe4,0xef,0x5f,0x7e,0x0e,0x87,0x47,0xa2,0x57,0xa3,0x64,0x7c,0x65,0x7d,
+ 0x00,0x9d,0x24,0x60,0xc5,0x12,0x06,0x60,0x67,0x12,0x63,0x7f,0xc6,0x60,0x63,0x77,
+ 0x07,0xb6,0x0e,0x8e,0x4e,0xa2,0x5e,0xa3,0x00,0x9c,0xe4,0x60,0xd5,0x12,0x60,0x76,
+ 0x07,0x60,0x5d,0x7f,0x4e,0xa2,0x5e,0xa3,0x00,0x9d,0x24,0x60,0xc5,0x12,0x06,0x60,
+ 0x67,0x12,0x59,0x7f,0x70,0x20,0x69,0x00,0xf0,0x21,0xcf,0x00,0xf0,0x24,0x20,0x9f,
+ 0x30,0x9e,0x4b,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0x56,0x77,0x00,0x97,0x24,0x60,
+ 0x51,0x75,0x06,0x60,0x67,0x12,0x50,0x7f,0x54,0x77,0x7e,0x1c,0x0e,0xa7,0x07,0x2a,
+ 0x13,0xe8,0x47,0x77,0x17,0xa6,0x07,0xa7,0x76,0x1c,0x07,0x60,0x50,0x73,0x50,0x74,
+ 0x09,0xf0,0x75,0x12,0x75,0x1c,0x32,0x12,0x52,0x1c,0x45,0x1c,0x05,0xc5,0x02,0xd5,
+ 0x07,0x20,0x47,0x01,0x67,0x0d,0xf5,0xe7,0x20,0x8f,0x30,0x8e,0xf0,0x20,0xcf,0x00,
+ 0x70,0x25,0x7a,0x00,0x2a,0x12,0x3c,0x12,0x0d,0x60,0xde,0x12,0x46,0x7b,0x23,0xf0,
+ 0xa7,0x12,0xe7,0x1c,0x07,0xa7,0x07,0x2a,0x1c,0xe0,0xe6,0x12,0xe6,0x1c,0xc6,0x1c,
+ 0x26,0xa5,0x87,0x65,0xd7,0x1c,0x77,0x1c,0xb7,0x1c,0x87,0xb5,0x36,0xa6,0x97,0xb6,
+ 0xed,0x0f,0x0d,0xe8,0xd2,0x12,0x32,0x3c,0xd2,0x05,0xb2,0x1c,0xe3,0x12,0x33,0x3c,
+ 0xe3,0x05,0xb3,0x1c,0xa7,0x62,0x72,0x1c,0x73,0x1c,0x74,0x60,0x37,0x7f,0x0d,0x20,
+ 0x4d,0x01,0x0e,0x20,0x4e,0x01,0x0c,0xa6,0x1c,0xa7,0x87,0x3c,0x67,0x1e,0x7e,0x0c,
+ 0xd7,0xef,0x32,0x77,0x07,0xbd,0x32,0x77,0x06,0x60,0x07,0xb6,0x6a,0x00,0x70,0x21,
+ 0xcf,0x00,0x02,0x01,0x01,0x2b,0x0e,0xe0,0x1a,0x77,0x07,0x84,0x2e,0x77,0x2e,0x75,
+ 0x46,0x12,0x76,0x1c,0x2e,0x73,0x36,0x1c,0x06,0xa6,0x07,0xb6,0x07,0x20,0x57,0x0f,
+ 0xf7,0xe7,0x13,0xf0,0xf1,0x2e,0x27,0x77,0x14,0x60,0x27,0x75,0x07,0xa6,0x06,0x2a,
+ 0x03,0xe8,0x61,0x0c,0x06,0xe0,0x01,0xf0,0x06,0x62,0x16,0x05,0x46,0x01,0x07,0xb6,
+ 0x01,0xf0,0x07,0xb4,0x07,0x20,0x57,0x0f,0xf1,0xe7,0x07,0x60,0x1f,0x76,0x06,0xb7,
+ 0x20,0x76,0x06,0xb7,0x07,0x77,0x07,0x87,0x1f,0x76,0x67,0x1c,0x07,0xa6,0x1e,0x77,
+ 0x07,0xb6,0xcf,0x00,0x8e,0x23,0x00,0x00,0xf8,0x06,0x00,0x00,0x7a,0x25,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0x04,0x07,0x00,0x00,0x0c,0x07,0x00,0x00,0x07,0x0a,0x04,0x00,
+ 0x20,0x9e,0x00,0x00,0x41,0x9e,0x00,0x00,0x42,0x9e,0x00,0x00,0x00,0x00,0x03,0x18,
+ 0x00,0x00,0x01,0x24,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,0x06,0x0a,0x04,0x00,
+ 0x00,0x00,0x07,0x18,0x36,0x00,0x04,0x1a,0xc8,0x00,0x00,0x00,0x5e,0xa5,0x00,0x00,
+ 0xec,0xa4,0x00,0x00,0x8a,0x9e,0x00,0x00,0x8c,0x82,0x00,0x00,0x40,0x9f,0x00,0x00,
+ 0x41,0x9f,0x00,0x00,0x40,0x09,0x04,0x00,0x64,0x09,0x04,0x00,0xa8,0xf7,0xfb,0xff,
+ 0x65,0x09,0x04,0x00,0xcc,0x00,0x00,0x00,0x66,0x09,0x04,0x00,0x42,0x01,0x03,0x01,
+ 0x44,0x01,0x15,0x12,0x35,0x2e,0x55,0x1c,0x27,0x12,0x37,0x3c,0x27,0x1c,0x16,0x33,
+ 0x67,0x1c,0x21,0x3e,0x17,0x1c,0x07,0xa6,0x33,0x60,0x53,0x1b,0x36,0x1f,0x54,0x1b,
+ 0x46,0x1e,0x46,0x01,0x07,0xb6,0xcf,0x00,0xf0,0x25,0x78,0x00,0xf0,0x24,0x2d,0x12,
+ 0x4d,0x01,0x12,0x33,0x83,0x2c,0x80,0x74,0x81,0x7f,0x81,0x76,0x06,0x8e,0x4e,0xa1,
+ 0x00,0x91,0x0d,0x2a,0x14,0xe0,0x7f,0x75,0x05,0xa7,0x7f,0x74,0x47,0x16,0x05,0xb7,
+ 0xde,0x12,0x6d,0x12,0x07,0xf0,0xe7,0x1c,0xe2,0x12,0x67,0xa3,0x14,0x60,0x7b,0x7f,
+ 0x0e,0x20,0x4e,0x01,0x0d,0x87,0x47,0xa6,0x6e,0x0c,0xf5,0xef,0xc8,0xf0,0x2d,0x2a,
+ 0x3f,0xe0,0x74,0x76,0x06,0xa7,0x07,0x30,0x17,0x30,0x17,0x34,0x06,0xb7,0x6e,0xa5,
+ 0x16,0x61,0x07,0x60,0x56,0x0c,0x4e,0xa5,0x07,0xe8,0x11,0xf0,0x07,0x20,0xe4,0x12,
+ 0x74,0x1c,0x54,0xa4,0x46,0x0c,0x10,0xe0,0x7c,0x12,0x4c,0x01,0x5c,0x0c,0xf6,0xef,
+ 0x0a,0xf0,0x07,0x20,0xe4,0x12,0x74,0x1c,0x54,0xa4,0x46,0x0c,0x05,0xe8,0x7c,0x12,
+ 0x4c,0x01,0x5c,0x0c,0xf6,0xef,0x0c,0x60,0x0d,0x60,0x07,0xf0,0xe7,0x12,0xd7,0x1c,
+ 0xd2,0x12,0x67,0xa3,0x14,0x60,0x61,0x7f,0x0d,0x20,0x0d,0x01,0xc1,0x0c,0xf6,0xef,
+ 0x0d,0x60,0x07,0xf0,0xe7,0x1c,0xd2,0x12,0x67,0xa3,0x14,0x60,0x5c,0x7f,0x0d,0x20,
+ 0x4d,0x01,0xd7,0x12,0xc7,0x1c,0x47,0x01,0x4e,0xa6,0x67,0x0c,0xf3,0xef,0x87,0xf0,
+ 0x1d,0x2a,0x85,0xe0,0x54,0x76,0x06,0xa7,0x07,0x30,0x17,0x30,0x07,0x34,0x06,0xb7,
+ 0x4e,0xad,0x53,0x7b,0x07,0x60,0x0b,0xb7,0x05,0x60,0x00,0x95,0x26,0x65,0xe6,0x1c,
+ 0x10,0x96,0xe9,0x12,0x44,0xf0,0x78,0x1c,0x07,0x20,0x07,0x01,0x61,0x0c,0xfb,0xef,
+ 0x6d,0x0c,0xd6,0x0a,0x30,0x96,0x00,0x8c,0x0a,0x60,0xc7,0x12,0x97,0x1c,0x20,0x97,
+ 0x1a,0xf0,0xe2,0x12,0xa2,0x1c,0x10,0x81,0x01,0xa3,0x46,0x7f,0x82,0x1c,0x02,0xa4,
+ 0x20,0x87,0xe7,0x1c,0xc2,0x12,0x67,0xa3,0x14,0x2a,0x01,0xe8,0x24,0x60,0x3f,0x7f,
+ 0x0e,0x20,0x01,0xf0,0x0e,0x60,0x0e,0x01,0x30,0x84,0x41,0x0c,0xea,0xef,0x0a,0x20,
+ 0x4a,0x01,0x0c,0x20,0x4c,0x01,0x10,0x85,0x05,0xa7,0x7a,0x0c,0xf3,0xef,0x0b,0xa6,
+ 0xd7,0x0c,0x08,0xe0,0x39,0x71,0x16,0x1c,0x24,0x62,0x46,0x1c,0x06,0xb7,0x7d,0x05,
+ 0x4d,0x01,0x06,0xf0,0x35,0x75,0x56,0x1c,0x21,0x62,0x16,0x1c,0x06,0xbd,0x0d,0x60,
+ 0x00,0x84,0x47,0x1c,0x07,0x01,0x00,0x91,0x0b,0xa7,0x07,0x20,0x0b,0xb7,0x0d,0x2a,
+ 0x04,0xe0,0x2e,0x77,0x07,0xab,0x2e,0x79,0x09,0xf0,0x10,0x84,0x04,0xa6,0x07,0x60,
+ 0x2d,0x78,0xb3,0xf7,0xd7,0x12,0xd7,0x1c,0x79,0x1c,0x0d,0x20,0x0d,0x01,0xb1,0x0c,
+ 0xf9,0xef,0x0d,0x60,0x29,0x78,0x19,0xf0,0xea,0x12,0xea,0x1c,0xca,0x1c,0xe2,0x12,
+ 0xd2,0x1c,0xb3,0x12,0x20,0x7f,0x22,0x1c,0x92,0x1c,0x02,0xc7,0x0a,0xd7,0x0e,0x20,
+ 0x07,0xf0,0x0e,0x60,0xdc,0x12,0x3c,0x3c,0xd7,0x12,0x67,0x3c,0x7c,0x1c,0x8c,0x1c,
+ 0x0e,0x01,0xb1,0x0c,0xe9,0xef,0x0d,0x20,0x4d,0x01,0xbd,0x0f,0xf2,0xe7,0x10,0x77,
+ 0x07,0x85,0x45,0xa3,0x07,0x60,0x76,0x12,0x14,0x61,0x08,0xf0,0x52,0x12,0x72,0x1c,
+ 0x62,0xa2,0x24,0x0c,0x02,0xe8,0x06,0x20,0x46,0x01,0x07,0x20,0x07,0x01,0x31,0x0c,
+ 0xf5,0xef,0x12,0x77,0x07,0xb6,0x00,0x85,0x56,0x14,0x46,0x01,0x11,0x77,0x07,0xb6,
+ 0xf0,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00,0x44,0x01,0x00,0x00,0xc4,0x09,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0x54,0x08,0x04,0x00,0xfc,0x00,0x00,0x00,0x4c,0x2e,0x00,0x00,
+ 0x41,0x9e,0x00,0x00,0x74,0x84,0x00,0x00,0x20,0x9e,0x00,0x00,0x42,0x9e,0x00,0x00,
+ 0x10,0x03,0x00,0x00,0xb4,0x04,0x00,0x00,0x00,0x60,0x02,0x00,0x5a,0x08,0x04,0x00,
+ 0x5b,0x08,0x04,0x00,0x70,0x25,0x7b,0x00,0x23,0x12,0x63,0x01,0xb7,0x72,0xb7,0x7f,
+ 0x2d,0x12,0x6d,0x01,0xdc,0x12,0x0c,0x20,0x1c,0x3e,0x0e,0x60,0xb5,0x7b,0x0b,0xf0,
+ 0xe2,0x12,0x92,0x3c,0xd3,0x12,0xb1,0x7f,0xb3,0x7f,0xb2,0x14,0x42,0x01,0xb2,0x77,
+ 0xe7,0x1c,0x07,0xb2,0x0e,0x20,0xe7,0x12,0x67,0x01,0xc7,0x0c,0xf1,0xef,0x6b,0x00,
+ 0x70,0x21,0xcf,0x00,0x70,0x24,0x7e,0x00,0xad,0x7e,0xe2,0x12,0x03,0x60,0x44,0x61,
+ 0xac,0x7f,0x07,0x60,0x0e,0xb7,0x2e,0xb7,0x3e,0xb7,0xfe,0xb7,0xae,0xb7,0x07,0x2c,
+ 0xbe,0xb7,0xf7,0x67,0xce,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x70,0x24,0x00,0x9f,
+ 0xa5,0x77,0x07,0xa7,0xa5,0x76,0x06,0x85,0xa5,0x76,0x65,0x0f,0x0a,0xe0,0x74,0x12,
+ 0x74,0x1c,0x74,0x1c,0xa3,0x72,0xa3,0x73,0x44,0x3c,0x15,0x60,0xa3,0x7f,0x16,0x60,
+ 0x01,0xf0,0x06,0x60,0x9a,0x77,0x27,0xb6,0x00,0x8f,0x70,0x20,0xcf,0x00,0x70,0x24,
+ 0x00,0x9f,0x06,0x60,0x9e,0x77,0x07,0xb6,0x9e,0x76,0x06,0x87,0x9e,0x75,0x57,0x16,
+ 0x06,0x97,0x9d,0x76,0x06,0x87,0xd7,0x30,0x06,0x97,0x9c,0x76,0x06,0x87,0xe7,0x31,
+ 0xf7,0x31,0x06,0x97,0xa2,0x60,0x9a,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0xf0,0x25,
+ 0x78,0x00,0xf0,0x24,0x98,0x7e,0x0e,0x92,0x98,0x77,0x00,0x97,0x42,0x62,0x83,0x61,
+ 0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x95,0x7f,0x95,0x77,0x00,0x97,0x42,0x62,
+ 0x83,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x90,0x7f,0x92,0x77,0x00,0x97,
+ 0x42,0x62,0xa3,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x8c,0x7f,0x8e,0x77,
+ 0x00,0x97,0x42,0x62,0xa3,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x87,0x7f,
+ 0x8b,0x77,0x00,0x97,0x42,0x62,0xa3,0x61,0x94,0x60,0x05,0x60,0x56,0x12,0x57,0x12,
+ 0x83,0x7f,0x87,0x77,0x00,0x97,0x42,0x62,0x23,0x12,0x94,0x60,0x05,0x60,0x56,0x12,
+ 0x57,0x12,0x7e,0x7f,0x70,0x7d,0xd2,0x12,0x03,0x60,0x64,0x64,0x6d,0x7f,0x0e,0x8e,
+ 0x27,0x64,0xe7,0x1c,0x07,0xa7,0x07,0x2a,0x05,0xe0,0x4e,0xa7,0x0d,0xb7,0x5e,0xa7,
+ 0x1d,0xb7,0x99,0xf0,0x36,0x64,0xe6,0x1c,0x06,0xa4,0x14,0x2a,0x4e,0xa5,0x5e,0xa6,
+ 0x19,0xe0,0x54,0x12,0x04,0x24,0x0d,0xb4,0x64,0x12,0x74,0x05,0x1d,0xb4,0x03,0x60,
+ 0x34,0x12,0x72,0x12,0xd2,0x1c,0x09,0xf0,0x4c,0x12,0xdc,0x1c,0x2c,0xb5,0x2c,0x12,
+ 0x3c,0x1c,0x6c,0xb6,0x04,0x20,0x06,0x24,0x46,0x01,0x03,0x24,0x04,0x01,0x71,0x0c,
+ 0xf3,0xef,0x79,0xf0,0x24,0x2a,0x19,0xe0,0x54,0x12,0x74,0x05,0x0d,0xb4,0x64,0x12,
+ 0x04,0x24,0x1d,0xb4,0x03,0x60,0x34,0x12,0x72,0x12,0xd2,0x1c,0x09,0xf0,0x4c,0x12,
+ 0xdc,0x1c,0x6c,0xb6,0x2c,0x12,0x3c,0x1c,0x2c,0xb5,0x04,0x20,0x05,0x24,0x45,0x01,
+ 0x03,0x24,0x04,0x01,0x71,0x0c,0xf3,0xef,0x5e,0xf0,0x34,0x2a,0x25,0xe0,0x54,0x12,
+ 0x04,0x24,0x0d,0xb4,0x1d,0xb6,0x5b,0x73,0x04,0x60,0x1a,0xf0,0x32,0x12,0x32,0x24,
+ 0x02,0xb5,0x02,0x60,0xed,0x12,0x4d,0x1c,0x48,0x64,0x8d,0x1c,0x0c,0xf0,0x02,0x20,
+ 0xec,0x12,0x2c,0x1c,0x9b,0x62,0xbc,0x1c,0x0d,0xab,0x0c,0xac,0xcb,0x0f,0x03,0xe0,
+ 0x01,0x20,0x03,0xb1,0x03,0xf0,0x02,0x01,0x61,0x0c,0xf1,0xef,0x04,0x20,0x03,0x20,
+ 0x04,0x01,0x71,0x0c,0xe3,0xef,0x37,0xf0,0x44,0x2a,0x21,0xe0,0x0d,0xb5,0x64,0x12,
+ 0x04,0x24,0x1d,0xb4,0x49,0x73,0x04,0x60,0x16,0xf0,0x43,0xb6,0x02,0x60,0xed,0x12,
+ 0x4d,0x1c,0x4f,0x64,0xfd,0x1c,0x0a,0xf0,0x02,0x20,0xec,0x12,0x2c,0x1c,0x0d,0xab,
+ 0x5c,0xac,0xcb,0x0f,0x03,0xe0,0x01,0x20,0x03,0xb1,0x03,0xf0,0x02,0x01,0x51,0x0c,
+ 0xf3,0xef,0x04,0x20,0x03,0x20,0x04,0x01,0x71,0x0c,0xe7,0xef,0x14,0xf0,0x54,0x12,
+ 0x74,0x05,0x0d,0xb4,0x64,0x12,0x74,0x05,0x1d,0xb4,0x7d,0x1c,0x0d,0x20,0x04,0x60,
+ 0x53,0x12,0x43,0x05,0x0d,0xb3,0x63,0x12,0x43,0x05,0x4d,0xb3,0x04,0x20,0x44,0x01,
+ 0x0d,0x24,0x74,0x0f,0xf5,0xe7,0x1b,0x77,0x17,0xad,0x8d,0x3c,0x86,0x2c,0xd6,0x16,
+ 0xa7,0xb6,0xd6,0x12,0x86,0x3e,0xb7,0xb6,0x2d,0x76,0xe6,0x1c,0x06,0xa6,0x26,0x2a,
+ 0x07,0xa6,0x96,0x00,0x86,0x3c,0x66,0x01,0x85,0x2c,0x65,0x16,0xc7,0xb5,0x86,0x3e,
+ 0xd7,0xb6,0x27,0x77,0xe7,0x1c,0x07,0xa9,0x27,0x77,0xe7,0x1c,0x07,0xa8,0x98,0x1c,
+ 0x26,0x72,0x28,0x1c,0x26,0x77,0xe7,0x1c,0x07,0xa7,0x20,0x97,0x0a,0x7a,0xca,0xa7,
+ 0xda,0xac,0x8c,0x3c,0x7c,0x1e,0x44,0xf0,0xa0,0x25,0x26,0x00,0xd0,0x83,0x00,0x00,
+ 0xfe,0xff,0xff,0xff,0xa0,0x0b,0x00,0x00,0x00,0x80,0x01,0x00,0x66,0x9e,0x00,0x00,
+ 0xc4,0x09,0x00,0x00,0x20,0x9e,0x00,0x00,0x00,0xb0,0x10,0x00,0xaa,0xa5,0x55,0x5a,
+ 0x00,0x00,0x03,0x00,0x00,0xa0,0x00,0x00,0xf6,0x1e,0x00,0x00,0x40,0x01,0x04,0x00,
+ 0x0c,0x01,0x04,0x00,0xff,0xff,0xf0,0xff,0x04,0x01,0x04,0x00,0x08,0x01,0x04,0x00,
+ 0xe0,0x0a,0x00,0x00,0x1c,0x9e,0x00,0x00,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,
+ 0x00,0x00,0x03,0x18,0x00,0x00,0x04,0x1a,0x00,0x00,0x05,0x1a,0x00,0x00,0x06,0x1a,
+ 0x00,0x00,0x01,0x24,0x26,0x9e,0x00,0x00,0x22,0x9e,0x00,0x00,0x20,0x01,0x00,0x00,
+ 0x95,0x00,0x00,0x00,0x96,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x97,0x00,0x00,0x00,
+ 0x27,0x12,0xc7,0x1c,0x20,0x8b,0xb7,0x1c,0xca,0x76,0xe6,0x1c,0x06,0xa6,0x67,0x1c,
+ 0x67,0x01,0x30,0x97,0x7f,0x32,0xf9,0x1c,0x0e,0xa7,0x1e,0xab,0x8b,0x3c,0x7b,0x1e,
+ 0xd8,0x1c,0x68,0x01,0x92,0x12,0xf1,0x11,0xb2,0x03,0xf9,0x11,0x83,0x12,0xc1,0x7f,
+ 0x62,0x01,0xea,0xb2,0x82,0x3e,0xfa,0xb2,0x92,0x12,0xd2,0x1c,0xbf,0x73,0x32,0x1c,
+ 0xf1,0x11,0xb2,0x03,0xf9,0x11,0x83,0x12,0xbb,0x7f,0x62,0x01,0xbc,0x77,0x07,0xb2,
+ 0x82,0x3e,0xbb,0x77,0x07,0xb2,0x20,0x8a,0x74,0x32,0x4a,0x1c,0x2e,0xa7,0x3e,0xab,
+ 0x8b,0x3c,0x7b,0x1e,0xa2,0x12,0xf1,0x11,0xb2,0x03,0xf9,0x11,0x30,0x83,0xb1,0x7f,
+ 0x62,0x01,0xb4,0x77,0x07,0xb2,0x82,0x3e,0xb4,0x77,0x07,0xb2,0xa2,0x12,0xc2,0x1c,
+ 0xae,0x75,0x52,0x1c,0xf1,0x11,0xb2,0x03,0xf9,0x11,0x30,0x83,0xaa,0x7f,0x62,0x01,
+ 0xaf,0x77,0x07,0xb2,0x82,0x3e,0xae,0x77,0x07,0xb2,0xae,0x77,0xe7,0x1c,0x07,0xa6,
+ 0xae,0x77,0xe7,0x1c,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x85,0x2c,0x75,0x16,0xab,0x76,
+ 0x06,0xb5,0x76,0x12,0x86,0x3e,0xaa,0x74,0x04,0xb6,0xaa,0x74,0x04,0xb5,0xaa,0x75,
+ 0x05,0xb6,0x7d,0x05,0x6d,0x01,0xa9,0x76,0x06,0xbd,0x8d,0x3e,0xa9,0x76,0x06,0xbd,
+ 0xc7,0x14,0x67,0x01,0xa8,0x76,0x06,0xb7,0x87,0x3e,0xa7,0x76,0x06,0xb7,0xa7,0x77,
+ 0x66,0x67,0xe6,0x1c,0x06,0xa6,0x07,0xb6,0x56,0x67,0xe6,0x1c,0x06,0xa6,0x17,0xb6,
+ 0x46,0x67,0xe6,0x1c,0x06,0xa6,0x27,0xb6,0x06,0x60,0x37,0xb6,0xb7,0x64,0xe7,0x1c,
+ 0x07,0xa7,0x27,0x2a,0xcd,0x64,0xed,0x1c,0xdc,0x64,0xec,0x1c,0x0d,0xa3,0x0c,0xa6,
+ 0x86,0x3c,0xe7,0x64,0xe7,0x1c,0x07,0xa4,0xf7,0x64,0xe7,0x1c,0x07,0xa7,0x87,0x3c,
+ 0x10,0xe0,0x02,0x60,0x63,0x1e,0x74,0x1e,0x96,0x7f,0x0d,0xa3,0x0c,0xa6,0x86,0x3c,
+ 0x07,0x65,0xe7,0x1c,0x07,0xa4,0x17,0x65,0xe7,0x1c,0x07,0xa7,0x87,0x3c,0x12,0x60,
+ 0x01,0xf0,0x22,0x60,0x63,0x1e,0x74,0x1e,0x8e,0x7f,0xc7,0x64,0xe7,0x1c,0x07,0xa3,
+ 0xd7,0x64,0xe7,0x1c,0x07,0xa7,0x87,0x3c,0x02,0x60,0x73,0x1e,0x8a,0x7f,0xb7,0x64,
+ 0x7e,0x1c,0x0e,0xa2,0x89,0x7f,0x89,0x77,0xc6,0x60,0x07,0xb6,0x07,0xb6,0x88,0x72,
+ 0xf3,0x63,0x84,0x61,0x88,0x7f,0x88,0x77,0x07,0x83,0x07,0x60,0x75,0x12,0x76,0x12,
+ 0x18,0xf0,0x34,0x12,0x64,0x1c,0xa8,0x62,0x84,0x1c,0x04,0xa2,0x14,0x60,0x42,0x0e,
+ 0x12,0x3e,0x64,0x12,0x54,0x34,0x05,0xe8,0x05,0x20,0x45,0x01,0x80,0x7b,0xb2,0x1c,
+ 0x04,0xf0,0x07,0x20,0x47,0x01,0x7a,0x7d,0xd2,0x1c,0x44,0x01,0x02,0xb4,0x06,0x20,
+ 0x66,0x01,0x53,0xa4,0x46,0x0c,0xe5,0xef,0x7a,0x76,0x06,0xb7,0x7a,0x77,0x07,0xb5,
+ 0x86,0x60,0x79,0x77,0x07,0x96,0x74,0x77,0x07,0x87,0x36,0x65,0x76,0x1c,0x06,0xa6,
+ 0x06,0x2a,0x09,0xe0,0x76,0x77,0x07,0xa6,0x76,0x7e,0xe6,0x16,0x07,0xb6,0x07,0xa6,
+ 0x75,0x72,0x26,0x16,0x0f,0xf0,0xc6,0x64,0x76,0x1c,0x06,0xa2,0xd3,0x64,0x37,0x1c,
+ 0x07,0xa7,0x87,0x3c,0x72,0x1e,0x70,0x7f,0x6d,0x77,0x07,0xa6,0x06,0x34,0x07,0xb6,
+ 0x07,0xa6,0x46,0x34,0x07,0xb6,0x69,0x76,0x06,0xa7,0x17,0x34,0x06,0xb7,0x6b,0x75,
+ 0x05,0xa7,0x6b,0x74,0x47,0x16,0x60,0x76,0x06,0x86,0xb4,0x66,0x64,0x1c,0x04,0xa4,
+ 0x47,0x1e,0x05,0xb7,0x68,0x75,0x05,0xa7,0x07,0x34,0x05,0xb7,0x15,0x60,0x66,0x77,
+ 0x07,0xb5,0x05,0x60,0x66,0x77,0x07,0xb5,0x05,0x60,0x65,0x77,0x07,0xd5,0x85,0x32,
+ 0x65,0x77,0x07,0xd5,0x65,0x75,0x65,0x77,0x07,0xd5,0x05,0x62,0x65,0x77,0x07,0xb5,
+ 0x07,0x60,0x12,0xf0,0x64,0x12,0x74,0x1c,0xa3,0x62,0x43,0x1c,0x03,0xa5,0x61,0x78,
+ 0x85,0x1c,0x61,0x7b,0xb4,0x1c,0x04,0xa2,0x05,0xb2,0x03,0xa5,0x60,0x7d,0xd5,0x1c,
+ 0x04,0xa4,0x05,0xb4,0x07,0x20,0x67,0x01,0x56,0xa5,0x57,0x0c,0xeb,0xef,0x5c,0x72,
+ 0x03,0x60,0x44,0x62,0x44,0x7f,0x44,0x77,0x07,0x87,0xbe,0x64,0xe7,0x1c,0x07,0xa7,
+ 0x17,0x2a,0x46,0x77,0x07,0xa6,0x02,0xe8,0x26,0x34,0x02,0xf0,0x56,0x72,0x26,0x16,
+ 0x07,0xb6,0x3d,0x7e,0x0e,0x87,0xf3,0x66,0x37,0x1c,0x07,0xa3,0x53,0x72,0x83,0x3c,
+ 0x53,0x74,0x53,0x7f,0x0e,0x87,0x04,0x67,0x47,0x1c,0x07,0xa7,0x73,0x12,0x43,0x3c,
+ 0x73,0x1e,0x50,0x72,0x43,0x01,0x50,0x74,0x33,0x7f,0x0e,0x87,0x50,0x75,0x57,0x1c,
+ 0x07,0xa7,0x73,0x12,0x43,0x3c,0x73,0x1e,0x4e,0x72,0x43,0x01,0x54,0x62,0x2d,0x7f,
+ 0x0e,0x87,0x4c,0x76,0x76,0x1c,0x06,0xa6,0x06,0x2a,0xd2,0xe8,0xe6,0x64,0x76,0x1c,
+ 0x06,0xa6,0xf5,0x64,0x75,0x1c,0x05,0xa2,0x82,0x3c,0x62,0x1e,0xc6,0x64,0x76,0x1c,
+ 0x06,0xa5,0xd6,0x64,0x76,0x1c,0x06,0xa6,0x86,0x3c,0x56,0x1e,0x43,0x78,0x87,0x1c,
+ 0xf1,0x11,0x62,0x03,0xf9,0x11,0x07,0xa3,0x07,0x7f,0x23,0x12,0x63,0x01,0x12,0x60,
+ 0x19,0x7f,0x15,0x60,0x3e,0x77,0x07,0xb5,0x0e,0x87,0x3d,0x7b,0x7b,0xf0,0x00,0x00,
+ 0x98,0x00,0x00,0x00,0xd0,0x83,0x00,0x00,0x00,0xfe,0xff,0xff,0x30,0x9e,0x00,0x00,
+ 0x31,0x9e,0x00,0x00,0x32,0x9e,0x00,0x00,0x33,0x9e,0x00,0x00,0x34,0x9e,0x00,0x00,
+ 0x35,0x9e,0x00,0x00,0xa7,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x36,0x9e,0x00,0x00,
+ 0x37,0x9e,0x00,0x00,0x38,0x9e,0x00,0x00,0x39,0x9e,0x00,0x00,0x3a,0x9e,0x00,0x00,
+ 0x3b,0x9e,0x00,0x00,0x3c,0x9e,0x00,0x00,0x3d,0x9e,0x00,0x00,0x86,0x9e,0x00,0x00,
+ 0x0c,0x27,0x00,0x00,0x5a,0x27,0x00,0x00,0x78,0x2e,0x00,0x00,0x62,0x08,0x04,0x00,
+ 0x00,0x08,0x04,0x00,0xc4,0x09,0x00,0x00,0x1c,0x9e,0x00,0x00,0x0c,0x08,0x04,0x00,
+ 0x58,0x08,0x04,0x00,0x59,0x08,0x04,0x00,0x2c,0x08,0x04,0x00,0x40,0x08,0x04,0x00,
+ 0xfe,0x00,0x00,0x00,0xef,0x00,0x00,0x00,0xc4,0x30,0x00,0x00,0x41,0x08,0x04,0x00,
+ 0xf8,0xff,0xff,0xff,0x68,0x08,0x04,0x00,0x69,0x08,0x04,0x00,0x84,0x08,0x04,0x00,
+ 0x8c,0x08,0x04,0x00,0x8e,0x08,0x04,0x00,0x96,0x00,0x00,0x00,0x90,0x08,0x04,0x00,
+ 0x98,0x08,0x04,0x00,0xd0,0x08,0x04,0x00,0xd0,0x00,0x00,0x00,0xe8,0x08,0x04,0x00,
+ 0x14,0x09,0x04,0x00,0xfb,0x00,0x00,0x00,0x00,0x40,0x02,0x00,0x60,0x03,0x00,0x00,
+ 0xd8,0x09,0x00,0x00,0x00,0x20,0x02,0x00,0xbc,0x01,0x00,0x00,0xcb,0x00,0x00,0x00,
+ 0xbc,0x21,0x02,0x00,0xc8,0x00,0x00,0x00,0xca,0x00,0x00,0x00,0x9c,0x08,0x04,0x00,
+ 0xc9,0x00,0x00,0x00,0xb7,0x1c,0x07,0xa6,0x06,0x2a,0x96,0x77,0x06,0xe0,0x07,0x85,
+ 0x35,0x31,0x07,0x95,0x95,0x77,0x07,0xb6,0x0a,0xf0,0x16,0x2a,0x07,0x86,0x03,0xe0,
+ 0x36,0x35,0x07,0x96,0x04,0xf0,0x36,0x31,0x07,0x96,0x8f,0x77,0x07,0xb5,0x8f,0x76,
+ 0x06,0xa7,0x57,0x34,0x06,0xb7,0x8e,0x75,0x05,0xa6,0x8e,0x77,0x07,0x87,0xbd,0x66,
+ 0xd7,0x1c,0x07,0xa7,0x47,0x3c,0x8c,0x7e,0xe6,0x16,0x67,0x1e,0x47,0x01,0x05,0xb7,
+ 0x86,0x2d,0x8a,0x77,0x07,0x96,0x06,0x2c,0x8a,0x77,0x07,0x96,0x06,0x60,0x89,0x77,
+ 0x07,0xb6,0xf6,0x61,0x89,0x77,0x07,0xb6,0x89,0x76,0x06,0xa7,0x17,0x34,0x04,0xf0,
+ 0x87,0x76,0x06,0xa7,0x87,0x72,0x27,0x16,0x06,0xb7,0x86,0x7f,0x02,0x61,0x86,0x7f,
+ 0x02,0x60,0x86,0x77,0x07,0xb2,0x86,0x77,0x07,0x84,0x7a,0x73,0x03,0x85,0x16,0x67,
+ 0x56,0x1c,0x06,0xa6,0x66,0x3d,0x64,0x31,0x74,0x31,0x46,0x1e,0x07,0x96,0x07,0x84,
+ 0xe6,0x66,0x56,0x1c,0x06,0xa6,0x16,0x3d,0x14,0x31,0x24,0x31,0x46,0x1e,0x07,0x96,
+ 0x07,0x84,0xd6,0x66,0x56,0x1c,0x06,0xa6,0x06,0x3d,0x04,0x31,0x46,0x1e,0x07,0x96,
+ 0x79,0x74,0x04,0x86,0xc7,0x66,0x75,0x1c,0x05,0xa7,0xd7,0x3c,0xd6,0x30,0xe6,0x30,
+ 0x67,0x1e,0x04,0x97,0x75,0x75,0x05,0xb2,0x07,0x60,0xf2,0x61,0x34,0x60,0x0f,0xf0,
+ 0x76,0x1c,0x66,0xa6,0x62,0x0c,0x09,0xe0,0x05,0xae,0xf6,0x25,0x06,0x30,0x48,0x12,
+ 0x68,0x1b,0x86,0x12,0xe6,0x1e,0x46,0x01,0x05,0xb6,0x07,0x20,0x47,0x01,0x03,0x86,
+ 0x46,0xae,0xe7,0x0c,0xed,0xef,0x69,0x72,0x03,0x60,0x69,0x74,0x6a,0x7f,0x07,0x60,
+ 0x6a,0x76,0x06,0xb7,0x15,0x60,0x69,0x76,0x06,0xb5,0x69,0x76,0x06,0xb7,0x63,0x73,
+ 0x3e,0x12,0x06,0x60,0x62,0x12,0x3a,0x12,0x6b,0x64,0x0c,0x2c,0xfd,0x67,0x1b,0xf0,
+ 0xe7,0x12,0x47,0x1c,0x64,0x78,0x87,0x1c,0x07,0xb2,0x57,0x12,0x37,0x3c,0x57,0x05,
+ 0x97,0x1c,0xa7,0x1c,0x61,0x78,0x87,0x1c,0x37,0xbc,0x47,0xbd,0x57,0xbc,0x67,0xbd,
+ 0x77,0xb2,0x87,0xb2,0x05,0x20,0x64,0x20,0xa5,0x2a,0xea,0xe7,0x06,0x20,0x6f,0x64,
+ 0xfe,0x1c,0x46,0x2a,0x24,0xe8,0x04,0x60,0x45,0x12,0x69,0x12,0xf1,0x11,0xb9,0x03,
+ 0xf9,0x11,0xde,0xf7,0x47,0x12,0x37,0x3c,0x37,0x1c,0x54,0x78,0x87,0x1c,0x0d,0x60,
+ 0x07,0xb5,0x27,0x12,0x47,0x1c,0x52,0x7b,0xb7,0x1c,0x37,0x3c,0xe7,0x1c,0x0b,0x60,
+ 0x37,0xbc,0x47,0xb5,0x57,0xb5,0x67,0xb5,0x77,0xb5,0x87,0xb5,0x04,0x20,0xa4,0x2a,
+ 0xe9,0xe7,0x06,0x20,0x0f,0x65,0xf3,0x1c,0x46,0x2a,0x05,0xe0,0x0b,0xf0,0x06,0x60,
+ 0x6c,0x12,0x65,0x12,0x3e,0x7e,0x04,0x60,0x62,0x12,0x62,0x1c,0x67,0x12,0x37,0x3c,
+ 0x72,0x1c,0xd8,0xf7,0x44,0x72,0xb3,0x12,0x3b,0x7f,0x43,0x7e,0x44,0x77,0x0e,0xb7,
+ 0x17,0x01,0x1e,0xb1,0x27,0x01,0x2e,0xb1,0x87,0x3f,0x3e,0xb7,0x47,0x61,0x4e,0xb7,
+ 0x40,0x7c,0x0c,0xa7,0x5e,0xb7,0x1c,0xa7,0x6e,0xb7,0x9e,0xbb,0x22,0x7a,0x0a,0x87,
+ 0x42,0x67,0x27,0x1c,0x07,0xa7,0xae,0xb7,0x07,0x60,0xbe,0xb7,0x3a,0x77,0x07,0xa6,
+ 0x07,0xbd,0x17,0xa6,0x17,0xbd,0x38,0x77,0x27,0xbd,0x37,0xbd,0x07,0xbd,0x17,0xbd,
+ 0x47,0xbd,0x57,0xbd,0x36,0x7f,0x36,0x76,0x06,0x87,0x47,0x30,0x57,0x30,0x06,0x97,
+ 0x35,0x76,0x35,0x77,0x07,0xd6,0x35,0x76,0x36,0x77,0x07,0xd6,0x1c,0xa7,0x87,0x3c,
+ 0x0c,0xa6,0x67,0x1e,0x34,0x76,0x06,0xd7,0xa6,0x61,0x33,0x77,0x07,0xb6,0x33,0x77,
+ 0x07,0xbd,0x0a,0x87,0x43,0x67,0x37,0x1c,0x07,0xa6,0x31,0x77,0x07,0xd6,0x4e,0xa6,
+ 0x31,0x77,0x07,0xb6,0x31,0x7f,0x31,0x77,0x07,0x9b,0xf0,0x20,0x68,0x00,0xf0,0x21,
+ 0xcf,0x00,0x00,0x00,0x08,0x01,0x04,0x00,0x9d,0x08,0x04,0x00,0x40,0x08,0x04,0x00,
+ 0x41,0x08,0x04,0x00,0x1c,0x9e,0x00,0x00,0x8f,0xff,0xff,0xff,0xa0,0x08,0x04,0x00,
+ 0xa4,0x08,0x04,0x00,0xcc,0x08,0x04,0x00,0x66,0x09,0x04,0x00,0x68,0x08,0x04,0x00,
+ 0xfd,0x00,0x00,0x00,0x5e,0x31,0x00,0x00,0x72,0x2d,0x00,0x00,0x3c,0x01,0x04,0x00,
+ 0x04,0x01,0x04,0x00,0x0c,0x01,0x04,0x00,0x48,0x01,0x04,0x00,0x8a,0x9e,0x00,0x00,
+ 0xe9,0x05,0x00,0x00,0xc4,0x09,0x00,0x00,0x63,0xa4,0x00,0x00,0x64,0xa4,0x00,0x00,
+ 0xe5,0xa3,0x00,0x00,0x02,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x1a,0x04,0x00,0x00,
+ 0x83,0x00,0x00,0x00,0xfa,0xa3,0x00,0x00,0x7a,0x9e,0x00,0x00,0x00,0xe0,0x02,0x00,
+ 0x20,0x9e,0x00,0x00,0x00,0x08,0x03,0x00,0x73,0xa4,0x00,0x00,0x04,0x31,0x00,0x00,
+ 0x04,0x0a,0x04,0x00,0x36,0x50,0x00,0x00,0x40,0x0a,0x04,0x00,0x00,0x68,0x00,0x00,
+ 0x42,0x0a,0x04,0x00,0x44,0x0a,0x04,0x00,0x46,0x0a,0x04,0x00,0x47,0x0a,0x04,0x00,
+ 0x48,0x0a,0x04,0x00,0x4a,0x0a,0x04,0x00,0x2c,0x31,0x00,0x00,0x4c,0x06,0x04,0x00,
+ 0x16,0x60,0x82,0x77,0x07,0xb6,0x82,0x76,0x06,0x87,0x82,0x75,0x57,0x1e,0x06,0x97,
+ 0x82,0x76,0x06,0x87,0xd7,0x34,0x06,0x97,0x81,0x76,0x06,0x87,0xe7,0x35,0xf7,0x35,
+ 0x06,0x97,0xcf,0x00,0xcf,0x00,0x7e,0x72,0xcf,0x00,0xf0,0x24,0x7d,0x00,0x7d,0x77,
+ 0x07,0x83,0x7d,0x77,0x37,0x1c,0x07,0xa7,0x07,0x2a,0x32,0xe8,0x7c,0x77,0x17,0xa6,
+ 0x7c,0x74,0x05,0x60,0x7c,0x72,0x0b,0xf0,0x37,0x12,0x57,0x1c,0xaf,0x62,0xf7,0x1c,
+ 0x07,0xa7,0x77,0x1c,0x27,0x1c,0x07,0xc7,0x04,0xd7,0x05,0x20,0x14,0x20,0x05,0x01,
+ 0x61,0x0c,0xf2,0xef,0x72,0x77,0x07,0xad,0x05,0x60,0x54,0x12,0xff,0x61,0x70,0x7e,
+ 0x71,0x71,0x66,0x1c,0x11,0xf0,0x37,0x12,0x47,0x1c,0x67,0xa7,0x52,0x12,0x62,0x1c,
+ 0xe2,0x1c,0x7f,0x0c,0x02,0xe8,0x77,0x21,0x01,0xf0,0xb7,0x24,0x77,0x1c,0x17,0x1c,
+ 0x07,0xc7,0x02,0xd7,0x04,0x20,0x15,0x20,0x47,0x12,0x47,0x01,0xd7,0x0c,0xeb,0xef,
+ 0x6d,0x00,0xf0,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x63,0x77,0x07,0xa6,0x06,0x20,
+ 0x46,0x01,0x07,0xb6,0x62,0x77,0x07,0xa7,0x07,0x2a,0x07,0xe0,0x5a,0x77,0x07,0x87,
+ 0x85,0x67,0x75,0x1c,0x05,0xa5,0x05,0x2a,0x0d,0xe0,0x06,0x60,0x5b,0x77,0x07,0xb6,
+ 0x55,0x77,0x07,0x87,0xb6,0x64,0x67,0x1c,0x07,0xa7,0x0e,0x60,0x17,0x2a,0x12,0xe0,
+ 0x58,0x7f,0x10,0xf0,0x95,0x67,0x75,0x1c,0x05,0xa5,0x1e,0x60,0x56,0x0c,0x0a,0xe8,
+ 0xb6,0x64,0x67,0x1c,0x07,0xa7,0x17,0x2a,0x01,0xe0,0x51,0x7f,0x06,0x60,0x4e,0x77,
+ 0x07,0xb6,0x0e,0x60,0xe2,0x12,0x6e,0x00,0x70,0x20,0xcf,0x00,0xf0,0x24,0x20,0x9f,
+ 0x30,0x9e,0x44,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0x4a,0x77,0x00,0x97,0x24,0x60,
+ 0x4a,0x75,0x06,0x60,0x67,0x12,0x49,0x7f,0x40,0x77,0x7e,0x1c,0x0e,0xa7,0x07,0x2a,
+ 0x13,0xe8,0x3e,0x77,0x17,0xa6,0x07,0xa7,0x76,0x1c,0x07,0x60,0x45,0x73,0x3c,0x74,
+ 0x09,0xf0,0x75,0x12,0x75,0x1c,0x32,0x12,0x52,0x1c,0x45,0x1c,0x05,0xc5,0x02,0xd5,
+ 0x07,0x20,0x47,0x01,0x67,0x0d,0xf5,0xe7,0x20,0x8f,0x30,0x8e,0xf0,0x20,0xcf,0x00,
+ 0x70,0x24,0x00,0x9f,0x06,0x60,0x3b,0x77,0x07,0xb6,0x16,0x60,0x3b,0x77,0x07,0xb6,
+ 0xa2,0x60,0x3a,0x7f,0x00,0x8f,0x70,0x20,0xcf,0x00,0x37,0x77,0x07,0xa6,0x16,0x36,
+ 0xfd,0xef,0xcf,0x00,0xcf,0x00,0xcf,0x00,0x42,0x01,0x03,0x01,0x35,0x76,0xa7,0x61,
+ 0xf1,0x11,0x27,0x03,0xf9,0x11,0x17,0x1c,0x77,0x1c,0x76,0x1c,0x06,0xc5,0x54,0x12,
+ 0x74,0x01,0x30,0x77,0x07,0xa6,0x30,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x74,0x0d,
+ 0x17,0xe0,0x2e,0x77,0x27,0xa3,0x37,0xa6,0x86,0x3c,0x36,0x1e,0x06,0x20,0x66,0x01,
+ 0x27,0xb6,0x86,0x3e,0x37,0xb6,0x47,0xa3,0x57,0xa6,0x86,0x3c,0x36,0x1e,0x46,0x0d,
+ 0x07,0xe8,0x56,0x12,0x66,0x01,0x47,0xb6,0x86,0x3e,0x57,0xb6,0x67,0xb2,0x77,0xb1,
+ 0x23,0x77,0x87,0xa6,0x62,0x0c,0x01,0xe0,0x87,0xb2,0x97,0xa7,0x71,0x0c,0x02,0xe0,
+ 0x1f,0x77,0x97,0xb1,0x1e,0x77,0xa7,0xa6,0x26,0x0c,0x01,0xe0,0xa7,0xb2,0xb7,0xa7,
+ 0x17,0x0c,0x02,0xe0,0x1a,0x77,0xb7,0xb1,0xcf,0x00,0x00,0x00,0x40,0x01,0x04,0x00,
+ 0x0c,0x01,0x04,0x00,0x00,0x00,0x0f,0x00,0x04,0x01,0x04,0x00,0x08,0x01,0x04,0x00,
+ 0x00,0x80,0x02,0x00,0x1c,0x9e,0x00,0x00,0xc8,0x00,0x00,0x00,0x20,0x9e,0x00,0x00,
+ 0xec,0xa4,0x00,0x00,0xc0,0x86,0x02,0x00,0x5c,0xa5,0x00,0x00,0x20,0xaa,0x00,0x00,
+ 0x12,0x2c,0x00,0x00,0x36,0x00,0x04,0x1a,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,
+ 0x5e,0xa5,0x00,0x00,0x74,0x08,0x04,0x00,0x70,0x08,0x04,0x00,0xe0,0x0a,0x00,0x00,
+ 0x00,0xe0,0x02,0x00,0x44,0xa4,0x00,0x00,0x45,0xa4,0x00,0x00,0x73,0xa4,0x00,0x00,
+ 0x70,0x25,0x7a,0x00,0x42,0x01,0x43,0x01,0x04,0x01,0xad,0x77,0x07,0xa7,0xad,0x76,
+ 0x06,0xaf,0x8f,0x3c,0x7f,0x1e,0x86,0x2c,0x5e,0x60,0xec,0x12,0x05,0x60,0xaa,0x7a,
+ 0x1a,0xf0,0x52,0x0f,0x16,0xe8,0x87,0x65,0x57,0x1c,0x77,0x1c,0xa7,0x1c,0x87,0xad,
+ 0x3d,0x14,0x5d,0x01,0xed,0x01,0x4d,0x01,0x97,0xa7,0x17,0x14,0x57,0x01,0xe7,0x01,
+ 0x47,0x01,0x7b,0x12,0xdb,0x1c,0x4b,0x01,0x6b,0x0c,0x03,0xe0,0xb6,0x12,0x7e,0x12,
+ 0xdc,0x12,0x05,0x20,0x45,0x01,0xf5,0x0c,0xe4,0xef,0x22,0x60,0x62,0x0c,0x09,0xe8,
+ 0x02,0x60,0x26,0x2a,0x06,0xe0,0x62,0x12,0x0c,0x2a,0x03,0xe8,0x0e,0x2a,0x22,0x00,
+ 0x22,0x28,0x6a,0x00,0x70,0x21,0xcf,0x00,0xf0,0x25,0x79,0x00,0x27,0x12,0x47,0x01,
+ 0x03,0x01,0x45,0x01,0x5b,0x12,0x5b,0x1c,0x02,0x60,0x2f,0x12,0x07,0x24,0x01,0x24,
+ 0x4c,0x61,0x1b,0xf0,0xe3,0x12,0xa3,0x1c,0x33,0x1c,0x43,0x1c,0x3d,0x12,0xbd,0x1c,
+ 0x03,0xc6,0x76,0x01,0x1d,0xc9,0x79,0x01,0x96,0x1c,0x13,0xc3,0x73,0x01,0x36,0x05,
+ 0x0d,0xc3,0x73,0x01,0x36,0x05,0xe6,0x01,0x6c,0x0c,0x01,0xe0,0x62,0x1c,0x0e,0x20,
+ 0x4e,0x01,0x1e,0x0d,0xe7,0xe7,0x0f,0x20,0x4f,0x01,0x7f,0x0d,0x06,0xe8,0xfa,0x12,
+ 0xf1,0x11,0x5a,0x03,0xf9,0x11,0x0e,0x60,0xf4,0xf7,0x69,0x00,0xf0,0x21,0xcf,0x00,
+ 0xf0,0x24,0x7d,0x00,0x7a,0x77,0x07,0xa2,0x17,0xa3,0x79,0x74,0x85,0x61,0x79,0x7f,
+ 0x7a,0x7d,0x0d,0xa5,0x05,0x2a,0x79,0x77,0x7a,0x7e,0x03,0xe0,0x07,0x92,0x0e,0x92,
+ 0x2d,0xf0,0x0e,0x86,0x26,0x1c,0x0e,0x96,0x07,0x87,0x72,0x05,0xe2,0x01,0x75,0x77,
+ 0x07,0x87,0x75,0x74,0x74,0x1c,0x04,0xa4,0x75,0x73,0x37,0x1c,0x07,0xa7,0x87,0x3c,
+ 0x47,0x1e,0x27,0x0d,0x04,0xe8,0x06,0x60,0x72,0x77,0x07,0xb6,0x15,0xf0,0x87,0x60,
+ 0x57,0x0c,0x14,0xe0,0x15,0x60,0x6e,0x77,0x07,0xb5,0x62,0x12,0xa3,0x60,0x6d,0x7f,
+ 0x0e,0x92,0x6d,0x77,0x07,0xb2,0x12,0x01,0x6d,0x77,0x07,0xb1,0x22,0x01,0x6c,0x77,
+ 0x07,0xb1,0x82,0x3f,0x6c,0x77,0x07,0xb2,0x07,0x2c,0x0d,0xb7,0x5f,0x77,0x07,0xa6,
+ 0x06,0x20,0x07,0xb6,0x65,0x77,0x07,0xa6,0x65,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,
+ 0x64,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x63,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,
+ 0x62,0x7e,0x0e,0xa5,0x62,0x74,0x04,0xa6,0x86,0x3c,0x56,0x1e,0x61,0x75,0x05,0xa2,
+ 0x02,0x3d,0x62,0x1e,0x60,0x76,0x06,0xa3,0x83,0x3d,0x23,0x1e,0x37,0x0c,0x07,0xe0,
+ 0x0e,0xb7,0x17,0x01,0x04,0xb1,0x27,0x01,0x05,0xb1,0x87,0x3f,0x06,0xb7,0x6d,0x00,
+ 0xf0,0x20,0xcf,0x00,0x70,0x24,0x7e,0x00,0x58,0x7e,0x0e,0xa7,0x17,0x2a,0x03,0xe0,
+ 0x27,0x60,0x0e,0xb7,0xff,0xf0,0x27,0x2a,0xfd,0xe0,0x54,0x7f,0x55,0x77,0x07,0xa7,
+ 0x07,0x2a,0xd0,0xe8,0xfe,0xa7,0x07,0x2a,0x20,0xe8,0x52,0x77,0x07,0xa7,0x52,0x76,
+ 0x06,0xa6,0x86,0x3c,0x76,0x1e,0x51,0x77,0x07,0xa7,0x07,0x3d,0x67,0x1e,0x50,0x76,
+ 0x06,0xa6,0x86,0x3d,0x76,0x1e,0x4f,0x77,0x07,0xa5,0x4f,0x77,0x07,0xa7,0x87,0x3c,
+ 0x57,0x1e,0x4e,0x75,0x05,0xa5,0x05,0x3d,0x75,0x1e,0x4d,0x77,0x07,0xa7,0x87,0x3d,
+ 0x57,0x1e,0x67,0x0c,0x02,0xe0,0x07,0x60,0xfe,0xb7,0x4a,0x77,0x07,0xa7,0x07,0x2a,
+ 0x3e,0x77,0x26,0xe8,0x06,0x60,0xa7,0xb6,0x34,0x76,0x06,0xa6,0x34,0x75,0x05,0xa5,
+ 0x85,0x3c,0x65,0x1e,0x33,0x76,0x06,0xa6,0x06,0x3d,0x56,0x1e,0x32,0x75,0x05,0xa5,
+ 0x85,0x3d,0x65,0x1e,0x41,0x76,0x06,0xa4,0x41,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e,
+ 0x40,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x3f,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e,
+ 0x16,0x3e,0x65,0x0c,0xaf,0xe0,0x16,0x60,0x3c,0x75,0x05,0xb6,0xf7,0xb6,0xaa,0xf0,
+ 0x16,0x60,0xa7,0xb6,0xf7,0xa6,0x06,0x2a,0x1b,0x76,0x06,0x85,0x0e,0xe8,0x37,0x76,
+ 0x56,0x1c,0x06,0xa4,0x37,0x76,0x56,0x1c,0x06,0xa6,0x86,0x3c,0x46,0x1e,0xb7,0xb6,
+ 0x86,0x3e,0xc7,0xb6,0x34,0x74,0x45,0x1c,0x0d,0xf0,0x33,0x76,0x56,0x1c,0x06,0xa4,
+ 0x33,0x76,0x56,0x1c,0x06,0xa6,0x86,0x3c,0x46,0x1e,0xb7,0xb6,0x86,0x3e,0xc7,0xb6,
+ 0x30,0x76,0x65,0x1c,0x05,0xa6,0xd7,0xb6,0x06,0x60,0xe7,0xb6,0x83,0xf0,0x00,0x00,
+ 0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00,0x8a,0x9e,0x00,0x00,0x20,0x9e,0x00,0x00,
+ 0x00,0x80,0x02,0x00,0x58,0x3e,0x00,0x00,0xce,0xa5,0x00,0x00,0xd0,0xa5,0x00,0x00,
+ 0xd4,0xa5,0x00,0x00,0x1c,0x9e,0x00,0x00,0x1e,0x01,0x00,0x00,0x1f,0x01,0x00,0x00,
+ 0x71,0xa4,0x00,0x00,0xd0,0x83,0x00,0x00,0x6d,0xa4,0x00,0x00,0x6e,0xa4,0x00,0x00,
+ 0x6f,0xa4,0x00,0x00,0x70,0xa4,0x00,0x00,0x69,0xa4,0x00,0x00,0x6a,0xa4,0x00,0x00,
+ 0x6b,0xa4,0x00,0x00,0x6c,0xa4,0x00,0x00,0x66,0x9e,0x00,0x00,0xc0,0x3e,0x00,0x00,
+ 0x64,0xa4,0x00,0x00,0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,
+ 0x3a,0xaa,0x00,0x00,0x76,0x9e,0x00,0x00,0x77,0x9e,0x00,0x00,0x78,0x9e,0x00,0x00,
+ 0x79,0x9e,0x00,0x00,0xa5,0xa0,0x00,0x00,0x65,0xa4,0x00,0x00,0x66,0xa4,0x00,0x00,
+ 0x67,0xa4,0x00,0x00,0x68,0xa4,0x00,0x00,0x31,0xaa,0x00,0x00,0x0f,0x01,0x00,0x00,
+ 0x10,0x01,0x00,0x00,0x0e,0x01,0x00,0x00,0x0c,0x01,0x00,0x00,0x0d,0x01,0x00,0x00,
+ 0xba,0x00,0x00,0x00,0x17,0x60,0xad,0x76,0x06,0xb7,0xfe,0xb7,0xad,0x77,0x07,0xa7,
+ 0xad,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0xac,0x77,0x07,0xa7,0x07,0x3d,0x67,0x1e,
+ 0xab,0x76,0x06,0xa6,0x86,0x3d,0x76,0x1e,0xaa,0x77,0x07,0x87,0xaa,0x75,0x75,0x1c,
+ 0x05,0xa5,0xa9,0x74,0x47,0x1c,0x07,0xa7,0x87,0x3c,0x57,0x1e,0x67,0x1c,0xa7,0x76,
+ 0x06,0xb7,0x17,0x01,0xa7,0x76,0x06,0xb1,0x27,0x01,0xa6,0x76,0x06,0xb1,0x87,0x3f,
+ 0xa6,0x76,0x06,0xb7,0x6e,0x00,0x70,0x20,0xcf,0x00,0xa4,0x77,0x37,0xa6,0x06,0x2a,
+ 0xa4,0xe0,0xa3,0x75,0x05,0xa6,0x06,0x2a,0x40,0xe0,0xa2,0x76,0x06,0xa4,0xa2,0x76,
+ 0x06,0xa6,0x86,0x3c,0x46,0x1e,0xa1,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0xa0,0x76,
+ 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0xbd,0xe1,0x9e,0x76,0x06,0xa4,0x9e,0x76,
+ 0x06,0xa6,0x86,0x3c,0x46,0x1e,0x9d,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x9c,0x76,
+ 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0x02,0xe8,0x16,0x60,0xa6,0xf0,0x17,0xa6,
+ 0x06,0x20,0x46,0x01,0x17,0xb6,0x55,0x60,0x65,0x0c,0xba,0xe1,0x16,0x60,0x17,0xb6,
+ 0xa7,0xb6,0x83,0x76,0x06,0x85,0x93,0x76,0x56,0x1c,0x06,0xa4,0x93,0x76,0x56,0x1c,
+ 0x06,0xa6,0x86,0x3c,0x46,0x1e,0xb7,0xb6,0x86,0x3e,0xc7,0xb6,0x90,0x72,0x25,0x1c,
+ 0x05,0xa6,0xd7,0xb6,0x06,0x60,0xe7,0xb6,0xa3,0xf1,0x16,0x2a,0x2b,0xe0,0x81,0x74,
+ 0x04,0xa3,0x81,0x74,0x04,0xa4,0x84,0x3c,0x34,0x1e,0x80,0x73,0x03,0xa3,0x03,0x3d,
+ 0x43,0x1e,0x7f,0x74,0x04,0xa4,0x84,0x3d,0x34,0x1e,0x04,0x2a,0x09,0xe8,0x17,0xa5,
+ 0x05,0x20,0x45,0x01,0x17,0xb5,0x34,0x60,0x54,0x0c,0x8a,0xe1,0x17,0xb6,0x41,0xf0,
+ 0x79,0x74,0x04,0xa3,0x79,0x74,0x04,0xa4,0x84,0x3c,0x34,0x1e,0x78,0x73,0x03,0xa3,
+ 0x03,0x3d,0x43,0x1e,0x77,0x74,0x04,0xa4,0x84,0x3d,0x34,0x1e,0x17,0xb6,0x04,0x2a,
+ 0x4d,0xe9,0x5c,0xf0,0x26,0x2a,0x74,0xe1,0x6b,0x74,0x04,0xa3,0x6b,0x74,0x04,0xa4,
+ 0x84,0x3c,0x34,0x1e,0x6a,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x69,0x74,0x04,0xa4,
+ 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x4e,0xe1,0x67,0x74,0x04,0xa3,0x67,0x74,0x04,0xa4,
+ 0x84,0x3c,0x34,0x1e,0x66,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x65,0x74,0x04,0xa4,
+ 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x0f,0xe8,0x17,0xa4,0x04,0x20,0x44,0x01,0x17,0xb4,
+ 0x50,0x75,0x05,0x85,0x63,0x73,0x35,0x1c,0x05,0xa5,0x45,0x0c,0x49,0xe1,0x15,0x60,
+ 0x17,0xb5,0x37,0xb6,0x45,0xf1,0x16,0x60,0xbd,0xf0,0x16,0x2a,0xbd,0xe0,0x05,0x60,
+ 0xa7,0xb5,0x4f,0x75,0x05,0xa3,0x03,0x2a,0x30,0xe0,0x4e,0x74,0x04,0xa3,0x4e,0x74,
+ 0x04,0xa4,0x84,0x3c,0x34,0x1e,0x4d,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x4c,0x74,
+ 0x04,0xa4,0x84,0x3d,0x34,0x1e,0x04,0x2a,0x16,0xe1,0x4a,0x74,0x04,0xa3,0x4a,0x74,
+ 0x04,0xa4,0x84,0x3c,0x34,0x1e,0x49,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x48,0x74,
+ 0x04,0xa4,0x84,0x3d,0x34,0x1e,0x04,0x2a,0x04,0xe8,0x17,0xb6,0x27,0x60,0x05,0xb7,
+ 0x17,0xf1,0x17,0xa3,0x03,0x20,0x43,0x01,0x17,0xb3,0x31,0x75,0x05,0x85,0x44,0x72,
+ 0x25,0x1c,0x05,0xa5,0x35,0x0c,0x0c,0xe1,0xbb,0xf0,0x13,0x2a,0x22,0xe0,0x35,0x76,
+ 0x06,0xa4,0x35,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e,0x34,0x74,0x04,0xa4,0x04,0x3d,
+ 0x64,0x1e,0x33,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0xf9,0xe0,0x31,0x76,
+ 0x06,0xa4,0x31,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e,0x30,0x74,0x04,0xa4,0x04,0x3d,
+ 0x64,0x1e,0x2f,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e,0x17,0xb3,0x06,0x2a,0xe7,0xe8,
+ 0xcd,0xf7,0x23,0x2a,0xe5,0xe0,0x23,0x74,0x04,0xa2,0x23,0x74,0x04,0xa4,0x84,0x3c,
+ 0x24,0x1e,0x22,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x21,0x74,0x04,0xa4,0x84,0x3d,
+ 0x24,0x1e,0x04,0x2a,0xc0,0xe0,0x1f,0x74,0x04,0xa2,0x1f,0x74,0x04,0xa4,0x84,0x3c,
+ 0x24,0x1e,0x1e,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x1d,0x74,0x04,0xa4,0x84,0x3d,
+ 0x24,0x1e,0x04,0x2a,0x3f,0xe8,0x0a,0x75,0x05,0x85,0x1d,0x74,0x45,0x1c,0x17,0xa4,
+ 0x05,0xa5,0x45,0x0c,0xbd,0xe0,0x17,0xb6,0x37,0xb3,0xba,0xf0,0x31,0xaa,0x00,0x00,
+ 0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0xb7,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x76,0x9e,0x00,0x00,
+ 0x77,0x9e,0x00,0x00,0x78,0x9e,0x00,0x00,0x79,0x9e,0x00,0x00,0x66,0x9e,0x00,0x00,
+ 0xd8,0xa5,0x00,0x00,0x46,0xa4,0x00,0x00,0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00,
+ 0x49,0xa4,0x00,0x00,0x4a,0xa4,0x00,0x00,0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00,
+ 0x4d,0xa4,0x00,0x00,0x0c,0x01,0x00,0x00,0x0d,0x01,0x00,0x00,0xba,0x00,0x00,0x00,
+ 0xb9,0x00,0x00,0x00,0x17,0xb6,0x5a,0xf0,0x26,0x2a,0x82,0xe0,0x05,0x60,0xa7,0xb5,
+ 0x92,0x75,0x05,0xa3,0x03,0x2a,0x2f,0xe0,0x91,0x74,0x04,0xa3,0x91,0x74,0x04,0xa4,
+ 0x84,0x3c,0x34,0x1e,0x90,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x8f,0x74,0x04,0xa4,
+ 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x56,0xe0,0x8d,0x74,0x04,0xa3,0x8d,0x74,0x04,0xa4,
+ 0x84,0x3c,0x34,0x1e,0x8c,0x73,0x03,0xa3,0x03,0x3d,0x43,0x1e,0x8b,0x74,0x04,0xa4,
+ 0x84,0x3d,0x34,0x1e,0x04,0x2a,0x59,0xe0,0x17,0xa5,0x05,0x20,0x45,0x01,0x17,0xb5,
+ 0x87,0x76,0x06,0x86,0x87,0x72,0x26,0x1c,0x06,0xa6,0x56,0x0c,0x51,0xe0,0x16,0x60,
+ 0x17,0xb6,0x37,0xb4,0x4d,0xf0,0x13,0x2a,0x23,0xe0,0x78,0x74,0x04,0xa2,0x78,0x74,
+ 0x04,0xa4,0x84,0x3c,0x24,0x1e,0x77,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x76,0x74,
+ 0x04,0xa4,0x84,0x3d,0x24,0x1e,0x04,0x2a,0x3b,0xe0,0x74,0x74,0x04,0xa2,0x74,0x74,
+ 0x04,0xa4,0x84,0x3c,0x24,0x1e,0x73,0x72,0x02,0xa2,0x02,0x3d,0x42,0x1e,0x72,0x74,
+ 0x04,0xa4,0x84,0x3d,0x24,0x1e,0x17,0xb3,0x04,0x2a,0x29,0xe0,0x05,0xb4,0x28,0xf0,
+ 0x23,0x2a,0x26,0xe0,0x66,0x76,0x06,0xa4,0x66,0x76,0x06,0xa6,0x86,0x3c,0x46,0x1e,
+ 0x65,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x64,0x76,0x06,0xa6,0x86,0x3d,0x46,0x1e,
+ 0x06,0x2a,0x03,0xe8,0x16,0x60,0x17,0xb6,0x12,0xf0,0x60,0x76,0x06,0xa4,0x60,0x76,
+ 0x06,0xa6,0x86,0x3c,0x46,0x1e,0x5f,0x74,0x04,0xa4,0x04,0x3d,0x64,0x1e,0x5e,0x76,
+ 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x06,0x2a,0x03,0xe0,0x14,0x60,0x17,0xb4,0x05,0xb6,
+ 0xcf,0x00,0xf0,0x24,0x7c,0x00,0x5b,0x77,0x77,0xa7,0x07,0x2a,0x05,0xe8,0x57,0x77,
+ 0x07,0x87,0x76,0x67,0x67,0x1c,0x07,0xf0,0x58,0x77,0x07,0xa7,0x07,0x2a,0x57,0x77,
+ 0x02,0xe8,0x17,0xa7,0x01,0xf0,0x07,0xa7,0x56,0x73,0x03,0xa6,0x13,0xa4,0x84,0x3c,
+ 0x64,0x1e,0x06,0x60,0x65,0x12,0x53,0x7d,0xae,0x61,0x7f,0x12,0x7f,0x01,0x1d,0xf0,
+ 0x57,0x12,0x57,0x1c,0x37,0x1c,0x27,0xa1,0x37,0xa2,0x2c,0x12,0x5c,0x01,0x17,0x12,
+ 0x57,0x01,0xf1,0x11,0xe7,0x03,0xf9,0x11,0xc7,0x1c,0x77,0x1c,0xd7,0x1c,0x07,0xc7,
+ 0x77,0x01,0x7f,0x0d,0x08,0xe8,0x87,0x65,0x67,0x1c,0x77,0x1c,0x37,0x1c,0x87,0xb1,
+ 0x97,0xb2,0x06,0x20,0x46,0x01,0x05,0x20,0x45,0x01,0x45,0x0c,0xe1,0xef,0x42,0x77,
+ 0x07,0xb6,0x42,0x77,0x06,0x60,0x07,0xb6,0x6c,0x00,0xf0,0x20,0xcf,0x00,0xf0,0x25,
+ 0x60,0x9f,0x70,0x9e,0x36,0x77,0x07,0x87,0x3e,0x76,0x76,0x1c,0x06,0xa6,0x06,0x2a,
+ 0x4f,0xe8,0x3c,0x76,0x06,0xa4,0x3c,0x76,0x06,0xa6,0x86,0x3c,0x3c,0x75,0x75,0x1c,
+ 0x05,0xa5,0x3b,0x72,0x27,0x1c,0x07,0xa7,0x87,0x3c,0x46,0x1e,0x57,0x1e,0x67,0x0c,
+ 0x39,0x75,0x39,0x77,0x04,0xe0,0x16,0x60,0x05,0xb6,0x56,0x60,0x05,0xf0,0x07,0xa6,
+ 0x06,0x2a,0x86,0x00,0x01,0xe0,0x05,0xb6,0x07,0xb6,0x32,0x77,0x07,0xa7,0x07,0x2a,
+ 0x2f,0xe8,0x2c,0x77,0x07,0xa6,0x2c,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x7e,0x12,
+ 0x7e,0x1c,0x7e,0x1c,0x2e,0x3e,0x02,0x12,0x03,0x60,0x44,0x61,0x2c,0x7f,0x22,0x77,
+ 0x07,0xa7,0x22,0x76,0x06,0xa5,0x85,0x3c,0x75,0x1e,0x06,0x60,0x1d,0x73,0x7e,0x01,
+ 0x14,0x60,0x11,0xf0,0x67,0x12,0x37,0x3c,0x67,0x05,0x37,0x1c,0x82,0x62,0x27,0x1c,
+ 0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,0xe7,0x0d,0x03,0xe8,0x07,0x12,0x67,0x1c,
+ 0x07,0xb4,0x06,0x20,0x46,0x01,0x56,0x0c,0xed,0xef,0x02,0x12,0x13,0x73,0x1c,0x7f,
+ 0x60,0x8f,0x70,0x8e,0xf0,0x21,0xcf,0x00,0xd8,0xa5,0x00,0x00,0x46,0xa4,0x00,0x00,
+ 0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00,0x49,0xa4,0x00,0x00,0x4a,0xa4,0x00,0x00,
+ 0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00,0x4d,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0xb9,0x00,0x00,0x00,0x20,0xaa,0x00,0x00,0x4a,0xa0,0x00,0x00,0x86,0x9e,0x00,0x00,
+ 0x8a,0x9e,0x00,0x00,0x00,0xe0,0x02,0x00,0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00,
+ 0x83,0x00,0x00,0x00,0x3e,0xa4,0x00,0x00,0x3f,0xa4,0x00,0x00,0x84,0x00,0x00,0x00,
+ 0x85,0x00,0x00,0x00,0xd9,0xa5,0x00,0x00,0x00,0x9e,0x00,0x00,0x22,0x83,0x00,0x00,
+ 0x00,0x2d,0x00,0x00,0x70,0x25,0x7a,0x00,0xbd,0x77,0x07,0x8f,0xbd,0x77,0xf7,0x1c,
+ 0x07,0xa7,0x07,0x2a,0x77,0xe8,0xbb,0x77,0x07,0xa6,0xbb,0x77,0x07,0xa7,0xbb,0x71,
+ 0x7c,0x12,0x4c,0x3c,0x75,0x12,0x65,0x3c,0x5c,0x1c,0xb9,0x74,0xc4,0x1c,0x03,0x60,
+ 0x7d,0x12,0x7d,0x1c,0x37,0x3c,0x7d,0x1c,0x0c,0x28,0x6e,0x12,0x4e,0x3c,0x67,0x12,
+ 0x67,0x3c,0x7e,0x1c,0x01,0xa7,0x27,0x2a,0x58,0xe0,0x04,0xa7,0x07,0x2a,0x55,0xe8,
+ 0xb1,0x7b,0xd7,0x12,0x37,0x1c,0xb0,0x75,0x57,0x1c,0x37,0x3c,0xb7,0x1c,0x77,0xa5,
+ 0x87,0xa2,0x82,0x3c,0x52,0x1e,0xad,0x77,0xf7,0x1c,0x07,0xa7,0xad,0x75,0xf5,0x1c,
+ 0x05,0xa5,0x85,0x3c,0x75,0x1e,0x25,0x0c,0x12,0xe0,0x67,0x12,0x67,0x1c,0x6a,0x12,
+ 0x3a,0x3c,0xa7,0x1c,0x37,0x1c,0xa4,0x7a,0xa7,0x1c,0x37,0x3c,0xb7,0x1c,0x77,0xab,
+ 0x87,0xa7,0x87,0x3c,0xb7,0x1e,0x5b,0x12,0x2b,0x3e,0x7b,0x0c,0x14,0xe8,0x9d,0x7b,
+ 0x67,0x12,0x67,0x1c,0x6a,0x12,0x3a,0x3c,0xa7,0x1c,0x37,0x1c,0x9b,0x7a,0xa7,0x1c,
+ 0x37,0x3c,0x7b,0x1c,0x7b,0xaa,0x8b,0xa7,0x87,0x3c,0xa7,0x1e,0x75,0x0c,0x1d,0xe0,
+ 0x25,0x3e,0x25,0x0c,0x1a,0xe0,0x74,0xa7,0xc5,0x12,0x45,0x1c,0xe5,0x1c,0x75,0xa5,
+ 0x57,0x05,0xe7,0x01,0x67,0x01,0x72,0x12,0x72,0x01,0xa5,0x65,0x25,0x0d,0x04,0xe8,
+ 0x91,0x75,0x75,0x05,0x57,0x12,0x67,0x01,0x77,0x01,0x8f,0x75,0xf5,0x1c,0x05,0xa5,
+ 0x15,0x3e,0x75,0x0d,0x02,0xe8,0x47,0x60,0x01,0xb7,0x03,0x20,0x01,0x20,0x74,0x20,
+ 0xa3,0x2a,0xa0,0xe7,0x6a,0x00,0x70,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,0x01,0x65,
+ 0x10,0x05,0x2a,0x12,0x86,0x77,0x07,0xa7,0x07,0x2a,0x17,0xe8,0x06,0x60,0x84,0x77,
+ 0x07,0xb6,0x7a,0x77,0x84,0x72,0x13,0x60,0x44,0x60,0x07,0xa5,0x15,0x2a,0x02,0xe0,
+ 0x07,0xb6,0x05,0xf0,0x15,0x24,0x45,0x01,0x53,0x0c,0x01,0xe8,0x07,0xb4,0x07,0x20,
+ 0x27,0x0f,0xf3,0xe7,0x06,0x60,0x79,0x77,0x07,0xb6,0x79,0x77,0x07,0xa7,0x0a,0xb7,
+ 0x7a,0x77,0x07,0xa7,0x1a,0xb7,0x79,0x77,0x07,0xa7,0x2a,0xb7,0xa6,0x12,0x07,0x60,
+ 0x6d,0x74,0x75,0x12,0x45,0x1c,0x76,0x73,0x35,0x1c,0x05,0xa5,0x96,0xb5,0x07,0x20,
+ 0x56,0x20,0xa7,0x2a,0xf6,0xe7,0x61,0x77,0x07,0x8e,0x72,0x77,0xe7,0x1c,0x07,0xa7,
+ 0x74,0x32,0x47,0x1c,0x00,0x97,0x70,0x77,0xe7,0x1c,0x07,0xa7,0x47,0x1c,0x10,0x97,
+ 0x6f,0x77,0xa7,0xa6,0xb7,0xa5,0x85,0x3c,0x65,0x1e,0x40,0x95,0x56,0x12,0x6c,0x73,
+ 0x36,0x1c,0x66,0x01,0x60,0x96,0xc7,0xa6,0xd7,0xa4,0x84,0x3c,0x64,0x1e,0x50,0x94,
+ 0x46,0x12,0x36,0x1c,0x66,0x01,0x70,0x96,0xe7,0xa6,0xf7,0xa8,0x88,0x3c,0x68,0x1e,
+ 0x65,0x77,0x07,0xa7,0x65,0x76,0x06,0xa9,0x89,0x3c,0x79,0x1e,0x95,0x12,0x85,0x05,
+ 0xc0,0x95,0x62,0x77,0x07,0xa7,0x62,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x20,0x96,
+ 0x61,0x77,0x07,0xa7,0x61,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x30,0x96,0x20,0x87,
+ 0x76,0x05,0xd0,0x96,0x0d,0x60,0x5d,0x73,0xe3,0x1c,0x90,0x93,0x5d,0x74,0xe4,0x1c,
+ 0xa0,0x94,0x5c,0x75,0xe5,0x1c,0xe0,0x95,0x5c,0x76,0xe6,0x1c,0xb0,0x96,0x10,0x87,
+ 0x83,0x2c,0x37,0x16,0xf0,0x97,0x10,0x85,0x85,0x3e,0x04,0x64,0x04,0x1c,0x04,0x95,
+ 0x00,0x87,0x37,0x16,0x46,0x64,0x06,0x1c,0x06,0x97,0x00,0x84,0x84,0x3e,0x83,0x64,
+ 0x03,0x1c,0x03,0x94,0x87,0xf1,0xd6,0x12,0x36,0x3c,0xd6,0x1c,0x76,0x1c,0x4f,0x75,
+ 0x65,0x1c,0x05,0xab,0xb7,0x1c,0x3e,0x75,0x57,0x1c,0x07,0xa7,0x47,0x2a,0x78,0xe9,
+ 0x07,0x2a,0x76,0xe9,0x4b,0x77,0x76,0x1c,0x56,0xa7,0x66,0xa2,0x82,0x3c,0x72,0x1e,
+ 0x87,0x32,0x27,0x0c,0x22,0xe8,0x00,0x83,0x32,0x0c,0x08,0xe0,0x44,0x64,0x04,0x1c,
+ 0x04,0xa4,0x56,0xb4,0x85,0x64,0x05,0x1c,0x05,0xa5,0x66,0xb5,0xd7,0x12,0x37,0x3c,
+ 0xd7,0x1c,0x40,0x76,0x67,0x1c,0x57,0xa6,0x67,0xa7,0x87,0x3c,0x67,0x1e,0x00,0x86,
+ 0x67,0x05,0x90,0x83,0x03,0xac,0x82,0x12,0xc2,0x05,0xf1,0x11,0x72,0x03,0xf9,0x11,
+ 0x83,0x32,0x63,0x05,0x39,0x7f,0x2c,0x1c,0x8b,0xf0,0x60,0x84,0x24,0x0c,0x7d,0xe0,
+ 0x37,0x77,0xe7,0x1c,0x07,0xa7,0x45,0x12,0x73,0x32,0x35,0x1c,0x75,0x05,0x25,0x0d,
+ 0x08,0xe8,0x40,0x85,0x33,0x74,0x45,0x1c,0x75,0x05,0x65,0x01,0x56,0xb5,0x85,0x3e,
+ 0x66,0xb5,0xd5,0x12,0x35,0x3c,0xd5,0x1c,0x2b,0x76,0x65,0x1c,0x55,0xa6,0x65,0xa2,
+ 0x82,0x3c,0x62,0x1e,0x60,0x85,0x52,0x05,0x0e,0xa5,0x1e,0xa6,0x86,0x3c,0x56,0x1e,
+ 0x29,0x75,0xe5,0x1c,0x05,0xa5,0x56,0x05,0x4f,0xf0,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0x1a,0x01,0x00,0x00,0xe4,0xa3,0x00,0x00,0xe5,0xa3,0x00,0x00,0xfa,0xa3,0x00,0x00,
+ 0xa4,0xa2,0x00,0x00,0x8a,0x9e,0x00,0x00,0x83,0x00,0x00,0x00,0x1b,0x01,0x00,0x00,
+ 0x1c,0x01,0x00,0x00,0xb4,0x00,0x00,0x00,0x1d,0x01,0x00,0x00,0x62,0xa4,0x00,0x00,
+ 0xa5,0xa0,0x00,0x00,0x04,0xa4,0x00,0x00,0x4a,0xa0,0x00,0x00,0x2c,0xa4,0x00,0x00,
+ 0x70,0x05,0x00,0x00,0x9d,0x00,0x00,0x00,0x9f,0x00,0x00,0x00,0x20,0x9e,0x00,0x00,
+ 0x00,0xff,0xff,0xff,0x30,0x9e,0x00,0x00,0x31,0x9e,0x00,0x00,0x32,0x9e,0x00,0x00,
+ 0x33,0x9e,0x00,0x00,0x34,0x9e,0x00,0x00,0x35,0x9e,0x00,0x00,0x99,0x00,0x00,0x00,
+ 0x9b,0x00,0x00,0x00,0xc1,0x00,0x00,0x00,0x9c,0x00,0x00,0x00,0x1c,0x02,0x00,0x00,
+ 0x18,0x02,0x00,0x00,0xa2,0xa0,0x00,0x00,0xd0,0x83,0x00,0x00,0x9e,0x00,0x00,0x00,
+ 0x80,0xff,0xff,0xff,0x9a,0x00,0x00,0x00,0x96,0x05,0xf1,0x11,0x62,0x03,0xf9,0x11,
+ 0x73,0x32,0x73,0x05,0x7e,0x7f,0x92,0x1c,0x0a,0xf0,0x7d,0x76,0x62,0x1c,0xc0,0x87,
+ 0xf1,0x11,0x72,0x03,0xf9,0x11,0x60,0x83,0x63,0x1c,0x78,0x7f,0x82,0x1c,0x2c,0x12,
+ 0x6c,0x01,0xd6,0x12,0x36,0x3c,0xd6,0x1c,0x77,0x77,0x76,0x1c,0x76,0xa7,0x86,0xa2,
+ 0x82,0x3c,0x72,0x1e,0x87,0x2c,0x27,0x0c,0x24,0xe8,0x10,0x83,0x32,0x0c,0x08,0xe0,
+ 0xc4,0x63,0x04,0x1c,0x04,0xa4,0x76,0xb4,0x05,0x64,0x05,0x1c,0x05,0xa5,0x86,0xb5,
+ 0xd7,0x12,0x37,0x3c,0xd7,0x1c,0x6b,0x76,0x67,0x1c,0x77,0xa6,0x87,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x10,0x86,0x67,0x05,0xa0,0x83,0x03,0xa3,0x80,0x93,0x20,0x82,0x32,0x05,
+ 0xf1,0x11,0x72,0x03,0xf9,0x11,0x83,0x32,0x63,0x05,0x60,0x7f,0x80,0x84,0x42,0x1c,
+ 0x3b,0xf0,0x70,0x85,0x25,0x0c,0x2d,0xe0,0x60,0x77,0xe7,0x1c,0x07,0xa7,0x73,0x32,
+ 0x35,0x1c,0x75,0x05,0x25,0x0d,0x08,0xe8,0x50,0x85,0x5c,0x74,0x45,0x1c,0x75,0x05,
+ 0x65,0x01,0x76,0xb5,0x85,0x3e,0x86,0xb5,0xd5,0x12,0x35,0x3c,0xd5,0x1c,0x55,0x76,
+ 0x65,0x1c,0x75,0xa6,0x85,0xa2,0x82,0x3c,0x62,0x1e,0x70,0x85,0x52,0x05,0x2e,0xa5,
+ 0x3e,0xa6,0x86,0x3c,0x56,0x1e,0xb0,0x83,0x03,0xa5,0x56,0x05,0x30,0x84,0x46,0x05,
+ 0xf1,0x11,0x62,0x03,0xf9,0x11,0x73,0x32,0x73,0x05,0x48,0x7f,0x30,0x85,0x52,0x1c,
+ 0x0b,0xf0,0x47,0x76,0x62,0x1c,0xd0,0x87,0xf1,0x11,0x72,0x03,0xf9,0x11,0x70,0x83,
+ 0x63,0x1c,0x42,0x7f,0x20,0x83,0x32,0x1c,0x62,0x01,0x90,0x84,0x04,0xa7,0x7c,0x0c,
+ 0x10,0xe8,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x41,0x76,0xe6,0x1c,0x06,0xa6,
+ 0x75,0x12,0x65,0x05,0x5c,0x0d,0x06,0xe0,0x07,0x24,0x67,0x05,0x7c,0x12,0x6c,0x01,
+ 0x01,0xf0,0x7c,0x12,0xa0,0x85,0x05,0xa7,0x72,0x0c,0x0f,0xe8,0x2e,0xa6,0x3e,0xa7,
+ 0x87,0x3c,0x67,0x1e,0xb0,0x83,0x03,0xa6,0x75,0x12,0x65,0x05,0x52,0x0d,0x06,0xe0,
+ 0x07,0x24,0x67,0x05,0x72,0x12,0x62,0x01,0x01,0xf0,0x72,0x12,0xe0,0x84,0x04,0xa7,
+ 0x07,0x2a,0xb7,0x12,0xb7,0x1c,0x86,0x2c,0x26,0x16,0x85,0x2c,0xc5,0x16,0xb7,0x1c,
+ 0x77,0x1c,0xa7,0x1c,0x07,0xe8,0x47,0xb6,0x82,0x3e,0x57,0xb2,0x67,0xb5,0x8c,0x3e,
+ 0x77,0xbc,0x06,0xf0,0x47,0xb5,0x8c,0x3e,0x57,0xbc,0x67,0xb6,0x82,0x3e,0x77,0xb2,
+ 0xb7,0x12,0xb7,0x1c,0xb7,0x1c,0x77,0x1c,0xa7,0x1c,0xd6,0x12,0x36,0x3c,0xd6,0x1c,
+ 0x1d,0x75,0x56,0x1c,0x96,0xa5,0xa6,0xa6,0x86,0x3c,0x56,0x1e,0x46,0x3e,0x87,0xb6,
+ 0x0d,0x20,0x4d,0x01,0x1c,0x77,0x1c,0x76,0x06,0xa6,0x6d,0x0c,0x74,0xee,0x05,0x60,
+ 0x1b,0x72,0x53,0x12,0x12,0xf0,0x56,0x12,0x36,0x3c,0x56,0x1c,0x76,0x1c,0x18,0x74,
+ 0x46,0x1c,0x06,0xa4,0x46,0x12,0x46,0x1c,0x46,0x1c,0x66,0x1c,0xa6,0x1c,0x96,0xa4,
+ 0x44,0x2a,0x01,0xe0,0x86,0xb3,0x05,0x20,0x45,0x01,0x02,0xa6,0x65,0x0c,0xeb,0xef,
+ 0x0e,0x73,0x03,0xa7,0x74,0x12,0x34,0x3c,0x74,0x1c,0x0c,0x72,0x04,0x20,0x0d,0x7f,
+ 0x01,0x65,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x00,0x00,0xd0,0x83,0x00,0x00,
+ 0x00,0xff,0xff,0xff,0xa2,0xa0,0x00,0x00,0xa0,0x00,0x00,0x00,0x80,0xff,0xff,0xff,
+ 0x9a,0x00,0x00,0x00,0x8a,0x9e,0x00,0x00,0xa5,0xa0,0x00,0x00,0x4a,0xa0,0x00,0x00,
+ 0xc1,0x01,0x00,0x00,0x8c,0x82,0x00,0x00,0x70,0x25,0x7a,0x00,0x86,0x7e,0x86,0x77,
+ 0x07,0xa7,0x07,0x2a,0x56,0xe8,0x0e,0xa7,0x1e,0xa5,0x85,0x3c,0x75,0x1e,0x1b,0x60,
+ 0x5b,0x0c,0x4f,0xe0,0x82,0x77,0x07,0xa7,0x82,0x76,0x06,0xaa,0x8a,0x3c,0x7a,0x1e,
+ 0x81,0x77,0x07,0x8d,0x67,0x67,0xd7,0x1c,0x07,0xa7,0x77,0x1c,0x7a,0x0d,0x48,0xe8,
+ 0x57,0x67,0xd7,0x1c,0x07,0xa7,0x7a,0x0c,0x0e,0xe8,0xba,0x0b,0x7b,0x7c,0x2c,0xba,
+ 0x7b,0x7f,0x0e,0xa6,0x1e,0xa7,0x87,0x3c,0x67,0x1e,0x7b,0x0c,0x39,0xe8,0x3c,0xbb,
+ 0x0c,0xba,0x1c,0xba,0x2e,0xf0,0x76,0x77,0x07,0xac,0x76,0x77,0x07,0xad,0x03,0x60,
+ 0xf2,0x67,0x36,0x12,0x5c,0x01,0x5d,0x01,0x16,0xf0,0x67,0x12,0x67,0x1c,0xe7,0x1c,
+ 0x27,0xa4,0x54,0x01,0xc4,0x05,0xe4,0x01,0x37,0xa7,0x57,0x01,0xd7,0x05,0xe7,0x01,
+ 0x47,0x1c,0x47,0x01,0x74,0x12,0x54,0x01,0x24,0x0d,0x27,0x0a,0x01,0xe8,0x63,0x12,
+ 0x06,0x20,0x46,0x01,0x72,0x12,0x56,0x0c,0x5f,0x77,0xe7,0xef,0x16,0x60,0x07,0xb6,
+ 0x06,0x60,0x17,0xb6,0x36,0x12,0x36,0x1c,0x76,0x1c,0x26,0xa5,0x27,0xb5,0x36,0xa6,
+ 0x37,0xb6,0x59,0x77,0x07,0xa6,0x60,0x77,0x07,0xb6,0x6a,0x00,0x70,0x21,0xcf,0x00,
+ 0x5a,0x77,0x66,0x67,0xd6,0x1c,0x06,0xa6,0x07,0xb6,0x56,0x67,0xd6,0x1c,0x06,0xa6,
+ 0x17,0xb6,0x46,0x67,0x6d,0x1c,0x0d,0xa6,0x27,0xb6,0x06,0x60,0x4f,0x77,0x07,0xb6,
+ 0xe8,0xf7,0xf0,0x25,0x78,0x00,0xf0,0x24,0x42,0x01,0x03,0x01,0x26,0x12,0x06,0x24,
+ 0x46,0x01,0x4c,0x77,0x07,0x87,0x0f,0x60,0x1a,0x12,0x0a,0x24,0x4a,0x01,0x4f,0x7b,
+ 0xac,0x61,0x6d,0x67,0x7d,0x1c,0x5e,0x67,0x7e,0x1c,0x43,0x67,0x73,0x1c,0x4c,0x75,
+ 0x75,0x1c,0x00,0x95,0x4c,0x75,0x75,0x1c,0x10,0x95,0x29,0xf0,0xa5,0x12,0x69,0x12,
+ 0xf1,0x11,0xc9,0x03,0xf9,0x11,0x20,0x96,0x1d,0xf0,0x97,0x12,0x57,0x1c,0x77,0x1c,
+ 0xb7,0x1c,0x07,0xc4,0x74,0x01,0x0d,0xa7,0x47,0x0d,0x12,0xe0,0x0e,0xa7,0x47,0x0d,
+ 0x0f,0xe0,0x03,0xa7,0x47,0x0d,0x0c,0xe0,0x00,0x86,0x06,0xa8,0x10,0x86,0x06,0xa7,
+ 0x87,0x3c,0x87,0x1e,0x07,0x3d,0x07,0x3b,0x74,0x0d,0x02,0xe8,0x0f,0x20,0x4f,0x01,
+ 0x05,0x20,0x45,0x01,0x51,0x0d,0xe1,0xef,0x20,0x86,0x06,0x20,0x46,0x01,0x62,0x0d,
+ 0xd5,0xef,0x27,0x60,0xf7,0x0c,0x22,0x00,0xf0,0x20,0x68,0x00,0xf0,0x21,0xcf,0x00,
+ 0xf0,0x24,0x7c,0x00,0x24,0x7c,0x30,0x77,0x07,0xa6,0x30,0x77,0x07,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x1e,0x60,0x07,0x2a,0x16,0xe8,0x0c,0xa7,0x1c,0xae,0x8e,0x3c,0x7e,0x1e,
+ 0x0d,0x60,0x0e,0x2a,0x0b,0xe0,0x0e,0xf0,0xd7,0x12,0xd7,0x1c,0xc7,0x1c,0x27,0xa2,
+ 0x37,0xa3,0x27,0x7f,0x02,0x2a,0x04,0xe0,0x0d,0x20,0x4d,0x01,0xed,0x0c,0xf4,0xef,
+ 0xed,0x0c,0x3e,0x00,0x24,0x77,0x07,0xa7,0x07,0x2a,0x23,0x77,0x0f,0xe8,0x06,0x60,
+ 0x0e,0x2a,0x02,0xe0,0x07,0xa6,0x06,0x20,0x07,0xb6,0x1f,0x77,0x07,0xa5,0xa6,0x60,
+ 0x56,0x0c,0x15,0xe0,0x06,0x60,0x1b,0x75,0x05,0xb6,0x10,0xf0,0x0e,0x2a,0x04,0xe8,
+ 0x07,0xa6,0x06,0x20,0x07,0xb6,0x01,0xf0,0x07,0xbe,0x17,0x77,0x07,0xa5,0xa6,0x60,
+ 0x56,0x0c,0x05,0xe0,0x15,0x60,0x13,0x76,0x06,0xb5,0x06,0x60,0x07,0xb6,0x6c,0x00,
+ 0xf0,0x20,0xcf,0x00,0x8a,0x9e,0x00,0x00,0x63,0xa4,0x00,0x00,0x3e,0xa4,0x00,0x00,
+ 0x3f,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00,0x86,0x9e,0x00,0x00,0x00,0x28,0x00,0x00,
+ 0x4f,0xa0,0x00,0x00,0x4d,0xa0,0x00,0x00,0x3d,0xaa,0x00,0x00,0x00,0xe0,0x02,0x00,
+ 0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x6a,0x9f,0x00,0x00,0x6b,0x9f,0x00,0x00,
+ 0xe2,0x4d,0x00,0x00,0x64,0xa4,0x00,0x00,0xda,0xa5,0x00,0x00,0xf0,0x25,0x78,0x00,
+ 0xa4,0x71,0x10,0x05,0xa4,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0xa3,0x77,0x00,0x97,
+ 0x34,0x60,0xa2,0x75,0xa3,0x76,0x07,0x60,0xa3,0x7f,0xa3,0x77,0xe7,0x1c,0x07,0xa7,
+ 0x07,0x2a,0x18,0xe8,0xa2,0x77,0x17,0xa6,0x07,0xa7,0x76,0x1c,0x07,0x60,0xa0,0x72,
+ 0xa1,0x73,0xa1,0x74,0x0d,0xf0,0x75,0x12,0x75,0x1c,0x2f,0x12,0x5f,0x1c,0x3d,0x12,
+ 0x5d,0x1c,0x45,0x1c,0x0d,0xcd,0x05,0xc5,0xd5,0x14,0x0f,0xd5,0x07,0x20,0x47,0x01,
+ 0x67,0x0d,0xf1,0xe7,0x9a,0x77,0x57,0xa7,0x17,0x2e,0x07,0x2a,0x07,0xe8,0x98,0x72,
+ 0x4e,0xa3,0x5e,0xa4,0x98,0x7f,0x98,0x72,0x83,0x61,0x98,0x7f,0x94,0x77,0x57,0xa7,
+ 0x47,0x2e,0x07,0x2a,0x09,0xe8,0x87,0x77,0x07,0x87,0x95,0x72,0x47,0xa3,0x57,0xa4,
+ 0x91,0x7f,0x94,0x72,0xa3,0x61,0x91,0x7f,0x8d,0x77,0x57,0xa7,0x27,0x2e,0x07,0x2a,
+ 0x0b,0xe8,0x91,0x72,0x8c,0x7f,0x7f,0x77,0x07,0x87,0x90,0x72,0x47,0xa3,0x57,0xa4,
+ 0x89,0x7f,0x8f,0x72,0xa3,0x61,0x89,0x7f,0x7b,0x77,0x07,0x8e,0xa7,0x67,0xe7,0x1c,
+ 0x07,0xa7,0x07,0x2a,0x06,0xe8,0x7d,0x77,0x07,0xa2,0x17,0xa3,0x89,0x74,0xa5,0x61,
+ 0x89,0x7f,0xd1,0x67,0x1e,0x1c,0x0e,0xa7,0x07,0x2a,0x49,0xe9,0x78,0x77,0x07,0xa3,
+ 0x86,0x72,0x02,0x1c,0x02,0x93,0x17,0xa5,0x85,0x74,0x04,0x1c,0x04,0x95,0x0e,0x60,
+ 0xed,0x12,0x6c,0x78,0x37,0xf1,0x08,0x87,0x26,0x65,0x67,0x1c,0x07,0xae,0xde,0x1c,
+ 0x4e,0x01,0x7d,0x77,0x07,0x1c,0x07,0x87,0x7e,0x0c,0x7e,0x02,0xd2,0x12,0x12,0x28,
+ 0xe2,0x1c,0x42,0x01,0x22,0x1c,0x33,0x60,0x7a,0x7f,0x7a,0x73,0x03,0x1c,0x03,0x92,
+ 0x0c,0x60,0xa9,0x61,0x14,0xf1,0x02,0x12,0x72,0x20,0x03,0x60,0x04,0x61,0x76,0x7f,
+ 0xd7,0x12,0x04,0x60,0x05,0x61,0x31,0xf0,0x76,0x12,0xf1,0x11,0x96,0x03,0xf9,0x11,
+ 0xc6,0x1c,0x66,0x1c,0x6b,0x71,0x16,0x1c,0x06,0xc6,0x76,0x01,0x70,0x72,0x62,0x0d,
+ 0x05,0xe8,0xc6,0x61,0x06,0x1c,0x76,0x1c,0x06,0xb5,0x12,0xf0,0x6d,0x73,0x36,0x0d,
+ 0x05,0xe8,0xc6,0x61,0x06,0x1c,0x76,0x1c,0x06,0xb4,0x0a,0xf0,0xc3,0x61,0x03,0x1c,
+ 0x73,0x1c,0xf6,0x37,0x02,0xe8,0xff,0x63,0xf6,0x1c,0x66,0x3a,0x76,0x20,0x03,0xb6,
+ 0xc6,0x61,0x06,0x1c,0x76,0x1c,0x06,0xa6,0x56,0x01,0x81,0x60,0x01,0x1c,0x16,0x1c,
+ 0x06,0xa3,0x03,0x20,0x06,0xb3,0x07,0x20,0x47,0x01,0xe7,0x0c,0xcd,0xef,0x07,0x60,
+ 0x75,0x12,0x76,0x12,0x07,0x01,0x84,0x60,0x04,0x1c,0x74,0x1c,0x04,0xa4,0x46,0x0c,
+ 0x15,0x0a,0x46,0x0a,0x07,0x20,0x07,0x2b,0xf5,0xe7,0x07,0x60,0x56,0x72,0x02,0x1c,
+ 0x02,0x97,0x76,0x12,0x07,0x01,0x84,0x60,0x04,0x1c,0x74,0x1c,0x04,0xa4,0x46,0x0c,
+ 0x06,0xe0,0x51,0x0f,0x04,0xe8,0x4f,0x73,0x03,0x1c,0x03,0x91,0x46,0x12,0x07,0x20,
+ 0x07,0x2b,0xf0,0xe7,0xd6,0x12,0x02,0x60,0x2b,0x12,0x16,0xf0,0xc7,0x61,0x07,0x1c,
+ 0x67,0x1c,0x07,0xa7,0x57,0x01,0x57,0x0f,0x0d,0xe0,0x67,0x12,0xf1,0x11,0x97,0x03,
+ 0xf9,0x11,0xc7,0x1c,0x77,0x1c,0x3a,0x74,0x47,0x1c,0x07,0xc7,0x77,0x01,0x72,0x1c,
+ 0x0b,0x20,0x4b,0x01,0x06,0x20,0x46,0x01,0xe6,0x0c,0xe8,0xef,0x0b,0x2a,0x04,0xe8,
+ 0xb3,0x12,0x37,0x7f,0x2a,0x12,0x01,0xf0,0xba,0x12,0x36,0x75,0x05,0x1c,0x05,0x85,
+ 0x5b,0x0d,0x2b,0xe8,0x08,0x87,0x66,0x67,0x67,0x1c,0x07,0xa7,0xa7,0x0d,0x1b,0xe0,
+ 0x24,0xf0,0xc7,0x61,0x07,0x1c,0x67,0x1c,0x07,0xa7,0x57,0x01,0x32,0x71,0x01,0x1c,
+ 0x01,0x81,0x17,0x0f,0x0d,0xe0,0x67,0x12,0xf1,0x11,0x97,0x03,0xf9,0x11,0xc7,0x1c,
+ 0x77,0x1c,0x23,0x74,0x47,0x1c,0x07,0xc7,0x77,0x01,0x72,0x1c,0x03,0x20,0x43,0x01,
+ 0x06,0x20,0x46,0x01,0x03,0xf0,0xd6,0x12,0x02,0x60,0x23,0x12,0xe6,0x0c,0xe1,0xef,
+ 0x03,0x2a,0x03,0xe8,0x1f,0x7f,0x2a,0x0d,0x2a,0x0a,0x08,0x87,0xe5,0x67,0x57,0x1c,
+ 0x07,0xa6,0xf1,0x11,0xa6,0x03,0xf9,0x11,0x46,0x3a,0xd5,0x12,0x02,0x60,0x53,0xf0,
+ 0xd0,0x00,0x00,0x00,0x1c,0x9e,0x00,0x00,0x36,0x00,0x05,0x1a,0x36,0x00,0x04,0x1a,
+ 0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,0xc8,0x00,0x00,0x00,0x20,0x9e,0x00,0x00,
+ 0xdc,0xa5,0x00,0x00,0x5e,0xa5,0x00,0x00,0xec,0xa4,0x00,0x00,0x44,0xaa,0x00,0x00,
+ 0x10,0x07,0x00,0x00,0x7a,0x25,0x00,0x00,0x00,0x80,0x02,0x00,0xc0,0x2b,0x00,0x00,
+ 0x24,0x07,0x00,0x00,0x36,0xc0,0x02,0x00,0x38,0x07,0x00,0x00,0x44,0x07,0x00,0x00,
+ 0x36,0xe0,0x02,0x00,0x48,0x2a,0x00,0x00,0xb0,0x00,0x00,0x00,0xb4,0x00,0x00,0x00,
+ 0x3e,0x84,0x00,0x00,0xbc,0x00,0x00,0x00,0x22,0x83,0x00,0x00,0xc0,0x01,0x00,0x00,
+ 0x40,0xfe,0xff,0xff,0xb8,0x00,0x00,0x00,0x57,0x12,0xf1,0x11,0x97,0x03,0xf9,0x11,
+ 0xc7,0x1c,0x77,0x1c,0xad,0x71,0x17,0x1c,0x07,0xc4,0x43,0x12,0x73,0x01,0xf3,0x37,
+ 0x02,0xe0,0x36,0x0d,0x01,0xf0,0x63,0x0d,0x03,0xe8,0x64,0x05,0x07,0xd4,0x01,0xf0,
+ 0x07,0xd2,0x05,0x20,0x45,0x01,0xe5,0x0c,0xe7,0xef,0x0c,0x20,0x4c,0x01,0xa3,0x72,
+ 0x02,0x1c,0x02,0x82,0x2c,0x0f,0xe7,0xe6,0x08,0x87,0x23,0x65,0x37,0x1c,0x07,0xa7,
+ 0x7d,0x1c,0x4d,0x01,0x9f,0x74,0x04,0x1c,0x04,0x84,0x4e,0x0c,0xc4,0xee,0x9d,0x77,
+ 0x57,0xa7,0x27,0x2e,0x07,0x2a,0x05,0xe8,0x9c,0x72,0x9c,0x7f,0x97,0x72,0xa3,0x61,
+ 0x9c,0x7f,0x9c,0x77,0x07,0x8e,0x4e,0xa2,0x5e,0xa3,0x57,0x67,0xe7,0x1c,0x07,0xa7,
+ 0x0d,0x60,0x00,0x9d,0xc4,0x60,0x98,0x75,0xd6,0x12,0x98,0x7f,0x99,0x7c,0x0c,0x87,
+ 0x99,0x76,0x06,0xb7,0x17,0x01,0x98,0x76,0x06,0xb1,0x27,0x01,0x98,0x76,0x06,0xb1,
+ 0x87,0x3f,0x97,0x76,0x06,0xb7,0x4e,0xa2,0x5e,0xa3,0x96,0x7b,0xeb,0x1c,0x0b,0xa6,
+ 0x96,0x7a,0xea,0x1c,0x0a,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x3d,0x00,0x9d,0xd4,0x60,
+ 0x8a,0x75,0xd6,0x12,0x07,0x3b,0x89,0x7f,0x0c,0x87,0x90,0x76,0x06,0xb7,0x17,0x01,
+ 0x90,0x76,0x06,0xb1,0x27,0x01,0x8f,0x76,0x06,0xb1,0x87,0x3f,0x8f,0x76,0x06,0xb7,
+ 0x4e,0xa2,0x5e,0xa3,0x47,0x67,0xe7,0x1c,0x07,0xa7,0x00,0x9d,0xa4,0x60,0x7e,0x75,
+ 0xd6,0x12,0x7e,0x7f,0x0c,0x87,0x89,0x75,0x05,0xb7,0x17,0x01,0x89,0x76,0x06,0xb1,
+ 0x27,0x01,0x88,0x78,0x08,0xb1,0x87,0x3f,0x88,0x71,0x01,0xb7,0x4e,0xa2,0x5e,0xa3,
+ 0x0b,0xa6,0x0a,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x3d,0x00,0x9d,0xb4,0x60,0x72,0x75,
+ 0xd6,0x12,0x07,0x3b,0x72,0x7f,0x0c,0x87,0xe7,0x01,0x80,0x7b,0x0b,0xb7,0x17,0x01,
+ 0x80,0x7a,0x0a,0xb1,0x27,0x01,0x7f,0x79,0x09,0xb1,0x87,0x3f,0x7f,0x78,0x08,0xb7,
+ 0x4e,0xa2,0x5e,0xa3,0x37,0x67,0xe7,0x1c,0x07,0xa7,0x00,0x9d,0xc4,0x60,0x66,0x75,
+ 0xd6,0x12,0x66,0x7f,0x0c,0x87,0x79,0x76,0x06,0xb7,0x17,0x01,0x79,0x76,0x06,0xb1,
+ 0x27,0x01,0x78,0x76,0x06,0xb1,0x87,0x3f,0x78,0x76,0x06,0xb7,0x6c,0x72,0x02,0xa6,
+ 0x6c,0x73,0x03,0xa7,0x87,0x3c,0x67,0x1e,0x6b,0x74,0x04,0xa6,0x06,0x3d,0x76,0x1e,
+ 0x6a,0x75,0x05,0xa7,0x87,0x3d,0x67,0x1e,0x71,0x76,0x06,0x86,0x76,0x05,0x70,0x73,
+ 0x36,0x0d,0x20,0xe0,0x70,0x74,0x64,0x0d,0x1d,0xe0,0x0b,0xa5,0x0a,0xa6,0x86,0x3c,
+ 0x56,0x1e,0x09,0xa5,0x05,0x3d,0x65,0x1e,0x08,0xa6,0x86,0x3d,0x56,0x1e,0x6a,0x75,
+ 0x05,0x85,0x65,0x05,0x35,0x0d,0x0e,0xe0,0x54,0x0d,0x0c,0xe0,0x68,0x76,0x06,0xa7,
+ 0x45,0x61,0x75,0x0c,0x04,0xe0,0x16,0x60,0x66,0x77,0x07,0xb6,0x1a,0xf0,0x07,0x20,
+ 0x06,0xb7,0x17,0xf0,0x06,0x60,0x61,0x75,0x05,0xb6,0x61,0x75,0x05,0xb6,0x5b,0x76,
+ 0x06,0x97,0x52,0x77,0x07,0xa6,0x52,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x51,0x76,
+ 0x06,0xa6,0x06,0x3d,0x76,0x1e,0x50,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x56,0x76,
+ 0x06,0x97,0x27,0x67,0xe7,0x1c,0x07,0xac,0x0c,0x2a,0x09,0xe0,0x56,0x77,0x07,0xa6,
+ 0x06,0x2a,0xd2,0xe8,0x15,0x60,0x54,0x76,0x36,0xb5,0x07,0xbc,0xcd,0xf0,0x1c,0x2a,
+ 0x09,0xe0,0x50,0x77,0x07,0xa6,0x26,0x2a,0xc7,0xe8,0x4f,0x76,0x36,0xbc,0x26,0x60,
+ 0x07,0xb6,0xc2,0xf0,0x2c,0x2a,0xc0,0xe0,0x4b,0x7b,0x0b,0xad,0x0d,0x2a,0x15,0xe0,
+ 0x4b,0x76,0x06,0xa7,0x27,0x2a,0x4a,0x77,0x0e,0xe0,0x36,0xa6,0x26,0x2a,0x0b,0xe8,
+ 0x07,0xc6,0x06,0x20,0x66,0x01,0x07,0xd6,0x55,0x60,0x65,0x0c,0xad,0xe0,0x07,0xdd,
+ 0x17,0x60,0x0b,0xb7,0xa9,0xf0,0x07,0xdd,0xa7,0xf0,0x1d,0x2a,0x94,0xe0,0x40,0x76,
+ 0x06,0xc7,0x07,0x20,0x67,0x01,0x06,0xd7,0x46,0x66,0x76,0x0c,0x85,0xe8,0x3d,0x77,
+ 0x06,0x60,0x97,0xb6,0x3d,0x76,0x07,0xb6,0x16,0x01,0x17,0xb1,0x26,0x01,0x27,0xb1,
+ 0x86,0x3f,0x37,0xb6,0x36,0x67,0x6e,0x1c,0x0e,0xa6,0x06,0x24,0x66,0x01,0xa7,0xb6,
+ 0x86,0x3e,0xb7,0xb6,0x36,0x7f,0x36,0x77,0x07,0xa6,0x17,0xa7,0x87,0x3c,0x67,0x1e,
+ 0x07,0x2a,0x34,0x77,0x6d,0xe0,0x07,0xc6,0x06,0x20,0x66,0x01,0x07,0xd6,0x57,0x60,
+ 0x67,0x0c,0x7a,0xe0,0x61,0xf0,0x00,0x00,0x36,0xe0,0x02,0x00,0xb4,0x00,0x00,0x00,
+ 0xb0,0x00,0x00,0x00,0x44,0xaa,0x00,0x00,0x58,0x07,0x00,0x00,0x7a,0x25,0x00,0x00,
+ 0xc0,0x2b,0x00,0x00,0x1c,0x9e,0x00,0x00,0x36,0x00,0x05,0x1a,0xb4,0x26,0x00,0x00,
+ 0x34,0x0a,0x04,0x00,0x46,0xa4,0x00,0x00,0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00,
+ 0x49,0xa4,0x00,0x00,0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x4a,0xa4,0x00,0x00,
+ 0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00,0x4d,0xa4,0x00,0x00,0x52,0xa4,0x00,0x00,
+ 0x53,0xa4,0x00,0x00,0x54,0xa4,0x00,0x00,0x55,0xa4,0x00,0x00,0x56,0xa4,0x00,0x00,
+ 0x57,0xa4,0x00,0x00,0x58,0xa4,0x00,0x00,0x59,0xa4,0x00,0x00,0x4e,0xa4,0x00,0x00,
+ 0x4f,0xa4,0x00,0x00,0x50,0xa4,0x00,0x00,0x51,0xa4,0x00,0x00,0x4c,0xa6,0x00,0x00,
+ 0x39,0xff,0xff,0xff,0xc7,0x00,0x00,0x00,0x50,0xa6,0x00,0x00,0x54,0xa6,0x00,0x00,
+ 0x72,0xa4,0x00,0x00,0x63,0xa4,0x00,0x00,0x86,0x9e,0x00,0x00,0x66,0x9e,0x00,0x00,
+ 0x56,0xa6,0x00,0x00,0x7a,0x9e,0x00,0x00,0x00,0xe0,0x02,0x00,0x88,0x27,0x00,0x00,
+ 0x00,0x08,0x03,0x00,0x58,0xa6,0x00,0x00,0xad,0x77,0x37,0xbd,0x0b,0xbc,0x14,0xf0,
+ 0x06,0x60,0x07,0xd6,0x11,0xf0,0x2d,0x2a,0x0f,0xe0,0xa9,0x77,0x07,0xa6,0x37,0xa7,
+ 0x27,0x2a,0x02,0xe8,0x26,0x2a,0x08,0xe8,0x07,0x60,0xa6,0x76,0x06,0xd7,0x15,0x60,
+ 0xa3,0x76,0x36,0xb5,0xa5,0x76,0x06,0xb7,0xa1,0x77,0x37,0xa6,0x06,0x2a,0x1a,0xe8,
+ 0x06,0x60,0x37,0xb6,0xa1,0x76,0x06,0xa6,0x26,0x2a,0xa0,0x76,0x06,0x86,0x06,0xe0,
+ 0x38,0x67,0x86,0x1c,0x06,0xa6,0x07,0xb6,0x17,0xb6,0x0b,0xf0,0x65,0x67,0x65,0x1c,
+ 0x05,0xa5,0x07,0xb5,0x55,0x67,0x65,0x1c,0x05,0xa5,0x17,0xb5,0x4d,0x67,0xd6,0x1c,
+ 0x06,0xa6,0x27,0xb6,0x97,0x77,0x07,0xa5,0x97,0x76,0x06,0xb5,0x97,0x71,0x15,0x16,
+ 0x07,0xb5,0x92,0x75,0x05,0x85,0x29,0x64,0x59,0x1c,0x09,0xa4,0x04,0x2a,0x8e,0xe8,
+ 0x06,0xa8,0x06,0x60,0x92,0x7a,0x8b,0x64,0x5b,0x1c,0x9c,0x64,0x5c,0x1c,0x90,0x73,
+ 0x53,0x1c,0x90,0x72,0x02,0x1c,0x02,0x93,0x90,0x74,0x7f,0x12,0x41,0xf0,0xa7,0x12,
+ 0x67,0x1c,0x07,0xa2,0x27,0x12,0x87,0x16,0x07,0x2a,0x02,0xe8,0x0c,0xad,0x01,0xf0,
+ 0x0b,0xad,0x8a,0x73,0x63,0x1c,0x23,0xa7,0x63,0xa3,0xae,0x61,0xf1,0x11,0xe7,0x03,
+ 0xf9,0x11,0x37,0x1c,0x77,0x1c,0x86,0x73,0x73,0x1c,0x03,0xce,0xe3,0x12,0x73,0x01,
+ 0x3d,0x0d,0x04,0xe8,0x0f,0xa7,0x72,0x1e,0x0f,0xb2,0x20,0xf0,0x82,0x72,0x62,0x1c,
+ 0x02,0xad,0x0d,0x20,0x4d,0x01,0x02,0xbd,0x51,0x60,0xd1,0x0c,0x17,0xe0,0x0d,0x60,
+ 0x02,0xbd,0x78,0x7d,0x0d,0x1c,0x0d,0x8d,0x0d,0xa2,0x32,0x0d,0x04,0xe8,0x47,0x1c,
+ 0x07,0xc3,0x32,0x14,0x07,0xf0,0x2d,0x12,0x0d,0x28,0x47,0x1c,0xd3,0x0d,0x07,0xc3,
+ 0x03,0xe8,0x32,0x1c,0x07,0xd2,0x02,0xf0,0x3e,0x14,0x07,0xde,0x06,0x20,0x46,0x01,
+ 0x09,0xa7,0x76,0x0c,0xbc,0xef,0x3f,0x64,0xf5,0x1c,0x05,0xa7,0x37,0x2a,0x6b,0x7e,
+ 0x0e,0xe0,0x2e,0xa6,0x65,0x12,0x65,0x1c,0x65,0x1c,0x57,0x12,0x47,0x3c,0x57,0x1c,
+ 0x67,0x1c,0x69,0x71,0x17,0x1e,0x00,0x97,0x12,0x60,0x83,0x61,0x22,0xf0,0x47,0x2a,
+ 0x06,0xe0,0x6e,0xa7,0x97,0x21,0x77,0x1c,0x64,0x72,0x27,0x1e,0x17,0xf0,0x2e,0xa6,
+ 0x65,0x12,0x65,0x1c,0x65,0x1c,0x57,0x12,0x47,0x3c,0x57,0x1c,0x67,0x1c,0x5e,0x73,
+ 0x37,0x1e,0x00,0x97,0x12,0x60,0x83,0x61,0x84,0x60,0x05,0x60,0x56,0x12,0x57,0x12,
+ 0x5b,0x7f,0x6e,0xa7,0x97,0x21,0x77,0x1c,0x58,0x74,0x47,0x1e,0x00,0x97,0x42,0x62,
+ 0x13,0x60,0x84,0x60,0x05,0x60,0x56,0x12,0x57,0x12,0x54,0x7f,0x55,0x7f,0x55,0x7f,
+ 0x56,0x7f,0x09,0x60,0x56,0x7d,0x4e,0x7b,0x10,0xf2,0x97,0x12,0x97,0x1c,0x54,0x75,
+ 0x57,0x1c,0x27,0xae,0x54,0x76,0x76,0xbe,0x37,0xac,0x86,0xbc,0x56,0xa8,0x52,0x77,
+ 0x07,0x1c,0x07,0x98,0x8d,0xb8,0x66,0xa2,0x43,0x71,0x01,0x1c,0x01,0x92,0x9d,0xb2,
+ 0x17,0x60,0xad,0xb7,0xbd,0xb7,0x07,0x60,0x0d,0xb7,0x1d,0xb7,0x2d,0xb7,0x3d,0xb7,
+ 0xa8,0x61,0xf1,0x11,0xe8,0x03,0xf9,0x11,0x87,0x12,0xc7,0x1c,0x77,0x1c,0xb7,0x1c,
+ 0x07,0xa6,0x4d,0xb6,0x17,0xa7,0x5d,0xb7,0x6d,0xbe,0x7d,0xbc,0xe2,0x12,0xc3,0x12,
+ 0x43,0x7f,0xca,0x12,0x05,0xf0,0x0a,0x20,0x4a,0x01,0xe2,0x12,0xa3,0x12,0x3f,0x7f,
+ 0x87,0x12,0xa7,0x1c,0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x3c,0x73,
+ 0x03,0xa5,0x3c,0x74,0x04,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x05,0xe0,0x29,0x75,
+ 0x05,0x1c,0x05,0x85,0xa5,0x0c,0xe7,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,
+ 0xd7,0x1c,0x46,0x65,0x67,0x1c,0x07,0xba,0xca,0x12,0xa8,0x61,0xf1,0x11,0xe8,0x03,
+ 0xf9,0x11,0x05,0xf0,0x0a,0x24,0x4a,0x01,0xe2,0x12,0xa3,0x12,0x2c,0x7f,0x87,0x12,
+ 0xa7,0x1c,0x07,0x24,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x29,0x77,0x07,0xa5,
+ 0x29,0x71,0x01,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x02,0xe0,0x0a,0x2a,0xea,0xe7,
+ 0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,0xd6,0x12,0x76,0x1c,0x05,0x63,0x65,0x1c,
+ 0x05,0xba,0xc6,0xbe,0x07,0x20,0x67,0x01,0x0d,0xb7,0x87,0x3e,0x1d,0xb7,0xc8,0x12,
+ 0xea,0x12,0x1d,0x72,0x02,0x1c,0x02,0x99,0xe9,0x12,0xbf,0xf0,0x86,0x9e,0x00,0x00,
+ 0x66,0x9e,0x00,0x00,0x56,0xa6,0x00,0x00,0x63,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0x2c,0xa4,0x00,0x00,0x2d,0xa4,0x00,0x00,0xf0,0xff,0xff,0xff,0x88,0x05,0x00,0x00,
+ 0xbb,0x00,0x00,0x00,0xb0,0x00,0x00,0x00,0x00,0xc0,0x02,0x00,0x20,0x9e,0x00,0x00,
+ 0x00,0xe0,0x02,0x00,0x5c,0xa6,0x00,0x00,0x00,0x00,0x05,0x1a,0xb4,0x26,0x00,0x00,
+ 0x00,0x28,0x00,0x00,0xf8,0x4c,0x00,0x00,0x80,0x4e,0x00,0x00,0x73,0xa4,0x00,0x00,
+ 0x8a,0x9e,0x00,0x00,0x7a,0x9e,0x00,0x00,0xb8,0x00,0x00,0x00,0xf8,0x3c,0x00,0x00,
+ 0x44,0xa4,0x00,0x00,0x45,0xa4,0x00,0x00,0xb4,0x00,0x00,0x00,0xa7,0x12,0x07,0x24,
+ 0xb7,0x73,0x03,0xa5,0xb7,0x74,0x04,0xa6,0x86,0x3c,0x56,0x1e,0xa5,0x61,0xf1,0x11,
+ 0x57,0x03,0xf9,0x11,0x87,0x1c,0x75,0x12,0x75,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01,
+ 0x65,0x0d,0x12,0xe8,0x75,0x12,0x05,0x24,0x55,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01,
+ 0x65,0x0d,0x98,0x00,0x08,0xe8,0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc7,0x77,0x01,
+ 0x67,0x0d,0xef,0xe0,0x08,0x20,0x48,0x01,0x0a,0x24,0x4a,0x01,0xa2,0x12,0x83,0x12,
+ 0xa5,0x7f,0x8e,0x12,0xa7,0x61,0xf1,0x11,0xa7,0x03,0xf9,0x11,0xa3,0x76,0x06,0x1c,
+ 0x06,0x97,0x05,0xf0,0x0e,0x20,0x4e,0x01,0xa2,0x12,0xe3,0x12,0x9e,0x7f,0x9e,0x71,
+ 0x01,0x1c,0x01,0x87,0xe7,0x1c,0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,
+ 0x97,0x72,0x02,0xa5,0x97,0x73,0x03,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x05,0xe0,
+ 0x97,0x74,0x04,0x1c,0x04,0x84,0xe4,0x0c,0xe5,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,
+ 0x67,0x1e,0xd7,0x1c,0x45,0x65,0x57,0x1c,0x07,0xbe,0x8e,0x12,0xa7,0x61,0xf1,0x11,
+ 0xa7,0x03,0xf9,0x11,0x8d,0x76,0x06,0x1c,0x06,0x97,0x05,0xf0,0x0e,0x24,0x4e,0x01,
+ 0xa2,0x12,0xe3,0x12,0x88,0x7f,0x88,0x71,0x01,0x1c,0x01,0x87,0xe7,0x1c,0x07,0x24,
+ 0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x81,0x72,0x02,0xa5,0x81,0x73,0x03,0xa7,
+ 0x87,0x3c,0x57,0x1e,0x76,0x0d,0x02,0xe0,0x0e,0x2a,0xe8,0xe7,0x0d,0xa6,0x1d,0xa7,
+ 0x87,0x3c,0x67,0x1e,0xd6,0x12,0x76,0x1c,0x05,0x63,0x65,0x1c,0x05,0xbe,0xc6,0xba,
+ 0x07,0x20,0x67,0x01,0x0d,0xb7,0x87,0x3e,0x1d,0xb7,0x0a,0x2a,0x77,0xe7,0x9e,0x12,
+ 0x78,0x74,0x04,0x1c,0x04,0x89,0x89,0xf0,0xe7,0x12,0x07,0x20,0x70,0x76,0x06,0xa5,
+ 0x08,0xa6,0x86,0x3c,0x56,0x1e,0xaf,0x61,0xf1,0x11,0xf7,0x03,0xf9,0x11,0xc7,0x1c,
+ 0x75,0x12,0x75,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01,0x65,0x0d,0x12,0xe8,0x75,0x12,
+ 0x05,0x24,0x55,0x1c,0xb5,0x1c,0x05,0xc5,0x75,0x01,0x65,0x0d,0x9c,0x00,0x08,0xe8,
+ 0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc7,0x77,0x01,0x67,0x0d,0x6c,0xe0,0x0c,0x20,
+ 0x4c,0x01,0x0e,0x20,0x4e,0x01,0xe2,0x12,0xc3,0x12,0x5e,0x7f,0xca,0x12,0xa2,0x61,
+ 0xf1,0x11,0xe2,0x03,0xf9,0x11,0x5e,0x71,0x01,0x1c,0x01,0x92,0x05,0xf0,0x0a,0x20,
+ 0x4a,0x01,0xe2,0x12,0xa3,0x12,0x57,0x7f,0x5a,0x73,0x03,0x1c,0x03,0x87,0xa7,0x1c,
+ 0x07,0x20,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,0x50,0x74,0x04,0xa5,0x08,0xa7,
+ 0x87,0x3c,0x57,0x1e,0x76,0x0d,0x05,0xe0,0x51,0x75,0x05,0x1c,0x05,0x85,0xa5,0x0c,
+ 0xe6,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,0xd7,0x1c,0x46,0x65,0x67,0x1c,
+ 0x07,0xba,0xca,0x12,0xaf,0x61,0xf1,0x11,0xef,0x03,0xf9,0x11,0x49,0x77,0x07,0x1c,
+ 0x07,0x9f,0x05,0xf0,0x0a,0x24,0x4a,0x01,0xe2,0x12,0xa3,0x12,0x42,0x7f,0x44,0x71,
+ 0x01,0x1c,0x01,0x87,0xa7,0x1c,0x07,0x24,0x77,0x1c,0xb7,0x1c,0x07,0xc6,0x76,0x01,
+ 0x3b,0x72,0x02,0xa5,0x08,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x0d,0x02,0xe0,0x0a,0x2a,
+ 0xe9,0xe7,0x0d,0xa6,0x1d,0xa7,0x87,0x3c,0x67,0x1e,0xd6,0x12,0x76,0x1c,0x05,0x63,
+ 0x65,0x1c,0x05,0xba,0xc6,0xbe,0x07,0x20,0x67,0x01,0x0d,0xb7,0x87,0x3e,0x1d,0xb7,
+ 0x05,0xf0,0x9e,0x12,0x33,0x73,0x03,0x1c,0x03,0x89,0x2d,0x78,0x32,0x74,0x04,0x1c,
+ 0x04,0x84,0xe4,0x0c,0x71,0xe7,0x8d,0xa2,0x97,0x12,0x37,0x3c,0x97,0x05,0x2e,0x75,
+ 0x57,0x1c,0xa6,0x62,0x76,0x1c,0x06,0xb2,0x9d,0xa4,0xb6,0x62,0x76,0x1c,0x06,0xb4,
+ 0xad,0xaf,0xc6,0x62,0x76,0x1c,0x06,0xbf,0xbd,0xa3,0xd6,0x62,0x76,0x1c,0x06,0xb3,
+ 0xe6,0x62,0x76,0x1c,0x2d,0xa5,0x06,0xb5,0x86,0x62,0x67,0x1c,0x4d,0xa5,0x5d,0xa6,
+ 0x86,0x3c,0x56,0x1e,0x77,0xb6,0x86,0x3e,0x87,0xb6,0xf7,0x12,0x27,0x05,0x57,0x01,
+ 0x17,0x22,0x05,0xe8,0x37,0x12,0x47,0x05,0x57,0x01,0x17,0x22,0x0c,0xe0,0x95,0x12,
+ 0x95,0x1c,0x19,0x77,0x75,0x1c,0xf6,0x12,0x26,0x1c,0x16,0x3a,0x25,0xb6,0x37,0x12,
+ 0x47,0x1c,0x17,0x3a,0x35,0xb7,0x09,0x20,0x49,0x01,0x13,0x7c,0x0c,0xa7,0x1c,0xae,
+ 0x8e,0x3c,0x7e,0x1e,0xe9,0x0c,0xe9,0xed,0x02,0x12,0x72,0x20,0x03,0x60,0x44,0x61,
+ 0x0f,0x7f,0x1f,0x60,0xef,0x0c,0x68,0xe0,0x0c,0xa7,0x1c,0xa4,0x84,0x3c,0x74,0x1e,
+ 0x05,0x60,0x0b,0x7b,0xad,0x61,0x2e,0x60,0x5d,0xf0,0x00,0x00,0x44,0xa4,0x00,0x00,
+ 0x45,0xa4,0x00,0x00,0xf8,0x3c,0x00,0x00,0xbc,0x00,0x00,0x00,0xb0,0x00,0x00,0x00,
+ 0xb4,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x8a,0x9e,0x00,0x00,0x22,0x83,0x00,0x00,
+ 0x00,0xe0,0x02,0x00,0x87,0x60,0x07,0x1c,0x57,0x1c,0x07,0xa7,0x07,0x2a,0x40,0xe0,
+ 0x56,0x12,0x56,0x1c,0xc6,0x1c,0x26,0xa7,0x36,0xaa,0x53,0x12,0x03,0x20,0x43,0x01,
+ 0x79,0x12,0x09,0x20,0xa6,0x12,0x56,0x01,0x57,0x01,0xf1,0x11,0xd7,0x03,0xf9,0x11,
+ 0x67,0x1c,0x77,0x1c,0xb7,0x1c,0x2a,0xf0,0x32,0x12,0x32,0x1c,0xc2,0x1c,0x22,0xa6,
+ 0x32,0xa8,0x92,0x12,0x62,0x05,0x42,0x01,0x2e,0x0c,0x1e,0xe8,0xa2,0x12,0x02,0x20,
+ 0x82,0x05,0x42,0x01,0x2e,0x0c,0x18,0xe8,0x58,0x01,0x56,0x01,0xf1,0x11,0xd6,0x03,
+ 0xf9,0x11,0x86,0x1c,0x66,0x1c,0xb6,0x1c,0x07,0xc2,0x72,0x01,0x06,0xc6,0x76,0x01,
+ 0x26,0x0d,0x05,0xe8,0x86,0x60,0x06,0x1c,0x36,0x1c,0x06,0xbf,0x05,0xf0,0x87,0x60,
+ 0x07,0x1c,0x57,0x1c,0x07,0xbf,0x04,0xf0,0x03,0x20,0x43,0x01,0x43,0x0c,0xd4,0xef,
+ 0x05,0x20,0x45,0x01,0x45,0x0c,0xb6,0xef,0x02,0x12,0x72,0x20,0xb0,0x73,0xb0,0x7f,
+ 0xb1,0x77,0x77,0xa7,0x07,0x2a,0x05,0xe8,0xb0,0x77,0x07,0x87,0x78,0x67,0x87,0x1c,
+ 0x11,0xf0,0xae,0x77,0x07,0xa7,0x07,0x2a,0x0c,0xe8,0xad,0x77,0x07,0xa7,0xad,0x76,
+ 0x06,0xae,0x8e,0x3c,0x7e,0x1e,0x2e,0x3e,0xac,0x77,0x17,0xa7,0x7e,0x0d,0x7e,0x02,
+ 0x02,0xf0,0xa9,0x77,0x07,0xae,0x02,0x12,0x72,0x20,0x03,0x60,0x44,0x61,0xa7,0x7f,
+ 0xa8,0x77,0x07,0xa7,0xa8,0x76,0x06,0xa5,0x85,0x3c,0x75,0x1e,0x06,0x60,0x9b,0x73,
+ 0x7e,0x01,0x14,0x60,0x12,0xf0,0x67,0x12,0x37,0x3c,0x67,0x05,0x37,0x1c,0x8d,0x62,
+ 0xd7,0x1c,0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,0xe7,0x0d,0x04,0xe8,0x87,0x60,
+ 0x07,0x1c,0x67,0x1c,0x07,0xb4,0x06,0x20,0x46,0x01,0x56,0x0c,0xec,0xef,0x98,0x7c,
+ 0x02,0x12,0x72,0x20,0xc3,0x12,0x8e,0x7f,0x90,0x77,0x07,0x87,0x97,0x71,0x01,0x1c,
+ 0x01,0x97,0xf2,0x67,0x27,0x1c,0x07,0xa7,0x07,0x2a,0xf1,0xe8,0x02,0x12,0x72,0x20,
+ 0x03,0x60,0x44,0x61,0x8e,0x7f,0x8e,0x67,0x0e,0x1c,0xe2,0x12,0x03,0x60,0x44,0x63,
+ 0x8b,0x7f,0x4d,0x64,0x0d,0x1c,0xd2,0x12,0x03,0x60,0x44,0x63,0x88,0x7f,0x0c,0xa7,
+ 0x89,0x76,0x06,0xa4,0x84,0x3c,0x74,0x1e,0x07,0x60,0x7c,0x7a,0xeb,0x12,0xdc,0x12,
+ 0x7c,0xf0,0x86,0x65,0x76,0x1c,0x66,0x1c,0xa6,0x1c,0x86,0xa9,0x96,0xa6,0x93,0x12,
+ 0x03,0x24,0x43,0x01,0x05,0x60,0x09,0x20,0x62,0x12,0x02,0x24,0x02,0x01,0x7f,0x78,
+ 0x08,0x1c,0x08,0x91,0x12,0x20,0x7e,0x71,0x01,0x1c,0x01,0x92,0x1d,0xf0,0x7b,0x78,
+ 0x08,0x1c,0x08,0x82,0xa8,0x61,0xf1,0x11,0x38,0x03,0xf9,0x11,0x0e,0xf0,0x8f,0x12,
+ 0x2f,0x1c,0xff,0x1c,0x78,0x71,0x1f,0x1c,0x0f,0xcf,0xf1,0x12,0x71,0x01,0x01,0x22,
+ 0x02,0xe0,0xf5,0x1c,0x65,0x01,0x02,0x20,0x42,0x01,0x71,0x71,0x01,0x1c,0x01,0x81,
+ 0x21,0x0d,0xed,0xef,0x03,0x20,0x43,0x01,0x39,0x0d,0xe1,0xef,0x73,0x12,0x73,0x1c,
+ 0xc2,0x61,0x02,0x1c,0x23,0x1c,0x03,0xd5,0x63,0x12,0x63,0x1c,0xb3,0x1c,0x03,0xc2,
+ 0x72,0x01,0x59,0x12,0x79,0x01,0x92,0x0d,0x01,0xe8,0x03,0xd5,0x62,0x12,0x02,0x24,
+ 0x23,0x12,0x23,0x1c,0xe3,0x1c,0x03,0xcf,0x7f,0x01,0x9f,0x0d,0x01,0xe8,0x03,0xd5,
+ 0x63,0x12,0x03,0x20,0x3f,0x12,0x3f,0x1c,0xbf,0x1c,0x0f,0xc8,0x78,0x01,0x98,0x0d,
+ 0x01,0xe8,0x0f,0xd5,0x75,0x12,0x35,0x3c,0x75,0x05,0xa5,0x1c,0x88,0x62,0x85,0x1c,
+ 0x75,0xaf,0x85,0xa5,0x85,0x3c,0xf5,0x1e,0x66,0x1c,0xc6,0x1c,0x06,0xcf,0x7f,0x01,
+ 0x5f,0x0d,0x01,0xe8,0x06,0xd5,0x26,0x12,0x26,0x1c,0xd6,0x1c,0x06,0xc2,0x72,0x01,
+ 0x52,0x0d,0x01,0xe8,0x06,0xd5,0x36,0x12,0x36,0x1c,0xc6,0x1c,0x06,0xc3,0x73,0x01,
+ 0x53,0x0d,0x01,0xe8,0x06,0xd5,0x07,0x20,0x47,0x01,0x47,0x0c,0x82,0xef,0x4a,0x77,
+ 0x17,0xac,0x0c,0x20,0x0d,0x60,0x44,0x71,0x01,0x1c,0x01,0x8b,0x72,0x32,0x2b,0x1c,
+ 0x10,0xf0,0xde,0x12,0xde,0x1c,0x83,0x67,0x03,0x1c,0x3e,0x1c,0x0e,0xc2,0x72,0x01,
+ 0x0b,0xa7,0xf1,0x11,0x72,0x03,0xf9,0x11,0x43,0x66,0x40,0x7f,0x0e,0xd2,0x0d,0x20,
+ 0x4d,0x01,0xdc,0x0d,0xee,0xef,0x36,0x77,0x07,0xa7,0x36,0x76,0x06,0xa5,0x85,0x3c,
+ 0x75,0x1e,0x07,0x60,0x2a,0x72,0x1f,0x60,0x2c,0xf0,0x86,0x65,0x76,0x1c,0x66,0x1c,
+ 0x26,0x1c,0x96,0xa4,0x76,0x12,0x36,0x3c,0x76,0x05,0x26,0x1c,0x88,0x62,0x86,0x1c,
+ 0x76,0xa3,0x86,0xa6,0x86,0x3c,0x36,0x1e,0x44,0x1c,0x43,0x64,0x03,0x1c,0x43,0x1c,
+ 0x03,0xc3,0x73,0x01,0x13,0x3a,0x63,0x0d,0x12,0xe0,0x76,0x12,0x76,0x1c,0xcd,0x61,
+ 0x0d,0x1c,0xd6,0x1c,0x81,0x67,0x01,0x1c,0x14,0x1c,0x06,0xc3,0x73,0x01,0x04,0xc6,
+ 0x76,0x01,0x63,0x0d,0x04,0xe8,0x86,0x60,0x06,0x1c,0x76,0x1c,0x06,0xbf,0x07,0x20,
+ 0x47,0x01,0x57,0x0c,0xd2,0xef,0x02,0x12,0x72,0x20,0x19,0x73,0x11,0x7f,0x20,0x7f,
+ 0x12,0x77,0x07,0x87,0x20,0x72,0x27,0x1c,0x07,0xa7,0x07,0x2a,0x57,0xe8,0x1e,0x77,
+ 0x37,0xa7,0x27,0x2a,0x53,0xe0,0x10,0x77,0x07,0xae,0xee,0x1c,0x02,0x12,0x72,0x20,
+ 0x03,0x60,0x44,0x61,0x0e,0x7f,0x0e,0x77,0x07,0xa7,0x0e,0x76,0x06,0xa5,0x85,0x3c,
+ 0x75,0x1e,0x06,0x60,0x02,0x73,0x7e,0x01,0x14,0x60,0x3a,0xf0,0x8a,0x9e,0x00,0x00,
+ 0x00,0x2d,0x00,0x00,0x20,0xaa,0x00,0x00,0x1c,0x9e,0x00,0x00,0x4a,0xa0,0x00,0x00,
+ 0x3e,0xa4,0x00,0x00,0x3f,0xa4,0x00,0x00,0x86,0x9e,0x00,0x00,0x22,0x83,0x00,0x00,
+ 0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00,0xb0,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,
+ 0xb4,0x00,0x00,0x00,0x00,0xe0,0x02,0x00,0x20,0x9e,0x00,0x00,0x3e,0x84,0x00,0x00,
+ 0x0e,0x46,0x00,0x00,0x86,0x00,0x00,0x00,0x66,0x9e,0x00,0x00,0x67,0x12,0x37,0x3c,
+ 0x67,0x05,0x37,0x1c,0x88,0x62,0x87,0x1c,0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,
+ 0xe7,0x0d,0x04,0xe8,0x87,0x60,0x07,0x1c,0x67,0x1c,0x07,0xb4,0x06,0x20,0x46,0x01,
+ 0x56,0x0c,0xec,0xef,0x02,0x12,0x72,0x20,0xbd,0x73,0xbd,0x7f,0xbc,0x77,0x07,0xa7,
+ 0xbd,0x76,0x06,0xaf,0xbd,0x7d,0x0d,0x1c,0x8f,0x3c,0x7f,0x1e,0x0d,0x9f,0x0d,0xa2,
+ 0xbb,0x71,0x01,0x1c,0x01,0x92,0xba,0x77,0x07,0xb2,0x0d,0x60,0x0b,0xf1,0xd7,0x12,
+ 0x37,0x3c,0xd7,0x05,0xb8,0x73,0x37,0x1c,0xc6,0x62,0x76,0x1c,0x06,0xa5,0xa6,0x62,
+ 0x76,0x1c,0x06,0xa4,0xd6,0x62,0x76,0x1c,0x06,0xa6,0xb8,0x62,0x87,0x1c,0x07,0xa7,
+ 0x53,0x12,0x43,0x05,0x43,0x01,0x1f,0x60,0x3f,0x0c,0x35,0xe8,0x63,0x12,0x73,0x05,
+ 0x43,0x01,0x3f,0x0c,0x30,0xe8,0x87,0x65,0xd7,0x1c,0x77,0x1c,0xaa,0x71,0x17,0x1c,
+ 0x87,0xa7,0xfc,0x12,0x22,0x60,0x72,0x0c,0x03,0xe0,0x7c,0x12,0x0c,0x24,0x4c,0x01,
+ 0xa6,0x73,0x03,0xaa,0xa6,0x12,0x06,0x24,0x67,0x0d,0x03,0xe8,0x07,0x20,0x7a,0x12,
+ 0x4a,0x01,0x87,0x65,0xd7,0x1c,0x77,0x1c,0x9f,0x74,0x47,0x1c,0x97,0xa7,0x16,0x60,
+ 0x9f,0x75,0x05,0x1c,0x05,0x96,0x28,0x60,0x78,0x0c,0x04,0xe0,0x76,0x12,0x06,0x24,
+ 0x06,0x01,0x05,0x91,0x99,0x72,0x12,0xa9,0x96,0x12,0x06,0x24,0x67,0x0d,0x26,0xe8,
+ 0x07,0x20,0x79,0x12,0x22,0xf0,0x1c,0x60,0x23,0x60,0x43,0x0c,0x03,0xe0,0x04,0x24,
+ 0x4c,0x12,0x4c,0x01,0x91,0x74,0x04,0xaa,0xa4,0x12,0x04,0x24,0x45,0x0d,0x03,0xe8,
+ 0x05,0x20,0x5a,0x12,0x4a,0x01,0x18,0x60,0x8d,0x75,0x05,0x1c,0x05,0x98,0x2f,0x60,
+ 0x7f,0x0c,0x03,0xe0,0x07,0x24,0x07,0x01,0x05,0x91,0x87,0x72,0x12,0xa9,0x97,0x12,
+ 0x07,0x24,0x76,0x0d,0x03,0xe8,0x06,0x20,0x69,0x12,0x49,0x01,0x08,0x60,0x84,0x73,
+ 0x03,0x1c,0x03,0x98,0x84,0x74,0x04,0x1c,0x04,0x98,0xdb,0x12,0x35,0xf0,0x82,0x75,
+ 0x05,0x1c,0x05,0x87,0xd7,0x1c,0x77,0x1c,0x81,0x76,0x67,0x1c,0x07,0xce,0x7e,0x01,
+ 0x0e,0x22,0x24,0xe0,0xb2,0x12,0xc3,0x12,0xd4,0x12,0x7d,0x7f,0x72,0x01,0x2e,0x1b,
+ 0x7e,0x01,0x2e,0x3a,0x7c,0x71,0x01,0x1c,0x01,0x87,0xf1,0x11,0xe7,0x03,0xf9,0x11,
+ 0x74,0x72,0x02,0x1c,0x02,0x83,0x73,0x1c,0x72,0x72,0x02,0x1c,0x02,0x93,0xd7,0x12,
+ 0x17,0x3c,0x07,0x24,0x67,0x01,0xf1,0x11,0xe7,0x03,0xf9,0x11,0x6e,0x74,0x04,0x1c,
+ 0x04,0x85,0x75,0x1c,0x6c,0x74,0x04,0x1c,0x04,0x95,0xe8,0x1c,0x0d,0x20,0x4d,0x01,
+ 0xd9,0x0c,0xcd,0xe7,0x0c,0x20,0x4c,0x01,0xca,0x0c,0x12,0xe8,0xc7,0x12,0x17,0x3c,
+ 0x07,0x24,0x67,0x01,0x68,0x76,0x06,0x1c,0x06,0x97,0x60,0x77,0x07,0x1c,0x07,0x8d,
+ 0xa2,0x61,0xf1,0x11,0xc2,0x03,0xf9,0x11,0x60,0x71,0x01,0x1c,0x01,0x92,0xe8,0xf7,
+ 0xbd,0x12,0xbe,0x12,0x3e,0x3c,0xbe,0x1c,0x57,0x73,0x3e,0x1c,0x5f,0x74,0x4e,0x1c,
+ 0x59,0x75,0x05,0x1c,0x05,0x82,0x72,0x3c,0x83,0x12,0x5c,0x7f,0x62,0x01,0x4e,0xb2,
+ 0x82,0x3e,0x5e,0xb2,0x53,0x76,0x06,0x1c,0x06,0x82,0x72,0x3c,0x83,0x12,0x57,0x7f,
+ 0x62,0x01,0x6e,0xb2,0x27,0x12,0x87,0x3e,0x7e,0xb7,0x55,0x78,0x08,0x87,0x55,0x71,
+ 0x17,0x1c,0x07,0xa7,0x27,0x2a,0x06,0xe0,0x54,0x73,0x32,0x1c,0x62,0x01,0x6e,0xb2,
+ 0x82,0x3e,0x7e,0xb2,0xd5,0x12,0x35,0x3c,0x56,0x12,0xd6,0x1c,0x42,0x74,0x46,0x1c,
+ 0x4f,0x77,0x67,0x1c,0x04,0x2c,0x07,0xb4,0x48,0x77,0x76,0x1c,0xd5,0x05,0x3d,0x78,
+ 0x85,0x1c,0x87,0x62,0x57,0x1c,0x77,0xa4,0x87,0xa7,0x87,0x3c,0x47,0x1e,0x86,0xb7,
+ 0x87,0x3e,0x96,0xb7,0xef,0x62,0xf5,0x1c,0x05,0xa7,0xa6,0xb7,0x07,0x60,0xb6,0xb7,
+ 0x0d,0x20,0x4d,0x01,0x31,0x71,0x01,0x1c,0x01,0x81,0x1d,0x0c,0xf0,0xee,0x40,0x77,
+ 0x57,0xa7,0x07,0x2f,0x07,0x2a,0x31,0xe8,0x2d,0x72,0x02,0x1c,0x02,0x82,0x02,0x2a,
+ 0x05,0xe8,0x3c,0x72,0x2a,0x74,0x04,0x1c,0x04,0x83,0x3b,0x7f,0x0e,0x60,0x29,0x7d,
+ 0x28,0x7c,0x1c,0xf0,0xe7,0x12,0x37,0x3c,0xe7,0x1c,0xd7,0x1c,0x2f,0x75,0x57,0x1c,
+ 0x47,0xab,0x57,0xa3,0x83,0x3c,0x67,0xaf,0x77,0xa4,0x84,0x3c,0x87,0xa6,0x97,0xa5,
+ 0x85,0x3c,0x65,0x1e,0x05,0x3d,0xa7,0xa6,0xb7,0xa7,0x87,0x3c,0x30,0x72,0xb3,0x1e,
+ 0xf4,0x1e,0x05,0x3b,0x76,0x1e,0x2c,0x7f,0x0e,0x20,0x4e,0x01,0x0c,0xa7,0x7e,0x0c,
+ 0xe1,0xef,0x07,0x2a,0x02,0xe8,0x2a,0x72,0x28,0x7f,0x21,0x77,0x07,0x87,0x29,0x76,
+ 0x67,0x1c,0x07,0xa7,0x07,0x2a,0xa2,0xe8,0x22,0x77,0x57,0xa7,0x77,0x36,0x10,0xe8,
+ 0x26,0x77,0x07,0xa7,0x26,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x25,0x77,0x07,0xa7,
+ 0x07,0x3d,0x67,0x1e,0x24,0x76,0x06,0xa3,0x83,0x3d,0x23,0x72,0x73,0x1e,0x1a,0x7f,
+ 0x14,0x77,0x07,0x87,0x1d,0x76,0x06,0xa6,0x1d,0x75,0x40,0xf0,0x40,0x9f,0x00,0x00,
+ 0x00,0x2d,0x00,0x00,0x41,0x9f,0x00,0x00,0xb0,0x00,0x00,0x00,0xb4,0x00,0x00,0x00,
+ 0x94,0x9f,0x00,0x00,0x8a,0x9e,0x00,0x00,0x20,0x9e,0x00,0x00,0xb8,0x00,0x00,0x00,
+ 0xbc,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0xe0,0x02,0x00,
+ 0xe0,0x3d,0x00,0x00,0xc4,0x00,0x00,0x00,0x08,0x01,0x00,0x00,0xd0,0x83,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0x20,0x01,0x00,0x00,0x80,0xff,0xff,0xff,0x0b,0x01,0x00,0x00,
+ 0x44,0xaa,0x00,0x00,0x68,0x07,0x00,0x00,0x7a,0x25,0x00,0x00,0x78,0x07,0x00,0x00,
+ 0x0c,0x07,0x00,0x00,0x8d,0x00,0x00,0x00,0x52,0xa4,0x00,0x00,0x53,0xa4,0x00,0x00,
+ 0x54,0xa4,0x00,0x00,0x55,0xa4,0x00,0x00,0x8c,0x07,0x00,0x00,0x05,0xa5,0x85,0x3c,
+ 0x65,0x1e,0xa6,0x76,0x06,0xa6,0x06,0x3d,0x56,0x1e,0xa5,0x75,0x05,0xa5,0x85,0x3d,
+ 0x65,0x1e,0xa4,0x76,0x76,0x1c,0x06,0xa4,0xa4,0x76,0x76,0x1c,0x06,0xa6,0x86,0x3c,
+ 0x46,0x1e,0xa2,0x74,0x74,0x1c,0x04,0xa4,0x04,0x3d,0x64,0x1e,0xa1,0x76,0x76,0x1c,
+ 0x06,0xa6,0x86,0x3d,0x46,0x1e,0x56,0x0c,0x9f,0x76,0x24,0xe8,0x07,0x60,0x06,0xb7,
+ 0x9e,0x76,0x0c,0xf0,0x9d,0x74,0x04,0xa5,0x05,0x20,0x45,0x01,0x04,0xb5,0x9b,0x78,
+ 0x87,0x1c,0x07,0xa7,0x27,0x3e,0x57,0x0c,0x02,0xe0,0x17,0x60,0x06,0xb7,0x95,0x77,
+ 0x07,0xa7,0x07,0x2a,0x97,0x77,0x02,0xe8,0xa6,0x60,0x04,0xf0,0x07,0xa6,0x06,0x2a,
+ 0x02,0xe8,0x06,0x24,0x07,0xb6,0x07,0xa7,0x07,0x2a,0x08,0xe8,0x16,0x60,0x91,0x77,
+ 0x07,0xb6,0x04,0xf0,0x06,0xa5,0x05,0x2a,0xdd,0xef,0xe9,0xf7,0x8f,0x71,0x10,0x1c,
+ 0x68,0x00,0xf0,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,0x01,0x64,0x10,0x05,0x8b,0x77,
+ 0x07,0xae,0x3c,0x60,0x0e,0x2a,0x03,0xe8,0xec,0x12,0x0c,0x24,0x4c,0x01,0x88,0x77,
+ 0x07,0xa5,0xa6,0x60,0x56,0x0c,0x01,0xe0,0x07,0xb6,0x0a,0x12,0x1a,0x21,0xa6,0x12,
+ 0x07,0x60,0x04,0x2c,0x75,0x12,0x06,0xd4,0x83,0x60,0x03,0x1c,0x73,0x1c,0x03,0xb5,
+ 0x07,0x20,0x16,0x20,0xa7,0x2a,0xf7,0xe7,0x6d,0x64,0xf1,0x11,0xde,0x03,0xf9,0x11,
+ 0x7d,0x72,0x7d,0x73,0xe3,0x1c,0xd4,0x12,0x7d,0x7f,0x7d,0x76,0xa6,0xa5,0xb6,0xa7,
+ 0x87,0x3c,0x57,0x1e,0x7c,0x71,0x71,0x1c,0x1f,0x12,0x7b,0x72,0x27,0x1c,0x7b,0x12,
+ 0x6b,0x01,0xc6,0xa5,0xd6,0xa7,0x87,0x3c,0x57,0x1e,0x76,0x72,0x72,0x1c,0x76,0x73,
+ 0x37,0x1c,0x79,0x12,0x69,0x01,0x05,0x60,0x75,0x73,0xf1,0x11,0xcd,0x03,0xf9,0x11,
+ 0xf8,0x67,0x57,0x12,0x37,0x1c,0x72,0x74,0x47,0x1c,0x07,0xa7,0x27,0x2a,0x45,0xe0,
+ 0x54,0x12,0x34,0x3c,0x54,0x05,0x47,0x12,0xe7,0x1c,0x37,0x1c,0x6e,0x76,0x67,0x1c,
+ 0x37,0xac,0x47,0xa6,0x86,0x3c,0xc6,0x1e,0x57,0xac,0x67,0xa7,0x87,0x3c,0xc7,0x1e,
+ 0x66,0x1c,0xd4,0x1c,0x34,0x1c,0x67,0x7c,0xc4,0x1c,0x34,0xa1,0x44,0xac,0x8c,0x3c,
+ 0x1c,0x1e,0xc6,0x05,0x66,0x01,0x77,0x1c,0x54,0xac,0x64,0xa4,0x84,0x3c,0xc4,0x1e,
+ 0x47,0x05,0x74,0x12,0x64,0x01,0x67,0x12,0x77,0x01,0x78,0x0d,0x03,0xe8,0xf7,0x0d,
+ 0x03,0xe8,0x03,0xf0,0x76,0x32,0x01,0xf0,0xb6,0x12,0x47,0x12,0x77,0x01,0x78,0x0d,
+ 0x03,0xe8,0x27,0x0d,0x03,0xe8,0x03,0xf0,0x74,0x32,0x01,0xf0,0x94,0x12,0x57,0x12,
+ 0x37,0x3c,0x57,0x05,0x37,0x1c,0x54,0x71,0x17,0x1c,0x66,0x01,0x57,0xb6,0x86,0x3e,
+ 0x67,0xb6,0x64,0x01,0x77,0xb4,0x84,0x3e,0x87,0xb4,0x05,0x20,0xa5,0x2a,0xb1,0xe7,
+ 0x0e,0x60,0x4a,0x78,0xa9,0x12,0x3f,0xf0,0xe7,0x12,0x37,0x3c,0xe7,0x1c,0x87,0x1c,
+ 0x4b,0x76,0x76,0x1c,0x46,0xa5,0x56,0xac,0x8c,0x3c,0x5c,0x1e,0x66,0xa5,0x76,0xab,
+ 0x8b,0x3c,0x5b,0x1e,0x3c,0x7a,0x0d,0x60,0x46,0x72,0x72,0x1c,0xb0,0x92,0x0d,0x01,
+ 0xa0,0x91,0x0a,0xa7,0x07,0x2a,0x21,0xe8,0xd7,0x12,0x37,0x3c,0xd7,0x05,0x87,0x1c,
+ 0x3e,0x72,0x27,0x1c,0x57,0xa6,0x67,0xa2,0x82,0x3c,0x62,0x1e,0xc2,0x14,0x77,0xa6,
+ 0x87,0xa3,0x83,0x3c,0x63,0x1e,0xb3,0x14,0x72,0x01,0x73,0x01,0x3a,0x7f,0xe7,0x12,
+ 0xe7,0x1c,0x23,0x61,0x03,0x1c,0x37,0x1c,0x07,0xc6,0x62,0x0c,0x06,0xe0,0x07,0xd2,
+ 0x84,0x62,0x04,0x1c,0x04,0xa5,0xb0,0x84,0x04,0xb5,0x0d,0x20,0x6a,0x20,0xad,0x2a,
+ 0xd6,0xe7,0x0e,0x20,0x4e,0x01,0x22,0x76,0x06,0xa2,0x2e,0x0c,0xbd,0xef,0x9a,0x12,
+ 0x2e,0x7d,0xd3,0x12,0x05,0x60,0x54,0x12,0x8b,0x2c,0x24,0x7e,0x0c,0x2c,0xe8,0x12,
+ 0x19,0x60,0x6a,0xf0,0x04,0x20,0x44,0x01,0x46,0x12,0x5a,0xf0,0x03,0xaf,0xbf,0x0f,
+ 0x59,0xe8,0x67,0x12,0x37,0x3c,0x67,0x1c,0xe7,0x1c,0x21,0x71,0x17,0x1c,0x07,0xa1,
+ 0xf1,0x0f,0x4c,0xe0,0x6f,0x12,0x6f,0x1c,0x21,0x61,0x01,0x1c,0x1f,0x1c,0x0a,0xc1,
+ 0x0f,0xcf,0x1f,0x0c,0x3b,0xe8,0x07,0xbc,0x41,0xf0,0x00,0x00,0x54,0xa4,0x00,0x00,
+ 0x55,0xa4,0x00,0x00,0x8e,0x00,0x00,0x00,0x8f,0x00,0x00,0x00,0x90,0x00,0x00,0x00,
+ 0x91,0x00,0x00,0x00,0x3c,0xa4,0x00,0x00,0x3d,0xa4,0x00,0x00,0xc6,0x00,0x00,0x00,
+ 0x60,0xa6,0x00,0x00,0x62,0xa4,0x00,0x00,0xd0,0x00,0x00,0x00,0xe5,0xa3,0x00,0x00,
+ 0x94,0x9f,0x00,0x00,0x46,0xa1,0x00,0x00,0x8c,0xa1,0x00,0x00,0x8c,0x82,0x00,0x00,
+ 0x20,0x9e,0x00,0x00,0x81,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0x8a,0x9e,0x00,0x00,
+ 0x8e,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0xb8,0x02,0x00,0x00,0x08,0x01,0x00,0x00,
+ 0x0b,0x01,0x00,0x00,0xc0,0x0c,0x00,0x00,0x95,0x9f,0x00,0x00,0x57,0x12,0x37,0x3c,
+ 0x57,0x1c,0x87,0x1c,0xbe,0x76,0x67,0x1c,0x07,0xbc,0x04,0xf0,0x06,0x20,0x46,0x01,
+ 0x26,0x0f,0xa4,0xe7,0x03,0xa7,0xb7,0x0f,0x04,0xe8,0x81,0x60,0x01,0x1c,0x17,0x1c,
+ 0x07,0xb9,0x05,0x20,0x83,0x20,0x1a,0x20,0x24,0x0f,0x94,0xe7,0xb5,0x77,0x07,0xac,
+ 0xb5,0x77,0x07,0xab,0xb5,0x74,0x05,0x60,0x56,0x12,0x8f,0x2c,0xb4,0x7e,0x12,0x60,
+ 0x24,0xf0,0x04,0xa7,0xf7,0x0f,0x1f,0xe0,0x57,0x12,0x37,0x3c,0x57,0x1c,0xe7,0x1c,
+ 0xb0,0x73,0x37,0x1c,0x87,0xa3,0x97,0xa7,0x87,0x3c,0x37,0x1e,0x07,0x3d,0x07,0x3b,
+ 0xb7,0x0d,0x11,0xe0,0x0e,0xf0,0x67,0x12,0x07,0x20,0x47,0x01,0x83,0x60,0x03,0x1c,
+ 0x63,0x1c,0x03,0xaa,0x0a,0x2a,0x04,0xe0,0x04,0xb6,0x03,0xb2,0x76,0x12,0x03,0xf0,
+ 0x76,0x12,0xc6,0x0c,0xf0,0xef,0x05,0x20,0x84,0x20,0x05,0x01,0xc1,0x0c,0xd9,0xef,
+ 0x0e,0x60,0xeb,0x12,0x8a,0x2c,0x9d,0x79,0x11,0xf0,0x0d,0xa7,0xa7,0x0f,0x0b,0xe8,
+ 0xe2,0x12,0x32,0x3c,0xe2,0x1c,0x92,0x1c,0x9b,0x74,0x42,0x1c,0xd3,0x12,0x94,0x60,
+ 0x9a,0x7f,0x0e,0x20,0x4e,0x01,0x0b,0x20,0x4b,0x01,0x8d,0x20,0xcb,0x0f,0xed,0xe7,
+ 0x97,0x77,0x07,0xbe,0x97,0x77,0x07,0xa8,0x97,0x76,0x06,0xb8,0x86,0x12,0x06,0x20,
+ 0x46,0x01,0x07,0xb6,0x35,0x60,0x65,0x0c,0x02,0xe0,0x06,0x60,0x07,0xb6,0x07,0xac,
+ 0x02,0x12,0x72,0x20,0x03,0x60,0xa4,0x60,0x90,0x7f,0x8c,0x77,0x07,0xab,0x8f,0x72,
+ 0x04,0x60,0x86,0x7d,0x63,0x64,0xf1,0x11,0xc3,0x03,0xf9,0x11,0x1e,0x60,0x2c,0xf0,
+ 0x02,0xaf,0xf7,0x12,0x37,0x3c,0xf7,0x05,0x37,0x1c,0xd7,0x1c,0x89,0x76,0x76,0x1c,
+ 0x06,0xbe,0x88,0x76,0x76,0x1c,0x47,0x12,0x37,0x3c,0x47,0x1c,0xd7,0x1c,0x86,0x79,
+ 0x97,0x1c,0x77,0xaa,0x87,0xa5,0x85,0x3c,0xa5,0x1e,0x36,0xb5,0x85,0x3e,0x46,0xb5,
+ 0x97,0xaa,0xa7,0xa5,0x85,0x3c,0xa5,0x1e,0x56,0xb5,0x85,0x3e,0x66,0xb5,0xb7,0xa5,
+ 0xc7,0xa7,0x87,0x3c,0x57,0x1e,0x76,0xb7,0x87,0x3e,0x86,0xb7,0x81,0x60,0x01,0x1c,
+ 0x1f,0x1c,0x0f,0xbe,0x04,0x20,0x82,0x20,0x04,0x01,0xb1,0x0c,0xd1,0xef,0x04,0x60,
+ 0x46,0x12,0x65,0x64,0xf1,0x11,0xc5,0x03,0xf9,0x11,0x68,0x7d,0x5f,0x12,0xdf,0x1c,
+ 0x0e,0x2c,0xf2,0x67,0x87,0x60,0x07,0x1c,0x67,0x1c,0x07,0xa3,0x03,0x2a,0x12,0xe0,
+ 0xf7,0x12,0x47,0x1c,0x6b,0x79,0x97,0x1c,0x07,0xb3,0x67,0x12,0x37,0x3c,0x67,0x05,
+ 0x57,0x1c,0xd7,0x1c,0x68,0x7b,0xb7,0x1c,0x37,0xbe,0x47,0xb2,0x57,0xbe,0x67,0xb2,
+ 0x77,0xb3,0x87,0xb3,0x06,0x20,0x64,0x20,0xa6,0x2a,0xe4,0xe7,0xcd,0x12,0x4d,0x3c,
+ 0xc7,0x12,0x67,0x3c,0x7d,0x1c,0x55,0x79,0x9d,0x1c,0x60,0x71,0x1d,0x1c,0x0b,0x60,
+ 0xba,0x12,0x62,0x64,0xf1,0x11,0xc2,0x03,0xf9,0x11,0xa0,0x92,0x92,0x1c,0xb0,0x92,
+ 0x63,0x64,0xf1,0x11,0x38,0x03,0xf9,0x11,0x94,0x12,0x84,0x1c,0xc0,0x94,0xb0,0x87,
+ 0xb7,0x1c,0x53,0x75,0x57,0x1c,0x07,0xa7,0x07,0x2a,0x52,0xe8,0xc0,0x87,0xb7,0x1c,
+ 0x57,0x1c,0x07,0xa7,0x07,0x2a,0x4c,0xe8,0x17,0x60,0x0d,0xb7,0xce,0x12,0xce,0x1c,
+ 0xc7,0x12,0x37,0x3c,0x7e,0x1c,0xae,0x1c,0x4e,0x76,0x6e,0x1c,0x3e,0x3c,0x9e,0x1c,
+ 0xa7,0x12,0x37,0x3c,0xa7,0x05,0xa0,0x86,0x76,0x1c,0x96,0x1c,0x46,0x71,0x16,0x1c,
+ 0x36,0xa4,0x46,0xa5,0x85,0x3c,0x45,0x1e,0x87,0x1c,0x97,0x1c,0x17,0x1c,0x37,0xa3,
+ 0x47,0xa4,0x84,0x3c,0x34,0x1e,0x45,0x05,0x65,0x01,0x3e,0xb5,0x85,0x3e,0x4e,0xb5,
+ 0x56,0xa5,0x66,0xa3,0x83,0x3c,0x53,0x1e,0x57,0xa6,0x67,0xa7,0x87,0x3c,0x67,0x1e,
+ 0x73,0x05,0x63,0x01,0x5e,0xb3,0x37,0x12,0x87,0x3e,0x6e,0xb7,0x3e,0xa7,0x4e,0xa2,
+ 0x82,0x3c,0x72,0x1e,0x02,0x3d,0x02,0x3b,0x73,0x01,0x36,0x7f,0x7e,0xb2,0x82,0x3e,
+ 0x8e,0xb2,0x3e,0xa7,0x4e,0xa2,0x82,0x3c,0x72,0x1e,0x02,0x3d,0x5e,0xa7,0x6e,0xa3,
+ 0x83,0x3c,0x73,0x1e,0x03,0x3d,0x02,0x3b,0x03,0x3b,0x2f,0x7f,0x7d,0xb2,0x12,0xf0,
+ 0x06,0x60,0x0d,0xb6,0xc7,0x12,0xc7,0x1c,0xc5,0x12,0x35,0x3c,0x57,0x1c,0xa7,0x1c,
+ 0x28,0x72,0x27,0x1c,0x37,0x3c,0x97,0x1c,0x37,0xb6,0x47,0xb6,0x57,0xb6,0x67,0xb6,
+ 0x77,0xb6,0x87,0xb6,0x0a,0x20,0x6b,0x20,0x7d,0x20,0x63,0x64,0x3b,0x0f,0x8f,0xe7,
+ 0x18,0x77,0x07,0xae,0x22,0x77,0x07,0x8c,0x22,0x78,0xa0,0x98,0x22,0x76,0x87,0x12,
+ 0x05,0x60,0x0e,0x73,0x29,0x60,0x6f,0x64,0xe4,0x12,0xf1,0x11,0xf4,0x03,0xf9,0x11,
+ 0x43,0x1c,0x1d,0x7a,0xca,0x1c,0x4b,0x60,0x54,0x12,0x1c,0x71,0x1c,0x1c,0x1d,0x60,
+ 0x07,0xa2,0x42,0x2a,0x35,0xe0,0x07,0xb4,0x56,0xf0,0x00,0x00,0x0b,0x01,0x00,0x00,
+ 0x94,0x9f,0x00,0x00,0x86,0x9e,0x00,0x00,0x95,0x9f,0x00,0x00,0x8a,0x9e,0x00,0x00,
+ 0x08,0x01,0x00,0x00,0x66,0x01,0x00,0x00,0x8c,0x82,0x00,0x00,0xef,0x9f,0x00,0x00,
+ 0xe5,0xa3,0x00,0x00,0xe4,0xa3,0x00,0x00,0xc4,0x09,0x00,0x00,0xf0,0x9f,0x00,0x00,
+ 0x02,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x60,0x01,0x00,0x00,0x1a,0x04,0x00,0x00,
+ 0x83,0x00,0x00,0x00,0xc0,0x0c,0x00,0x00,0xee,0x0b,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0xfa,0xa3,0x00,0x00,0x0e,0xa4,0x00,0x00,0xa1,0x00,0x00,0x00,0xa2,0x00,0x00,0x00,
+ 0x02,0x2a,0x19,0xe0,0x32,0x12,0x52,0x1c,0xb8,0x78,0x82,0x1c,0x02,0xa2,0x02,0x2a,
+ 0x0e,0xe8,0x06,0xa2,0x02,0x2a,0x03,0xe0,0x78,0x12,0x98,0x24,0x08,0xbe,0x02,0x20,
+ 0x42,0x01,0x06,0xb2,0x0c,0xa8,0x28,0x0c,0x19,0xe0,0x07,0xbd,0x17,0xf0,0x07,0xb2,
+ 0x06,0xb2,0xa7,0xb2,0x13,0xf0,0x07,0xb9,0x32,0x12,0x52,0x1c,0xab,0x71,0x12,0x1c,
+ 0x02,0xa2,0x02,0x2a,0x03,0xe8,0x06,0xb4,0xa7,0xb4,0x08,0xf0,0xa7,0xa2,0x02,0x20,
+ 0x42,0x01,0xa7,0xb2,0x0a,0xa8,0x28,0x0c,0x01,0xe0,0x07,0xbb,0x07,0x20,0x06,0x20,
+ 0x65,0x20,0xf5,0x0f,0x95,0xe7,0xa1,0x76,0x06,0x87,0xa2,0x64,0x27,0x1c,0x07,0xac,
+ 0x0e,0x60,0x9f,0x7b,0x87,0xf0,0xb7,0x12,0xe7,0x1c,0x9e,0x73,0x37,0x1c,0x07,0xa7,
+ 0x07,0x2a,0x05,0xe8,0x0e,0x20,0x4e,0x01,0x6e,0x0c,0xf5,0xef,0x7b,0xf0,0x26,0x60,
+ 0x98,0x7d,0xb7,0x12,0xc7,0x1c,0x97,0x74,0x47,0x1c,0x07,0xa5,0x05,0x24,0x45,0x01,
+ 0x56,0x0c,0x6c,0xe8,0xd6,0x12,0xe6,0x1c,0x46,0x1c,0x15,0x60,0x06,0xb5,0x46,0x60,
+ 0x07,0xb6,0xe8,0x12,0x38,0x3c,0xb0,0x98,0x82,0x12,0xe2,0x05,0xd2,0x1c,0xc8,0x12,
+ 0x38,0x3c,0x89,0x12,0xc9,0x05,0xd3,0x12,0x93,0x1c,0x8b,0x71,0x12,0x1c,0x13,0x1c,
+ 0x74,0x60,0x8a,0x7f,0x9d,0x1c,0x84,0x72,0x2d,0x1c,0x0a,0x60,0xc0,0x98,0x09,0x28,
+ 0xd0,0x99,0xb0,0x89,0xb8,0x12,0x98,0x1c,0xb0,0x98,0xd0,0x82,0xd2,0x1c,0x97,0x12,
+ 0xe7,0x05,0x72,0x1c,0xd3,0x12,0x74,0x60,0x81,0x7f,0x7d,0x78,0xb0,0x82,0xa2,0x1c,
+ 0xc0,0x83,0xb3,0x1c,0xa3,0x1c,0x7e,0x71,0x12,0x1c,0x13,0x1c,0x84,0x60,0x7b,0x7f,
+ 0x07,0x60,0x0d,0xb7,0x62,0x64,0x2d,0x1c,0x03,0x65,0x3a,0x1c,0x7a,0x74,0x4a,0x0f,
+ 0xe4,0xe7,0x87,0x12,0xc7,0x1c,0x78,0x76,0x76,0x1c,0x06,0xa5,0xe8,0x1c,0x76,0x76,
+ 0x86,0x1c,0x06,0xb5,0x76,0x76,0x76,0x1c,0x06,0xa5,0x74,0x76,0x86,0x1c,0x06,0xb5,
+ 0x74,0x76,0x76,0x1c,0x06,0xa5,0x72,0x76,0x86,0x1c,0x06,0xb5,0x72,0x76,0x76,0x1c,
+ 0x06,0xa5,0x70,0x76,0x86,0x1c,0x06,0xb5,0x70,0x76,0x76,0x1c,0x06,0xa5,0x6e,0x76,
+ 0x86,0x1c,0x06,0xb5,0x6e,0x76,0x76,0x1c,0x06,0xa5,0x6c,0x76,0x86,0x1c,0x06,0xb5,
+ 0x6c,0x75,0x57,0x1c,0x07,0xa7,0x58,0x1c,0x08,0xb7,0x04,0xf0,0x0c,0x20,0x4c,0x01,
+ 0xac,0x2a,0x86,0xe7,0x5a,0x76,0x06,0x87,0xa8,0x64,0x87,0x1c,0x07,0xa6,0x6e,0x0c,
+ 0x03,0xe0,0x97,0x60,0xc7,0x0c,0x6f,0xe7,0x56,0x76,0x62,0x77,0x07,0xa3,0x62,0x77,
+ 0x07,0xa7,0x69,0x64,0x71,0x12,0xf1,0x11,0x91,0x03,0xf9,0x11,0x62,0x12,0x12,0x1c,
+ 0x4e,0x7b,0xb2,0x1c,0x7a,0x12,0x4a,0x3c,0x75,0x12,0x65,0x3c,0x5a,0x1c,0xa6,0x1c,
+ 0x50,0x7c,0xc6,0x1c,0x05,0x60,0xf1,0x11,0x39,0x03,0xf9,0x11,0x0a,0x28,0x3d,0x12,
+ 0x4d,0x3c,0x34,0x12,0x64,0x3c,0x4d,0x1c,0x46,0x7e,0x54,0x12,0xe4,0x1c,0x45,0x78,
+ 0x84,0x1c,0x04,0xa4,0x14,0x24,0x44,0x01,0x1b,0x60,0x4b,0x0c,0x5c,0xe8,0x02,0xa4,
+ 0x04,0x2a,0x59,0xe0,0x24,0x60,0x02,0xb4,0x5c,0x12,0x3c,0x3c,0x5c,0x05,0xc4,0x12,
+ 0x94,0x1c,0xe4,0x1c,0x4a,0x78,0x84,0x1c,0x34,0xa8,0x44,0xaf,0x8f,0x3c,0x8f,0x1e,
+ 0x1c,0x1c,0xec,0x1c,0x46,0x78,0x8c,0x1c,0x3c,0xbf,0x8f,0x3e,0x4c,0xbf,0x54,0xaf,
+ 0x64,0xa4,0x84,0x3c,0xf4,0x1e,0x5c,0xb4,0x84,0x3e,0x6c,0xb4,0x04,0x67,0x7c,0xb4,
+ 0x34,0x60,0x8c,0xb4,0x34,0x12,0x34,0x1c,0x3f,0x12,0x3f,0x3c,0xf4,0x1c,0x54,0x1c,
+ 0x3c,0x7c,0xc4,0x1c,0x34,0x3c,0xe4,0x1c,0x74,0xac,0x84,0xaf,0x8f,0x3c,0xcf,0x1e,
+ 0xfc,0x63,0x06,0xbb,0xfc,0x0c,0x34,0xaf,0x44,0xac,0x8c,0x3c,0xfc,0x1e,0x7f,0x12,
+ 0x7f,0x1c,0x7b,0x12,0x3b,0x3c,0xbf,0x1c,0x5f,0x1c,0x03,0xe8,0x31,0x78,0x8f,0x1c,
+ 0x02,0xf0,0x2f,0x7b,0xbf,0x1c,0x3f,0x3c,0xef,0x1c,0x3f,0xbc,0x8c,0x3e,0x4f,0xbc,
+ 0x54,0xac,0x64,0xae,0x8e,0x3c,0xce,0x1e,0x5f,0xbe,0x8e,0x3e,0x6f,0xbe,0x74,0xae,
+ 0x84,0xa4,0x84,0x3c,0xe4,0x1e,0x7f,0xb4,0x84,0x3e,0x8f,0xb4,0xa4,0x12,0x64,0x1c,
+ 0xd4,0x1c,0x74,0xa4,0x76,0xb4,0x05,0x20,0x62,0x20,0x76,0x20,0xa5,0x2a,0x94,0xe7,
+ 0x04,0x60,0x0f,0x7e,0x6c,0x64,0x7a,0x12,0xf1,0x11,0xca,0x03,0xf9,0x11,0x42,0x12,
+ 0x3b,0x60,0x46,0x12,0xe6,0x1c,0x0b,0x75,0x65,0x1c,0x05,0xa5,0x15,0x2a,0x5f,0xe0,
+ 0x0f,0x71,0x16,0x1c,0x06,0xa5,0x4d,0x12,0x3d,0x3c,0x4d,0x05,0xd3,0x12,0xa3,0x1c,
+ 0xe3,0x1c,0x12,0x76,0x63,0x1c,0x51,0xf0,0x02,0x03,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0x8a,0x9e,0x00,0x00,0x70,0x05,0x00,0x00,0x76,0x02,0x00,0x00,0x8c,0x82,0x00,0x00,
+ 0x1a,0x04,0x00,0x00,0x40,0x01,0x00,0x00,0x5c,0x05,0x00,0x00,0x66,0x05,0x00,0x00,
+ 0x7a,0x05,0x00,0x00,0x84,0x05,0x00,0x00,0x8e,0x05,0x00,0x00,0x98,0x05,0x00,0x00,
+ 0xa7,0x05,0x00,0x00,0xe4,0xa3,0x00,0x00,0xe5,0xa3,0x00,0x00,0x00,0x03,0x00,0x00,
+ 0x83,0x00,0x00,0x00,0x33,0xa6,0x43,0xaf,0x8f,0x3c,0x6f,0x1e,0x56,0x12,0xf1,0x11,
+ 0xc6,0x03,0xf9,0x11,0xd6,0x1c,0xe6,0x1c,0xc0,0x78,0x86,0x1c,0x36,0xbf,0x8f,0x3e,
+ 0x46,0xbf,0x53,0xa9,0x63,0xaf,0x8f,0x3c,0x9f,0x1e,0x56,0xbf,0x8f,0x3e,0x66,0xbf,
+ 0x56,0x12,0x56,0x1c,0x5f,0x12,0x3f,0x3c,0xf6,0x1c,0x46,0x1c,0xb8,0x79,0x96,0x1c,
+ 0x36,0x3c,0xe6,0x1c,0x36,0xb2,0x46,0xb2,0x56,0xb2,0x66,0xb2,0x76,0xb2,0x86,0xb2,
+ 0x96,0xb2,0x05,0x20,0x45,0x01,0x5b,0x0c,0xd5,0x01,0x75,0x0f,0xd3,0xe7,0x04,0x20,
+ 0xa4,0x2a,0x97,0xe7,0xaf,0x75,0x06,0x60,0x64,0x12,0x2b,0x60,0xae,0x7e,0x3c,0x60,
+ 0x6d,0x12,0x6f,0x64,0xf1,0x11,0x7f,0x03,0xf9,0x11,0x06,0x01,0x57,0x12,0x37,0x21,
+ 0x07,0xa7,0x73,0x12,0x03,0x24,0x43,0x01,0x3b,0x0c,0x3b,0xe8,0x17,0x2a,0x43,0x12,
+ 0x33,0x3c,0x43,0x1c,0xe3,0x1c,0xa4,0x77,0x37,0x1c,0x07,0xb1,0x0a,0xe0,0xa3,0x71,
+ 0x13,0x1c,0x67,0x12,0x37,0x3c,0x67,0x05,0xf7,0x1c,0xe7,0x1c,0x9b,0x72,0x27,0x1c,
+ 0x09,0xf0,0x9e,0x77,0x73,0x1c,0x67,0x12,0x37,0x3c,0x67,0x05,0xf7,0x1c,0xe7,0x1c,
+ 0x96,0x78,0x87,0x1c,0x37,0xaa,0x47,0xa2,0x82,0x3c,0xa2,0x1e,0x53,0xb2,0x82,0x3e,
+ 0x63,0xb2,0x57,0xaa,0x67,0xa2,0x82,0x3c,0xa2,0x1e,0x73,0xb2,0x82,0x3e,0x83,0xb2,
+ 0x77,0xa2,0x87,0xa7,0x87,0x3c,0x27,0x1e,0x93,0xb7,0x87,0x3e,0xa3,0xb7,0xa5,0xa7,
+ 0x05,0xb7,0x07,0x20,0x47,0x01,0xa5,0xb7,0x7c,0x0c,0x01,0xe0,0xa5,0xbd,0x04,0x20,
+ 0x44,0x01,0x06,0x20,0x05,0x20,0xa6,0x2a,0xb8,0xe7,0x89,0x77,0x07,0xb4,0x89,0x7d,
+ 0x0e,0x60,0x84,0x7c,0x6b,0x64,0xe7,0x12,0xc7,0x1c,0x87,0x76,0x76,0x1c,0x06,0xa6,
+ 0x16,0x2a,0x10,0xe0,0x86,0x79,0x97,0x1c,0x07,0xa7,0xe3,0x12,0x33,0x3c,0xe3,0x05,
+ 0xf1,0x11,0xb7,0x03,0xf9,0x11,0x73,0x1c,0xc3,0x1c,0xd2,0x12,0x81,0x71,0x13,0x1c,
+ 0x74,0x60,0x80,0x7f,0x0e,0x20,0x6d,0x20,0xae,0x2a,0xe5,0xe7,0x7f,0x7e,0x0d,0x60,
+ 0x19,0x60,0xd8,0x12,0x74,0x7c,0x7d,0x7b,0xe7,0x12,0xd7,0x25,0x07,0xa7,0x76,0x12,
+ 0x16,0x24,0x46,0x01,0x69,0x0c,0x73,0xe8,0x7a,0x72,0x02,0xaa,0x7a,0x73,0x03,0xa7,
+ 0xd5,0x12,0x35,0x3c,0xd5,0x05,0x64,0x64,0xa6,0x12,0xf1,0x11,0x46,0x03,0xf9,0x11,
+ 0x56,0x1c,0xc6,0x1c,0x65,0x71,0x16,0x1c,0x36,0xa3,0x46,0xa2,0x82,0x3c,0x32,0x1e,
+ 0xf1,0x11,0x47,0x03,0xf9,0x11,0x57,0x1c,0xc7,0x1c,0x17,0x1c,0x37,0xa4,0x47,0xa5,
+ 0x85,0x3c,0x45,0x1e,0x52,0x05,0x56,0xa5,0x66,0xa3,0x83,0x3c,0x53,0x1e,0x57,0xa6,
+ 0x67,0xa7,0x87,0x3c,0x67,0x1e,0x73,0x05,0x72,0x01,0x73,0x01,0x67,0x7f,0x72,0x01,
+ 0x0b,0x87,0x66,0x76,0x76,0x1c,0x06,0xa6,0x66,0x73,0x37,0x1c,0x07,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x27,0x0d,0x03,0xe8,0x27,0x60,0x0e,0xb7,0x04,0xf0,0x0e,0xa7,0x27,0x2a,
+ 0x01,0xe0,0x0e,0xb9,0x0e,0xa7,0x07,0x2a,0x37,0xe0,0xd6,0x12,0x36,0x3c,0xd6,0x05,
+ 0x67,0x64,0xf1,0x11,0xa7,0x03,0xf9,0x11,0x67,0x1c,0xc7,0x1c,0x47,0x74,0x47,0x1c,
+ 0x37,0xa5,0x47,0xa2,0x82,0x3c,0x52,0x1e,0xc6,0x1c,0x56,0x75,0x56,0x1c,0x76,0xa4,
+ 0x86,0xa5,0x85,0x3c,0x45,0x1e,0x52,0x05,0x57,0xa5,0x67,0xa3,0x83,0x3c,0x53,0x1e,
+ 0x96,0xa5,0xa6,0xa7,0x87,0x3c,0x57,0x1e,0x73,0x05,0x72,0x01,0x73,0x01,0x4a,0x7f,
+ 0x72,0x01,0x0b,0x87,0x4a,0x76,0x76,0x1c,0x06,0xa6,0x49,0x71,0x17,0x1c,0x07,0xa7,
+ 0x87,0x3c,0x67,0x1e,0x27,0x0d,0x08,0xe8,0x17,0x60,0x0e,0xb7,0x05,0xf0,0x17,0x2a,
+ 0x02,0xe8,0x47,0x2a,0x01,0xe0,0x0e,0xb8,0x0d,0x20,0x0e,0x20,0xad,0x2a,0x7c,0xe7,
+ 0x42,0x7f,0x3a,0x77,0x07,0x87,0xb0,0x97,0x41,0x72,0x27,0x1c,0x07,0xa7,0x07,0x2a,
+ 0x06,0xe9,0x38,0x77,0x07,0xac,0x36,0x77,0x07,0xa7,0x76,0x12,0x46,0x3c,0x75,0x12,
+ 0x65,0x3c,0x56,0x1c,0x3b,0x7b,0x6b,0x1c,0x3b,0x7a,0x09,0x60,0x78,0x12,0x78,0x1c,
+ 0x37,0x3c,0x78,0x1c,0xc0,0x98,0x06,0x28,0xe0,0x96,0xc8,0x12,0x48,0x3c,0xc7,0x12,
+ 0x67,0x3c,0x78,0x1c,0xd0,0x98,0xa0,0x88,0x08,0xa7,0x17,0x24,0x47,0x01,0x1d,0x60,
+ 0x7d,0x0c,0xcb,0xe8,0x0a,0xa7,0x07,0x2a,0x76,0xe0,0x0b,0xa7,0x07,0x2a,0xc5,0xe8,
+ 0x19,0x7e,0xc0,0x87,0x97,0x1c,0x15,0x71,0x17,0x1c,0x37,0x3c,0xe7,0x1c,0x77,0xa6,
+ 0x87,0xa2,0x82,0x3c,0x62,0x1e,0xb0,0x87,0x28,0x73,0x37,0x1c,0x07,0xa6,0xb0,0x87,
+ 0x27,0x74,0x47,0x1c,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x27,0x0c,0xae,0xe0,0xe0,0x87,
+ 0xb7,0x1c,0xd0,0x88,0x87,0x1c,0x07,0xa7,0x07,0x2a,0xa7,0xe8,0xb0,0x87,0x20,0x71,
+ 0x17,0x1c,0x07,0xa3,0x20,0x7f,0x62,0x01,0xc7,0x12,0xc7,0x1c,0xc6,0x12,0x36,0x3c,
+ 0x67,0x1c,0x97,0x1c,0x02,0x73,0x38,0xf0,0x00,0x03,0x00,0x00,0x83,0x00,0x00,0x00,
+ 0xe6,0xa3,0x00,0x00,0x8a,0x9e,0x00,0x00,0x1c,0x02,0x00,0x00,0x18,0x02,0x00,0x00,
+ 0xa5,0xa0,0x00,0x00,0x00,0xa1,0x00,0x00,0x70,0x05,0x00,0x00,0x5c,0x05,0x00,0x00,
+ 0x02,0x03,0x00,0x00,0x8c,0x82,0x00,0x00,0x18,0xa4,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0xe5,0xa3,0x00,0x00,0xe4,0xa3,0x00,0x00,0xc0,0x0c,0x00,0x00,0xae,0x00,0x00,0x00,
+ 0xaf,0x00,0x00,0x00,0x70,0x02,0x00,0x00,0x34,0x47,0x00,0x00,0xaa,0x00,0x00,0x00,
+ 0xa4,0xa2,0x00,0x00,0x22,0xa4,0x00,0x00,0xac,0x00,0x00,0x00,0xad,0x00,0x00,0x00,
+ 0xab,0x00,0x00,0x00,0x3e,0x84,0x00,0x00,0x37,0x1c,0x37,0x3c,0xe7,0x1c,0x77,0xa6,
+ 0x87,0xa7,0x87,0x3c,0x67,0x1e,0x26,0x12,0xd6,0x0b,0x67,0x0c,0x53,0xe8,0x27,0x0c,
+ 0x4e,0xe0,0x0a,0xbd,0x52,0xf0,0x17,0x2a,0x50,0xe0,0x0b,0xa7,0x07,0x2a,0x4d,0xe8,
+ 0xae,0x77,0xc0,0x8d,0x9d,0x1c,0xad,0x71,0x1d,0x1c,0x3d,0x3c,0x7d,0x1c,0x7d,0xa6,
+ 0x8d,0xa8,0x88,0x3c,0x68,0x1e,0xce,0x12,0xce,0x1c,0xc6,0x12,0x36,0x3c,0x6e,0x1c,
+ 0x9e,0x1c,0x1e,0x1c,0x3e,0x3c,0x7e,0x1c,0x7e,0xa2,0x8e,0xa6,0x86,0x3c,0xb0,0x87,
+ 0xa4,0x73,0x37,0x1c,0x62,0x1e,0x07,0xa3,0xa3,0x7f,0x62,0x01,0x28,0x0c,0x2a,0xe8,
+ 0x3e,0xa7,0x4e,0xa5,0x85,0x3c,0x75,0x1e,0x05,0x3d,0x05,0x3b,0x5e,0xa7,0x6e,0xa6,
+ 0x86,0x3c,0x76,0x1e,0x06,0x3d,0x06,0x3b,0x54,0x12,0xe4,0x01,0x67,0x12,0xe7,0x01,
+ 0x47,0x0d,0x0a,0xe8,0x3d,0xa6,0x4d,0xa7,0x87,0x3c,0x67,0x1e,0x07,0x3d,0x07,0x3b,
+ 0xf1,0x11,0x57,0x03,0xf9,0x11,0x09,0xf0,0x5d,0xa5,0x6d,0xa7,0x87,0x3c,0x57,0x1e,
+ 0x07,0x3d,0x07,0x3b,0xf1,0x11,0x67,0x03,0xf9,0x11,0x07,0x22,0x03,0xe0,0x27,0x60,
+ 0x0a,0xb7,0x03,0xf0,0x47,0x60,0xa0,0x88,0x08,0xb7,0x09,0x20,0xa0,0x88,0x08,0x20,
+ 0xa0,0x98,0x7b,0x20,0x0a,0x20,0xa9,0x2a,0x26,0xe7,0x07,0x60,0x83,0x73,0x74,0x12,
+ 0x76,0x12,0x36,0x1c,0x85,0x75,0x65,0x1c,0x05,0xa5,0x15,0x2a,0x02,0xe8,0x45,0x2a,
+ 0x03,0xe0,0x82,0x79,0x96,0x1c,0x06,0xb4,0x07,0x20,0xa7,0x2a,0xf1,0xe7,0x80,0x77,
+ 0x07,0x87,0x80,0x7b,0xb7,0x1c,0x07,0xa7,0x0d,0x60,0x07,0x2a,0x18,0xe1,0x1b,0xf1,
+ 0xd7,0x12,0x37,0x3c,0xd7,0x1c,0x74,0x7c,0xc7,0x1c,0x7b,0x71,0x17,0x1c,0x07,0xae,
+ 0xc7,0x12,0xe7,0x1c,0x75,0x72,0x27,0x1c,0x07,0xa7,0x17,0x2a,0x07,0xe8,0x47,0x2a,
+ 0x05,0xe8,0x76,0x73,0x03,0xa5,0x76,0x76,0x07,0x60,0xfc,0xf0,0xee,0x1c,0x75,0x76,
+ 0xe6,0x1c,0x07,0x60,0x06,0xd7,0x74,0x74,0x4e,0x1c,0x0e,0xd7,0xf6,0xf0,0x74,0x12,
+ 0x06,0xa3,0x07,0x20,0x86,0x20,0x3e,0x0f,0xed,0xe0,0xd7,0x12,0x37,0x3c,0xd7,0x1c,
+ 0x62,0x75,0x57,0x1c,0x6e,0x76,0x67,0x1c,0x57,0xa6,0x67,0xa5,0x85,0x3c,0x65,0x1e,
+ 0x77,0xa3,0x87,0xa6,0x86,0x3c,0x36,0x1e,0x47,0x12,0x37,0x3c,0x47,0x1c,0x5a,0x78,
+ 0x87,0x1c,0x67,0x79,0x97,0x1c,0x27,0xa4,0x37,0xab,0x8b,0x3c,0x4b,0x1e,0xbc,0x12,
+ 0x6c,0x01,0xa0,0x9c,0x47,0xa4,0x57,0xa9,0x89,0x3c,0x49,0x1e,0x98,0x12,0x68,0x01,
+ 0xb0,0x98,0x75,0x01,0xc0,0x95,0x8c,0x62,0x0c,0x1c,0x0c,0xc8,0x78,0x01,0xd0,0x98,
+ 0x5a,0x12,0x8a,0x05,0xea,0x01,0x6a,0x01,0x76,0x01,0xe0,0x96,0xcc,0x62,0x0c,0x1c,
+ 0x0c,0xc8,0x78,0x01,0xf0,0x98,0x86,0x05,0x68,0x12,0xe8,0x01,0x68,0x01,0xa2,0x12,
+ 0x72,0x01,0x83,0x12,0x73,0x01,0x53,0x7f,0x2c,0x12,0x49,0x77,0x07,0x87,0x49,0x76,
+ 0x76,0x1c,0x06,0xa6,0x26,0x2a,0x33,0xe0,0x50,0x76,0x76,0x1c,0x06,0xa6,0x4f,0x71,
+ 0x17,0x1c,0x07,0xa3,0x83,0x3c,0x63,0x1e,0x82,0x32,0x3c,0x0c,0x08,0xe0,0xc2,0x12,
+ 0x82,0x3c,0x4b,0x7f,0x62,0x01,0xf7,0x60,0x27,0x0c,0x01,0xe8,0x02,0x61,0xe7,0x12,
+ 0xe7,0x1c,0x41,0x76,0x76,0x1c,0x06,0xc6,0x6c,0x0c,0x04,0xe0,0x3e,0x72,0x27,0x1c,
+ 0x07,0xc2,0x03,0xf0,0x3c,0x73,0x37,0x1c,0x07,0xd2,0xe7,0x12,0xe7,0x1c,0x3a,0x74,
+ 0x47,0x1c,0x07,0xdc,0x87,0x32,0x72,0x0c,0x72,0x02,0xf1,0x11,0x2a,0x03,0xf9,0x11,
+ 0x8a,0x3e,0x6a,0x01,0xf1,0x11,0x28,0x03,0xf9,0x11,0x88,0x3e,0x1e,0xf0,0x16,0x2a,
+ 0x1d,0xe0,0x35,0x76,0x76,0x1c,0x06,0xa6,0x35,0x75,0x57,0x1c,0x07,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x75,0x12,0x35,0x3e,0x46,0x60,0x52,0x0c,0x0c,0xe8,0x75,0x12,0x25,0x3e,
+ 0x36,0x60,0x52,0x0c,0x07,0xe8,0x75,0x12,0x15,0x3e,0x26,0x60,0x52,0x0c,0x02,0xe8,
+ 0x72,0x0c,0x36,0x00,0x6a,0x1a,0x6a,0x01,0x68,0x1a,0x68,0x01,0x17,0x76,0x6e,0x1c,
+ 0x1b,0x77,0x7e,0x1c,0x0e,0xa7,0x17,0x2a,0x12,0xe8,0xc0,0x8c,0xd0,0x81,0xc1,0x0d,
+ 0x02,0xe8,0xab,0x1c,0x01,0xf0,0xab,0x05,0x6b,0x01,0xa0,0x9b,0xe0,0x8b,0xf0,0x8c,
+ 0xbc,0x0d,0x02,0xe8,0x89,0x1c,0x01,0xf0,0x89,0x05,0x69,0x01,0xb0,0x99,0xd7,0x12,
+ 0x37,0x3c,0xd7,0x1c,0x09,0x71,0x17,0x1c,0x15,0x72,0x27,0x1c,0x83,0x62,0x03,0x1c,
+ 0x03,0xcb,0x57,0xbb,0x8b,0x3e,0x67,0xbb,0xc4,0x62,0x04,0x1c,0x04,0xc9,0x77,0xb9,
+ 0x89,0x3e,0x87,0xb9,0x2a,0xf0,0x00,0x00,0x8a,0x9e,0x00,0x00,0x83,0x00,0x00,0x00,
+ 0xab,0x00,0x00,0x00,0x3e,0x84,0x00,0x00,0x70,0x05,0x00,0x00,0x98,0x05,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0xa3,0x00,0x00,0x00,0x1c,0x02,0x00,0x00,0x4a,0xa0,0x00,0x00,
+ 0x4b,0xa0,0x00,0x00,0x62,0xa6,0x00,0x00,0x76,0xa6,0x00,0x00,0x18,0x02,0x00,0x00,
+ 0xc0,0x01,0x00,0x00,0xc0,0x0c,0x00,0x00,0xa4,0x00,0x00,0x00,0xa5,0x00,0x00,0x00,
+ 0xd0,0x83,0x00,0x00,0x07,0x01,0x51,0x0c,0x0a,0xef,0x0d,0x20,0x4d,0x01,0xa9,0x75,
+ 0x05,0xa7,0x7d,0x0c,0xe5,0xee,0xa8,0x77,0x07,0x87,0xa8,0x76,0x67,0x1c,0x07,0xa5,
+ 0x16,0x60,0x56,0x0c,0x92,0xe0,0x56,0x60,0x56,0x0c,0x01,0xe0,0x07,0xb6,0x0c,0x60,
+ 0xa4,0x78,0xa4,0x7a,0xa5,0x79,0x85,0xf0,0xc3,0x12,0x33,0x3c,0xc3,0x1c,0x83,0x1c,
+ 0xa3,0x77,0x37,0x1c,0x07,0xad,0x87,0x12,0xd7,0x1c,0xa1,0x76,0x76,0x1c,0x06,0xa6,
+ 0x16,0x2a,0x21,0xe0,0xa7,0x12,0xd7,0x1c,0x06,0x60,0x07,0xb6,0x0e,0x60,0x3b,0x12,
+ 0x9b,0x77,0x7b,0x1c,0x10,0xf0,0xe2,0x12,0x32,0x3c,0xe2,0x1c,0xd7,0x12,0xd7,0x1c,
+ 0xd7,0x1c,0x76,0x12,0x46,0x3c,0x76,0x05,0x62,0x1c,0x92,0x1c,0xb3,0x12,0x94,0x60,
+ 0x95,0x7f,0x0e,0x20,0x4e,0x01,0x8c,0x71,0x01,0x87,0x8c,0x72,0x27,0x1c,0x07,0xa7,
+ 0x7e,0x0c,0xe9,0xef,0x54,0xf0,0x46,0x2a,0x52,0xe8,0x8f,0x74,0x47,0x1c,0x07,0xa7,
+ 0x17,0x2a,0x4d,0xe8,0xa7,0x12,0xd7,0x1c,0x07,0xa7,0xa0,0x97,0x72,0x12,0x32,0x3c,
+ 0x72,0x1c,0xd7,0x12,0xd7,0x1c,0xd7,0x1c,0x7e,0x12,0x4e,0x3c,0x7e,0x05,0xe2,0x1c,
+ 0x92,0x1c,0x82,0x75,0x53,0x1c,0x94,0x60,0x83,0x7f,0x7b,0x76,0x06,0x87,0x7b,0x7b,
+ 0xb7,0x1c,0x07,0xab,0x06,0x60,0xb0,0x96,0x62,0x12,0x64,0x12,0x10,0xf0,0x67,0x12,
+ 0x37,0x3c,0x67,0x1c,0xe7,0x1c,0x97,0x1c,0x17,0xa3,0x27,0xa5,0x85,0x3c,0x35,0x1e,
+ 0x52,0x1c,0x37,0xa5,0x47,0xa7,0x87,0x3c,0x57,0x1e,0x74,0x1c,0x06,0x20,0x06,0x01,
+ 0xb1,0x0c,0xed,0xef,0xb0,0x94,0xce,0x12,0x3e,0x3c,0xce,0x1c,0x8e,0x1c,0x73,0x71,
+ 0x1e,0x1c,0xb3,0x12,0x73,0x7f,0x62,0x01,0x5e,0xb2,0x82,0x3e,0x6e,0xb2,0xb0,0x82,
+ 0xb3,0x12,0x6f,0x7f,0x62,0x01,0x7e,0xb2,0x82,0x3e,0x8e,0xb2,0xa0,0x87,0x07,0x20,
+ 0x47,0x01,0xad,0x1c,0x0d,0xb7,0xb7,0x0c,0x02,0xe8,0x02,0x60,0x0d,0xb2,0x0c,0x20,
+ 0x4c,0x01,0x5c,0x73,0x03,0xa7,0x7c,0x0c,0x77,0xef,0x5b,0x77,0x07,0x87,0x65,0x74,
+ 0x47,0x1c,0x07,0xa7,0x07,0x2a,0x02,0xe9,0x5a,0x7a,0x56,0x77,0x07,0xa1,0x11,0x2a,
+ 0xfd,0xe0,0x61,0x77,0x07,0xa9,0x61,0x76,0x62,0x77,0x07,0xa7,0x62,0x75,0x05,0xab,
+ 0x8b,0x3c,0x7b,0x1e,0x61,0x77,0x07,0xa7,0x61,0x75,0x05,0xac,0x8c,0x3c,0x7c,0x1e,
+ 0x60,0x77,0x07,0xa7,0x60,0x75,0x05,0xad,0x8d,0x3c,0x7d,0x1e,0x5f,0x77,0x07,0xa7,
+ 0x5f,0x75,0x05,0xae,0x8e,0x3c,0x7e,0x1e,0xa6,0xa5,0xb6,0xa7,0x87,0x3c,0x57,0x1e,
+ 0x5c,0x75,0x75,0x1c,0xa0,0x95,0x5b,0x78,0x87,0x1c,0x67,0x01,0xb0,0x97,0xc6,0xa5,
+ 0xd6,0xa7,0x87,0x3c,0x57,0x1e,0x56,0x72,0x72,0x1c,0xc0,0x92,0x87,0x1c,0x67,0x01,
+ 0xd0,0x97,0x55,0x77,0x07,0xa7,0x55,0x76,0x06,0xa3,0x83,0x3c,0x73,0x1e,0x54,0x77,
+ 0x07,0xa7,0x54,0x76,0x06,0xa4,0x84,0x3c,0x74,0x1e,0x53,0x77,0x07,0xa8,0x67,0x64,
+ 0xf1,0x11,0x78,0x03,0xf9,0x11,0xa2,0x12,0x82,0x1c,0x50,0x75,0x52,0x1c,0x06,0x60,
+ 0xf1,0x11,0x79,0x03,0xf9,0x11,0x02,0xa7,0x27,0x2a,0xa2,0xe0,0x67,0x12,0xa7,0x1c,
+ 0x34,0x75,0x75,0x1c,0x05,0xa5,0x15,0x24,0x45,0x01,0x51,0x0c,0x99,0xe8,0x48,0x75,
+ 0x57,0x1c,0x07,0xa7,0x07,0x24,0x47,0x01,0x71,0x0c,0x92,0xe8,0x67,0x12,0x37,0x3c,
+ 0x67,0x05,0x87,0x1c,0xa7,0x1c,0x43,0x75,0x57,0x1c,0x37,0xaf,0x47,0xa5,0x85,0x3c,
+ 0xf5,0x1e,0xb5,0x0c,0x0a,0xe8,0x5c,0x0c,0x08,0xe8,0x57,0xaf,0x67,0xa7,0x87,0x3c,
+ 0xf7,0x1e,0xd7,0x0c,0x02,0xe8,0x7e,0x0c,0x7b,0xe0,0x55,0x1c,0x6f,0x12,0x3f,0x3c,
+ 0x6f,0x05,0xf7,0x12,0x97,0x1c,0xa7,0x1c,0x37,0x73,0x37,0x1c,0x37,0xa3,0x47,0xa4,
+ 0x84,0x3c,0x34,0x1e,0x45,0x05,0x65,0x01,0x8f,0x1c,0xaf,0x1c,0x32,0x74,0x4f,0x1c,
+ 0x5f,0xa3,0x6f,0xa4,0x84,0x3c,0x34,0x1e,0x44,0x1c,0x57,0xa3,0x67,0xa7,0x87,0x3c,
+ 0x37,0x1e,0x74,0x05,0x64,0x01,0x57,0x12,0x77,0x01,0xf3,0x67,0x73,0x0d,0x04,0xe8,
+ 0xa0,0x83,0x37,0x0d,0x03,0xe8,0x03,0xf0,0x75,0x32,0x01,0xf0,0xb0,0x85,0x47,0x12,
+ 0x77,0x01,0xf3,0x67,0x73,0x0d,0x04,0xe8,0xc0,0x83,0x37,0x0d,0x45,0xe8,0x45,0xf0,
+ 0x74,0x32,0x43,0xf0,0xa5,0xa0,0x00,0x00,0x1c,0x9e,0x00,0x00,0x21,0x01,0x00,0x00,
+ 0x8a,0x9e,0x00,0x00,0x8c,0xa6,0x00,0x00,0x96,0xa6,0x00,0x00,0x1c,0x02,0x00,0x00,
+ 0x70,0x05,0x00,0x00,0x8c,0x82,0x00,0x00,0x98,0x05,0x00,0x00,0x18,0x02,0x00,0x00,
+ 0x3e,0x84,0x00,0x00,0xa6,0x00,0x00,0x00,0xe4,0xa3,0x00,0x00,0x20,0x9e,0x00,0x00,
+ 0x36,0x9e,0x00,0x00,0x37,0x9e,0x00,0x00,0x3a,0x9e,0x00,0x00,0x3b,0x9e,0x00,0x00,
+ 0x38,0x9e,0x00,0x00,0x39,0x9e,0x00,0x00,0x3c,0x9e,0x00,0x00,0x3d,0x9e,0x00,0x00,
+ 0x81,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0xa7,0xa0,0x00,0x00,0xa8,0xa0,0x00,0x00,
+ 0xa9,0xa0,0x00,0x00,0xaa,0xa0,0x00,0x00,0xe5,0xa3,0x00,0x00,0x02,0x03,0x00,0x00,
+ 0x8e,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0xd0,0x84,0x53,0x12,0x63,0x01,0x64,0x01,
+ 0x06,0x20,0x62,0x20,0xa6,0x2a,0x57,0xe7,0x9f,0x77,0x07,0xb3,0x83,0x3e,0x9e,0x77,
+ 0x07,0xb3,0x9e,0x77,0x07,0xb4,0x84,0x3e,0x9e,0x77,0x07,0xb4,0x9e,0x77,0x07,0xa6,
+ 0x9e,0x77,0x07,0xa5,0x17,0x60,0x57,0x0c,0x9d,0x77,0x07,0x87,0x03,0xe0,0x9c,0x74,
+ 0x47,0x1c,0x02,0xf0,0x9c,0x75,0x57,0x1c,0x07,0xab,0x1b,0x3c,0x0a,0x60,0xac,0x12,
+ 0x9a,0x7d,0x68,0x64,0xf1,0x11,0x68,0x03,0xf9,0x11,0xb9,0x12,0x8a,0xf0,0xc7,0x12,
+ 0x37,0x3c,0xc7,0x1c,0xd7,0x1c,0x95,0x76,0x67,0x1c,0x07,0xab,0xd7,0x12,0xb7,0x1c,
+ 0x94,0x76,0x76,0x1c,0x06,0xa6,0x26,0x2a,0x74,0xe0,0x92,0x77,0x07,0xa5,0x92,0x77,
+ 0x06,0x60,0x2e,0xf0,0x74,0x12,0x87,0x20,0x04,0xa4,0xb4,0x0f,0x27,0xe0,0xb7,0x12,
+ 0x37,0x3c,0xb7,0x05,0x87,0x1c,0xd7,0x1c,0x8d,0x71,0x17,0x1c,0x37,0xa5,0x47,0xa2,
+ 0x82,0x3c,0x52,0x1e,0x6e,0x12,0x3e,0x3c,0x6e,0x1c,0xde,0x1c,0x89,0x73,0x3e,0x1c,
+ 0x2e,0xa5,0x3e,0xa6,0x86,0x3c,0x56,0x1e,0x62,0x05,0x57,0xa6,0x67,0xa3,0x83,0x3c,
+ 0x63,0x1e,0x4e,0xa6,0x5e,0xa7,0x87,0x3c,0x67,0x1e,0x73,0x05,0x72,0x01,0x73,0x01,
+ 0x81,0x7f,0x92,0x0c,0xc7,0x12,0x37,0x3c,0x06,0xe8,0x3a,0xf0,0x06,0x20,0x46,0x01,
+ 0x56,0x0f,0xd0,0xe7,0x44,0xf0,0xc7,0x1c,0xd7,0x1c,0x74,0x76,0x76,0x1c,0x06,0xa6,
+ 0xd6,0x1c,0x79,0x74,0x46,0x1c,0x06,0xa4,0x6d,0x75,0x05,0x85,0x78,0x73,0x53,0x1c,
+ 0x03,0xa3,0x34,0x0c,0x77,0x71,0x15,0x1c,0x08,0xe0,0x04,0x20,0x06,0xb4,0x05,0xa6,
+ 0x26,0x2a,0x2d,0xe0,0x74,0x72,0x27,0x1c,0x0c,0xf0,0x0a,0x20,0x4a,0x01,0xdb,0x1c,
+ 0x68,0x73,0x3b,0x1c,0x36,0x60,0x0b,0xb6,0x05,0xa6,0x06,0x2a,0x20,0xe8,0x6d,0x74,
+ 0x47,0x1c,0x2e,0xa5,0x3e,0xa6,0x86,0x3c,0x56,0x1e,0x57,0xb6,0x86,0x3e,0x67,0xb6,
+ 0x4e,0xa5,0x5e,0xa6,0x86,0x3c,0x56,0x1e,0x77,0xb6,0x86,0x3e,0x87,0xb6,0x0f,0xf0,
+ 0xc7,0x1c,0xd7,0x1c,0x5a,0x75,0x57,0x1c,0x07,0xa7,0xd7,0x1c,0x5f,0x76,0x67,0x1c,
+ 0x04,0xf0,0x16,0x2a,0x04,0xe0,0x5c,0x7b,0xb7,0x1c,0x06,0x60,0x07,0xb6,0x0c,0x20,
+ 0x4c,0x01,0x4d,0x71,0x01,0xa7,0x7c,0x0c,0x72,0xef,0x0a,0x2a,0x08,0xe8,0x5a,0x77,
+ 0x07,0xa6,0x5a,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x7a,0x0c,0x2a,0x00,0x58,0x77,
+ 0x07,0xba,0x46,0x77,0x07,0x87,0x57,0x76,0x76,0x1c,0x06,0xa6,0x06,0x2a,0x05,0xe0,
+ 0x56,0x77,0x07,0xa6,0xf2,0x67,0x26,0x16,0xd4,0xf0,0x4f,0x76,0x06,0xa6,0x4f,0x75,
+ 0x05,0xa5,0x85,0x3c,0x65,0x1e,0x05,0x01,0x04,0x60,0x3f,0x7c,0x50,0x7d,0x7d,0x1c,
+ 0x50,0x7e,0x7e,0x1c,0x50,0x73,0x73,0x1c,0x3f,0x12,0x4f,0x72,0x72,0x1c,0x16,0xf0,
+ 0x86,0x65,0x46,0x1c,0x66,0x1c,0xc6,0x1c,0x86,0xa3,0x96,0xa6,0x0d,0xab,0xb3,0x0c,
+ 0x0b,0xe8,0x0e,0xab,0x3b,0x0c,0x08,0xe8,0x0f,0xa3,0x36,0x0c,0x05,0xe8,0x02,0xa3,
+ 0x63,0x0c,0x02,0xe8,0x01,0x24,0x41,0x01,0x04,0x20,0x44,0x01,0x54,0x0c,0xe8,0xef,
+ 0x15,0x60,0x15,0x0c,0x33,0xe8,0x3d,0x76,0x76,0x1c,0x06,0xa4,0x3d,0x76,0x76,0x1c,
+ 0x06,0xac,0x05,0x60,0x3c,0x7d,0x7d,0x1c,0x3c,0x76,0x76,0x1c,0x6f,0x12,0x3b,0x7e,
+ 0xa2,0x61,0x16,0xf0,0x0d,0xa3,0x0f,0xaa,0x4b,0x12,0xf1,0x11,0x2b,0x03,0xf9,0x11,
+ 0x0b,0xf0,0xb6,0x12,0x36,0x1c,0x66,0x1c,0xe6,0x1c,0x06,0xc6,0x76,0x01,0x06,0x22,
+ 0x01,0xe0,0x65,0x1c,0x03,0x20,0x43,0x01,0x3a,0x0c,0xf3,0xe7,0x04,0x20,0x44,0x01,
+ 0x4c,0x0c,0xe8,0xe7,0x11,0x2a,0x05,0xe0,0x66,0x67,0x76,0x1c,0x06,0xa6,0x66,0x1c,
+ 0x03,0xf0,0x2b,0x76,0x76,0x1c,0x06,0xa6,0x56,0x0c,0x35,0x00,0x2a,0x76,0x06,0xa6,
+ 0x76,0x36,0x29,0x76,0x59,0xe8,0x05,0x2a,0x02,0xe8,0x07,0x60,0x53,0xf0,0x06,0xa5,
+ 0x27,0x78,0x87,0x1c,0x07,0xa7,0x57,0x0c,0x4b,0xe0,0x1b,0x77,0x07,0xa6,0xf9,0x67,
+ 0x96,0x16,0x56,0xf0,0xa7,0xa0,0x00,0x00,0xa8,0xa0,0x00,0x00,0xa9,0xa0,0x00,0x00,
+ 0xaa,0xa0,0x00,0x00,0xe5,0xa3,0x00,0x00,0xa5,0xa0,0x00,0x00,0x1c,0x9e,0x00,0x00,
+ 0xb3,0x00,0x00,0x00,0xb2,0x00,0x00,0x00,0x8a,0x9e,0x00,0x00,0x1c,0x02,0x00,0x00,
+ 0x70,0x05,0x00,0x00,0x4a,0xa0,0x00,0x00,0x4b,0xa0,0x00,0x00,0x00,0x03,0x00,0x00,
+ 0xc0,0x01,0x00,0x00,0xc0,0x0c,0x00,0x00,0xa7,0x05,0x00,0x00,0xb1,0x00,0x00,0x00,
+ 0xb0,0x00,0x00,0x00,0x18,0x02,0x00,0x00,0x40,0x9f,0x00,0x00,0x41,0x9f,0x00,0x00,
+ 0x3b,0xa4,0x00,0x00,0x11,0x01,0x00,0x00,0x2c,0xa4,0x00,0x00,0x12,0x01,0x00,0x00,
+ 0x13,0x01,0x00,0x00,0x14,0x01,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0xe0,0x02,0x00,
+ 0x17,0x01,0x00,0x00,0x2d,0xa4,0x00,0x00,0x58,0xa8,0x00,0x00,0x18,0x01,0x00,0x00,
+ 0x57,0x12,0x07,0x20,0x06,0xb7,0x0f,0xf0,0x05,0x2a,0x0c,0xe8,0x06,0xa5,0xa4,0x7b,
+ 0xb7,0x1c,0x07,0xa7,0x57,0x0c,0xf4,0xe7,0xa3,0x77,0x07,0xa6,0xa3,0x7c,0xc6,0x1e,
+ 0x07,0xb6,0x01,0xf0,0x06,0xb5,0x9f,0x77,0x07,0xa7,0x77,0x36,0x03,0xe8,0x16,0x60,
+ 0x9f,0x77,0x07,0xb6,0x9f,0x7e,0x0e,0xa7,0x07,0x2a,0x42,0xe8,0x9e,0x7f,0x9e,0x77,
+ 0x07,0xa2,0x17,0xa3,0x9e,0x74,0x85,0x61,0x9e,0x7f,0x9e,0x77,0x07,0xb2,0x12,0x01,
+ 0x9e,0x77,0x07,0xb1,0x22,0x01,0x9d,0x77,0x07,0xb1,0x82,0x3f,0x9d,0x77,0x07,0xb2,
+ 0x9d,0x77,0x07,0xa6,0x9d,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x9c,0x76,0x06,0xa6,
+ 0x06,0x3d,0x76,0x1e,0x9b,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x07,0x2a,0x1a,0xe0,
+ 0x99,0x77,0x07,0xa6,0x99,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x98,0x76,0x06,0xa6,
+ 0x06,0x3d,0x76,0x1e,0x97,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x07,0x2a,0x0a,0xe0,
+ 0x95,0x75,0x05,0xa6,0x06,0x20,0x46,0x01,0x05,0xb6,0x25,0x60,0x65,0x0c,0x05,0xe0,
+ 0x0e,0xb7,0x03,0xf0,0x06,0x60,0x8f,0x77,0x07,0xb6,0x16,0x60,0x7c,0x77,0x07,0xb6,
+ 0x8e,0x76,0x06,0x87,0x07,0x20,0x06,0x97,0x8d,0x7e,0x0e,0xa7,0x07,0x2a,0x7f,0xe0,
+ 0x81,0x77,0x07,0xa6,0x81,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x80,0x76,0x06,0xa6,
+ 0x06,0x3d,0x76,0x1e,0x7f,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x07,0x2a,0x10,0xe0,
+ 0x7d,0x77,0x07,0xa7,0x7d,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x7c,0x77,0x07,0xa7,
+ 0x07,0x3d,0x67,0x1e,0x7b,0x76,0x06,0xad,0x8d,0x3d,0x7d,0x1e,0x0d,0x2a,0x05,0xe8,
+ 0x69,0x7f,0x06,0x60,0x7a,0x77,0x17,0xb6,0x23,0xf3,0x1e,0xa7,0x26,0x60,0x76,0x0c,
+ 0x04,0xe8,0x07,0x20,0x1e,0xb7,0x63,0x7f,0x1b,0xf3,0x56,0x60,0x76,0x0c,0x0f,0xe8,
+ 0x07,0x20,0x1e,0xb7,0x17,0x60,0xae,0xb7,0xbe,0xbd,0xce,0xbd,0x71,0x77,0x07,0x87,
+ 0x71,0x71,0x17,0x1c,0x07,0xa7,0xde,0xb7,0x07,0x60,0xee,0xb7,0x09,0xf3,0x5a,0x77,
+ 0x07,0xa2,0x17,0xa3,0x5a,0x74,0x85,0x61,0x5a,0x7f,0x86,0x2c,0x26,0x16,0x59,0x77,
+ 0x07,0xb6,0x12,0x01,0x17,0x12,0x58,0x75,0x05,0xb1,0x22,0x01,0x58,0x75,0x05,0xb1,
+ 0x82,0x3f,0x57,0x75,0x05,0xb2,0x64,0x75,0x05,0xb6,0x64,0x75,0x05,0xb7,0x64,0x75,
+ 0x05,0xb1,0x64,0x75,0x05,0xb2,0x64,0x75,0x05,0xb6,0x64,0x76,0x06,0xb7,0x64,0x77,
+ 0x07,0xb1,0x64,0x77,0x07,0xb2,0xae,0xbd,0x64,0x76,0x06,0xa6,0x64,0x77,0x07,0xa7,
+ 0x87,0x3c,0x67,0x1e,0x63,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x62,0x77,0x07,0xa7,
+ 0x87,0x3d,0x67,0x1e,0x4e,0xb7,0x17,0x01,0x5e,0xb1,0x27,0x01,0x6e,0xb1,0x87,0x3f,
+ 0x7e,0xb7,0x1e,0xbd,0x17,0x60,0x0e,0xb7,0x5c,0x77,0x67,0xbd,0xc9,0xf2,0x4c,0x76,
+ 0x06,0x8d,0x5a,0x76,0xd6,0x1c,0x06,0xa6,0x06,0x2a,0x03,0xe0,0x27,0x60,0x0e,0xb7,
+ 0x31,0xf3,0x16,0x2a,0xdd,0xe1,0x17,0x2a,0xb4,0xe2,0x07,0x60,0xae,0xb7,0x54,0x77,
+ 0xd7,0x1c,0x07,0xa6,0x06,0x2a,0x50,0x77,0x03,0xe0,0x26,0x60,0x67,0xb6,0xb1,0xf1,
+ 0x16,0x2a,0x0a,0xe1,0x67,0xa6,0x06,0x2a,0xec,0xe0,0x4e,0x77,0x07,0xa7,0x07,0x2a,
+ 0x07,0xe0,0x4d,0x77,0x07,0xa7,0x17,0x2a,0x3c,0xe0,0x4c,0x76,0x06,0xb7,0x3c,0xf0,
+ 0x17,0x2a,0x37,0xe0,0x49,0x77,0x07,0xa7,0x17,0x2a,0x36,0xe8,0x49,0x77,0x07,0xa6,
+ 0x06,0x2a,0x2f,0xe0,0x46,0x77,0x07,0xa5,0x15,0x2a,0x2d,0xe0,0x46,0x77,0x07,0xa7,
+ 0x66,0x64,0xf1,0x11,0x67,0x03,0xf9,0x11,0x44,0x76,0x67,0x1c,0x44,0x72,0x27,0x1c,
+ 0x37,0xa6,0x47,0xa2,0x82,0x3c,0x62,0x1e,0x42,0x76,0x06,0xa5,0x42,0x76,0x06,0xa6,
+ 0x86,0x3c,0x56,0x1e,0x62,0x05,0x57,0xa6,0x67,0xa3,0x83,0x3c,0x63,0x1e,0x3e,0x77,
+ 0x07,0xa6,0x3e,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x73,0x05,0x72,0x01,0x73,0x01,
+ 0x3c,0x7f,0x72,0x01,0x97,0x32,0x27,0x0d,0x07,0xe8,0x26,0x60,0x2b,0x77,0x67,0xb6,
+ 0x03,0xf0,0x06,0x60,0x2e,0x77,0x07,0xb6,0x1a,0x77,0x07,0x85,0x36,0x77,0x6c,0xf0,
+ 0x18,0x01,0x00,0x00,0x2c,0xa4,0x00,0x00,0x80,0xff,0xff,0xff,0x62,0xa4,0x00,0x00,
+ 0x31,0xaa,0x00,0x00,0xac,0x2c,0x00,0x00,0x20,0x9e,0x00,0x00,0x00,0x80,0x02,0x00,
+ 0x58,0x3e,0x00,0x00,0x65,0xa4,0x00,0x00,0x66,0xa4,0x00,0x00,0x67,0xa4,0x00,0x00,
+ 0x68,0xa4,0x00,0x00,0x46,0xa4,0x00,0x00,0x47,0xa4,0x00,0x00,0x48,0xa4,0x00,0x00,
+ 0x49,0xa4,0x00,0x00,0x4a,0xa4,0x00,0x00,0x4b,0xa4,0x00,0x00,0x4c,0xa4,0x00,0x00,
+ 0x4d,0xa4,0x00,0x00,0x59,0xa8,0x00,0x00,0x5c,0xa8,0x00,0x00,0x66,0x9e,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0xba,0x00,0x00,0x00,0x69,0xa4,0x00,0x00,0x6a,0xa4,0x00,0x00,
+ 0x6b,0xa4,0x00,0x00,0x6c,0xa4,0x00,0x00,0x6d,0xa4,0x00,0x00,0x6e,0xa4,0x00,0x00,
+ 0x6f,0xa4,0x00,0x00,0x70,0xa4,0x00,0x00,0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,
+ 0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,0x20,0xaa,0x00,0x00,0xb4,0x00,0x00,0x00,
+ 0xbc,0x00,0x00,0x00,0x4a,0xa0,0x00,0x00,0xa5,0xa0,0x00,0x00,0x60,0xa8,0x00,0x00,
+ 0xef,0x9f,0x00,0x00,0xe4,0xa3,0x00,0x00,0x8a,0x9e,0x00,0x00,0x00,0x03,0x00,0x00,
+ 0x01,0xa1,0x00,0x00,0x02,0xa1,0x00,0x00,0x03,0xa1,0x00,0x00,0x04,0xa1,0x00,0x00,
+ 0xc0,0x0c,0x00,0x00,0x42,0xa4,0x00,0x00,0x07,0xa6,0xb7,0x77,0x07,0xa7,0x87,0x3c,
+ 0x67,0x1e,0x56,0x67,0x56,0x1c,0x06,0xa6,0xb5,0x73,0x35,0x1c,0x05,0xa5,0x56,0x1b,
+ 0x76,0x0d,0xe7,0xe8,0xb3,0x77,0x07,0xa7,0xb3,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,
+ 0xb2,0x77,0x07,0xa7,0x07,0x3d,0x67,0x1e,0xb1,0x76,0x06,0xa6,0x86,0x3d,0x76,0x1e,
+ 0xb0,0x77,0x07,0xa5,0xb0,0x77,0x07,0xa7,0x87,0x3c,0x57,0x1e,0xaf,0x75,0x05,0xa5,
+ 0x05,0x3d,0x75,0x1e,0xae,0x77,0x07,0xa7,0x87,0x3d,0x57,0x1e,0x67,0x0c,0x06,0xe0,
+ 0x06,0x60,0xab,0x77,0x17,0xb6,0x16,0x60,0xab,0x77,0x67,0xb6,0x06,0x60,0xaa,0x77,
+ 0x19,0xf0,0x67,0xa7,0x17,0x2a,0xbd,0xe0,0x1e,0xa6,0x06,0x20,0x46,0x01,0x1e,0xb6,
+ 0xa7,0x74,0x4d,0x1c,0x0d,0xa7,0x17,0x3e,0x67,0x0c,0x04,0xe8,0xa5,0x77,0x07,0xa7,
+ 0x07,0x2a,0x06,0xe8,0x16,0x60,0xa3,0x77,0x07,0xb6,0x06,0x60,0x9e,0x77,0x67,0xb6,
+ 0x16,0x60,0xa1,0x77,0x07,0xb6,0xa5,0xf0,0x26,0x2a,0xa3,0xe0,0x67,0xa6,0x06,0x2a,
+ 0x34,0xe0,0x9e,0x77,0x07,0xa6,0x8c,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x56,0x67,
+ 0xd6,0x1c,0x06,0xa6,0x8a,0x75,0x5d,0x1c,0x0d,0xa5,0x56,0x1b,0x76,0x0d,0x65,0xe8,
+ 0x88,0x77,0x07,0xa7,0x88,0x76,0x06,0xa6,0x86,0x3c,0x76,0x1e,0x87,0x77,0x07,0xa7,
+ 0x07,0x3d,0x67,0x1e,0x86,0x76,0x06,0xa6,0x86,0x3d,0x76,0x1e,0x85,0x77,0x07,0xa5,
+ 0x85,0x77,0x07,0xa7,0x87,0x3c,0x57,0x1e,0x84,0x75,0x05,0xa5,0x05,0x3d,0x75,0x1e,
+ 0x83,0x77,0x07,0xa7,0x87,0x3d,0x57,0x1e,0x67,0x0c,0x47,0xe0,0x06,0x60,0x80,0x77,
+ 0x17,0xb6,0x16,0x60,0x80,0x77,0x67,0xb6,0x40,0xf0,0x67,0xa7,0x17,0x2a,0x3d,0xe0,
+ 0x1e,0xa6,0x06,0x20,0x46,0x01,0x1e,0xb6,0x7d,0x77,0xd7,0x1c,0x07,0xa7,0x17,0x3e,
+ 0x67,0x0c,0x04,0xe8,0x7b,0x77,0x07,0xa7,0x07,0x2a,0x2c,0xe8,0x76,0x73,0x16,0x60,
+ 0x79,0x77,0x07,0xb6,0x7b,0x76,0x06,0xa6,0x7b,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,
+ 0x7a,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x79,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,
+ 0x6c,0x74,0x44,0xa5,0x54,0xa6,0x86,0x3c,0x56,0x1e,0x64,0xa5,0x05,0x3d,0x65,0x1e,
+ 0x74,0xa6,0x86,0x3d,0x56,0x1e,0x67,0x05,0x72,0x76,0xd6,0x1c,0x06,0xa5,0x71,0x76,
+ 0x6d,0x1c,0x0d,0xa6,0x86,0x3c,0x56,0x1e,0x76,0x0c,0x02,0xe0,0x27,0x60,0x01,0xf0,
+ 0x07,0x60,0x63,0xb7,0x06,0x60,0x60,0x77,0x07,0xb6,0x5e,0x73,0x63,0xa7,0x07,0x2a,
+ 0x28,0xe0,0x63,0x76,0x06,0xa6,0x63,0x77,0x07,0xa7,0x87,0x3c,0x67,0x1e,0x62,0x76,
+ 0x06,0xa6,0x06,0x3d,0x76,0x1e,0x61,0x77,0x07,0xa7,0x87,0x3d,0x67,0x1e,0x54,0x74,
+ 0x44,0xa5,0x54,0xa6,0x86,0x3c,0x56,0x1e,0x64,0xa5,0x05,0x3d,0x65,0x1e,0x74,0xa6,
+ 0x86,0x3d,0x56,0x1e,0x67,0x05,0x5c,0x76,0x06,0x86,0x59,0x75,0x65,0x1c,0x05,0xa5,
+ 0x59,0x78,0x86,0x1c,0x06,0xa6,0x86,0x3c,0x56,0x1e,0x76,0x0c,0x02,0xe0,0x27,0x60,
+ 0x63,0xb7,0x48,0x75,0x65,0xa5,0x25,0x2a,0xfb,0xe0,0x45,0x76,0x07,0x60,0x16,0xb7,
+ 0x36,0xb7,0x4b,0x74,0x04,0xa4,0x4b,0x77,0x07,0xa7,0x87,0x3c,0x47,0x1e,0x4a,0x74,
+ 0x04,0xa4,0x04,0x3d,0x74,0x1e,0x49,0x77,0x07,0xa7,0x87,0x3d,0x47,0x1e,0x46,0xb7,
+ 0x17,0x01,0x56,0xb1,0x27,0x01,0x66,0xb1,0x87,0x3f,0x76,0xb7,0x06,0xb5,0xe0,0xf0,
+ 0x26,0x2a,0xdb,0xe0,0x2e,0xa6,0x06,0x2a,0xda,0xe8,0x17,0x2a,0xd2,0xe0,0x43,0x7c,
+ 0x0c,0xa2,0x5d,0xa3,0x43,0x7b,0x00,0x9b,0x34,0x60,0x42,0x75,0x43,0x76,0x07,0x60,
+ 0x43,0x7f,0x0c,0xa2,0x5d,0xa3,0x49,0x67,0xd9,0x1c,0x09,0xa7,0x0e,0x60,0x00,0x9e,
+ 0xc4,0x60,0xb5,0x12,0xe6,0x12,0x3d,0x7f,0x3e,0x7a,0x0a,0x88,0xb0,0x98,0x0c,0xa2,
+ 0x5d,0xa3,0x3c,0x78,0xd8,0x1c,0x08,0xa6,0x3c,0x71,0xd1,0x1c,0xa0,0x91,0x01,0xa7,
+ 0x87,0x3c,0x67,0x1e,0x07,0x3d,0x00,0x9e,0xd4,0x60,0xb5,0x12,0xe6,0x12,0x07,0x3b,
+ 0x33,0x7f,0x0a,0x82,0xc0,0x92,0x0c,0xa2,0x1c,0xa3,0x34,0x74,0x85,0x61,0x34,0x7f,
+ 0x0c,0xa2,0x5d,0xa3,0x09,0xa7,0x00,0x9e,0xc4,0x60,0xb5,0x12,0xe6,0x12,0x2b,0x7f,
+ 0x0a,0x89,0x0c,0xa2,0x5d,0xa3,0x08,0xa6,0xa0,0x88,0x08,0xa7,0x87,0x3c,0x67,0x1e,
+ 0x07,0x3d,0x00,0x9e,0xd4,0x60,0xb5,0x12,0xe6,0x12,0x07,0x3b,0x24,0x7f,0x0a,0x87,
+ 0xb0,0x8b,0x0b,0x2a,0x03,0xe0,0xc0,0x8c,0x0c,0x2a,0x04,0xe8,0x09,0x2a,0xd3,0xe0,
+ 0x07,0x2a,0xd1,0xe0,0x0b,0x7e,0x46,0xf0,0x43,0xa4,0x00,0x00,0xbd,0x00,0x00,0x00,
+ 0x56,0xa4,0x00,0x00,0x57,0xa4,0x00,0x00,0x58,0xa4,0x00,0x00,0x59,0xa4,0x00,0x00,
+ 0x52,0xa4,0x00,0x00,0x53,0xa4,0x00,0x00,0x54,0xa4,0x00,0x00,0x55,0xa4,0x00,0x00,
+ 0x66,0x9e,0x00,0x00,0x20,0xaa,0x00,0x00,0xa5,0xa0,0x00,0x00,0xb9,0x00,0x00,0x00,
+ 0x72,0xa4,0x00,0x00,0x31,0xaa,0x00,0x00,0x62,0xa4,0x00,0x00,0x42,0xa4,0x00,0x00,
+ 0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,0x3a,0xaa,0x00,0x00,
+ 0xbe,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x1c,0x9e,0x00,0x00,0x20,0x9e,0x00,0x00,
+ 0x00,0x00,0x03,0x18,0x00,0x00,0x06,0x18,0x00,0x00,0x02,0x18,0xb4,0x26,0x00,0x00,
+ 0x34,0x0a,0x04,0x00,0xb5,0x00,0x00,0x00,0xb6,0x00,0x00,0x00,0x00,0xa0,0x02,0x00,
+ 0x48,0x2a,0x00,0x00,0x1e,0xa7,0x07,0x20,0x47,0x01,0x1e,0xb7,0x2d,0x60,0x7d,0x0c,
+ 0x37,0xe0,0x07,0x60,0x3e,0xb7,0x1e,0xb7,0x56,0x7f,0x56,0x76,0x06,0xa6,0x56,0x77,
+ 0x07,0xa7,0x87,0x3c,0x67,0x1e,0x55,0x76,0x06,0xa6,0x06,0x3d,0x76,0x1e,0x54,0x77,
+ 0x07,0xa7,0x87,0x3d,0x67,0x1e,0x4e,0xb7,0x17,0x01,0x5e,0xb1,0x27,0x01,0x6e,0xb1,
+ 0x87,0x3f,0x7e,0xb7,0x0e,0xbd,0x1c,0xf0,0x37,0xbf,0x0c,0xac,0x0e,0xa6,0x86,0x3c,
+ 0xc6,0x1e,0x02,0xa5,0x05,0x3d,0x65,0x1e,0x03,0xa6,0x86,0x3d,0x56,0x1e,0x47,0xb6,
+ 0x16,0x01,0x57,0xb1,0x26,0x01,0x67,0xb1,0x86,0x3f,0x77,0xb6,0x26,0x60,0x07,0xb6,
+ 0x07,0xf0,0x27,0x2a,0x05,0xe0,0x43,0x7f,0x03,0xf0,0x36,0x2a,0x01,0xe0,0x42,0x7f,
+ 0x43,0x76,0xd6,0xa5,0xe6,0xa7,0x87,0x3c,0x57,0x1e,0x7f,0x12,0x6f,0x01,0xa6,0xa5,
+ 0x05,0x2a,0x68,0xe8,0x3f,0x75,0x05,0x82,0x3f,0x75,0x25,0x1c,0x05,0xa4,0x04,0x2a,
+ 0x61,0xe0,0x3d,0x75,0x05,0xc3,0x03,0x20,0x63,0x01,0x05,0xd3,0xb6,0xae,0xc6,0xa6,
+ 0x86,0x3c,0xe6,0x1e,0x63,0x0c,0x56,0xe8,0x05,0xd4,0x42,0xaa,0x15,0x60,0x37,0x7b,
+ 0xac,0x61,0x7f,0x01,0x37,0x73,0xfd,0x12,0x0d,0x28,0x1c,0xf0,0x96,0x12,0x46,0x1c,
+ 0x66,0x1c,0xbe,0x12,0x6e,0x1c,0x0e,0xce,0xe1,0x12,0x71,0x01,0x36,0x1c,0x1f,0x0d,
+ 0x03,0xe8,0x06,0xce,0x7e,0x05,0x07,0xf0,0xd1,0x0d,0x03,0xe8,0x06,0xce,0x7e,0x1c,
+ 0x02,0xf0,0x06,0xc1,0x1e,0x14,0x06,0xde,0x04,0x20,0x44,0x01,0x48,0x0c,0xe6,0xe7,
+ 0x05,0x20,0x45,0x01,0x5a,0x0c,0x2e,0xe8,0x52,0xa8,0x14,0x60,0x59,0x12,0xf1,0x11,
+ 0xc9,0x03,0xf9,0x11,0xf3,0xf7,0x1d,0x77,0x0f,0x60,0x17,0xbf,0x16,0x7c,0x0c,0xa5,
+ 0x16,0x7e,0x0e,0xa6,0x86,0x3c,0x56,0x1e,0x15,0x72,0x02,0xa5,0x05,0x3d,0x65,0x1e,
+ 0x14,0x73,0x03,0xa6,0x86,0x3d,0x56,0x1e,0x47,0xa4,0x57,0xa5,0x85,0x3c,0x45,0x1e,
+ 0x67,0xa4,0x04,0x3d,0x54,0x1e,0x77,0xa5,0x85,0x3d,0x45,0x1e,0x56,0x05,0x15,0x75,
+ 0xd5,0x1c,0x05,0xa4,0x15,0x71,0x1d,0x1c,0x0d,0xa5,0x85,0x3c,0x45,0x1e,0x65,0x0c,
+ 0x73,0xef,0x8e,0xf7,0x01,0x64,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,0x00,0x00,
+ 0xac,0x2c,0x00,0x00,0x37,0xaa,0x00,0x00,0x38,0xaa,0x00,0x00,0x39,0xaa,0x00,0x00,
+ 0x3a,0xaa,0x00,0x00,0xaa,0x41,0x00,0x00,0x94,0x3f,0x00,0x00,0x66,0x9e,0x00,0x00,
+ 0x1c,0x9e,0x00,0x00,0x11,0x01,0x00,0x00,0x62,0xa8,0x00,0x00,0x00,0xe0,0x02,0x00,
+ 0x00,0xc0,0x02,0x00,0xb7,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x70,0x24,0x7e,0x00,
+ 0xf1,0x60,0x41,0x0c,0x38,0xe0,0x37,0x12,0x27,0x1e,0x37,0x2e,0x07,0x2a,0x3f,0xe0,
+ 0x36,0x12,0x27,0x12,0x45,0x12,0x06,0x8f,0x07,0x9f,0x16,0x8f,0x17,0x9f,0x26,0x8f,
+ 0x27,0x9f,0x36,0x8f,0x37,0x9f,0xf7,0x20,0xf6,0x20,0xf5,0x24,0x51,0x0c,0xf3,0xef,
+ 0x46,0x12,0xf6,0x24,0x46,0x3e,0x06,0x20,0x46,0x3c,0x27,0x12,0x67,0x1c,0x63,0x1c,
+ 0xf4,0x2e,0x3e,0x60,0x4e,0x0c,0x1e,0xe0,0x31,0x12,0x75,0x12,0x46,0x12,0x01,0x8f,
+ 0x05,0x9f,0x35,0x20,0x31,0x20,0x36,0x24,0x6e,0x0c,0xf9,0xef,0x45,0x12,0x35,0x24,
+ 0x25,0x3e,0x05,0x20,0x25,0x3c,0x34,0x2e,0x53,0x1c,0x57,0x1c,0x04,0x2a,0x05,0xe0,
+ 0x6e,0x00,0x70,0x20,0xcf,0x00,0x27,0x12,0x05,0xf0,0x03,0xa6,0x07,0xb6,0x07,0x20,
+ 0x03,0x20,0x04,0x24,0x04,0x2a,0xf9,0xe7,0x6e,0x00,0x70,0x20,0xcf,0x00,0x27,0x12,
+ 0xf4,0xf7,0x70,0x24,0x00,0x9f,0x37,0x60,0x72,0x0e,0x4c,0xe8,0x04,0x2a,0x47,0xe8,
+ 0x04,0x24,0x03,0x01,0x27,0x12,0x05,0xf0,0x46,0x12,0x06,0x24,0x04,0x2a,0x3f,0xe8,
+ 0x64,0x12,0x07,0xb1,0x07,0x20,0x36,0x60,0x67,0x0e,0xf6,0xe7,0x36,0x60,0x46,0x0c,
+ 0x2e,0xe0,0x85,0x2c,0x35,0x16,0x56,0x12,0x86,0x3c,0x56,0x1e,0x65,0x12,0x05,0x3d,
+ 0x65,0x1e,0xff,0x60,0x4f,0x0c,0x30,0xe0,0x76,0x12,0x41,0x12,0x06,0x95,0x16,0x95,
+ 0x26,0x95,0x36,0x95,0xf6,0x20,0xf1,0x24,0x1f,0x0c,0xf8,0xef,0x41,0x12,0xf1,0x24,
+ 0x41,0x3e,0x01,0x20,0x41,0x3c,0x71,0x1c,0xf4,0x2e,0x37,0x60,0x47,0x0c,0x1e,0xe0,
+ 0x16,0x12,0x47,0x12,0x3f,0x60,0x06,0x95,0x36,0x20,0x37,0x24,0x7f,0x0c,0xfb,0xef,
+ 0x47,0x12,0x37,0x24,0x27,0x3e,0x07,0x20,0x27,0x3c,0x34,0x2e,0x17,0x1c,0x04,0x2a,
+ 0x06,0xe8,0x43,0x01,0x07,0xb3,0x07,0x20,0x04,0x24,0x04,0x2a,0xfb,0xe7,0x00,0x8f,
+ 0x70,0x20,0xcf,0x00,0x27,0x12,0xc2,0xf7,0x71,0x12,0xe2,0xf7,0x17,0x12,0xef,0xf7,
+ 0x02,0x2a,0x19,0xe8,0x03,0x2a,0x02,0xe0,0x0b,0x00,0x15,0xf0,0x07,0x60,0x21,0x12,
+ 0x34,0x12,0xf1,0x37,0x03,0xe8,0xf1,0x33,0x01,0xf0,0x14,0x3c,0x41,0x0f,0x02,0xe8,
+ 0x41,0x0c,0xfb,0xe7,0x01,0xf0,0x14,0x3e,0x42,0x0c,0x01,0xe8,0x42,0x05,0x77,0x06,
+ 0x43,0x0c,0xf9,0xef,0x72,0x12,0xcf,0x00,0x02,0x2a,0x18,0xe8,0x03,0x2a,0x02,0xe0,
+ 0x0b,0x00,0x14,0xf0,0x07,0x60,0x21,0x12,0x34,0x12,0xf1,0x37,0x03,0xe8,0xf1,0x33,
+ 0x01,0xf0,0x14,0x3c,0x41,0x0f,0x02,0xe8,0x41,0x0c,0xfb,0xe7,0x01,0xf0,0x14,0x3e,
+ 0x42,0x0c,0x01,0xe8,0x42,0x05,0x77,0x06,0x43,0x0c,0xf9,0xef,0xcf,0x00,0x03,0x2a,
+ 0x02,0xe0,0x0b,0x00,0x16,0xf0,0x07,0x60,0x31,0x12,0x21,0x17,0xe2,0x01,0xe3,0x01,
+ 0x34,0x12,0x01,0xf0,0x14,0x3c,0x42,0x0c,0xfd,0xe7,0x01,0xf0,0x14,0x3e,0x42,0x0c,
+ 0x01,0xe8,0x42,0x05,0x77,0x06,0x43,0x0c,0xf9,0xef,0xf1,0x37,0x01,0xe8,0x07,0x28,
+ 0x72,0x12,0xcf,0x00,0x25,0x12,0xe2,0x01,0xe3,0x01,0x01,0x60,0x14,0x60,0x03,0x2a,
+ 0x01,0xe0,0x0b,0x00,0x27,0x12,0x07,0x2a,0x02,0xe0,0x02,0x60,0xcf,0x00,0x30,0x24,
+ 0x00,0x91,0xf6,0x61,0x71,0x12,0x61,0x0b,0x01,0x2a,0x03,0xe8,0xf6,0x29,0x67,0x12,
+ 0x08,0xf0,0x06,0x24,0x71,0x12,0x61,0x0b,0x01,0x2a,0xf8,0xe7,0x06,0x2a,0xf2,0xe7,
+ 0x07,0x62,0x00,0x81,0x30,0x20,0x74,0x1b,0x72,0x1b,0x02,0x3c,0x11,0x06,0x31,0x0c,
+ 0x01,0xe8,0x31,0x05,0x44,0x06,0xf9,0xef,0x12,0x12,0xf5,0x37,0x01,0xe8,0x02,0x28,
+ 0xcf,0x00,0xf0,0x25,0x60,0x92,0x70,0x93,0x40,0x94,0x50,0x95,0x07,0x2d,0x27,0x16,
+ 0x25,0x12,0x05,0x3f,0x06,0x2d,0x46,0x16,0x41,0x12,0x01,0x3f,0x63,0x12,0x73,0x03,
+ 0x17,0x03,0x56,0x03,0x15,0x03,0x67,0x1c,0x31,0x12,0x01,0x3f,0x17,0x1c,0x67,0x0c,
+ 0x02,0xe0,0x06,0x33,0x65,0x1c,0x76,0x12,0x06,0x3f,0x56,0x1c,0x10,0x96,0x07,0x3d,
+ 0x06,0x2d,0x63,0x16,0x37,0x1c,0x00,0x97,0x00,0x86,0x10,0x87,0x20,0x96,0x30,0x97,
+ 0x50,0x87,0x27,0x03,0x70,0x86,0x46,0x03,0x67,0x1c,0x20,0x82,0x30,0x83,0x73,0x1c,
+ 0xf0,0x21,0xcf,0x00,0xf0,0x25,0x78,0x00,0x81,0x62,0x10,0x05,0x40,0x92,0x50,0x93,
+ 0x20,0x94,0x30,0x95,0x4d,0x12,0x57,0x12,0x2b,0x12,0x3e,0x12,0x05,0x2a,0x58,0xe0,
+ 0x43,0x0c,0x76,0xe0,0x06,0x2d,0x46,0x0c,0xd4,0xe0,0x87,0x2d,0x47,0x0c,0x8b,0xe9,
+ 0x07,0x61,0x75,0x12,0x9f,0x76,0xd3,0x12,0x73,0x0b,0x36,0x1c,0x06,0xa6,0x56,0x1c,
+ 0x07,0x62,0x67,0x05,0x07,0x2a,0x06,0xe8,0x7d,0x1b,0x7e,0x1b,0xb4,0x12,0x64,0x0b,
+ 0x4e,0x1e,0x7b,0x1b,0xdc,0x12,0x0c,0x3f,0x09,0x2d,0xd9,0x16,0xe2,0x12,0xc3,0x12,
+ 0x95,0x7f,0x28,0x12,0xe2,0x12,0xc3,0x12,0x94,0x7f,0x2a,0x12,0x2e,0x12,0x9e,0x03,
+ 0x08,0x3d,0xb7,0x12,0x07,0x3f,0x78,0x1e,0xe8,0x0c,0x08,0xe0,0x27,0x12,0x07,0x24,
+ 0xd8,0x1c,0xd8,0x0c,0x02,0xe8,0xe8,0x0c,0x8d,0xe9,0x7a,0x12,0x8e,0x14,0xe2,0x12,
+ 0xc3,0x12,0x88,0x7f,0x28,0x12,0xe2,0x12,0xc3,0x12,0x87,0x7f,0x27,0x12,0x29,0x03,
+ 0x08,0x3d,0x05,0x2d,0x5b,0x16,0xb8,0x1e,0x98,0x0c,0x08,0xe0,0x26,0x12,0x06,0x24,
+ 0xd8,0x1c,0xd8,0x0c,0x4b,0xe9,0x98,0x0c,0x49,0xe1,0x17,0x24,0xa2,0x12,0x02,0x3d,
+ 0x72,0x1e,0x0c,0x60,0xc3,0x12,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,
+ 0x53,0x0c,0x77,0xe8,0x06,0x2d,0x56,0x0c,0x76,0xe0,0x86,0x2d,0x56,0x0c,0x45,0xe9,
+ 0x05,0x61,0x54,0x12,0x73,0x76,0x73,0x12,0x53,0x0b,0x36,0x1c,0x06,0xa6,0x46,0x1c,
+ 0x0c,0x62,0x6c,0x05,0x0c,0x2a,0x79,0xe0,0x12,0x60,0xe7,0x0c,0x03,0xe8,0xdb,0x0c,
+ 0x01,0xe0,0xc2,0x12,0xc3,0x12,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,0xcf,0x00,
+ 0x04,0x2a,0x04,0xe0,0x12,0x60,0x43,0x12,0x68,0x7f,0x2d,0x12,0x07,0x2d,0xd7,0x0c,
+ 0x5e,0xe0,0x87,0x2d,0xd7,0x0c,0x27,0xe9,0x06,0x61,0x65,0x12,0x61,0x77,0xd3,0x12,
+ 0x63,0x0b,0x37,0x1c,0x07,0xa6,0x56,0x1c,0x07,0x62,0x67,0x05,0x07,0x2a,0xbe,0xe0,
+ 0xde,0x05,0xda,0x12,0x0a,0x3f,0x08,0x2d,0xd8,0x16,0x1c,0x60,0xe2,0x12,0xa3,0x12,
+ 0x59,0x7f,0x60,0x92,0xe2,0x12,0xa3,0x12,0x58,0x7f,0x29,0x12,0x27,0x12,0x87,0x03,
+ 0x60,0x8e,0x0e,0x3d,0xb6,0x12,0x06,0x3f,0x6e,0x1e,0x7e,0x0c,0x08,0xe0,0x26,0x12,
+ 0x06,0x24,0xde,0x1c,0xde,0x0c,0x02,0xe8,0x7e,0x0c,0x11,0xe9,0x69,0x12,0x7e,0x05,
+ 0xe2,0x12,0xa3,0x12,0x4c,0x7f,0x60,0x92,0xe2,0x12,0xa3,0x12,0x4b,0x7f,0x26,0x12,
+ 0x28,0x03,0x60,0x87,0x07,0x3d,0x03,0x2d,0x3b,0x16,0xb7,0x1e,0x87,0x0c,0x08,0xe0,
+ 0x25,0x12,0x05,0x24,0xd7,0x1c,0xd7,0x0c,0xd3,0xe8,0x87,0x0c,0xd1,0xe0,0x16,0x24,
+ 0x92,0x12,0x02,0x3d,0x62,0x1e,0xc3,0x12,0x81,0x62,0x10,0x1c,0x68,0x00,0xf0,0x21,
+ 0xcf,0x00,0x0c,0x60,0x9e,0xf7,0x86,0x2c,0x56,0x0c,0xd2,0xe8,0x05,0x60,0x54,0x12,
+ 0x89,0xf7,0x86,0x2c,0x46,0x0c,0xb8,0xe0,0x87,0x60,0x75,0x12,0x2b,0xf7,0x87,0x2c,
+ 0xd7,0x0c,0xcc,0xe8,0x06,0x60,0x65,0x12,0xa1,0xf7,0x7a,0x12,0xca,0x1b,0xd7,0x12,
+ 0x67,0x0b,0x7a,0x1e,0xcd,0x1b,0x60,0x9d,0xe8,0x12,0x68,0x0b,0xe9,0x12,0xc9,0x1b,
+ 0xb7,0x12,0x67,0x0b,0x79,0x1e,0xad,0x12,0x0d,0x3f,0x04,0x2d,0xa4,0x16,0x70,0x94,
+ 0x82,0x12,0xd3,0x12,0x28,0x7f,0x2e,0x12,0x82,0x12,0xd3,0x12,0x27,0x7f,0x28,0x12,
+ 0x70,0x87,0x27,0x03,0x0e,0x3d,0x96,0x12,0x06,0x3f,0x6e,0x1e,0x7e,0x0c,0x06,0xe0,
+ 0x26,0x12,0x06,0x24,0xae,0x1c,0xae,0x0c,0xa9,0xe0,0x68,0x12,0x7e,0x05,0xe2,0x12,
+ 0xd3,0x12,0x1c,0x7f,0x80,0x92,0xe2,0x12,0xd3,0x12,0x1b,0x7f,0x70,0x86,0x26,0x03,
+ 0x80,0x87,0x07,0x3d,0x05,0x2d,0x59,0x16,0x97,0x1e,0x67,0x0c,0x06,0xe0,0x25,0x12,
+ 0x05,0x24,0xa7,0x1c,0xa7,0x0c,0x8d,0xe0,0x52,0x12,0x76,0x14,0x08,0x3d,0x28,0x1e,
+ 0x07,0x2d,0x87,0x16,0x84,0x12,0x04,0x3f,0x60,0x85,0x03,0x2d,0x35,0x16,0x60,0x8d,
+ 0x0d,0x3f,0x73,0x12,0x53,0x03,0xd7,0x03,0x45,0x03,0x4d,0x03,0x57,0x1c,0x34,0x12,
+ 0x04,0x3f,0x47,0x1c,0x57,0x0c,0x02,0xe0,0x04,0x33,0x4d,0x1c,0x75,0x12,0x05,0x3f,
+ 0xd5,0x1c,0x56,0x0c,0x5e,0xe8,0x56,0x0f,0x55,0xe8,0x82,0x12,0x0c,0x60,0x2a,0xf7,
+ 0x8c,0x05,0x00,0x00,0x08,0x84,0x00,0x00,0xd0,0x83,0x00,0x00,0x7d,0x1b,0xe9,0x12,
+ 0x69,0x0b,0xec,0x12,0x7c,0x1b,0xb4,0x12,0x64,0x0b,0x4c,0x1e,0x7b,0x1b,0xda,0x12,
+ 0x0a,0x3f,0x08,0x2d,0xd8,0x16,0x92,0x12,0xa3,0x12,0x34,0x7f,0x2e,0x12,0x92,0x12,
+ 0xa3,0x12,0x33,0x7f,0x29,0x12,0x27,0x12,0x87,0x03,0x0e,0x3d,0xc6,0x12,0x06,0x3f,
+ 0x6e,0x1e,0x7e,0x0c,0x09,0xe0,0x26,0x12,0x06,0x24,0xde,0x1c,0xde,0x0c,0x4d,0xe8,
+ 0x7e,0x0c,0x4b,0xe0,0x19,0x24,0xde,0x1c,0x7e,0x05,0xe2,0x12,0xa3,0x12,0x27,0x7f,
+ 0x60,0x92,0xe2,0x12,0xa3,0x12,0x26,0x7f,0x27,0x12,0x87,0x03,0x60,0x8e,0x0e,0x3d,
+ 0x05,0x2d,0x5c,0x16,0xce,0x1e,0x7e,0x0c,0x09,0xe0,0x26,0x12,0x06,0x24,0xde,0x1c,
+ 0xde,0x0c,0x31,0xe8,0x7e,0x0c,0x2f,0xe0,0x12,0x24,0xde,0x1c,0x7e,0x05,0x9c,0x12,
+ 0x0c,0x3d,0x2c,0x1e,0x03,0xf7,0x87,0x61,0x75,0x12,0x74,0xf6,0x67,0x12,0xb6,0xf6,
+ 0x56,0x12,0x2e,0xf7,0xcb,0x1b,0x07,0x3d,0x05,0x2d,0x53,0x16,0x37,0x1c,0x7b,0x0c,
+ 0xa4,0xe7,0x82,0x12,0x02,0x24,0x0c,0x60,0xcd,0xf6,0x85,0x61,0x54,0x12,0xba,0xf6,
+ 0x85,0x60,0x54,0x12,0xb7,0xf6,0x86,0x61,0x65,0x12,0xd8,0xf6,0x86,0x60,0x65,0x12,
+ 0xd5,0xf6,0x67,0x0c,0x71,0xe7,0x12,0x24,0xa7,0x1c,0x6f,0xf7,0x7e,0x0c,0x55,0xe7,
+ 0x18,0x24,0xae,0x1c,0x53,0xf7,0x62,0x12,0xd1,0xf7,0x69,0x12,0xb5,0xf7,0x19,0x24,
+ 0xde,0x1c,0xed,0xf6,0x1a,0x24,0xd8,0x1c,0x71,0xf6,0x00,0x00,0x08,0x84,0x00,0x00,
+ 0xd0,0x83,0x00,0x00,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x70,0x24,0x7e,0x00,
+ 0x0e,0x7f,0x06,0x66,0x0e,0x77,0x07,0xb6,0x0e,0x7f,0x0e,0x7f,0x0f,0x72,0x43,0x60,
+ 0x0f,0x7f,0x0f,0x7f,0x10,0x7f,0x10,0x7f,0x11,0x7e,0x0e,0xa7,0x17,0x2a,0x07,0xe8,
+ 0x07,0x2a,0x03,0xe8,0x27,0x2a,0xf9,0xe7,0x04,0xf0,0x0d,0x7f,0xf6,0xf7,0x0d,0x7f,
+ 0xf4,0xf7,0x0d,0x7f,0xf2,0xf7,0x00,0x00,0x40,0x08,0x00,0x00,0x20,0x01,0x04,0x00,
+ 0xaa,0x08,0x00,0x00,0x6c,0x26,0x00,0x00,0x80,0xc3,0xc9,0x01,0x9a,0x23,0x00,0x00,
+ 0x40,0x1b,0x00,0x00,0xec,0x0d,0x00,0x00,0x98,0x09,0x00,0x00,0x20,0xaa,0x00,0x00,
+ 0x88,0x1b,0x00,0x00,0x88,0x1c,0x00,0x00,0xfc,0x1c,0x00,0x00,0xbe,0xbe,0xbe,0xbe,
+ 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig new file mode 100755 index 00000000..34cf42cb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_LW86X0
+ tristate "LW86X0 Touchscreen Driver"
+ default y
+ depends on ARCH_WMT
+ ---help---
+ Say Y here if you have an WMT based board with touchscreen
+ attached to it.
+ If unsure, say N.
+ To compile this driver as a module, choose M here: the
+ module will be called lw86x0_ts.
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile new file mode 100755 index 00000000..a7cbba75 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/Makefile @@ -0,0 +1,34 @@ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_lw86x0
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := lw86x0_ts.o wmt_ts.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c new file mode 100755 index 00000000..ce741c9c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.c @@ -0,0 +1,1321 @@ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +//#include <linux/earlysuspend.h> +#include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> +#include <linux/pm_runtime.h> + +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include <linux/earlysuspend.h> +#endif +#include <linux/input/mt.h> + +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <mach/hardware.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/suspend.h> +#include <linux/async.h> +#include <linux/wait.h> +#include <linux/hrtimer.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/kthread.h> +#include <linux/firmware.h> +#include <linux/power/wmt_battery.h> +#include "../../../video/backlight/wmt_bl.h" +#include "lw86x0_ts.h" +#include "wmt_ts.h" +//#include "wmt_custom_lw86x0.h" + +#define TIME_CHECK_CHARGE 3000 + +#define MAX_MULTI_DATA_SIZE 256 + +#define HDMI_BASE_ADDR (HDMI_TRANSMITTE_BASE_ADDR + 0xC000) +#define REG_HDMI_HOTPLUG_DETECT (HDMI_BASE_ADDR + 0x3ec) + +struct i2c_client *lw_i2c_client = NULL; +struct i2c_client *client;//add by jackie +extern char g_dbgmode; +extern int COL_NUM; +extern int ROW_NUM; +extern int SKIP_ZERO_POINT; + +struct wmtts_device lw86x0_tsdev; +static int tsirq_gpio; + +static int skip_zero_num = 0; + +u16 mcu_status_old = 0xffff; +u16 mcu_status = 0xffff; + +typedef struct Fw_Version{ //add by jackie + u8 magic_num1; + u8 magic_num2; + u8 mj_ver; + u8 mn_ver; +}Fw_Ver;//add by jackie + +//struct for report touch info +struct ts_event { + u16 x[SUPPORT_POINT_NUM_MAX];//point x + u16 y[SUPPORT_POINT_NUM_MAX];//point y + u16 pressure[SUPPORT_POINT_NUM_MAX];//point pressure + u8 touch_point;//touch point number +}; + +struct lw86x0_ts_data { + struct input_dev *input_dev; + struct ts_event event; + struct work_struct touch_event_work; + struct workqueue_struct *ts_workqueue; +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +}l_tsdata; + +static struct mutex ts_data_mutex; +static int l_powermode = -1; +static int l_hdmimode = -1; + +static int l_keylen = 4; +static int l_baseaxis = 1; //0:x-axis,1:y-axis +int l_keypos[TS_KEY_NUM+1][2]; + +unsigned int l_tskey[TS_KEY_NUM][2] = { + {0,KEY_MENU}, + {0,KEY_HOME}, + {0,KEY_BACK}, + {0,KEY_SEARCH}, +}; +static int l_early_suspend = 0; // 1:the early suspend function has been excuted + +static int stop_timer = 0; +struct work_struct phone_status_work; +struct timer_list polling_phone_status_timer; +static int check_chip_status(void); +static int first_init_reg = 1; +static u16 auto_coff_value[20] = {0}; +//static finger_up_status = 1; + +u8 get_fw_file_check_sum(void); +u16 get_fw_check_sum(void); + +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); +//static struct ts_event old_event; + +void swap_byte_in_buffer(u16* buf, int count ) +{ + int i; + for(i = 0; i < count; i++ ) + { + buf[i] = swap16(buf[i]); + } +} + +/** +** for read register +** rxbuf:read value +** txdata:read register address +** rxlength:read value length +**/ + +static int lw86x0_i2c_rxdata(char *rxbuf, char*txdata, int rxlength) +{ + int ret; + //int reg;//add jackie + + struct i2c_msg msgs[] = { + { + .addr = lw_i2c_client->addr, + .flags = 0, + .len = 2, + .buf = txdata, + }, + { + .addr = lw_i2c_client->addr, + .flags = I2C_M_RD, + .len = rxlength, + .buf = rxbuf, + }, + }; + + //ret = wmt_i2c_xfer_continue_if_4(msgs, 2, 1); + + ret = i2c_transfer(lw_i2c_client->adapter, &msgs[0], 2);//add by jackie + if (ret != 2) + { + dbg("msg i2c rxdata error: %d\n", ret); + return -1; + } + else + { + return 0; + } + +#if 0 + struct i2c_msg xfer_msg[2]; + if (reg < 0x80) { + i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)); + msleep(5); + } + return i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)) == ARRAY_SIZE(xfer_msg) ? 0 : -EFAULT; +#endif + +} + +/** +** for write register +** txdata:register address and value u8 +** length:txdata length +**/ + +static int lw86x0_i2c_txdata(char *txdata, int length) +{ + int ret; + + struct i2c_msg msg[] = { + { + .addr = lw_i2c_client->addr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + + + ret = i2c_transfer(lw_i2c_client->adapter, &msg[0], 1);//1 + + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, 1); + if (ret != 1) + { + dbg("i2c txdata error: %d\n", ret); + return -1; + } + else + { + return 0; + } + +} + +/** +** Interface write register for other functions +** addr:write register address +** value:write register value +**/ + +int lw86x0_write_reg(u16 addr, u16 value) +{ + u8 buf[4]; + int ret = -1; + unsigned char * pVal = (unsigned char *) &value; + unsigned char * pOffset = (unsigned char *) &addr; + buf[0] = pOffset[1]; + buf[1] = pOffset[0]; + buf[2] = pVal[1]; + buf[3] = pVal[0]; + ret = lw86x0_i2c_txdata(buf, 4); + if (ret < 0) + { + dbg("lw86x0_write_reg error: %d\n", ret); + return -1; + } + return 0; +} + +/*int lw86x0_write_reg_multi(u16 start_addr, u16 value[], u16 num) +{ + u8 buf[MAX_MULTI_DATA_SIZE]; + int ret = -1; + int i = 0; + unsigned char * pVal = (unsigned char *) &value[0]; + unsigned char * pOffset = (unsigned char *) &addr; + buf[0] = pOffset[1]; + buf[1] = pOffset[0]; + //buf[2] = pVal[1]; + //buf[3] = pVal[0]; + for(i = 0; i < num; i++) + { + pVal = (unsigned char *) &value[i]; + buf[2*i + 2] = pVal[1]; + buf[2*i + 3] = pVal[0]; + } + + ret = lw86x0_i2c_txdata(buf, num*2+2); + + if (ret < 0) + { + dbg("lw86x0_write_reg error: %d\n", ret); + return -1; + } + return 0; +}*/ +/** +** Interface read register for other functions +** addr:read register address +** pdata:read register value +** regcnt:read register count +**/ + +int lw86x0_read_reg(u16 addr, u16 *pdata, int regcnt) +{ + int ret; + + u16 offset_reverse = swap16(addr); + ret = lw86x0_i2c_rxdata((char*)pdata, (char*)&offset_reverse, 2*regcnt); + + if (ret < 0) + { + dbg("lw86x0_read_reg error: %d\n", ret); + return -1; + } + else + { + swap_byte_in_buffer(pdata, regcnt); + return 0; + } +} + +int wmt_ts_load_firmware(char* firmwarename, unsigned char** firmdata, int* fwlen) +{ + int i; + const struct firmware *fw_entry; + for (i = 0; i < 3; i++) { + if(request_firmware(&fw_entry, firmwarename, &lw_i2c_client->dev)!=0) + printk(KERN_ERR "cat't request firmware #%d\n", i); + else + break; + } + if (i == 3) + return -EINVAL; + + if (fw_entry->size <= 0) { + printk(KERN_ERR "load firmware error\n"); + release_firmware(fw_entry); + return -1; + } + + *firmdata = kzalloc(fw_entry->size + 1, GFP_KERNEL); + memcpy(*firmdata, fw_entry->data, fw_entry->size); + *fwlen = fw_entry->size; + release_firmware(fw_entry); + + return 0; +} + +static u16 *default_setting_table; +static int cfg_len; + +static int load_cfgfile(void) +{ + u32 val[2]; + u16 temp[200]; + int i = 0; + char cfgname[32] = {0}; + u8 *pData; + int fileLen; + char *p; + char *s; + + wmt_ts_get_configfilename(cfgname); + if (wmt_ts_load_firmware(cfgname, &pData, &fileLen)) { + errlog("Load config file failed~ \n"); + return -1; + } + s = pData; + p = strstr(s, "COL_NUM"); + sscanf(p, "COL_NUM=%d;", &COL_NUM); + p = strstr(s, "ROW_NUM"); + sscanf(p, "ROW_NUM=%d;", &ROW_NUM); + p = strstr(s, "SKIP_ZERO_POINT"); + sscanf(p, "SKIP_ZERO_POINT=%d;", &SKIP_ZERO_POINT); + dbg("COL_NUM=%d;ROW_NUM=%d;SKIP_ZERO_POINT=%d;",COL_NUM,ROW_NUM,SKIP_ZERO_POINT); + + p = pData; + while (*p != '{') { + p++; + if(*p == '\0') { + errlog("Bad config file\n"); + i = -1; + goto end; + } + } + while (*p != '}') { + if (!strncmp(p, "0x", 2)) { + i++; + if ((i & 0x0001) != 0) { + sscanf(p, "0x%x,0x%x,", val, val+1); + temp[i-1] = val[0] & 0x0000FFFF; + temp[i] = val[1] & 0x0000FFFF; + } + } + p++; + if(*p == '\0') { + i = -1; + errlog("Bad config file\n"); + goto end; + } + }; + + dbg("the number of data:0x%x\n", i); + default_setting_table = kzalloc(i*2, GFP_KERNEL); + memcpy(default_setting_table, temp, i*2); + cfg_len = i; + + dbg("paring config file end.\n"); +end: + kfree(pData); + return i; +} + +void lw86x0_stop_timer(int flags) +{ + stop_timer = flags; +} + + +static u16 get_trim_info(void) +{ + u16 trim_info = 0; + u8 buf[2] = {0}; + lw86x0_write_reg(0x00e4, 0x0000); + lw86x0_write_reg(0x00e2, 0x0302); + lw86x0_write_reg(0x00e3, 0x0000); + lw86x0_write_reg(0x00e2, 0x034e); + lw86x0_write_reg(0x00e2, 0x0302); + lw86x0_read_reg(0x00e4, buf, 1); + lw86x0_write_reg(0x00e2, 0x0000); + trim_info = buf[1]; + dbg("trim info is %04x",trim_info); + return trim_info; +} + +/** +** load default register setting +**/ + +void lw86x0_load_def_setting(void) +{ + int i = 0; + u16 trim_value = 0; + u16 trim_info = 0; + + lw86x0_write_reg(0x00e6, 0x3311); + trim_info = get_trim_info(); + for(i = 0; i < cfg_len / 2; i++) + { + if(default_setting_table[2*i] == 0xffff) + { + msleep(default_setting_table[2*i+1]); + } + else + { + if(default_setting_table[2*i] == 0x00ee) + { + lw86x0_read_reg(0x00ee, &trim_value, 1); + if(trim_value == 0x00a0) + { + trim_value = 0x00c0 + trim_info; + } + else + { + trim_value = 0x100 + trim_value; + } + lw86x0_write_reg(0x00ee, trim_value); + } + else + { + lw86x0_write_reg(default_setting_table[2*i], default_setting_table[2*i+1]); + } + //lw86x0_write_reg(default_setting_table[2*i], default_setting_table[2*i+1]); + } + /*if(i == 0) + { + msleep(100); + }*/ + } + if(first_init_reg == 1) + { + for(i = 0; i < 19; i++) + { + lw86x0_read_reg(0x0092+i, &auto_coff_value[i], 1); + } + first_init_reg = 0; + } + else + { + lw86x0_write_reg(0x0035, 0x0070); + lw86x0_write_reg(0x0060, 0x0307); + lw86x0_write_reg(0x0091, 0x0200); + for(i = 0; i < 19; i++) + { + lw86x0_write_reg(0x0092+i, auto_coff_value[i]); + } + lw86x0_write_reg(0x0035, 0x2070); + msleep(100); + lw86x0_write_reg(0x0060, 0x0306); + } +} + +/** +** set reset pin for lw86x0 +**/ + +static void lw86x0_hw_reset(void) +{ + wmt_rst_output(0); + //msleep(500); + msleep(30); + wmt_rst_output(1); +} + +static void lw86x0_ts_release(void) +{ + int i = 0; + struct lw86x0_ts_data *data = &l_tsdata; + int down = 0; + + // dbg("lw86x0_ts_release"); + + for (i = 0; i < l_keylen; i++) + { + down |= l_tskey[i][0]; + } + if (down != 0) + { + // if down clear the flag + for ( i = 0; i < l_keylen; i++) + { + l_tskey[i][0] = 0; + }; + //dbg("key up!\n"); + if (wmt_ts_enable_keyled()) + wmt_ts_turnoff_light(); + } + else + { + if (!lw86x0_tsdev.penup) + { + input_mt_sync(data->input_dev); + input_sync(data->input_dev); + //dbg("rpt pen\n"); + } + lw86x0_tsdev.penup = 1; + //dbg("pen up\n"); + //wake_up(&ts_penup_wait_queue); + } +} + +/** +**set wmt touch key count +**/ + +void wmt_ts_set_keylen(int keylen) +{ + l_keylen = keylen; +} + +/** +**set wmt touch baseaxis +**axis:0--x axis,1--y axis. +**/ + +void wmt_ts_set_baseaxis(int axis) +{ + l_baseaxis = axis; +} + +/** +** set wmt touch key info struct keypos +** index:set key number +** min:key min point value +** max:key max point value +**/ + +void wmt_ts_set_keypos(int index, int min,int max) +{ + l_keypos[index][0] = min; + l_keypos[index][1] = max; +} + +/** +** report key info to wmt android +**/ +#if 0 + +static int lw86x0_report_key_info(void) +{ + struct lw86x0_ts_data *data = &l_tsdata; + u16 x, y; + u16 key_stpos,key_vrpos; // the stable and variable position for touch key + int i =0; + lw86x0_read_reg(0x0161, &x, 1); + lw86x0_read_reg(0x016B, &y, 1); + if (wmt_ts_enable_tskey() != 0) + { + switch (l_baseaxis) + { + case 0: + key_stpos = y; + key_vrpos = x; + break; + case 1: + default: + key_stpos = x; + key_vrpos = y; + break; + } + } + for (i=0;i < l_keylen;i++) + { + if ((key_vrpos>=l_keypos[i][0]) && (key_vrpos<=l_keypos[i][1])) + { + // report the key + if (0 == l_tskey[i][0]) + { + input_report_key(data->input_dev, l_tskey[i][1], 1); + input_report_key(data->input_dev, l_tskey[i][1], 0); + input_sync(data->input_dev); + l_tskey[i][0] = 1; + dbg("report tskey:%d\n",i); + if (wmt_ts_enable_keyled()) + wmt_ts_turnon_light(); + } + return 1;//key + } + } + return 0;//no key + +} +#endif + +static void check_mode(void) +{ + int dcin = wmt_charger_is_dc_plugin(); + int hdmiin = (REG32_VAL(REG_HDMI_HOTPLUG_DETECT) & BIT31) >> 31; + + if (dcin == l_powermode && hdmiin == l_hdmimode) + return; + if (!dcin && !hdmiin) { + klog("DC and HDMI removed\n"); + lw86x0_write_reg(0x01e9, 0x0000); + } else { + klog("DC or HDMI in\n"); + lw86x0_write_reg(0x01e9, 0x0001); + } + l_powermode = dcin; + l_hdmimode = hdmiin; +} + +/** +** report touch info to wmt android +** touch_number: touch count +**/ + +static void lw86x0_report_touch_info(u16 touch_number) +{ + struct lw86x0_ts_data *data = &l_tsdata; + struct ts_event *event = &data->event; + u16 i; + + //old_event = *event; + //dbg("Enter into lw86x0_report_touch_info"); + check_mode(); + if(touch_number == 0) + { + input_mt_sync(data->input_dev); + input_sync(data->input_dev); + return; + } + if(touch_number> wmt_ts_get_fingernum()){ + //dbg("Invalid Touch point count is found %d",touch_number); + return; + } + event->touch_point = touch_number; + + //memset(event->x, 0, SUPPORT_POINT_NUM*sizeof(u16) ); + //memset(event->y, 0, SUPPORT_POINT_NUM*sizeof(u16) ); + //memset(event->pressure, 0, SUPPORT_POINT_NUM*sizeof(u16) ); + for( i = 0; i <touch_number; i++ ) + { + lw86x0_read_reg(0x0161+i, &event->x[i], 1); + lw86x0_read_reg(0x016B+i, &event->y[i], 1); + lw86x0_read_reg(0x0175+i, &event->pressure[i], 1); + } + + for (i = 0; i < touch_number; i++) + { + int x = (event->x[i]) & 0x03ff; + int y = (event->y[i]) & 0x03ff; + int id = ((event->x[i])>>12)&0x000f; + int tmp; + + if(x>wmt_ts_get_resolvX()) + { + x = wmt_ts_get_resolvX(); + } + + if(y>wmt_ts_get_resolvY()) + { + y= wmt_ts_get_resolvY(); + } + + if (wmt_ts_get_xaxis()) { + tmp = x; + x = y; + y = tmp; + } + if (wmt_ts_get_xdir()) + x = wmt_ts_get_resolvX() - x; + if (wmt_ts_get_ydir()) + y = wmt_ts_get_resolvY() - y; + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = x; + x = y; + y = wmt_ts_get_resolvX() - tmp; + } + + dbg("id %d [%d, %d] p %d",id, x, y, event->pressure[i]); + //input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,event->pressure[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, id); + input_mt_sync(data->input_dev); + } + /* SYN_REPORT */ + input_sync(data->input_dev); +} + +/** +**lw86x0 touch irq work function +**/ + +static void lw86x0_ts_touch_irq_work(struct work_struct *work) +{ + + u16 int_touch_status=0; + mutex_lock(&ts_data_mutex); + + //dbg("Enter into lw86x0_ts_touch_irq_work"); + + //finger_up_status = 0; + lw86x0_read_reg(0x01f5, &int_touch_status, 1); + + //dbg("Read 0x1f5 = %d",int_touch_status); + if( int_touch_status & 0x0001) + { + u16 touch_number=0; + lw86x0_read_reg(0x0160, &touch_number, 1); + //dbg("tn=%d\n",touch_number); + if(touch_number==0) + { + skip_zero_num++; + if(SKIP_ZERO_POINT==skip_zero_num) + { + dbg("tn=%d\n",touch_number); + lw86x0_write_reg(0x01f2, 0x0010); + lw86x0_report_touch_info(touch_number); + lw86x0_ts_release(); + //finger_up_status = 1; + } + else if(SKIP_ZERO_POINT<skip_zero_num) + { + skip_zero_num = SKIP_ZERO_POINT+1; + } + } + else if(touch_number==15) + { + //dbg("touch_number=%d\n",touch_number); + } + else + { + dbg("tn=%d\n",touch_number); + lw86x0_write_reg(0x01f2, 0x0011); + skip_zero_num = 0; + lw86x0_report_touch_info(touch_number); + } + } + else + { + //finger_up_status = 1; + } + lw86x0_write_reg(0x01f5, 0xffff);//clear interrupt + //mdelay(500); + //dbg("clear interrupt 1"); + lw86x0_write_reg(0x01f5, 0xffff);//clear interrupt + //mdelay(500); + //dbg("clear interrupt 2"); + //lw86x0_write_reg(0x01f5, 0xffff);//clear interrupt + //mdelay(500); + //dbg("clear interrupt 3"); + //lw86x0_write_reg(0x01f5, 0xffff);//clear interrupt + //mdelay(500); + //dbg("clear interrupt 4"); + //dbg("Write 0x1f5 = 0xffff"); + //lw86x0_read_reg(0x01f5, &int_touch_status, 1); + //dbg("Re-Read 0x1f5 = %d",int_touch_status); + + if(g_dbgmode==0) + { + //dbg("Enable Irq"); + wmt_enable_gpirq(tsirq_gpio); + } + mutex_unlock(&ts_data_mutex); +} + +static irqreturn_t lw86x0_ts_interrupt(int irq, void *dev_id) +{ + //dbg("enter lw86x0_ts_interrupt"); + //if (!wmt_is_tsirq_enable(tsirq_gpio)) + //{ + // dbg("tsirq not enabled"); + // return IRQ_NONE; + //} + if (wmt_is_tsint(tsirq_gpio)) + { + wmt_clr_int(tsirq_gpio); + wmt_disable_gpirq(tsirq_gpio); + if(!l_early_suspend) + { + //dbg("tsirq enabled"); + queue_work(l_tsdata.ts_workqueue, &l_tsdata.touch_event_work); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void reset_chip(void) +{ + printk("\nReset LW IC\n\n"); + lw86x0_write_reg(0x00e6, 0x3311); + lw86x0_write_reg(0x00e0, 0x0005); + lw86x0_write_reg(0x0214, 0x0020); + lw86x0_write_reg(0x033d, 0x8100); + mdelay(500); + wmt_rst_output(0); + wmt_set_irq_mode(tsirq_gpio, 0); + mdelay(100); + wmt_rst_output(1); + wmt_set_gpirq(tsirq_gpio, GIRQ_FALLING); + lw86x0_load_def_setting(); + if(g_dbgmode==0) + { + wmt_enable_gpirq(tsirq_gpio); + } +} + + +static int check_chip_status(void) +{ + u16 read_value = 0; + u16 read_sram = 0; + int ret = lw86x0_read_reg(0x00e6, &read_value, 1); + if(ret != 0) + { + reset_chip(); + return 0; + } + if(read_value != 0x3311) + { + reset_chip(); + return 0; + } + else + { + lw86x0_read_reg(0x00e0, &read_value, 1); + if(read_value != 0x0005 && read_value != 0x000d) + { + dbg("0x00e0!=0x0005,0x000d\n"); + reset_chip(); + return 0; + } + lw86x0_read_reg(0x0180, &read_sram, 1); + if(read_sram != 0) + { + dbg("0x0180!=0\n"); + reset_chip(); + return 0; + } + lw86x0_read_reg(0x0181, &mcu_status, 1); + if(mcu_status_old == mcu_status) + { + dbg("0x0180 old!=new\n"); + reset_chip(); + mcu_status_old = mcu_status; + return 0; + } + else + { + mcu_status_old = mcu_status; + return 1; + } + } + return 1; +} + +static void phone_status_listener(struct work_struct *work) +{ + if(stop_timer == 0) + { + check_chip_status(); + } +} + +static void lw86x0_ts_polling_phone_status(long unsigned int dev_addr) +{ + schedule_work(&phone_status_work); + mod_timer(&polling_phone_status_timer, jiffies + msecs_to_jiffies(2000)); +} + +/** +** lw86x0 ts early suspend function +**/ +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ts_early_suspend(void) +{ + wmt_disable_gpirq(tsirq_gpio); +} + +//#ifdef CONFIG_HAS_EARLYSUSPEND + +static void lw86x0_ts_early_suspend(struct early_suspend *handler) +{ + printk("lw86x0_ts_early_suspend\n"); + ts_early_suspend(); + l_early_suspend = 1; + lw86x0_write_reg(0x000c, 0xffff); + lw86x0_write_reg(0x033d, 0x0d60); + lw86x0_write_reg(0x00e2, 0x0300); + lw86x0_write_reg(0x000d, 0x4000); + lw86x0_write_reg(0x00e5, 0x4c01); + stop_timer = 1; +} + +/** +** lw86x0 late resume function +**/ +static void ts_late_resume(void) +{ + printk("ts_late_resume\n"); + //wmt_disable_gpirq(tsirq_gpio); + //lw86x0_hw_reset(); + l_early_suspend = 0; + + wmt_set_gpirq(tsirq_gpio, GIRQ_FALLING); + if(g_dbgmode==0) + { + printk("g_dbgmode==0\n"); + wmt_enable_gpirq(tsirq_gpio); + } +} + + +static void lw86x0_ts_late_resume(struct early_suspend *handler) +{ + printk("==lw86x0_ts_resume=\n"); + int ret = check_chip_status(); + if(ret == 1) + { + lw86x0_write_reg(0x000d, 0xc000); + lw86x0_write_reg(0x00e2, 0x0100); + lw86x0_write_reg(0x00e5, 0x4c00); + lw86x0_write_reg(0x000c, 0xffff); + } + ts_late_resume(); + l_early_suspend = 0; + stop_timer = 0; +} +#endif + +/** +** lw86x0 ts suspend function +**/ + +static int lw86x0_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +/** +** lw86x0 resume function +**/ + +static int lw86x0_resume(struct platform_device *pdev) +{ + lw86x0_hw_reset(); + first_init_reg = 1; + lw86x0_load_def_setting(); + return 0; +} + +#ifdef SUPPORT_FW_UPGRADE +//add by jackie +#define BYTES_PER_PACKET 64 +//#define FILEPATH "/etc/firmware/TOUCH.BIN" +int fileLen; +u8 *pData; + +void read_data_from_fw_file(void) +{ + char fwname[32] = {0}; + wmt_ts_get_firmwfilename(fwname); + if (wmt_ts_load_firmware(fwname, &pData, &fileLen)) { + dbg("Load firmware file failed~ \n"); + return; + } +} + +u8 check_fw_version(void) +{ + //Fw_Ver* pfwVerInFile = NULL; + //Fw_Ver fwVer; + + u16 fw_check_sum; + u16 fw_file_check_sum = 0; + + read_data_from_fw_file(); + /*pfwVerInFile = (Fw_Ver* )&(pData[0x2000]); + + printk("struct data:%c%c%d%d\n",pfwVerInFile->magic_num1,pfwVerInFile->magic_num2,pfwVerInFile->mj_ver,pfwVerInFile->mn_ver);//add by jackie + lw86x0_write_reg(0x00e6,0x3311); + lw86x0_flash_read((u8*)&fwVer,0x2000,4); + printk("lw86x0_flash:%c%c%d%d\n",fwVer.magic_num1,fwVer.magic_num2,fwVer.mj_ver,fwVer.mn_ver);//add by jackie + //printk("lw86x0_flash:%d%d\n",fwVer.magic_num1,fwVer.magic_num2);//add by jackie + if((fwVer.magic_num1!='L'||fwVer.magic_num2!='W') + ||((fwVer.magic_num1=='L'&&fwVer.magic_num2=='W') + &&(pfwVerInFile->magic_num1=='L'&&pfwVerInFile->magic_num2=='W') + &&(fwVer.mj_ver!=pfwVerInFile->mj_ver || fwVer.mn_ver!=pfwVerInFile->mn_ver)) + )*/ + lw86x0_write_reg(0x00e6, 0x3311); + lw86x0_write_reg(0x0020, 0x9000); + lw86x0_write_reg(0x0002, 0x8900); + lw86x0_write_reg(0x0115, 0x0100); + lw86x0_write_reg(0x0020, 0x1000); + msleep(200); + fw_check_sum = get_fw_check_sum(); + fw_file_check_sum = get_fw_file_check_sum(); + printk("**********fw_check_sum = %04x, fw_file_check_sum = %04x\n",fw_check_sum,fw_file_check_sum); + if(((fw_check_sum&0xff00)!=0x8000)||((fw_check_sum&0x00ff)!=fw_file_check_sum)) + { + lw86x0_write_reg(0x0002, 0x8800); + printk("firmware crc check is not equal, update firmware......\n"); + return 1;//return 1 means needing upgrade + } + else + { + printk("firmware is not updated......\n"); + lw86x0_write_reg(0x0002, 0x8800); + return 0; + } +} + +void fw_download(void) +{ + int pkt_num = (fileLen+BYTES_PER_PACKET-1)/BYTES_PER_PACKET; + int i; + int last_pkt_size = ((int)fileLen) % BYTES_PER_PACKET; + printk("pkt_num is:%d\n",pkt_num);//add + if(last_pkt_size==0) + { + last_pkt_size = BYTES_PER_PACKET; + } + lw86x0_flash_write_prepare(); + for(i=0;i<pkt_num;i++) + { + lw86x0_flash_write(&pData[i*BYTES_PER_PACKET],i*BYTES_PER_PACKET,(i==pkt_num-1)?last_pkt_size:BYTES_PER_PACKET); + } + lw86x0_flash_write_finish(fileLen); + printk("firmware is updated......\n");//add +} + + +u8 get_fw_file_check_sum(void) +{ + //u16 dataLen; + //u8* pData = NULL; + u16 i; + u8 checksum = 0; + printk("**********dataLen = %04x\n",fileLen); + for(i=0;i<fileLen;i++) + { + checksum+=pData[i]; + } + return checksum; +} + +u16 get_fw_check_sum(void) +{ + u8 cnt = 10; + u16 check_sum = 0; + //u16 fw_length = 0; + while(cnt>0) + { + lw86x0_read_reg(0x0182, &check_sum, 1); + printk("**********check_sum = %04x\n",check_sum); + if((check_sum&0xff00)==0x8000) + { + break; + } + cnt--; + msleep(100); + } + return check_sum; +} + +static void fw_upgrader(void) +{ + u16 fw_check_sum; + u16 fw_file_check_sum = 0; + + if(check_fw_version()==0) + { + return; + } + + lw86x0_write_reg(0x00e6, 0x3311); + fw_download(); + lw86x0_write_reg(0x0020, 0x9000); + lw86x0_write_reg(0x0002, 0x8900); + lw86x0_write_reg(0x0115, 0x0100); + lw86x0_write_reg(0x0020, 0x1000); + msleep(200); + fw_check_sum = get_fw_check_sum(); + fw_file_check_sum = get_fw_file_check_sum(); + printk("**********fw_check_sum = %04x, fw_file_check_sum = %04x\n",fw_check_sum,fw_file_check_sum); + if(((fw_check_sum&0xff00)!=0x8000)||((fw_check_sum&0x00ff)!=fw_file_check_sum)) + { + printk("*********redownload fw\n"); + fw_download(); + lw86x0_write_reg(0x00e6, 0x3311); + lw86x0_write_reg(0x0020, 0x9000); + lw86x0_write_reg(0x0002, 0x8900); + lw86x0_write_reg(0x0115, 0x0100); + lw86x0_write_reg(0x0020, 0x1000); + msleep(200); + fw_check_sum = get_fw_check_sum(); + fw_file_check_sum = get_fw_file_check_sum(); + printk("**********re-check fw_check_sum = %04x, fw_file_check_sum = %04x\n",fw_check_sum,fw_file_check_sum); + if(((fw_check_sum&0xff00)!=0x8000)||((fw_check_sum&0x00ff)!=fw_file_check_sum)) + { + lw86x0_flash_write_prepare(); + } + } + else + { + } + lw86x0_write_reg(0x0002, 0x8800); + kfree(pData); + lw86x0_hw_reset(); + +} + +#endif + + +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_early_suspend = 1; + wmt_disable_gpirq(tsirq_gpio); + stop_timer = 1; + cancel_work_sync(&l_tsdata.touch_event_work); + cancel_work_sync(&phone_status_work); + printk("\nclose backlight\n\n"); + break; + case BL_OPEN: + l_early_suspend = 0; + wmt_enable_gpirq(tsirq_gpio); + lw86x0_write_reg(0x01f5,0xffff);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + stop_timer = 0; + printk("\nopen backlight\n\n"); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int lw86x0_ts_probe(struct platform_device *pdev) +{ + int err = 0; + int i = 0; + u16 read_from_e6 = 0; + lw_i2c_client = ts_get_i2c_client();//get i2c_client + + memset(&l_tsdata, 0 ,sizeof(l_tsdata)); + INIT_WORK(&l_tsdata.touch_event_work, lw86x0_ts_touch_irq_work); + mutex_init(&ts_data_mutex); + + l_tsdata.ts_workqueue = create_singlethread_workqueue("lw86x0-ts-queue"); + if (!l_tsdata.ts_workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + l_tsdata.input_dev = input_allocate_device(); + if (!l_tsdata.input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + l_tsdata.input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + l_tsdata.input_dev->propbit[0] = BIT_MASK(INPUT_PROP_DIRECT); + + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_X, 0, wmt_ts_get_resolvY(), 0, 0); + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvX(), 0, 0); + } else { + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_X, 0, wmt_ts_get_resolvX(), 0, 0); + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_POSITION_Y, 0, wmt_ts_get_resolvY(), 0, 0); + } + input_set_abs_params(l_tsdata.input_dev, + ABS_MT_TRACKING_ID, 0, 15, 0, 0); + + l_tsdata.input_dev->name = LW86X0_NAME; + for (i = 0; i < TS_KEY_NUM; i++) + { + set_bit(l_tskey[i][1], l_tsdata.input_dev->keybit); + }; + err = input_register_device(l_tsdata.input_dev); + if (err) { + errlog("lw86x0_ts_probe: failed to register input device."); + goto exit_input_register_device_failed; + } + +#ifdef SUPPORT_FW_UPGRADE + fw_upgrader(); + mdelay(500); +#endif + + err = load_cfgfile(); + if (err < 0) + goto exit_load_cfgfile_failed; + lw86x0_load_def_setting(); + +#ifdef CONFIG_HAS_EARLYSUSPEND + l_tsdata.early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB+ 1; + l_tsdata.early_suspend.suspend = lw86x0_ts_early_suspend; + l_tsdata.early_suspend.resume = lw86x0_ts_late_resume; + register_early_suspend(&l_tsdata.early_suspend); +#endif + + // init interrupt gpio + tsirq_gpio = wmt_ts_get_gpionum(); + wmt_set_gpirq(tsirq_gpio, GIRQ_FALLING);//GIRQ_FALLING); + wmt_disable_gpirq(tsirq_gpio); + + if(request_irq(wmt_get_tsirqnum(), lw86x0_ts_interrupt, IRQF_SHARED, "ts_lw86x0", l_tsdata.input_dev) < 0){ + errlog("Could not allocate intrrupt for ts_lw86x0 !\n"); + err = -1; + goto exit_register_irq; + } + lw86x0_ts_touch_irq_work(&l_tsdata.touch_event_work); + if(g_dbgmode==0) + { + wmt_enable_gpirq(tsirq_gpio); + } + msleep(5); + dbg("irqgpio=%d,irq=%d,resetgpio=%d\n", tsirq_gpio, wmt_get_tsirqnum(),wmt_ts_get_resetgpnum()); + + lw86x0_read_reg(0x00e6, &read_from_e6, 1); + if(read_from_e6 == 0x3311 || read_from_e6 == 0xa311) + { + INIT_WORK(&phone_status_work, phone_status_listener); + init_timer(&polling_phone_status_timer); + setup_timer(&polling_phone_status_timer, lw86x0_ts_polling_phone_status, (long unsigned int) pdev); + lw86x0_ts_polling_phone_status((long unsigned int) pdev); + } + + register_bl_notifier(&wmt_bl_notify); + + return 0; +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND//add by jackie + unregister_early_suspend(&l_tsdata.early_suspend); +#endif + kfree(default_setting_table); +exit_load_cfgfile_failed: + +exit_input_register_device_failed: + input_free_device(l_tsdata.input_dev); +exit_input_dev_alloc_failed: + cancel_work_sync(&l_tsdata.touch_event_work); + destroy_workqueue(l_tsdata.ts_workqueue); +exit_create_singlethread: + return err; +} + +static int lw86x0_ts_remove(struct platform_device *pdev) +{ + kfree(default_setting_table); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&l_tsdata.early_suspend); +#endif + free_irq(wmt_get_tsirqnum(), l_tsdata.input_dev); + input_unregister_device(l_tsdata.input_dev); + flush_workqueue(l_tsdata.ts_workqueue); + cancel_work_sync(&l_tsdata.touch_event_work); + destroy_workqueue(l_tsdata.ts_workqueue); + mutex_destroy(&ts_data_mutex); + del_timer(&polling_phone_status_timer); + unregister_bl_notifier(&wmt_bl_notify); + dbg("remove...\n"); + return 0; +} + + +static int lw86x0_ts_init(void) +{ + dbg("lw86x0_ts_init\n"); + lw86x0_hw_reset(); + return 0; +} + +static void lw86x0_ts_exit(void) +{ + dbg("lw86x0_ts_exit\n"); +} + +struct wmtts_device lw86x0_tsdev = { + .driver_name = "s_lw86x0_ts", + .ts_id = "lw86x0", + .init = lw86x0_ts_init, + .exit = lw86x0_ts_exit, + .probe = lw86x0_ts_probe, + .remove = lw86x0_ts_remove, + .suspend = lw86x0_suspend, + .resume = lw86x0_resume, + .penup = 1, +}; + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h new file mode 100755 index 00000000..cc2d9e26 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/lw86x0_ts.h @@ -0,0 +1,53 @@ +#ifndef _LW86X0_TS_H_ +#define _LW86X0_TS_H_ + +//#include "wmt_custom_lw86x0.h" + +// define byte swap of a WORD +#define swap16(a) ((((a)&0xff)<<8)|(((a)>>8)&0xff)) + +//struct _reg_word for ioctl read or write register +#define LW86X0_NAME "touch_lw86x0" + +#define SUPPORT_FW_UPGRADE +#define TS_KEY_NUM 4 +#define COL_NUM_MAX 28 +#define ROW_NUM_MAX 16 +#define SUPPORT_POINT_NUM_MAX 10 +#define MULTI_DATA_MAX_SIZE 49 + +typedef struct _reg_word +{ + u16 uOffset; + u16 uValue; + u16 multi_data[MULTI_DATA_MAX_SIZE]; + int data_size; +}reg_word; + +//struct _flash_op for ioctl write or read frimware +#define FLASH_XFER_PKT_SIZE 256 +typedef struct _flash_op +{ + u16 startaddr; //=0 if the first pkt + u16 lastpkt; // =1 if last pkt; =0, otherwise + u16 pktlen; //data length in this pkt + char data[FLASH_XFER_PKT_SIZE]; +}flash_op; + +//struct _raw_data for ioctl read cdc/amb/diff data +typedef struct _raw_data +{ + u8 row; + u8 col; + u16 data[COL_NUM_MAX*ROW_NUM_MAX]; +}rawdata; + +extern void wmt_ts_set_keylen(int keylen); +extern void wmt_ts_set_baseaxis(int axis); +extern void wmt_ts_set_keypos(int index, int min,int max); +extern int lw86x0_write_reg(u16 addr, u16 value); +extern int lw86x0_read_reg(u16 addr, u16 *pdata, int regcnt); +extern void getversion(void); +extern void lw86x0_stop_timer(int flags); + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c new file mode 100755 index 00000000..505dedfd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.c @@ -0,0 +1,1165 @@ +#include <linux/unistd.h> +#include <linux/time.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/suspend.h> +#include <linux/proc_fs.h> +#include <linux/input.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <asm/uaccess.h> +#include <linux/i2c.h>//add +#include "wmt_ts.h" +#include "lw86x0_ts.h" +//#include "wmt_custom_lw86x0.h" + + +struct i2c_client *l_client = NULL; + + + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' +#define LW86X0_READ_REG _IOWR(TS_IOC_MAGIC, 1, int*) +#define LW86X0_WRITE_REG _IOW(TS_IOC_MAGIC, 2, int*) +#define LW86X0_FLASH_DOWNLOAD _IOW(TS_IOC_MAGIC, 3, int *) +#define LW86X0_FLASH_UPLOAD _IOWR(TS_IOC_MAGIC, 4, int *) +#define LW86X0_CTRL_DEBUG_MODE _IOW(TS_IOC_MAGIC, 5, int *) +#define LW86X0_CTRL_RD_DIFF _IOR(TS_IOC_MAGIC, 6, int *) +#define LW86X0_CTRL_RD_CDC _IOR(TS_IOC_MAGIC, 7, int *) +#define LW86X0_CTRL_RD_AMB _IOR(TS_IOC_MAGIC, 8, int *) +#define LW86X0_CTRL_STOP_TIMER _IOR(TS_IOC_MAGIC, 15, int *) +#define TS_IOC_MAXNR 15 + +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define LIGHT_ON_WAIT_TIME 5000 // 5s + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +struct touch_tp_info { + char name[64]; + unsigned int i2caddr; + int xaxis; // 0:x,1:x swap with y + int xdir; // 1:positive,-1:revert + int ydir; // 1:positive,-1:revert + int finger_num; +}; + + +static struct touch_tp_info l_tp[] = { + {"LW86X0",(0x30>>1), 0, 1, 1}, +}; + +static int irq_gpio; +static int rst_gpio; +static int keyled_gpio = -1; +static int light_level; +static int light_time = 5000; // unit: ms +static int panelres_x; +static int panelres_y; +static int lcd_exchg = 0; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static TS_EVENT g_evLast; +static struct mutex cal_mutex; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +extern struct wmtts_device lw86x0_tsdev; +static struct wmtts_device* l_tsdev = &lw86x0_tsdev; +static unsigned char ts_i2c_addr = 0; + +static struct proc_dir_entry* l_tsproc = NULL; +static struct timer_list l_lighttimer; // for shaking +static int l_tskey_btn = 0; // zero to disable touch key, positive to support touch key + +#if 0 +//add +struct tp_infor{ + +char name[64]; +int i2caddr; +int xaxis; +int xdir; +int ydir; +int finger_num; +}; + +//add by jackie +//static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; +#endif +///////////////////////////////////////////////////// +// extrenal function +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +///////////////////////////////////////////////////// +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); + + +char g_dbgmode = 0; +int COL_NUM; +int ROW_NUM; +int SKIP_ZERO_POINT; + +int wmt_ts_get_configfilename(char* fname) +{ + sprintf(fname,"%s.cfg",l_tp[0].name); + return 0; +} + +int wmt_ts_get_firmwfilename(char* fname) +{ + sprintf(fname,"%s_fw.bin",l_tp[0].name); + return 0; +} + +int wmt_ts_get_xaxis(void) +{ + return l_tp[0].xaxis; +} + +int wmt_ts_get_xdir(void) +{ + return l_tp[0].xdir; +} + +int wmt_ts_get_ydir(void) +{ + return l_tp[0].ydir; +} + +int wmt_ts_get_fingernum(void) +{ + return l_tp[0].finger_num; +} + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +int wmt_ts_enable_tskey(void) +{ + return l_tskey_btn; +} + +int wmt_ts_enable_keyled(void) +{ + return (keyled_gpio>=0 ? 1:0); +} + + +static void ts_lighttimer_timeout(unsigned long timeout) +{ + // turn off the light + if (20 == keyled_gpio) + { + if (light_level>=0) + { + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + dbg("turn off the light!\n"); + } else { + REG32_VAL(__GPIO_BASE+0x00F0) |= BIT4; // output high + dbg("turn off the light!\n"); + } + } +} + + +static void wmt_ts_init_light(void) +{ + if (20 == keyled_gpio) + { + setup_timer(&l_lighttimer, ts_lighttimer_timeout, 0); + // init gpio20 and turn off light + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + REG32_VAL(__GPIO_BASE+0x00B0) |= BIT4; // output enable + REG32_VAL(__GPIO_BASE+0x0070) |= BIT4; // enable gpio + REG32_VAL(__GPIO_BASE+0x04F0) |= BIT4; // pull up + REG32_VAL(__GPIO_BASE+0x04B0) |= BIT4; // enable pull up/down + } +} + +void wmt_ts_turnoff_light(void) +{ + if (20 == keyled_gpio) + { + mod_timer(&l_lighttimer, jiffies + msecs_to_jiffies(light_time)); + } +} + +void wmt_ts_turnon_light(void) +{ + if (20 == keyled_gpio) + { + del_timer(&l_lighttimer); + if (light_level >= 0) + { + REG32_VAL(__GPIO_BASE+0x00F0) |= BIT4; // output high + dbg("turn on the light!\n"); + } else { + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + dbg("turn on the light!\n"); + } + } +} + +static void wmt_ts_remove_light(void) +{ + if (20 == keyled_gpio) + { + if (light_level >= 0) + { + REG32_VAL(__GPIO_BASE+0x00F0) &= ~BIT4; // output low + } else { + REG32_VAL(__GPIO_BASE+0x00F0) |= BIT4; // output high + } + del_timer(&l_lighttimer); + } +} + +int wmt_is_tsirq_enable(int num) +{ + int val = 0; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; +} + +int wmt_is_tsint(int num) +{ + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(int num) +{ + if (num > 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +void wmt_tsreset_init(int num) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num);//&= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); // out high + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //output enable + msleep(5); + //REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); +} + +// enable:0-disable,1-enable +void wmt_enable_rst_pull(int enable) +{ + if (enable) + { + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<rst_gpio); //enable pull up/down + } else { + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<rst_gpio); //disable pull up/down + } +} + +// up:0-pull down,1-pull up +void wmt_set_rst_pull(int up) +{ + if (up) + { + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<rst_gpio); //pull up + } else { + REG32_VAL(__GPIO_BASE+0x04c0) &= ~(1<<rst_gpio); //pull down + } +} + +// high:0-low level,1-high level +void wmt_rst_output(int high) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + if (high) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<rst_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<rst_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<rst_gpio); //set output +} + +void wmt_rst_input(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<rst_gpio); //set input +} + +int wmt_set_irq_mode(unsigned int num, int mode) +{ + if(num >11) + return -1; + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); //enable gpio + if(mode == 0) + { + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //set output + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + } + else if(mode == 1) + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + //msleep(5); + return 0; +} + + +int wmt_set_gpirq(unsigned int num, int type) +{ + int shift; + int offset; + unsigned long reg; + + if(num >11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case GIRQ_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case GIRQ_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case GIRQ_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case GIRQ_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + +int wmt_enable_gpirq(unsigned int num) +{ + if(num > 11) + return -1; + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(unsigned int num) +{ + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + if (wmt_ts_enable_keyled()) + wmt_ts_remove_light(); + if (l_tsdev->suspend !=NULL) + { + return l_tsdev->suspend(pdev, state); + } + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + klog("ts resume....\n"); + if (wmt_ts_enable_keyled()) + wmt_ts_init_light(); + if (l_tsdev->resume != NULL) + { + return l_tsdev->resume(pdev); + } + return 0; +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + if (l_tsdev->probe != NULL) + { + return l_tsdev->probe(pdev); + } + else + { + return 0; + } +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_ts_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + return ret; +} + +static int wmt_ts_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +static unsigned int wmt_ts_poll(struct file *filp, struct poll_table_struct *wait) +{ + return 0; +} + + +void read_diff(rawdata* pdata) +{ + //u16 Buffer[COL_NUM_MAX*ROW_NUM_MAX*2]; + u16 *Buffer; + u16 idx = 0; + int i,j; + u16 addr =0; + pdata->col = COL_NUM; + pdata->row = ROW_NUM; + Buffer = kzalloc(COL_NUM_MAX*ROW_NUM_MAX*2*2, GFP_KERNEL); + if (!Buffer) { + errlog("mem alloc fail.\n"); + return; + } + for(i=0;i<pdata->row;i++) + { + addr = 0x42f2+i*60; + printk("read_diff: addr=0x%04x\n",addr); + for(j=0;j<pdata->col*2;j++) + { + if(lw86x0_read_reg(addr+j, &Buffer[idx],1)!=0) + { + lw86x0_read_reg(addr+j, &Buffer[idx],1); + } + printk("read_diff: Buffer[%d]=0x%04x\n",idx,Buffer[idx]); + idx++; + } + } + for(i=0; i<pdata->col * pdata->row; i++) + { + pdata->data[i] = ((Buffer[i*2]<<8)&0xff00)|(Buffer[i*2+1]&0x00ff); + printk("read_diff: pdata->data[%d]=0x%04x\n",i,pdata->data[i]); + } + kfree(Buffer); +} + +void read_cdc(rawdata* pdata) +{ + int i,j; + u16 addr = 0x2fc8; + u16 idx = 0; + + pdata->col = COL_NUM; + pdata->row = ROW_NUM; + + for(i=0;i<pdata->col;i++) + { + for(j=0;j<pdata->row;j++) + { + printk("read_cdc: addr=0x%04x\n",addr+idx); + if(lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1)!=0) + { + lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1); + } + printk("read_cdc: pdata->data[%d]=0x%04x\n",j*pdata->col+i,pdata->data[j*pdata->col+i]); + idx++; + } + } +} + +void read_amb(rawdata* pdata) +{ + int i,j; + u16 addr = 0x2E04; + u16 idx = 0; + + pdata->col = COL_NUM; + pdata->row = ROW_NUM; + + for(i=0;i<pdata->col;i++) + { + for(j=0;j<pdata->row;j++) + { + printk("read_amb: addr=0x%04x\n",addr+idx); + if(lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1)!=0) + { + lw86x0_read_reg(addr+idx, &pdata->data[j*pdata->col+i],1); + } + printk("read_amb: pdata->data[%d]=0x%04x\n",j*pdata->col+i,pdata->data[j*pdata->col+i]); + idx++; + } + } + + +} + +void lw86x0_flash_write_prepare(void) +{ + lw86x0_stop_timer(1); + lw86x0_write_reg(0x00e2, 0x0300);//#write_en=1 tmr=1 + udelay(1); + //mass erase + lw86x0_write_reg(0x00e2, 0x0305);//#xe=1 mas1=1 + lw86x0_write_reg(0x00e2, 0x0315);//#erase=1 + udelay(5); + lw86x0_write_reg(0x00e2, 0x0395);//#nvstr=1 + mdelay(20); + lw86x0_write_reg(0x00e2, 0x0385);//#erase=0 + udelay(100); + lw86x0_write_reg(0x00e2, 0x0305);//#nvstr=0 + lw86x0_write_reg(0x00e2, 0x0300);//#xe=0 mas1=0 +} + +void lw86x0_flash_write(u8* pbData,u16 start_addr, u16 num) +{ + u16 yaddr = start_addr; + u16 xaddr = (start_addr)&0xFF80;//x addr is a 8bit address + u16 cnt = 0; + while(cnt<num) + { + while(1) + { + lw86x0_write_reg(0x00e3, xaddr);//#xaddr + lw86x0_write_reg(0x00e2, 0x0304);//#xe=1 + lw86x0_write_reg(0x00e2, 0x0324);//#prog=1 + udelay(5); + lw86x0_write_reg(0x00e2, 0x03a4);//#nvstr=1 + udelay(10); + do + { + u16 data = pbData[cnt]; + lw86x0_write_reg(0x00e3, yaddr);//#yaddr + lw86x0_write_reg(0x00e4, data);//#din + lw86x0_write_reg(0x00e2, 0xfbac);//#ye=0 + lw86x0_write_reg(0x00e2, 0x03a4);//#ye=0 + yaddr++; + cnt++; + if(cnt==num) + { + break; + } + }while(yaddr&0x007F); + xaddr+=0x0080; + udelay(20); + lw86x0_write_reg(0x00e2, 0x0384);//#prog=0 + udelay(100); + lw86x0_write_reg(0x00e2, 0x0304);//#nvstr=0 + lw86x0_write_reg(0x00e2, 0x0300);//#xe=0 + if(cnt==num) + { + break; + } + } + } + +} + +void lw86x0_flash_write_finish(u16 total_len) +{ + //write length of FW to last 2 byte of flash + u8 *pLen = (u8 *)&total_len; + lw86x0_flash_write(&(pLen[1]),0x7FFE, 1); + lw86x0_flash_write(&(pLen[0]),0x7FFF, 1); + + lw86x0_write_reg(0x00e2, 0x0300);//#tmr=1 + lw86x0_write_reg(0x00e2, 0x0200);//#tmr=0 + lw86x0_write_reg(0x00e2, 0x02c0);//#nvstr=1 se=1 + lw86x0_write_reg(0x00e2, 0x02eb);//#prog=1 ifren=1 ye=1 mas=1 + lw86x0_write_reg(0x00e2, 0x03eb);//#tmr=1 + lw86x0_write_reg(0x00e2, 0x02eb);//#tmr=0 + lw86x0_write_reg(0x00e2, 0x02c0);//#prog=0 ifren=0 ye=0 mas=0 + lw86x0_write_reg(0x00e2, 0x0200);//#nvstr=0 se=0 + lw86x0_write_reg(0x00e2, 0x0204);//#xe=1 + lw86x0_write_reg(0x00e2, 0x0214);//#erase=1 + udelay(5); + lw86x0_write_reg(0x00e2, 0x0294);//#nvstr=1 + mdelay(20); + lw86x0_write_reg(0x00e2, 0x0284);//#erase=0 + udelay(5); + lw86x0_write_reg(0x00e2, 0x0204);//#nvstr=0 + lw86x0_write_reg(0x00e2, 0x0200);//#xe=0 + lw86x0_write_reg(0x00e2, 0x0000); + lw86x0_write_reg(0x000c, 0xffff); + lw86x0_stop_timer(0); +} + +void lw86x0_flash_read(u8* pbData, u16 start_addr, u16 num) +{ + lw86x0_stop_timer(1); + u16 cnt; + u16 rd_data = 0; + u8 *buf; + for(cnt=0; cnt<num;cnt++) + { + lw86x0_write_reg(0x00e4, 0x0000);//#read data + lw86x0_write_reg(0x00e2, 0x0300);//#tmr=1 + lw86x0_write_reg(0x00e3, start_addr+cnt); + lw86x0_write_reg(0x00e2, 0x034c);//#se=1 ye=1 xe=1 + lw86x0_write_reg(0x00e2, 0x0300);//#se=1 ye=1 xe=1 + lw86x0_read_reg(0x00e4, &rd_data,1); + buf = (u8 *)&rd_data; + pbData[cnt] = buf[1]; + } + lw86x0_stop_timer(0); +} + + +static long wmt_ts_ioctl(/*struct inode * node,*/ struct file *dev, unsigned int cmd, unsigned long arg) +{ + reg_word regword; + //rawdata rdata; + rawdata *rdata; + flash_op f_pkt;//flash packet + + int ret = 0; + char ch; + rdata = kzalloc(sizeof(rawdata), GFP_KERNEL); + if (!rdata) { + errlog("mem alloc fail.\n"); + return -ENOMEM; + } + + if (_IOC_TYPE(cmd) != TS_IOC_MAGIC){ + dbg("CMD ERROR!"); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > TS_IOC_MAXNR){ + dbg("NO SUCH IO CMD!\n"); + return -ENOTTY; + } + + switch (cmd) { + case LW86X0_WRITE_REG: + copy_from_user(®word, (reg_word*)arg, sizeof(regword)); + dbg("write reg[%d] word value 0x%x", regword.uOffset, regword.uValue ); + ret = lw86x0_write_reg(regword.uOffset, regword.uValue); + if (ret != 0) + { + dbg("Faied to write reg. ret 0x%x\n",ret); + } + return 0; + case LW86X0_READ_REG: + copy_from_user(®word, (reg_word*)arg, sizeof(regword)); + ret = lw86x0_read_reg(regword.uOffset, ®word.uValue, 1); + if (ret != 0) + { + dbg("Faied to read reg. ret 0x%x\n",ret); + } + else + { + + dbg("read reg[%d]=0x%04x",regword.uOffset, regword.uValue); + } + copy_to_user((unsigned int*)arg, ®word, sizeof(regword)); + return 0; + case LW86X0_CTRL_DEBUG_MODE: + copy_from_user(&ch, (char*)arg, sizeof(char)); + printk("LW86X0_CTRL_DEBUG_MODE,%c", ch); + if(ch=='1') + { + g_dbgmode = 1; + wmt_disable_gpirq(irq_gpio); + } + else + { + g_dbgmode = 0; + wmt_enable_gpirq(irq_gpio); + } + return 0; + /* + case LW86X0_CTRL_RD_DIFF: + copy_from_user(&rdata, (rawdata*)arg, sizeof(rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_DIFF\n"); + read_diff(&rdata); + copy_to_user((unsigned int*)arg, &rdata, sizeof(rdata)); + return 0; + case LW86X0_CTRL_RD_CDC: + copy_from_user(&rdata, (rawdata*)arg, sizeof(rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_CDC\n"); + read_cdc(&rdata); + copy_to_user((unsigned int*)arg, &rdata, sizeof(rdata)); + return 0; + case LW86X0_CTRL_RD_AMB: + copy_from_user(&rdata, (rawdata*)arg, sizeof(rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_AMB\n"); + read_amb(&rdata); + copy_to_user((unsigned int*)arg, &rdata, sizeof(rdata)); + return 0; + */ + case LW86X0_CTRL_RD_DIFF: + copy_from_user(rdata, (rawdata*)arg, sizeof(*rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_DIFF\n"); + read_diff(rdata); + copy_to_user((unsigned int*)arg, rdata, sizeof(*rdata)); + return 0; + case LW86X0_CTRL_RD_CDC: + copy_from_user(rdata, (rawdata*)arg, sizeof(*rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_CDC\n"); + read_cdc(rdata); + copy_to_user((unsigned int*)arg, rdata, sizeof(*rdata)); + return 0; + case LW86X0_CTRL_RD_AMB: + copy_from_user(rdata, (rawdata*)arg, sizeof(*rdata)); + printk("tpd-ioctrl: LW86X0_CTRL_RD_AMB\n"); + read_amb(rdata); + copy_to_user((unsigned int*)arg, rdata, sizeof(*rdata)); + return 0; + case LW86X0_FLASH_DOWNLOAD: + copy_from_user(&f_pkt, (flash_op*)arg, sizeof(f_pkt)); + if(f_pkt.startaddr==0) + { + lw86x0_flash_write_prepare(); + } + lw86x0_flash_write(f_pkt.data, + f_pkt.startaddr, + f_pkt.pktlen); + printk("dnload: start addr = %04x\n",f_pkt.startaddr); + if(f_pkt.lastpkt==1) + { + u16 write_len = f_pkt.startaddr + f_pkt.pktlen; + lw86x0_flash_write_finish(write_len); + } + return 0; + case LW86X0_FLASH_UPLOAD: + copy_from_user(&f_pkt, (flash_op*)arg, sizeof(f_pkt)); + lw86x0_flash_read(f_pkt.data, f_pkt.startaddr, f_pkt.pktlen); + printk("upload: start addr = %04x\n",f_pkt.startaddr); + printk("\n"); + copy_to_user((int*)arg, &f_pkt, sizeof(f_pkt)); + return 0; + case LW86X0_CTRL_STOP_TIMER: + copy_from_user(&ch, (char*)arg, sizeof(char)); + if(ch == '1') + lw86x0_stop_timer(1); + else + lw86x0_stop_timer(0); + return 0; + } + kfree(rdata); + return -EINVAL; +} + +static ssize_t wmt_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) +{ + return 0; +} + + +static struct file_operations wmt_ts_fops = { + .read = wmt_ts_read, + .poll = wmt_ts_poll, + .unlocked_ioctl = wmt_ts_ioctl, + .open = wmt_ts_open, + .release = wmt_ts_close, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "out=%d\n", &val)) + { + switch(val) + { + case 1: // reset1 + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<irq_gpio); //out high + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set input + break; + case 0: // reset2 + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<irq_gpio); //out high + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set input + break; + default: + break; + }; + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + +unsigned char wmt_ts_get_i2caddr(void) +{ + return ts_i2c_addr; +} + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127; + char retval[128] = {0},*p=NULL,*s=NULL; + int Enable=0; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + + //check touch enable + p = retval; + sscanf(p,"%d:", &Enable); + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + //check touch IC name + p = strchr(p,':');p++; + if (strncmp(p, l_tp[0].name, strlen(l_tp[0].name))) { + errlog("Can't find %s!\n", l_tp[0].name); + return -ENODEV; + } + + //get firmware file name + s = strchr(p,':'); + memset(l_tp[0].name,0x00,sizeof(l_tp[0].name)); + strncpy(l_tp[0].name, p, (s-p)); + dbg("ts_fwname=%s\n", l_tp[0].name); + + p = s + 1; + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%x", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tp[0].xaxis),&(l_tp[0].xdir),&(l_tp[0].ydir), + &(l_tp[0].finger_num),&(l_tp[0].i2caddr)); + + dbg("%d;%d;%d;%d;%d;%d;%d;%d;%x;",irq_gpio,panelres_x,panelres_y,rst_gpio, + (l_tp[0].xaxis),(l_tp[0].xdir),(l_tp[0].ydir), + (l_tp[0].finger_num),(l_tp[0].i2caddr)); + + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + + return 0; +} +//#if 0 +//add by jackie i2c_board_info +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + //.addr = 0x18, //WMT_TS_I2C_ADDR,//why error? + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; +//add jackie static + int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + ts_i2c_board_info.addr = l_tp[0].i2caddr; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} +//add by jackie +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} +//add +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + +//add by jackie + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + printk(KERN_ERR "Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + return -1; + } + if (wmt_ts_enable_keyled()) + wmt_ts_init_light(); + // Create device node + if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("wmt ts driver init ok!\n"); + return ret; +} + +//add by jackie +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} +//add end + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + if (wmt_ts_enable_keyled()) + wmt_ts_remove_light(); + l_tsdev->exit(); + mutex_destroy(&cal_mutex); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + unregister_chrdev(TS_MAJOR, TS_NAME); + class_destroy(l_dev_class); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h new file mode 100755 index 00000000..ff1218ac --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/lw86x0_ts/wmt_ts.h @@ -0,0 +1,98 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/suspend.h> + +//#define DEBUG_WMT_TS +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (wmt_ts_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define DONOTHING 0xff + +#define WMT_TS_I2C_NAME "lw86x0-ts" +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(unsigned int num, int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(unsigned int num); +extern int wmt_enable_gpirq(unsigned int num); +extern int wmt_is_tsirq_enable(int num); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +void wmt_rst_input(void); +extern int wmt_is_tsint(int num); +extern void wmt_clr_int(int num); +extern void wmt_tsreset_init(int num); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern unsigned char wmt_ts_get_i2caddr(void); +extern void wmt_ts_turnoff_light(void); +extern void wmt_ts_turnon_light(void); +extern int wmt_ts_enable_tskey(void); +extern int wmt_ts_get_configfilename(char* fname); +extern int wmt_ts_get_firmwfilename(char* fname); +extern int wmt_ts_get_xaxis(void); +extern int wmt_ts_get_xdir(void); +extern int wmt_ts_get_ydir(void); +extern int wmt_ts_get_fingernum(void); +extern int wmt_ts_enable_keyled(void); +extern int wmt_set_irq_mode(unsigned int num, int mode); +extern int wmt_disable_gpirq(unsigned int num); +extern int wmt_enable_gpirq(unsigned int num); +extern int ts_i2c_register_device (void); +extern struct i2c_client* ts_get_i2c_client(void); + +extern void lw86x0_flash_write_prepare(void); +extern void lw86x0_flash_read(u8* pbData, u16 start_addr, u16 num); +extern void lw86x0_flash_write(u8* pbData,u16 start_addr, u16 num); +extern void lw86x0_flash_write_finish(u16 total_len); +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile new file mode 100755 index 00000000..f806933e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/Makefile @@ -0,0 +1,33 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=metusb + +obj-m := $(MY_MODULE_NAME).o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c new file mode 100755 index 00000000..e86bf03c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/metusb/metusb.c @@ -0,0 +1,856 @@ + +//#define DEBUG + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/usb/input.h> +#include <linux/hid.h> +#include <asm/uaccess.h> +#include <linux/fs.h> +#include <linux/syscalls.h> + + +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Xiaoyijian" +#define DRIVER_DESC "Metouch USB Touchscreen Driver" + +static int swap_xy = 0; +static int swapx=0; +static int swapy=0; + +static int v_shift=0; +static int v_flag=0; + +static int h_shift=0; +static int h_flag=0; + + +#define TP_TIMEOUT 30 +#define TP_TIMEROUT_MAX 3 + +/* device specifc data/functions */ +struct usbtouch_usb; +struct usbtouch_device_info { + int min_xc, max_xc; + int min_yc, max_yc; + int min_press, max_press; + int rept_size; + + /* + * Always service the USB devices irq not just when the input device is + * open. This is useful when devices have a watchdog which prevents us + * from periodically polling the device. Leave this unset unless your + * touchscreen device requires it, as it does consume more of the USB + * bandwidth. + */ + bool irq_always; + + void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); + + /* + * used to get the packet len. possible return values: + * > 0: packet len + * = 0: skip one byte + * < 0: -return value more bytes needed + */ + int (*get_pkt_len) (unsigned char *pkt, int len); + + int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); + int (*alloc) (struct usbtouch_usb *usbtouch); + int (*init) (struct usbtouch_usb *usbtouch); + void (*exit) (struct usbtouch_usb *usbtouch); +}; + +/* a usbtouch device */ +struct usbtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + unsigned char *buffer; + int buf_len; + struct urb *irq; + struct usb_interface *interface; + struct input_dev *input; + + struct workqueue_struct *tp_queue; + struct delayed_work tp_work; + struct mutex tp_timeout_mutex; + int tp_timer_count; + + struct usbtouch_device_info *type; + char name[128]; + char phys[64]; + void *priv; + int x, y; + int touch, press; +}; + +#define DEVTYPE_METOUCH 0 + +#define USB_DEVICE_HID_CLASS(vend, prod) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \ + | USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ + .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE + +/* Define these values to match your devices */ +#define METOUCH_VENDOR_ID 0x5A53 +#define METOUCH_PRODUCT_ID 0x0001 +#define METUSB_MINOR_BASE 0x0 + +static int metouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt); +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,unsigned char *pkt, int len); +static void usbtouch_irq(struct urb *urb); +static int usbtouch_open(struct input_dev *input); +static void usbtouch_close(struct input_dev *input); +static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message); +static int usbtouch_resume(struct usb_interface *intf); +static int usbtouch_reset_resume(struct usb_interface *intf); +static void usbtouch_free_buffers(struct usb_device *udev,struct usbtouch_usb *usbtouch); +static struct usb_endpoint_descriptor *usbtouch_get_input_endpoint(struct usb_host_interface *interface); +static int usbtouch_probe(struct usb_interface *intf,const struct usb_device_id *id); +static void usbtouch_disconnect(struct usb_interface *intf); +static int __init usbtouch_init(void); +static void __exit usbtouch_cleanup(void); +static void GetUserCfg(void); +static void AnlysCmd(char *cmd); +static int myatoi(char *str); +static void DeleteAllSpace(char *cmd); +int mypow(int t); + + +static struct usbtouch_device_info usbtouch_dev_info[] = { + [DEVTYPE_METOUCH] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 8, + .read_data = metouch_read_data, + }, +}; + +static struct usb_device_id metusb_table [] = { + { USB_DEVICE(METOUCH_VENDOR_ID, METOUCH_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, metusb_table); + +/***************************************************************************** + * METOUCH Part + */ +/* +AA 55 XL XH YL YH BTN CRC +****************************************************************************/ +static int metouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = (pkt[3] << 8) | pkt[2]; + dev->y = (pkt[5] << 8) | pkt[4]; + dev->touch = (pkt[6] & 0x03) ? 1 : 0; + + if (h_flag == 0) dev->x = dev->x + h_shift; + if (v_flag == 0) dev->y = dev->y + v_shift; + + if (h_flag>0) + { + if (dev->x > h_shift) dev->x = dev->x - h_shift; + else dev->x=0; + } + + if (v_flag>0) + { + if (dev->y > v_shift) dev->y = dev->y - v_shift; + else dev->y=0; + } + + if (dev->x > 4095) dev->x=4095; + if (dev->y > 4095) dev->y=4095; + + if (dev->x <0) dev->x=0; + if (dev->y <0) dev->y=0; + + if (swapx>0) dev->x = 4095 - dev->x; + if (swapy>0) dev->y = 4095 - dev->y; + + return 1; +} + + +/***************************************************************************** + * Generic Part + */ +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, + unsigned char *pkt, int len) +{ + struct usbtouch_device_info *type = usbtouch->type; + + if (!type->read_data(usbtouch, pkt)) + return; + + mutex_lock(&usbtouch->tp_timeout_mutex); + if( usbtouch->tp_timer_count < 0 ){ + queue_delayed_work(usbtouch->tp_queue, &usbtouch->tp_work, msecs_to_jiffies(TP_TIMEOUT)); + } + usbtouch->tp_timer_count = TP_TIMEROUT_MAX; + mutex_unlock(&usbtouch->tp_timeout_mutex); + + //input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); + input_report_abs(usbtouch->input, ABS_MT_TRACKING_ID, 0); + if (swap_xy) { + //input_report_abs(usbtouch->input, ABS_X, usbtouch->y); + //input_report_abs(usbtouch->input, ABS_Y, usbtouch->x); + input_report_abs(usbtouch->input, ABS_MT_POSITION_X, usbtouch->y ); + input_report_abs(usbtouch->input, ABS_MT_POSITION_Y, usbtouch->x ); + } else { + //input_report_abs(usbtouch->input, ABS_X, usbtouch->x); + //input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); + input_report_abs(usbtouch->input, ABS_MT_POSITION_X, usbtouch->x ); + input_report_abs(usbtouch->input, ABS_MT_POSITION_Y, usbtouch->y ); + } + //if (type->max_press) + // input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press); + //input_sync(usbtouch->input); + input_mt_sync(usbtouch->input); + input_sync(usbtouch->input); + + + +} + + +static void usbtouch_irq(struct urb *urb) +{ + struct usbtouch_usb *usbtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIME: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __func__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -EPIPE: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __func__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __func__, urb->status); + goto exit; + } + + usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); + +exit: + usb_mark_last_busy(interface_to_usbdev(usbtouch->interface)); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __func__, retval); +} + +static int usbtouch_open(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input_get_drvdata(input); + int r; + + usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface); + + r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0; + if (r < 0) + goto out; + + if (!usbtouch->type->irq_always) { + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) { + r = -EIO; + goto out_put; + } + } + + usbtouch->interface->needs_remote_wakeup = 1; +out_put: + usb_autopm_put_interface(usbtouch->interface); +out: + return r; +} + +static void usbtouch_close(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input_get_drvdata(input); + int r; + + if (!usbtouch->type->irq_always) + usb_kill_urb(usbtouch->irq); + r = usb_autopm_get_interface(usbtouch->interface); + usbtouch->interface->needs_remote_wakeup = 0; + if (!r) + usb_autopm_put_interface(usbtouch->interface); +} + +static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + + usb_kill_urb(usbtouch->irq); + + return 0; +} + +static int usbtouch_resume(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + struct input_dev *input = usbtouch->input; + int result = 0; + + mutex_lock(&input->mutex); + if (input->users || usbtouch->type->irq_always) + result = usb_submit_urb(usbtouch->irq, GFP_NOIO); + mutex_unlock(&input->mutex); + + return result; +} + +static int usbtouch_reset_resume(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + struct input_dev *input = usbtouch->input; + int err = 0; + + /* reinit the device */ + if (usbtouch->type->init) { + err = usbtouch->type->init(usbtouch); + if (err) { + dbg("%s - type->init() failed, err: %d", + __func__, err); + return err; + } + } + + /* restart IO if needed */ + mutex_lock(&input->mutex); + if (input->users) + err = usb_submit_urb(usbtouch->irq, GFP_NOIO); + mutex_unlock(&input->mutex); + + return err; +} + +static void usbtouch_free_buffers(struct usb_device *udev, + struct usbtouch_usb *usbtouch) +{ + usb_free_coherent(udev, usbtouch->type->rept_size, + usbtouch->data, usbtouch->data_dma); + kfree(usbtouch->buffer); +} + +static struct usb_endpoint_descriptor *usbtouch_get_input_endpoint(struct usb_host_interface *interface) +{ + int i; + + for (i = 0; i < interface->desc.bNumEndpoints; i++) + if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) + return &interface->endpoint[i].desc; + + return NULL; +} + + +static void tp_timeout_func(struct work_struct *work){ + struct usbtouch_usb *usbtouch = + container_of(work, struct usbtouch_usb, tp_work.work); + int button_up = -1; + + mutex_lock(&usbtouch->tp_timeout_mutex); + button_up = --usbtouch->tp_timer_count; + mutex_unlock(&usbtouch->tp_timeout_mutex); + + if( button_up < 0){ + input_mt_sync(usbtouch->input); + input_sync(usbtouch->input); + }else{ + queue_delayed_work(usbtouch->tp_queue, &usbtouch->tp_work, msecs_to_jiffies(TP_TIMEOUT)); + } + +} + +static int usbtouch_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usbtouch_usb *usbtouch; + struct input_dev *input_dev; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + struct usbtouch_device_info *type; + int err = -ENOMEM; + + GetUserCfg(); + + /* some devices are ignored */ + if (id->driver_info == -1) + return -ENODEV; + + endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting); + if (!endpoint) + return -ENXIO; + + usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!usbtouch || !input_dev) + goto out_free; + + type = &usbtouch_dev_info[id->driver_info]; + usbtouch->type = type; + if (!type->process_pkt) + type->process_pkt = usbtouch_process_pkt; + + usbtouch->data = usb_alloc_coherent(udev, type->rept_size, + GFP_KERNEL, &usbtouch->data_dma); + if (!usbtouch->data) + goto out_free; + + if (type->get_pkt_len) { + usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); + if (!usbtouch->buffer) + goto out_free_buffers; + } + + usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!usbtouch->irq) { + dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__); + goto out_free_buffers; + } + + usbtouch->interface = intf; + usbtouch->input = input_dev; + + if (udev->manufacturer) + strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(usbtouch->name, " ", sizeof(usbtouch->name)); + strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name)); + } + + if (!strlen(usbtouch->name)) + snprintf(usbtouch->name, sizeof(usbtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); + strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); + + input_dev->name = usbtouch->name; + input_dev->phys = usbtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->dev.parent = &intf->dev; + + + input_set_drvdata(input_dev, usbtouch); + + input_dev->open = usbtouch_open; + input_dev->close = usbtouch_close; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + + + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + + set_bit(ABS_MT_POSITION_X, input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, input_dev->absbit); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, type->min_xc, type->max_xc, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, type->min_yc, type->max_yc, 0, 0); + + mutex_init(&usbtouch->tp_timeout_mutex); + usbtouch->tp_timer_count = -1; + usbtouch->tp_queue= create_singlethread_workqueue("tp_queue"); + INIT_DELAYED_WORK(&usbtouch->tp_work, tp_timeout_func); + //queue_delayed_work(tp_queue, &tp_work, msecs_to_jiffies(TP_TIMEOUT)); + + //input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + //input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0); + //input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0); + + //if (type->max_press) + // input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, + // type->max_press, 0, 0); + + + if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT) + usb_fill_int_urb(usbtouch->irq, udev, + usb_rcvintpipe(udev, endpoint->bEndpointAddress), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch, endpoint->bInterval); + else + usb_fill_bulk_urb(usbtouch->irq, udev, + usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch); + + usbtouch->irq->dev = udev; + usbtouch->irq->transfer_dma = usbtouch->data_dma; + usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* device specific allocations */ + if (type->alloc) { + err = type->alloc(usbtouch); + if (err) { + dbg("%s - type->alloc() failed, err: %d", __func__, err); + goto out_free_urb; + } + } + + /* device specific initialisation*/ + if (type->init) { + err = type->init(usbtouch); + if (err) { + dbg("%s - type->init() failed, err: %d", __func__, err); + goto out_do_exit; + } + } + + err = input_register_device(usbtouch->input); + if (err) { + dbg("%s - input_register_device failed, err: %d", __func__, err); + goto out_do_exit; + } + + usb_set_intfdata(intf, usbtouch); + + if (usbtouch->type->irq_always) { + /* this can't fail */ + usb_autopm_get_interface(intf); + err = usb_submit_urb(usbtouch->irq, GFP_KERNEL); + if (err) { + usb_autopm_put_interface(intf); + err("%s - usb_submit_urb failed with result: %d", + __func__, err); + goto out_unregister_input; + } + } + + return 0; + +out_unregister_input: + input_unregister_device(input_dev); + input_dev = NULL; +out_do_exit: + if (type->exit) + type->exit(usbtouch); +out_free_urb: + usb_free_urb(usbtouch->irq); +out_free_buffers: + usbtouch_free_buffers(udev, usbtouch); +out_free: + input_free_device(input_dev); + kfree(usbtouch); + return err; +} + +static void usbtouch_disconnect(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + + dbg("%s - called", __func__); + + if (!usbtouch) + return; + + dbg("%s - usbtouch is initialized, cleaning up", __func__); + mutex_destroy(&usbtouch->tp_timeout_mutex); + usb_set_intfdata(intf, NULL); + /* this will stop IO via close */ + input_unregister_device(usbtouch->input); + usb_free_urb(usbtouch->irq); + if (usbtouch->type->exit) + usbtouch->type->exit(usbtouch); + usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); + kfree(usbtouch); +} + + +static void GetUserCfg(void) +{ +struct file *fd; +char buffer[256]; +loff_t pos; + +mm_segment_t old_fs = get_fs(); +set_fs(KERNEL_DS); + +memset((char *)&buffer[0],0,256); + +fd= filp_open("/etc/metouch.cfg",O_RDONLY,0); + +if (IS_ERR(fd)) + { + printk("Unable to open metouch config information.\n"); + goto exithere; + } +else + { + printk("open metouch config file ok.\n"); + + pos=0; + vfs_read(fd,buffer,256,&pos); + + if (pos < 0) + { + printk("reach the end of file\n"); + } + else + { + AnlysCmd(buffer); + } + filp_close(fd,NULL); + } +exithere:; +set_fs(old_fs); +} + +static void AnlysCmd(char *cmd) +{ +//static int swapx=0; +//static int swapy=0; +//static int v_shift=0; +//static int h_shift=0; +char *pstr=NULL; +char upx[10]; +char upy[10]; +char vsh[10]; +char hsh[10]; +int i=0; + +//clear all invisible char +DeleteAllSpace(cmd); + +//find UPSIDEX +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"UPSIDEX="); +if (pstr!=NULL) +{ +strncpy(upx,(char *)(pstr+strlen("UPSIDEX=")),4); + +i=0; +while (i<4) + { + if (upx[i]<0x20) + { + upx[i]=0; + swapx = myatoi(upx); + break; + } + i++; + } +} + +//find UPSIDEY +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"UPSIDEY="); +if (pstr!=NULL) +{ +strncpy(upy,(char *)(pstr+strlen("UPSIDEY=")),4); + +i=0; +while (i<4) + { + if (upy[i]<0x20) + { + upy[i]=0; + swapy = myatoi(upy); + break; + } + i++; + } +} + +//find V_SHIFT +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"V_SHIFT="); +if (pstr!=NULL) +{ +strncpy(vsh,(char *)(pstr+strlen("V_SHIFT=")),4); +i=0; +while (i<4) + { + if (vsh[i]<0x20) + { + vsh[i]=0; + v_shift = myatoi(vsh); + break; + } + i++; + } +} + +//find H_SHIFT +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"H_SHIFT="); +if (pstr!=NULL) +{ +strncpy(hsh,(char *)(pstr+strlen("H_SHIFT=")),4); +i=0; +while (i<4) + { + if (hsh[i]<0x20) + { + hsh[i]=0; + h_shift = myatoi(hsh); + break; + } + i++; + } +} +//v_flag +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"V_FLAG="); +if (pstr!=NULL) +{ +strncpy(hsh,(char *)(pstr+strlen("V_FLAG=")),4); + +i=0; +while (i<4) + { + if (hsh[i]<0x20) + { + hsh[i]=0; + v_flag = myatoi(hsh); + break; + } + i++; + } +} + +//H_flag +pstr=NULL; +pstr=strstr((const char*)cmd,(const char*)"H_FLAG="); +if (pstr!=NULL) +{ +strncpy(hsh,(char *)(pstr+strlen("H_FLAG=")),4); +i=0; +while (i<4) + { + if (hsh[i]<0x20) + { + hsh[i]=0; + h_flag = myatoi(hsh); + break; + } + i++; + } +} + +printk("%d\n",v_flag); +printk("%d\n",h_flag); +printk("%d\n",swapx); +printk("%d\n",swapy); +printk("%d\n",v_shift); +printk("%d\n",h_shift); +} + +static void DeleteAllSpace(char *cmd) +{ +char tmp[256]; +int i=0; +int j=0; +memset((char *)&tmp,0,256); +for (i=0;i<250;i++) + { + //printk("%02x ",cmd[i]&0xff); + + if ((cmd[i]!=0x09) && (cmd[i]!=0x20)) + { + tmp[j]=cmd[i]; + j++; + } + } +//printk("%s\n",cmd); + +//printk("\n"); +tmp[j]=0; +//for (i=0;i<250;i++) +// { + //printk("%02x ",tmp[i]&0xff); +// } +//printk("%s\n",tmp); + +strncpy(cmd,tmp,250); +} + +static int myatoi(char *str) +{ +int i; +int num=0; +int len = strlen(str); + + +for (i=0;i<len;i++) + { + // printk("%02x ",str[i]); + if (str[i]<0x30) + break; + else + { + // printk("s=%x d=%x s=%x ",str[i],str[i]-0x30,mypow(len-i-1)); + num = num + mypow(i)*(str[len-i-1]-0x30); + // printk("num = %d\n",num); + } + } +//printk("\n"); +return num; +} + +int mypow(int t) +{ +if (t==0) return 1; +if (t==1) return 10; +if (t==2) return 100; +if (t==3) return 1000; +if (t==4) return 10000; +else +return 0; +} + +static struct usb_driver usbtouch_driver = { + .name = "metusb", + .probe = usbtouch_probe, + .disconnect = usbtouch_disconnect, + .suspend = usbtouch_suspend, + .resume = usbtouch_resume, + .reset_resume = usbtouch_reset_resume, + .id_table = metusb_table, + .supports_autosuspend = 1, +}; + + +static int __init usbtouch_init(void) +{ + return usb_register(&usbtouch_driver); +} + +static void __exit usbtouch_cleanup(void) +{ + usb_deregister(&usbtouch_driver); +} + +module_init(usbtouch_init); +module_exit(usbtouch_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS("metusb"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile new file mode 100755 index 00000000..4539aa8d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile @@ -0,0 +1,33 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_semisens + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := sn310m-touch.o touch.o +#mach-sn310m-sample.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h new file mode 100755 index 00000000..fcf1e3c6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h @@ -0,0 +1,201 @@ +/**************************************************************** + * + * sn310m-touch-pdata.c + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ + +#ifndef __TOUCH_PDATA_H +#define __TOUCH_PDATA_H + +#ifdef CONFIG_HAS_EARLYSUSPEND + #include <linux/earlysuspend.h> +#endif + +#include <linux/interrupt.h> + +#ifndef errlog +#define errlog(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__, __LINE__ ,## args) +#endif + + +//#define DEBUG_TOUCH + +#undef dbg +#ifdef DEBUG_TOUCH +#define dbg(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__, __LINE__ ,## args) +#else +#define dbg(fmt, args...) +#endif + +#undef MSM_GPIO_TO_INT +#define MSM_GPIO_TO_INT(a) (a) + + + + +#define I2C_TOUCH_NAME "SN310M" +#define I2C_SEND_MAX_SIZE 512 // I2C Send/Receive data max size + +//-------------------------------------------- +// Button struct (1 = press, 0 = release) +//-------------------------------------------- +typedef struct button__t { + unsigned char bt0_press :1; // lsb + unsigned char bt1_press :1; + unsigned char bt2_press :1; + unsigned char bt3_press :1; + unsigned char bt4_press :1; + unsigned char bt5_press :1; + unsigned char bt6_press :1; + unsigned char bt7_press :1; // msb +} __attribute__ ((packed)) button_t; + +typedef union button__u { + unsigned char ubyte; + button_t bits; +} __attribute__ ((packed)) button_u; + +//-------------------------------------------- +// Touch Event type define +//-------------------------------------------- +#define TS_EVENT_UNKNOWN 0x00 +#define TS_EVENT_PRESS 0x01 +#define TS_EVENT_MOVE 0x02 +#define TS_EVENT_RELEASE 0x03 + +typedef struct finger__t { + unsigned int status; // true : ts data updated, false : no update data + unsigned int event; // ts event type + unsigned int id; // ts received id + unsigned int x; // ts data x + unsigned int y; // ts data y + unsigned int area; // ts finger area + unsigned int pressure; // ts finger pressure +} __attribute__ ((packed)) finger_t; + +struct touch { + int irq; + struct i2c_client *client; + struct touch_pdata *pdata; + struct input_dev *input; + char phys[32]; + + finger_t *finger; // finger data + struct mutex mutex; + + // sysfs control flags + unsigned char disabled; // interrupt status + unsigned char fw_version; + + unsigned char *fw_buf; + unsigned int fw_size; + int fw_status; + + // irq func used + struct workqueue_struct *work_queue; + struct work_struct work; + + // noise filter work + struct delayed_work filter_dwork; + +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend power; +#endif +}; + +struct i2c_client; +struct input_dev; +struct device; + +#define IRQ_MODE_THREAD 0 +#define IRQ_MODE_NORMAL 1 +#define IRQ_MODE_POLLING 2 + +//-------------------------------------------- +// IRQ type & trigger action +//-------------------------------------------- +// +// IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING, IRQF_TRIGGER_HIGH, IRQF_TRIGGER_LOW +// IRQF_DISABLED, IRQF_SHARED, IRQF_IRQPOLL, IRQF_ONESHOT, IRQF_NO_THREAD +// +//-------------------------------------------- +struct touch_pdata { + char *name; // input drv name + + int irq_gpio; // irq gpio define + int reset_gpio; // reset gpio define + int reset_level; // reset level setting (1 = High reset, 0 = Low reset) + + int irq_mode; // IRQ_MODE_THREAD, IRQ_MODE_NORMAL, IRQ_MODE_POLLING + int irq_flags; // irq flags setup : Therad irq mode(IRQF_TRIGGER_HIGH | IRQF_ONESHOT) + + int abs_max_x, abs_max_y; + int abs_min_x, abs_min_y; + + int area_max, area_min; + int press_max, press_min; + int id_max, id_min; + + int vendor, product, version; + + int max_fingers; + + int *keycode, keycnt; + int lcd_exchg; + + //-------------------------------------------- + // Control function + //-------------------------------------------- + void (*gpio_init) (void); // gpio early-init function + + irqreturn_t (*irq_func) (int irq, void *handle); + void (*touch_work) (struct touch *ts); + + void (*report) (struct touch *ts); + void (*key_report) (struct touch *ts, unsigned char button_data); + + int (*early_probe) (struct touch *ts); + int (*probe) (struct touch *ts); + void (*enable) (struct touch *ts); + void (*disable) (struct touch *ts); + int (*input_open) (struct input_dev *input); + void (*input_close) (struct input_dev *input); + + void (*event_clear) (struct touch *ts); + +#ifdef CONFIG_HAS_EARLYSUSPEND + void (*resume) (struct early_suspend *h); + void (*suspend) (struct early_suspend *h); +#endif + + /* by limst, added to control power for touch IC */ + int (*power) (int on); + + //-------------------------------------------- + // I2C control function + //-------------------------------------------- + int (*i2c_write) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*i2c_read) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + + //-------------------------------------------- + // Firmware update control function + //-------------------------------------------- + char *fw_filename; + int fw_filesize; + + int (*i2c_boot_write) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*i2c_boot_read) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*fw_control) (struct touch *ts, unsigned int fw_status); + int (*flash_firmware) (struct device *dev, const char *fw_name); + + //-------------------------------------------- + // Calibration control function + //-------------------------------------------- + int (*calibration) (struct touch *ts); +}; + +#endif // __TOUCH_PDATA_H + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c new file mode 100755 index 00000000..81275baf --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c @@ -0,0 +1,332 @@ +/**************************************************************** + * + * sn310m-touch.c : I2C Touchscreen driver (platform data struct) + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#include <linux/device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/hrtimer.h> +#include <asm/unaligned.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> + +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + +//---------------------------------------------- +#include "sn310m-touch-pdata.h" +#include "sn310m-touch.h" +#include "touch.h" + + +//---------------------------------------------- +unsigned char sn310m_id_tracking(struct touch *ts, unsigned char find_id); + +//---------------------------------------------- +// Touch i2c control function +//---------------------------------------------- +int sn310m_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) +{ + struct i2c_msg msg[2]; + int ret = 0; + unsigned char i = 0; + unsigned char cmd_tmp[10] = {0, }; + + if((len == 0) || (data == NULL)) { + dev_err(&client->dev, "I2C read error: Null pointer or length == 0\n"); + return -1; + } + + memset(cmd_tmp, 0x00, sizeof(cmd_tmp)); + + if(cmd_len) { + for(i = 0; i < cmd_len; i++) { + cmd_tmp[i] = cmd[cmd_len -1 -i]; + } + } + + memset(msg, 0x00, sizeof(msg)); + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = cmd_len; + msg[0].buf = cmd_tmp; + + msg[1].addr = client->addr; + msg[1].flags = client->flags & I2C_M_TEN; + msg[1].flags |= I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + if((ret = i2c_transfer(client->adapter, msg, 2)) != 2) { + dev_err(&client->dev, "I2C read error: (%d) reg: 0x%X len: %d\n", ret, cmd_tmp[0], len); + return -EIO; + } + + return len; +} + +int sn310m_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) +{ + int ret = 0; + unsigned char block_data[10] = {0, }; + unsigned char i = 0; + unsigned char cmd_tmp[10] = {0, }; + + if((cmd_len + len) >= sizeof(block_data)) { + dev_err(&client->dev, "I2C write error: wdata overflow reg: 0x%X len: %d\n", cmd[0], cmd_len + len); + return -1; + } + + memset(block_data, 0x00, sizeof(block_data)); + memset(cmd_tmp, 0x00, sizeof(cmd_tmp)); + + if(cmd_len) { + for(i = 0; i < cmd_len; i++) { + cmd_tmp[i] = cmd[cmd_len -1 -i]; + } + } + + if(cmd_len) + memcpy(&block_data[0], &cmd_tmp[0], cmd_len); + + if(len) + memcpy(&block_data[cmd_len], &data[0], len); + + if((ret = i2c_master_send(client, block_data, (cmd_len + len))) < 0) { + dev_err(&client->dev, "I2C write error: (%d) reg: 0x%X len: %d\n", ret, cmd[0], len); + return ret; + } + + return len; +} + +//---------------------------------------------- +// Touch initialize & finalize function +//---------------------------------------------- +int sn310m_input_open(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + dbg("%s\n", __func__); + + ts->pdata->enable(ts); + + return 0; +} + +void sn310m_enable(struct touch *ts) +{ + unsigned short cmd = REG_TS_STATUS; + unsigned int rdata = 0; + dbg("sn310m_enable++\n"); + if(ts->disabled) { + while(!gpio_get_value(ts->pdata->irq_gpio)) + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rdata, sizeof(rdata)); + wmt_gpio_set_irq_type(ts->pdata->irq_gpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts->pdata->irq_gpio); + dbg("enable_irq (%d)\n",ts->irq); + ts->disabled = false; + } + dbg("sn310m_enable--\n"); +} + +void sn310m_disable(struct touch *ts) +{ + dbg("sn310m_disable++\n"); + if(!ts->disabled) { + //disable_irq(ts->irq);//wmt_gpio_mask_irq(ts->pdata->irq_gpio);// + wmt_gpio_mask_irq(ts->pdata->irq_gpio); + dbg("disable_irq(ts->irq);\n"); + ts->disabled = true; + if(ts->pdata->event_clear){ + ts->pdata->event_clear(ts); + } + } + dbg("sn310m_disable--"); +} + +int sn310m_early_probe(struct touch *ts) +{ + // nothing to do... + + return 0; +} + +int sn310m_probe(struct touch *ts) +{ + unsigned short cmd = REG_FIRMWARE_VERSION; + unsigned short rdata = 0; + + if(ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rdata, sizeof(rdata)) < 0) { + errlog("fail to get touch ic firmware version.\n"); + return -1; + } + + ts->fw_version = rdata; + + dbg("touch ic firmware version : %d \n", rdata); + + return 0; +} + +//---------------------------------------------- +// calibration function +//---------------------------------------------- +int sn310m_calibration(struct touch *ts) +{ + // nothing to do... + + return 0; +} + +#define SN310M_NATIVE_INTERFACE +#if defined(SN310M_NATIVE_INTERFACE) +#include <linux/syscalls.h> +extern int g_MiscInitialize; +#endif + +//---------------------------------------------- +// Touch data processing function +//---------------------------------------------- +void sn310m_work(struct touch *ts) +{ + unsigned char find_slot = 0; + unsigned short cmd = 0; + status_reg_u status; + data_reg_t data; + button_u button; + unsigned int ids = 0; + int i = 0; + + mutex_lock(&ts->mutex); + + cmd = REG_TS_STATUS; + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&status.uint, sizeof(status_reg_u)); + + if(status.bits.ts_cnt <= ts->pdata->max_fingers) { + unsigned char cnt = 0; + + if(ts->pdata->keycode && (status.bits.ts_cnt == 0)) { + button.bits.bt0_press = (status.bits.button & 0x01) ? 1 : 0; + button.bits.bt1_press = (status.bits.button & 0x02) ? 1 : 0; + button.bits.bt2_press = (status.bits.button & 0x04) ? 1 : 0; + button.bits.bt3_press = (status.bits.button & 0x08) ? 1 : 0; + + ts->pdata->key_report(ts, button.ubyte); + } + + for(cnt = 0; cnt < status.bits.ts_cnt; cnt++) { + unsigned int id; + unsigned int x; + unsigned int y; + unsigned int area; + unsigned int pressure; + + cmd = REG_TS_DATA(cnt); + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&data.packet0, sizeof(data_reg_t)); + + id = data.packet0 >> 12; + x = data.packet0 & 0xfff; + y = data.packet1 & 0xfff; + area = data.packet2 & 0xfff; + pressure = ((data.packet1 >> 8) & 0x00f0) + (data.packet2 >> 12); + + dbg("DEBUG(%s) : cmd=%d, id=%d, x=%d, y=%d, area=%d, pressure=%d \n", __func__, cmd, id, x, y, area, pressure); + dbg("DEBUG(%s) : pkt0=%x pkt1=%x pkt2=%x \n", __func__, data.packet0, data.packet1, data.packet2); + + if((x >= ts->pdata->abs_max_x) || (y >= ts->pdata->abs_max_y)) { + if(ts->pdata->event_clear) + ts->pdata->event_clear(ts); + + dbg("ERROR(%s) : x(%d) or y(%d) value overflow!\n", __func__, x, y); + continue; + } + + if(ts->pdata->id_max) { + if((id >= ts->pdata->id_max) || (id < ts->pdata->id_min)) { + if(ts->pdata->event_clear) + ts->pdata->event_clear(ts); + + dbg("ERROR(%s) : id(%d) value overflow!\n", __func__, id); + continue; + } + if((find_slot = sn310m_id_tracking(ts, id)) == 0xFF) { + dbg("ERROR(%s) : Empty slot not found\n", __func__); + continue; + } + } + else { + if(id == 0) + continue; + + find_slot = cnt; + } + + if(ts->finger[find_slot].event == TS_EVENT_UNKNOWN) + ts->finger[find_slot].event = TS_EVENT_PRESS; + else if((ts->finger[find_slot].event == TS_EVENT_PRESS) || (ts->finger[find_slot].event == TS_EVENT_MOVE)) + ts->finger[find_slot].event = TS_EVENT_MOVE; + + if (ts->pdata->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ts->pdata->abs_max_x - tmp; + } + + ts->finger[find_slot].status = true; + ts->finger[find_slot].id = id; + ts->finger[find_slot].x = x; + ts->finger[find_slot].y = y; + ts->finger[find_slot].area = (ts->pdata->area_max < area) ? ts->pdata->area_max : area; + ts->finger[find_slot].pressure = (ts->pdata->press_max < pressure) ? ts->pdata->press_max : pressure; + ids |= 1 << find_slot; + } + } + + for(i = 0; i < ts->pdata->max_fingers; i++) { + if(!(ids & (1 << i))) { + if(ts->finger[i].event != TS_EVENT_UNKNOWN) { + ts->finger[i].status = true; + ts->finger[i].event = TS_EVENT_RELEASE; + } + } + } + + ts->pdata->report(ts); + mutex_unlock(&ts->mutex); + wmt_gpio_unmask_irq(ts->pdata->irq_gpio); +} + +unsigned char sn310m_id_tracking(struct touch *ts, unsigned char find_id) +{ + unsigned char find_slot = 0xFF; + int i = 0; + + for(i = 0; i < ts->pdata->max_fingers; i++) { + if(ts->finger[i].id == find_id) + find_slot = i; + + if((ts->finger[i].event == TS_EVENT_UNKNOWN) && (find_slot == 0xFF)) + find_slot = i; + } + return find_slot; +} + +//---------------------------------------------- +// Firmware update Control function +//---------------------------------------------- +int sn310m_flash_firmware(struct device *dev, const char *fw_name) +{ + // nothing to do... + return 0; +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h new file mode 100755 index 00000000..0469bf19 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h @@ -0,0 +1,97 @@ +/**************************************************************** + * + * sn310m-touch.c : i2c Touchscreen driver (platform data struct) + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#ifndef __SN310M_TOUCH_H +#define __SN310M_TOUCH_H + +//---------------------------------------------- +// register address for firmware update +//---------------------------------------------- +#define REG_CMD_ISP_MODE 0x02F1 // 0x0200 : prepare eFlash, 0x0100 : finish eFalsh +#define REG_CMD_FLASH_BUS 0x04F1 // 0x0000 : set eFlash bus functions +#define REG_CMD_FLASH_ENABLE 0x08F1 // 0xFFFF : enable eFlash functions +#define REG_CMD_FLASH_AUTH 0x00F4 // 0x0100 : get eFlash approach authority +#define REG_CMD_FLASH_CON_EN 0x02F4 // 0x0000 : enable eFlash controller +#define REG_CMD_FLASH_COMMAND 0x04F4 // 0x0200 : erase eFlash, 0x0000 : write eFlash +#define REG_CMD_FLASH_BUSY 0x08F4 // [15] bit is busy flag for eflash eperating. + +//---------------------------------------------- +// register setting value for firmware update +//---------------------------------------------- +#define REG_SET_PREPARE_FLASH_ACCESS 0x0200 +#define REG_SET_FINISH_FLASH_ACCESS 0x0100 +#define REG_SET_ENABLE_FLASH_ERASE 0x0200 +#define REG_SET_ENABLE_FLASH_WRITE 0x0000 + +#define SN310M_MAX_FW_SIZE (10*1024) // 10 Kbytes +#define REG_FIRMWARE_VERSION (0x3EE0) + +//---------------------------------------------- +// Touch status & data register address +//---------------------------------------------- +#define REG_TS_STATUS 0x00E0 + +typedef struct status_reg__t { + unsigned int ts_cnt :4; // lsb + unsigned int reserved1 :4; + unsigned int button :5; + unsigned int reserved2 :3; // msb +} __attribute__ ((packed)) status_reg_t; + +typedef union status_reg__u { + unsigned short uint; + status_reg_t bits; +} __attribute__ ((packed)) status_reg_u; + +#define REG_TS_DATA_BASE 0x02E0 +#define REG_TS_DATA(x) (((x * 6) << 8) + REG_TS_DATA_BASE) + +typedef struct data_reg__t { + unsigned short packet0; + unsigned short packet1; + unsigned short packet2; +} __attribute__ ((packed)) data_reg_t; + +typedef union data_reg__u { + unsigned int uint; + data_reg_t bits; +} __attribute__ ((packed)) data_reg_u; + + +//---------------------------------------------- +// i2c Control function +//---------------------------------------------- +extern int sn310m_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); +extern int sn310m_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + +//---------------------------------------------- +// Touch initialize & finalize function +//---------------------------------------------- +extern int sn310m_input_open(struct input_dev *input); +extern void sn310m_enable(struct touch *ts); +extern void sn310m_disable(struct touch *ts); +extern int sn310m_early_probe(struct touch *ts); +extern int sn310m_probe(struct touch *ts); + +//---------------------------------------------- +// Calibration function +//---------------------------------------------- +extern int sn310m_calibration(struct touch *ts); + +//---------------------------------------------- +// Touch data processing function +//---------------------------------------------- +extern void sn310m_work(struct touch *ts); + +//---------------------------------------------- +// Firmware update Control function +//---------------------------------------------- +extern int sn310m_flash_firmware(struct device *dev, const char *fw_name); + +#endif // __SN310M_TOUCH_H + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c new file mode 100755 index 00000000..39d6ce15 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c @@ -0,0 +1,1121 @@ +/**************************************************************** + * + * touch.c : I2C Touchscreen driver + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/hrtimer.h> +#include <asm/unaligned.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> + +//---------------------------------------------- +#if defined(CONFIG_HAS_EARLYSUSPEND) + #include <linux/wakelock.h> + #include <linux/earlysuspend.h> + #include <linux/suspend.h> +#endif + +//---------------------------------------------- +#include <linux/input/mt.h> +#include "sn310m-touch-pdata.h" +#include "sn310m-touch.h" + +//---------------------------------------------- +#include "touch.h" +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +#define SN310M_NATIVE_INTERFACE /* This is to debug semisens TSC */ + +#if defined(SN310M_NATIVE_INTERFACE) +#include <linux/miscdevice.h> +#include <linux/syscalls.h> +struct touch* g_ts; +int g_MiscInitialize = 0; +static int P_SN310M_Dist_Probe(struct touch* ts); +static int P_SN310M_Dist_Open(struct inode *inode, struct file *file); +static long P_SN310M_Dist_Ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static void P_SN310M_Dist_Remove(void); +#endif + +// function prototype define +//---------------------------------------------- +#ifdef CONFIG_HAS_EARLYSUSPEND + static void touch_suspend(struct early_suspend *h); + static void touch_resume(struct early_suspend *h); +#endif + +irqreturn_t touch_irq(int irq, void *handle); +#if 0 /* unused */ + static void touch_work(struct touch *ts); +#endif +static void touch_work_q(struct work_struct *work); +static void touch_key_report(struct touch *ts, unsigned char button_data); +static void touch_report_protocol_a(struct touch *ts); +static void touch_report_protocol_b(struct touch *ts); +static void touch_event_clear(struct touch *ts); +#if 0 /* unused */ + static void touch_enable(struct touch *ts); + static void touch_disable(struct touch *ts); +#endif +static void touch_input_close(struct input_dev *input); +static int touch_input_open(struct input_dev *input); +static int touch_check_functionality (struct touch_pdata *pdata); +void touch_hw_reset(struct touch *ts); +int touch_info_display(struct touch *ts); +int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id); +int touch_remove(struct i2c_client *client); + + +// Kinsey: +#define WMT_TS_I2C_NAME "wmt-ts" +static struct i2c_client *l_client; + + + + +//---------------------------------------------- +irqreturn_t touch_irq(int irq, void *handle) +{ + struct touch *ts = handle; + if (gpio_irqstatus(ts->pdata->irq_gpio)){ + wmt_gpio_ack_irq(ts->pdata->irq_gpio); + if (is_gpio_irqenable(ts->pdata->irq_gpio)){ + wmt_gpio_mask_irq(ts->pdata->irq_gpio); + #ifdef CONFIG_HAS_EARLYSUSPEND + if(!ts->earlysus) + queue_work(ts->work_queue, &ts->work); + #else + queue_work(ts->work_queue, &ts->work); + #endif + } + return IRQ_HANDLED; + } + return IRQ_NONE; + +} + +//---------------------------------------------- +static void touch_work_q(struct work_struct *work) +{ + struct touch *ts = container_of(work, struct touch, work); + ts->pdata->touch_work(ts); +} + +//---------------------------------------------- +static void touch_key_report(struct touch *ts, unsigned char button_data) +{ + static button_u button_old; + button_u button_new; + + button_new.ubyte = button_data; + if(button_old.ubyte != button_new.ubyte) { + if((button_old.bits.bt0_press != button_new.bits.bt0_press) && (ts->pdata->keycnt > 0)) { + if(button_new.bits.bt0_press) input_report_key(ts->input, ts->pdata->keycode[0], true); + else input_report_key(ts->input, ts->pdata->keycode[0], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[0](0x%04X) %s\n", ts->pdata->keycode[0], button_new.bits.bt0_press ? "press":"release"); + #endif + } + if((button_old.bits.bt1_press != button_new.bits.bt1_press) && (ts->pdata->keycnt > 1)) { + if(button_new.bits.bt1_press) input_report_key(ts->input, ts->pdata->keycode[1], true); + else input_report_key(ts->input, ts->pdata->keycode[1], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[1](0x%04X) %s\n", ts->pdata->keycode[1], button_new.bits.bt1_press ? "press":"release"); + #endif + } + if((button_old.bits.bt2_press != button_new.bits.bt2_press) && (ts->pdata->keycnt > 2)) { + if(button_new.bits.bt2_press) input_report_key(ts->input, ts->pdata->keycode[2], true); + else input_report_key(ts->input, ts->pdata->keycode[2], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[2](0x%04X) %s\n", ts->pdata->keycode[2], button_new.bits.bt2_press ? "press":"release"); + #endif + } + if((button_old.bits.bt3_press != button_new.bits.bt3_press) && (ts->pdata->keycnt > 3)) { + if(button_new.bits.bt3_press) input_report_key(ts->input, ts->pdata->keycode[3], true); + else input_report_key(ts->input, ts->pdata->keycode[3], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[3](0x%04X) %s\n", ts->pdata->keycode[3], button_new.bits.bt3_press ? "press":"release"); + #endif + } + if((button_old.bits.bt4_press != button_new.bits.bt4_press) && (ts->pdata->keycnt > 4)) { + if(button_new.bits.bt4_press) input_report_key(ts->input, ts->pdata->keycode[4], true); + else input_report_key(ts->input, ts->pdata->keycode[4], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[4](0x%04X) %s\n", ts->pdata->keycode[4], button_new.bits.bt4_press ? "press":"release"); + #endif + } + if((button_old.bits.bt5_press != button_new.bits.bt5_press) && (ts->pdata->keycnt > 5)) { + if(button_new.bits.bt5_press) input_report_key(ts->input, ts->pdata->keycode[5], true); + else input_report_key(ts->input, ts->pdata->keycode[5], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[5](0x%04X) %s\n", ts->pdata->keycode[5], button_new.bits.bt5_press ? "press":"release"); + #endif + } + if((button_old.bits.bt6_press != button_new.bits.bt6_press) && (ts->pdata->keycnt > 6)) { + if(button_new.bits.bt6_press) input_report_key(ts->input, ts->pdata->keycode[6], true); + else input_report_key(ts->input, ts->pdata->keycode[6], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[6](0x%04X) %s\n", ts->pdata->keycode[6], button_new.bits.bt6_press ? "press":"release"); + #endif + } + if((button_old.bits.bt7_press != button_new.bits.bt7_press) && (ts->pdata->keycnt > 7)) { + if(button_new.bits.bt7_press) input_report_key(ts->input, ts->pdata->keycode[7], true); + else input_report_key(ts->input, ts->pdata->keycode[7], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[7](0x%04X) %s\n", ts->pdata->keycode[7], button_new.bits.bt7_press ? "press":"release"); + #endif + } + button_old.ubyte = button_new.ubyte; + } +} + +//---------------------------------------------- +static void touch_report_protocol_a(struct touch *ts) +{ + int id; + + for(id = 0; id < ts->pdata->max_fingers; id++) { + + if(ts->finger[id].event == TS_EVENT_UNKNOWN) continue; + + if(ts->finger[id].event != TS_EVENT_RELEASE) { + if(ts->pdata->id_max) input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); + if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); + if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); + + input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); + dbg("%s : id = %d, x = %d, y = %d\n", __func__, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); + } + else { + ts->finger[id].event = TS_EVENT_UNKNOWN; + dbg("%s : release id = %d\n", __func__, ts->finger[id].id); + } + + input_mt_sync(ts->input); + } + + input_sync(ts->input); +} + +//---------------------------------------------- +static void touch_report_protocol_b(struct touch *ts) +{ + int id; +#if defined(DEBUG_TOUCH) + char *event_str[] = {"unknown", "press", "move", "release"}; +#endif + + for(id = 0; id < ts->pdata->max_fingers; id++) { + if((ts->finger[id].event == TS_EVENT_UNKNOWN) || (ts->finger[id].status == false)) + continue; + + input_mt_slot(ts->input, id); + ts->finger[id].status = false; + + if(ts->finger[id].event != TS_EVENT_RELEASE) { + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + + input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); + input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); + + if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); + if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); + +#if defined(DEBUG_TOUCH) + dbg("%s : event = %s, slot = %d, id = %d, x = %d, y = %d\n", __func__, event_str[ts->finger[id].event], id, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); +#endif + } + else { +#if defined(DEBUG_TOUCH) + dbg("%s : event = %s, slot = %d, id = %d\n", __func__, event_str[ts->finger[id].event], id, ts->finger[id].id); +#endif + ts->finger[id].event = TS_EVENT_UNKNOWN; + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false); + } + } + input_sync(ts->input); +} + +//---------------------------------------------- +static void touch_event_clear(struct touch *ts) +{ + unsigned char id; + + for(id = 0; id < ts->pdata->max_fingers; id++) { + if(ts->finger[id].event == TS_EVENT_MOVE) { + ts->finger[id].status = true; + ts->finger[id].event = TS_EVENT_RELEASE; + } + } + ts->pdata->report(ts); + if(ts->pdata->keycode) + ts->pdata->key_report(ts, 0x00); +} + +//---------------------------------------------- +static int touch_input_open(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + ts->pdata->enable(ts); + + dbg("%s\n", __func__); + + return 0; +} + +//---------------------------------------------- +static void touch_input_close(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + ts->pdata->disable(ts); + + dbg("%s\n", __func__); +} + +//---------------------------------------------- +static int touch_check_functionality(struct touch_pdata *pdata) +{ + if(!pdata) { + errlog("Error : Platform data is NULL pointer!\n"); return -1; + } + + pdata->i2c_read = sn310m_i2c_read; + pdata->i2c_write = sn310m_i2c_write; + + pdata->i2c_boot_read = sn310m_i2c_read; + pdata->i2c_boot_write = sn310m_i2c_write; + + pdata->enable = sn310m_enable; + pdata->disable = sn310m_disable; + pdata->probe = sn310m_probe; + + if(!pdata->report) { + if(pdata->id_max) pdata->report = touch_report_protocol_b; + else pdata->report = touch_report_protocol_a; + } + if(!pdata->key_report) pdata->key_report = touch_key_report; + + pdata->touch_work = sn310m_work; + + if(!pdata->irq_func) pdata->irq_func = touch_irq; + + if(!pdata->event_clear) pdata->event_clear = touch_event_clear; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!pdata->resume) pdata->resume = touch_resume; + if(!pdata->suspend) pdata->suspend = touch_suspend; +#endif + + //pdata->irq_gpio = 7; + + return 0; +} + +//---------------------------------------------- +void touch_hw_reset(struct touch *ts) +{ + if(ts->pdata->reset_gpio) { + if(gpio_request(ts->pdata->reset_gpio, "touch reset")) { + errlog("--------------------------------------------------------\n"); + errlog("%s : request port error!\n", "touch reset"); + errlog("--------------------------------------------------------\n"); + } + else { + if(ts->pdata->power) { + /* power sequence: reset low -> power on -> reset high */ + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + mdelay(15); + ts->pdata->power(1); + mdelay(50); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + } + else { + /* if there is no power control for touch, then just do reset (high -> low -> high) */ + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + gpio_set_value(ts->pdata->reset_gpio, 0); + mdelay(20); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + } + } + } +} + +//---------------------------------------------- +int touch_info_display(struct touch *ts) +{ + errlog("--------------------------------------------------------\n"); + errlog(" TOUCH SCREEN INFORMATION\n"); + errlog("--------------------------------------------------------\n"); + if(ts->pdata->irq_gpio) { + errlog("TOUCH INPUT Name = %s\n", ts->pdata->name); + + switch(ts->pdata->irq_mode) { + default : + case IRQ_MODE_THREAD: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_THREAD"); break; + case IRQ_MODE_NORMAL: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_NORMAL"); break; + case IRQ_MODE_POLLING: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_POLLING"); break; + } + errlog("TOUCH F/W Version = %d.%02d\n", ts->fw_version / 100, ts->fw_version % 100); + errlog("TOUCH FINGRES MAX = %d\n", ts->pdata->max_fingers); + errlog("TOUCH ABS X MAX = %d, TOUCH ABS X MIN = %d\n", ts->pdata->abs_max_x, ts->pdata->abs_min_x); + errlog("TOUCH ABS Y MAX = %d, TOUCH ABS Y MIN = %d\n", ts->pdata->abs_max_y, ts->pdata->abs_min_y); + + if(ts->pdata->area_max) + errlog("TOUCH MAJOR MAX = %d, TOUCH MAJOR MIN = %d\n", ts->pdata->area_max, ts->pdata->area_min); + + if(ts->pdata->press_max) + errlog("TOUCH PRESS MAX = %d, TOUCH PRESS MIN = %d\n", ts->pdata->press_max, ts->pdata->press_min); + + if(ts->pdata->id_max) { + errlog("TOUCH ID MAX = %d, TOUCH ID MIN = %d\n", ts->pdata->id_max, ts->pdata->id_min); + errlog("Mulit-Touch Protocol-B Used.\n"); + } + else + errlog("Mulit-Touch Protocol-A Used.\n"); + + if(ts->pdata->gpio_init) + errlog("GPIO early-init function implemented\n"); + + if(ts->pdata->reset_gpio) + errlog("H/W Reset function implemented\n"); + + #ifdef CONFIG_HAS_EARLYSUSPEND + errlog("Early-suspend function implemented\n"); + #endif + if(ts->pdata->fw_control) + errlog("Firmware update function(sysfs control) implemented\n"); + + /* flashing sample is not implemented yet */ + if(ts->pdata->flash_firmware) + errlog("Firmware update function(udev control) implemented\n"); + + if(ts->pdata->calibration) + errlog("Calibration function implemented\n"); + } + else { + errlog("TOUCH INPUT Name = %s\n", ts->pdata->name); + errlog("Dummy Touchscreen driver!\n"); + } + errlog("--------------------------------------------------------\n"); + return 0; +} + +//---------------------------------------------- +int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id) +{ + return -1; +} + +//---------------------------------------------- +// +// Power Management function +// +//---------------------------------------------- +#ifdef CONFIG_HAS_EARLYSUSPEND +static void touch_suspend(struct early_suspend *h) +{ + struct touch *ts = container_of(h, struct touch, power); + + dbg("%s++\n", __func__); + + /* TSC enters deep sleep mode */ + dbg("[%s] touch reset goes low!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + + ts->pdata->disable(ts); +} + +//---------------------------------------------- +static void touch_resume(struct early_suspend *h) +{ + struct touch *ts = container_of(h, struct touch, power); + + dbg("%s++\n", __func__); + + /* TSC enters active mode */ + dbg("[%s] touch reset goes high!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + + ts->pdata->enable(ts); +} +#endif + +//---------------------------------------------- +int touch_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("touch_remove++"); + + if(ts->irq) free_irq(ts->irq, ts); + + if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); + + if(ts->pdata->irq_gpio) gpio_free(ts->pdata->irq_gpio); + + input_unregister_device(ts->input); + + dev_set_drvdata(dev, NULL); + +#if defined(SN310M_NATIVE_INTERFACE) + P_SN310M_Dist_Remove(); +#endif + + kfree(ts->finger); ts->finger = NULL; + kfree(ts); ts = NULL; + + return 0; +} + +#if defined(SN310M_NATIVE_INTERFACE) +#define SN310M_DIST_MINOR 250 + +typedef struct { + unsigned int addr; + short *buf; + unsigned int size; +} packet_t; + +static const struct file_operations SN310M_Dist_Fops = +{ + .owner = THIS_MODULE, + .open = P_SN310M_Dist_Open, + .unlocked_ioctl = P_SN310M_Dist_Ioctl, +}; + + +static struct miscdevice SN310M_Dist_MiscDev = +{ + .minor = SN310M_DIST_MINOR, + .name = "sn310m_dist", + .fops = &SN310M_Dist_Fops, + .mode = 0x666, +}; + + +static long P_SN310M_Dist_Ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + packet_t* packet = (packet_t*)arg; + int i; + + mutex_lock(&g_ts->mutex); + switch(cmd) { + case 0: // write data + if(packet->size) { + unsigned short addr = (packet->addr >> 8) | (packet->addr & 0x00ff) << 8; + g_ts->pdata->i2c_write(g_ts->client, (unsigned char *)&addr, sizeof(addr), (unsigned char *)packet->buf, packet->size*2); + dbg("Request I2C Write\n"); + } + break; + + case 1: // read data + if(packet->size) { + unsigned short addr = (packet->addr >> 8) | (packet->addr & 0x00ff) << 8; + short buffer[500] = {0, }; + + g_ts->pdata->i2c_read(g_ts->client, (unsigned char *)&addr, sizeof(addr), (unsigned char *)buffer, packet->size*2); + for(i = 0; (i < packet->size) && (i < 500); i++) { + packet->buf[i] = buffer[i]; + } + dbg("Request I2C Read\n"); + } + break; + + default: + mutex_unlock(&g_ts->mutex); + return -ENOIOCTLCMD; + } + + mutex_unlock(&g_ts->mutex); + return 0; +} + +static int P_SN310M_Dist_Open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int P_SN310M_Dist_Probe(struct touch* ts) +{ + int result = 0; + + g_ts = ts; + result = misc_register(&SN310M_Dist_MiscDev); + if(result == 0) { + dbg("succeeded to register sn310m_misc_device \n"); + } + else { + errlog("failed to register sn310m_misc_device \n"); + } + + return result; +} + +static void P_SN310M_Dist_Remove(void) +{ + misc_deregister(&SN310M_Dist_MiscDev); + g_ts = NULL; +} +#endif +static const struct i2c_device_id sample_ts_id[] = { + { I2C_TOUCH_NAME, 0 }, + {}, +}; + + + +#define TS_DRIVER_NAME "wmt-touch" + +static void wmt_ts_platform_release(struct device *device) +{ + dbg("wmt_ts_platform_release\n"); + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +}; + +static int sn310m_keycode[] = { + KEY_HOME, KEY_MENU, KEY_BACK, KEY_SEARCH +}; + +struct touch_pdata sn310m_touch_pdata = { + + .name = "sn310m", // input drv name + .irq_gpio = 7,//SAMPLE_GPIO_0, // irq gpio define + .reset_gpio = 4,//SAMPLE_GPIO_1, // reset gpio define + .reset_level = 0, // reset level setting (1 = High reset, 0 = Low reset) + + .irq_mode = IRQ_MODE_NORMAL, // IRQ_MODE_THREAD, IRQ_MODE_NORMAL, IRQ_MODE_POLLING + .irq_flags = IRQF_SHARED ,//IRQF_TRIGGER_FALLING | IRQF_DISABLED, + + .abs_max_x = 600, + .abs_max_y = 1024, + + .area_max = 10, + .press_max = 255, + + .id_max = 10 + 1, + .id_min = 0, + + .vendor = 0x16B4, + .product = 0x0310, + .version = 0x0001, + + .max_fingers = 5, + + .keycnt = 4, + .keycode = sn310m_keycode, + .lcd_exchg = 0, + + //-------------------------------------------- + // Control function + //-------------------------------------------- + .touch_work = sn310m_work, + .enable = sn310m_enable, + .disable = sn310m_disable, + .early_probe = sn310m_early_probe, + .probe = sn310m_probe, + + //-------------------------------------------- + // I2C control function + //-------------------------------------------- + .i2c_write = sn310m_i2c_write, + .i2c_read = sn310m_i2c_read, + + //-------------------------------------------- + // Calibration function + //-------------------------------------------- + .calibration = sn310m_calibration, + + //-------------------------------------------- + // Firmware update control function + //-------------------------------------------- + .fw_filename = "sn310m_fw.bin", + .fw_filesize = (10 * 1024), // 10K bytes + .input_open = sn310m_input_open, + .flash_firmware = sn310m_flash_firmware, +}; + + +int temp; +static int wmt_ts_probe(struct platform_device *pdev) +{ + int rc = -1; + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts; + + + dbg("wmt_ts_probe\n"); + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "i2c byte data not supported\n"); + return -EIO; + } + + + client->dev.platform_data = &sn310m_touch_pdata; + + if(touch_check_functionality(client->dev.platform_data) < 0) { + dev_err(&client->dev, "Platform data is not available!\n"); + return -EINVAL; + } + + if(!(ts = kzalloc(sizeof(struct touch), GFP_KERNEL))) { + errlog("touch struct malloc error!\n"); + return -ENOMEM; + } + ts->client = client; + ts->pdata = client->dev.platform_data; + + + /* by limst, setting gpio for IRQ */ + if(ts->pdata->irq_gpio) { + int ret; + + ts->irq = IRQ_GPIO;//MSM_GPIO_TO_INT(ts->pdata->irq_gpio); + dbg("IRQ_GPIO(%d) IRQ(%d) REG\n", ts->pdata->irq_gpio, ts->irq); + + ret = gpio_request(ts->pdata->irq_gpio, "touch_int"); + if(ret < 0) + errlog("FAIL: touch_int gpio_request\n"); + else + dbg("OK: touch_int gpio_request value(%d)\n", gpio_get_value(ts->pdata->irq_gpio)); + + wmt_gpio_setpull(ts->pdata->irq_gpio,WMT_GPIO_PULL_UP); + gpio_direction_input(ts->pdata->irq_gpio); + wmt_gpio_set_irq_type(ts->pdata->irq_gpio, IRQ_TYPE_EDGE_FALLING); + } + + i2c_set_clientdata(client, ts); + + if(ts->pdata->max_fingers) { + if(!(ts->finger = kzalloc(sizeof(finger_t) * ts->pdata->max_fingers, GFP_KERNEL))) { + kfree(ts); + errlog("touch data struct malloc error!\n"); + return -ENOMEM; + } + } + + if(ts->pdata->gpio_init) ts->pdata->gpio_init(); + + if(ts->pdata->early_probe) { + if((rc = ts->pdata->early_probe(ts)) < 0) + goto err_free_mem; + } + + + dev_set_drvdata(dev, ts); + + if(!(ts->input = input_allocate_device())) + goto err_free_mem; + + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", ts->pdata->name); + + if(!ts->pdata->input_open) ts->input->open = touch_input_open; + else ts->input->open = ts->pdata->input_open; + if(!ts->pdata->input_close) ts->input->close = touch_input_close; + else ts->input->close = ts->pdata->input_close; + + /* + * by limst, for the test purpose, + * input device's name is forcedly set to the name of android idc file + */ + ts->input->name = "qwerty";//idc's filename //"touch_dev"; + //ts->input->name = ts->pdata->name; + ts->input->phys = ts->phys; + ts->input->dev.parent = dev; + ts->input->id.bustype = BUS_I2C; + + ts->input->id.vendor = ts->pdata->vendor; + ts->input->id.product = ts->pdata->product; + ts->input->id.version = ts->pdata->version; + + set_bit(EV_SYN, ts->input->evbit); + set_bit(EV_ABS, ts->input->evbit); + + /* Register Touch Key Event */ + if(ts->pdata->keycode) { + int key; + + set_bit(EV_KEY, ts->input->evbit); + + for(key = 0; key < ts->pdata->keycnt; key++) { + if(ts->pdata->keycode[key] <= 0) continue; + set_bit(ts->pdata->keycode[key] & KEY_MAX, ts->input->keybit); + } + } + + input_set_drvdata(ts->input, ts); + + if (sn310m_touch_pdata.lcd_exchg) { + input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); + } else { + input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); + } + + if(ts->pdata->area_max) + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, ts->pdata->area_min, ts->pdata->area_max, 0, 0); + + if(ts->pdata->press_max) + input_set_abs_params(ts->input, ABS_MT_PRESSURE, ts->pdata->press_min, ts->pdata->press_max, 0, 0); + + if(ts->pdata->id_max) { + input_set_abs_params(ts->input, ABS_MT_TRACKING_ID, ts->pdata->id_min, ts->pdata->id_max, 0, 0); + input_mt_init_slots(ts->input, ts->pdata->max_fingers); + } + + + mutex_init(&ts->mutex); + if(ts->irq) { + switch(ts->pdata->irq_mode) { + default : + case IRQ_MODE_THREAD: + INIT_WORK(&ts->work, touch_work_q); + if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) + goto err_free_input_mem; + + if((rc = request_threaded_irq(ts->irq, NULL, ts->pdata->irq_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->pdata->name, ts))) { + dev_err(dev, "threaded irq %d request fail!\n", ts->irq); + goto err_free_input_mem; + } + break; + case IRQ_MODE_NORMAL: + INIT_WORK(&ts->work, touch_work_q); + if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) + goto err_free_input_mem; + + if((rc = request_irq(ts->irq, ts->pdata->irq_func, ts->pdata->irq_flags, ts->pdata->name, ts))) { + errlog("irq %d request fail!\n", ts->irq); + goto err_free_input_mem; + } + dbg("irq %d request ok!\n", ts->irq); + break; + case IRQ_MODE_POLLING: + errlog("Error IRQ_MODE POLLING!! but defined irq_gpio\n"); + break; + } /* end of switch */ + } + ts->disabled = true; + + if((rc = input_register_device(ts->input))) { + dev_err(dev, "(%s) input register fail!\n", ts->input->name); + goto err_free_input_mem; + } + + /* by limst, added to turn on the power and reset of Touch IC */ + touch_hw_reset(ts); + +#if defined(CONFIG_HAS_EARLYSUSPEND) + if(ts->pdata->suspend) ts->power.suspend = ts->pdata->suspend; + if(ts->pdata->resume) ts->power.resume = ts->pdata->resume; + + ts->power.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + + register_early_suspend(&ts->power); +#endif + + if(ts->pdata->probe) { + ts->pdata->probe(ts); + } + + touch_info_display(ts); + +#if defined(SN310M_NATIVE_INTERFACE) + if(P_SN310M_Dist_Probe(ts) < 0) { + errlog("P_SN310M_Dist_Probe(), fail\n"); + } +#endif + + return 0; + + free_irq(ts->irq, ts); + input_unregister_device(ts->input); + err_free_input_mem: + input_free_device(ts->input); + ts->input = NULL; + err_free_mem: + kfree(ts->finger); + ts->finger = NULL; + kfree(ts); + ts = NULL; + return rc; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("wmt_ts_remove\n"); + + if(ts->irq) free_irq(ts->irq, ts); + + if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); + + if(ts->pdata->irq_gpio) gpio_free(ts->pdata->irq_gpio); + + input_unregister_device(ts->input); + + dev_set_drvdata(dev, NULL); + + #if defined(SN310M_NATIVE_INTERFACE) + P_SN310M_Dist_Remove(); + #endif + + kfree(ts->finger); ts->finger = NULL; + kfree(ts); ts = NULL; + + return 0; +} + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("%s++\n", __func__); + + /* TSC enters deep sleep mode */ + dbg("[%s] touch reset goes low!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + + + ts->pdata->disable(ts); + + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("%s++\n", __func__); + + /* TSC enters active mode */ + dbg("[%s] touch reset goes high!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + + ts->pdata->enable(ts); + //touch_hw_reset(ts); + + return 0; +} + + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + + + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + + ts_i2c_board_info.addr =(unsigned short) 0x3c; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + errlog("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + errlog("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static struct tp_info l_tpinfo; +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127; + char retval[200] = {0}; + char *p=NULL; + char *s=NULL; + int Enable=0; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(&l_tpinfo,0,sizeof(l_tpinfo)); + + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':'); + p++; + s = strchr(p,':'); + strncpy(l_tpinfo.name,p, (s-p)); + p = s+1; + //dbg("ts_name=%s\n", l_tpinfo.name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_tpinfo.irq_gpio,&l_tpinfo.panelres_x,&l_tpinfo.panelres_y,&l_tpinfo.rst_gpio, + &(l_tpinfo.xaxis),&(l_tpinfo.xdir),&(l_tpinfo.ydir), + &(l_tpinfo.max_finger_num),&l_tpinfo.i2caddr,&l_tpinfo.low_Impendence_mode,&l_tpinfo.download_option); + + if (ret < 8){ + errlog("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + if (strstr(l_tpinfo.name, sn310m_touch_pdata.name) == NULL){ + errlog("Can't find %s in the wmt.io.touch\n", sn310m_touch_pdata.name); + return -ENODEV; + } + + errlog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d,,i2c_addr=0x%X,low_Impendence_mode=%d,s_download_option=%d\n", + l_tpinfo.panelres_x, l_tpinfo.panelres_y, l_tpinfo.irq_gpio, l_tpinfo.rst_gpio, + l_tpinfo.xaxis,l_tpinfo.xdir,l_tpinfo.ydir, + l_tpinfo.max_finger_num,l_tpinfo.i2caddr,l_tpinfo.low_Impendence_mode,l_tpinfo.download_option); + + sn310m_touch_pdata.irq_gpio = l_tpinfo.irq_gpio; + sn310m_touch_pdata.reset_gpio = l_tpinfo.rst_gpio; + sn310m_touch_pdata.abs_max_x = l_tpinfo.panelres_x; + sn310m_touch_pdata.abs_max_y = l_tpinfo.panelres_y; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + sn310m_touch_pdata.lcd_exchg = 1; + } + + return 0; +} + + +static int __init sample_touch_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + + if (ts_i2c_register_device()<0){ + errlog("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + return 0; +} + +static void sample_touch_exit(void) +{ + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + ts_i2c_unregister_device(); + + return; +} + + +module_init(sample_touch_init); +module_exit(sample_touch_exit); + +#ifndef MODULE +__initcall(sample_touch_init); +#endif + + + +MODULE_AUTHOR("SEMISENS Co., Ltd."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Touchscreen Driver for SN310M"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h new file mode 100755 index 00000000..750112ea --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h @@ -0,0 +1,54 @@ +/**************************************************************** + * + * touch.c : I2C Touchscreen driver + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#ifndef _TOUCH_H_ +#define _TOUCH_H_ + +//---------------------------------------------- +// extern function define +//---------------------------------------------- +extern void touch_hw_reset(struct touch *ts); +extern int touch_info_display(struct touch *ts); +#if 0 /* depends on kernel version */ +extern int touch_probe(struct i2c_client *client); +extern int touch_remove(struct device *dev); +#else +extern int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id); +extern int touch_remove(struct i2c_client *client); +#endif + +struct tp_info +{ + char name[64]; + unsigned int xaxis; //0: x, 1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; + unsigned int download_option; // 0: disable 1:force download 2:force cancel download + unsigned int low_Impendence_mode; // 0: High Impendence Mode 1: Low Impendence Mode + unsigned int irq_gpio; + unsigned int rst_gpio; + unsigned int panelres_x; + unsigned int panelres_y; + unsigned int i2caddr; + unsigned int lcd_exchg; +#if 0 + struct input_dev *inputdev; + struct work_struct int_work; + struct i2c_client *i2cclient; + struct workqueue_struct *wq; +#if SUPPORT_TS_KEY + int key_num; +#endif +#endif + +}; + + + +#endif /* _TOUCH_H_ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig new file mode 100755 index 00000000..21574ec3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Kconfig @@ -0,0 +1,16 @@ +# +# SIS USB capacity touch screen driver configuration +# +config TOUCHSCREEN_SIS + tristate "SIS USB Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_sis + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile new file mode 100755 index 00000000..045ea698 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_sis
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := hid-sis.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c new file mode 100755 index 00000000..0b9cee3d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sis_usbhid_ts/hid-sis.c @@ -0,0 +1,1104 @@ +/* + * HID driver for sis 9237/9257 test touchscreens + * + * Copyright (c) 2008 Rafi Rubin + * Copyright (c) 2009 Stephane Chatty + * + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> +#include <linux/hid-debug.h> +//for i2c-bridge +#include <linux/usb.h> +#include "../../../hid/usbhid/usbhid.h" +#include <asm/uaccess.h> +#include <linux/types.h> + +#ifdef CONFIG_HID_SIS_UPDATE_FW +//for ioctl +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/cdev.h> + +#define INTERNAL_DEVICE_NAME "sis_zeus_hid_touch_device" +#define BRIDGE_DEVICE_NAME "sis_zeus_hid_bridge_touch_device" +#define SIS817_DEVICE_NAME "sis_aegis_hid_touch_device" +#define SISF817_DEVICE_NAME "sis_aegis_hid_bridge_touch_device" + +static int sis_char_devs_count = 1; /* device count */ +static int sis_char_major = 0; +static struct cdev sis_char_cdev; +static struct class *sis_char_class = NULL; +//20110111 Tammy system call for tool +static struct hid_device *hid_dev_backup = NULL; //backup address +static struct urb *backup_urb = NULL; +#endif //CONFIG_HID_SIS_UPDATE_FW + +///////////////// SIS START ///////////////// +#define USB_VENDOR_ID_SIS_TOUCH 0x1039 +#define USB_VENDOR_ID_SIS2_TOUCH 0x0457 +#define USB_PRODUCT_ID_SIS_TOUCH 0x0810 +#define USB_PRODUCT_ID_SIS2_TOUCH 0x0151 +#define USB_PRODUCT_ID_NEW_SIS2_TOUCH 0x0816 +#define USB_PRODUCT_ID_SIS9200_TOUCH 0x9200 +#define USB_PRODUCT_ID_SIS817_TOUCH 0x0817 +#define USB_PRODUCT_ID_SISF817_TOUCH 0xF817 + +//waltop id-table +#define USB_VENUS_ID_WALTOP 0x0503 +#define USB_VENUS_ID_WALTOP2 0x1040 +///////////////// SIS END ///////////////// +//#define CONFIG_HID_SIS_UPDATE_FW +//#define CONFIG_DEBUG_HID_SIS_INIT +//#define CONFIG_DEBUG_HID_SIS_SENDPOINT + +#define MAX_X 4095 +#define MAX_Y 4095 +//#define MAX_PRESSURE 2047 +#define MAX_SCANTIME 65535 +#define MAX_CONTACTID 31 + +#define MAX_POINT 10 +#define HID_DG_SCANTIME 0x000d0056 //new usage not defined in hid.h +#define REPORTID_10 0x10 +#define REPORTID_TYPE1 0x30 + +#define CTRL 0 +#define DIR_IN 0x1 + +struct Point { + u16 x, y, id, pressure, width, height; +}; + +struct sis_data { + int id, total, ReportID, scantime; + struct Point pt[MAX_POINT]; +}; + + +static int pkg_num=0; +static int idx=-1; + +/* + * this driver is aimed at two firmware versions in circulation: + * - dual pen/fingedrivers/hid/hid-sis.c:83:r single touch + * - finger multitouch, pen not working + */ + +static int sis_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + // No special mappings needed for the pen and single touch + if (field->physical == HID_GD_POINTER) + return -1; + + else if (field->physical && (field->physical != HID_GD_POINTER)) + return 0; + +#ifdef CONFIG_DEBUG_HID_SIS_INIT + printk (KERN_INFO "sis_input_mapping : usage->hid = %x\n", usage->hid); +#endif //CONFIG_DEBUG_HID_SIS_INIT + + switch (usage->hid & HID_USAGE_PAGE) { + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, field->logical_maximum, 0, 0); + return 1; + + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + /* we do not want to map these for now */ + case HID_DG_CONFIDENCE: + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + case HID_DG_INRANGE: + + //new usage for SiS817 Device(for later use) + case HID_DG_WIDTH: + //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); + //input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0); + //return 1; + case HID_DG_HEIGHT: + //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); + //input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + //return 1; + case HID_DG_TIPPRESSURE: + //hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); + //input_set_abs_params(hi->input, ABS_MT_PRESSURE, 0, 2047, 0, 0); + //return 1; + case HID_DG_SCANTIME: + return -1; + + case HID_DG_TIPSWITCH: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); + input_set_abs_params(hi->input, ABS_MT_PRESSURE, 0, 1, 0, 0); + return 1; + + case HID_DG_CONTACTID: + hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TRACKING_ID); + input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, 0, 127, 0, 0); + return 1; + } + return 0; + + /*case HID_UP_BUTTON: + return 0;*/ + + case 0xff000000: + /* ignore HID features */ + return -1; + + } + /* ignore buttons */ + return 0; +} + +//sis_input_mapped : unmapped usage that no use in sis_event +static int sis_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ +#ifdef CONFIG_DEBUG_HID_SIS_INIT + printk (KERN_INFO "sis_input_mapping : usage->hid = %x\n", usage->hid); +#endif //CONFIG_DEBUG_HID_SIS_INIT + + if (usage->type == EV_KEY || usage->type == EV_ABS) + clear_bit(usage->code, *bit); + + return 0; +} + +static void sis_event_emission(struct sis_data *nd, struct input_dev *input) +{ + int i; + bool all_touch_up = true; + for(i=0; i< nd->total; i++) + { + +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk(KERN_INFO "MT_event: finger(s)=%d, id=%d, x=%d, y=%d\n", nd->total, nd->pt[i].id, nd->pt[i].x, nd->pt[i].y); + printk(KERN_INFO "MT_event: pressure=%d, width=%d, height=%d, scantime=%d\n", nd->pt[i].pressure, nd->pt[i].width, nd->pt[i].height, nd->scantime); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + //checking correction of data + if(nd->pt[i].x > MAX_X || nd->pt[i].y > MAX_Y || nd->pt[i].id > MAX_CONTACTID /*|| nd->scantime > MAX_SCANTIME*/) + { + printk(KERN_INFO "point data error : abort sending point this time"); + break; + } + + if(nd->pt[i].pressure) + { + //input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(nd->pt[i].height,nd->pt[i].width)); + //input_report_abs(input, ABS_MT_TOUCH_MINOR, min(nd->pt[i].height,nd->pt[i].width)); + + input_report_abs(input, ABS_MT_PRESSURE, nd->pt[i].pressure); + input_report_abs(input, ABS_MT_POSITION_X, MAX_Y - nd->pt[i].y); + input_report_abs(input, ABS_MT_POSITION_Y, nd->pt[i].x); + input_report_abs(input, ABS_MT_TRACKING_ID, nd->pt[i].id); + input_mt_sync(input); + all_touch_up = false; + } + + if(i == (nd->total - 1) && all_touch_up == true) + input_mt_sync(input); + } + //input_sync(input); + //input_sync will be send by hid default flow +} + +static void sis_event_clear(struct sis_data *nd, int max) +{ + int i; + for(i=0; i<max; i++) + { + nd->pt[i].id = 0; + nd->pt[i].x = 0; + nd->pt[i].y = 0; + nd->pt[i].pressure = 0; + nd->pt[i].width = 0; + nd->pt[i].height = 0; + } + nd->scantime = 0; + idx = -1; + pkg_num = 0; +} + +static int sis_raw_event (struct hid_device *hid, struct hid_report *report, + u8 *raw_data, int size) +{ + struct sis_data *nd = hid_get_drvdata(hid); + nd->ReportID = raw_data[0]; + +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk(KERN_INFO "raw_event : ReportID = %d\n", nd->ReportID); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + hid_set_drvdata(hid, nd); + return 0; +} + +static void sis_event_lastdata(struct hid_device *hid, struct sis_data *nd, struct input_dev *input) +{ + int pkg_n=0; + +//817 method : original format + if ( (hid->product == USB_PRODUCT_ID_SIS817_TOUCH || hid->product == USB_PRODUCT_ID_SISF817_TOUCH) && nd->ReportID == REPORTID_10) + { +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event_lastdata : 817 original format\n"); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + sis_event_emission(nd, input); + sis_event_clear(nd, MAX_POINT); + } + //817 method : Extend Class Format + else if ( (hid->product == USB_PRODUCT_ID_SIS817_TOUCH || hid->product == USB_PRODUCT_ID_SISF817_TOUCH) && nd->ReportID != REPORTID_10) + { +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event_lastdata : 817 extend format\n"); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + if(nd->total >= 6) + { + idx = 4; + pkg_num = nd->total; + } + else if(nd->total >= 1) + { + sis_event_emission(nd, input); + sis_event_clear(nd, MAX_POINT); + } + else + { + if(pkg_num >0) + { + nd->total = pkg_num; + sis_event_emission(nd, input); + pkg_n = 0; + sis_event_clear(nd, MAX_POINT); + } + else + { + sis_event_clear(nd, MAX_POINT); + } + } + } + else //816 method + { +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event_lastdata : 816 format\n"); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + + if(nd->total >= 3) + { + idx = 1; + pkg_num = nd->total; + } + else if(nd->total >= 1) + { + sis_event_emission(nd, input); + sis_event_clear(nd, MAX_POINT); + } + else + { + if(pkg_num >0) + { + if((pkg_num%2)>0) + pkg_n = pkg_num+1; + else + pkg_n = pkg_num; + + if(pkg_n == (idx + 1) ) + { + nd->total = pkg_num; + sis_event_emission(nd, input); + pkg_n = 0; + sis_event_clear(nd, MAX_POINT); + } + } + else + { + sis_event_clear(nd, MAX_POINT); + } + } + } +} +/* + * this function is called upon all reports + * so that we can filter contact point information, + * decide whether we are in multi or single touch mode + * and call input_mt_sync after each point if necessary + */ +static int sis_event (struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct sis_data *nd = hid_get_drvdata(hid); + //printk (KERN_INFO "sis_event"); + + if (hid->claimed & HID_CLAIMED_INPUT) { + struct input_dev *input = field->hidinput->input; +#ifdef CONFIG_DEBUG_HID_SIS_SENDPOINT + printk (KERN_INFO "sis_event : usage->hid = %x, value = %d\n", usage->hid, value); +#endif //CONFIG_DEBUG_HID_SIS_SENDPOINT + switch (usage->hid) { + case HID_DG_INRANGE: + break; + + case HID_DG_TIPSWITCH: + idx++; + nd->pt[idx].pressure = !!value; + break; + + case HID_DG_CONTACTID: + nd->pt[idx].id = value; + break; + + case HID_GD_X: + nd->pt[idx].x = value; + break; + + case HID_GD_Y: + nd->pt[idx].y = value; + break; + + //new usage for SiS817 Extend Class Device + case HID_DG_SCANTIME: + nd->scantime = value; + if ( (nd->ReportID & 0xf0) > REPORTID_TYPE1 ) + sis_event_lastdata(hid, nd, input); + break; + + case HID_DG_WIDTH: + nd->pt[idx].width = value; + break; + + case HID_DG_HEIGHT: + nd->pt[idx].height = value; + break; + + case HID_DG_TIPPRESSURE: + nd->pt[idx].pressure = value; + break; + //end of new usage for SiS817 Extend Class Device + + case HID_DG_CONTACTCOUNT: + nd->total = value; + if ( (nd->ReportID & 0xf0) <= REPORTID_TYPE1 ) + sis_event_lastdata(hid, nd, input); + break; + default: + //fallback to the generic hidinput handling + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +#ifdef CONFIG_HID_SIS_UPDATE_FW +int sis_cdev_open(struct inode *inode, struct file *filp) //20120306 Yuger ioctl for tool +{ + //20110511, Yuger, kill current urb by method of usbhid_stop + struct usbhid_device *usbhid; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_open\n" ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( !hid_dev_backup ) + { + printk( KERN_INFO "sis_cdev_open : hid_dev_backup is not initialized yet" ); + return -1; + } + + usbhid = hid_dev_backup->driver_data; + + //20110602, Yuger, fix bug: not contact usb cause kernel panic + if( !usbhid ) + { + printk( KERN_INFO "sis_cdev_open : usbhid is not initialized yet" ); + return -1; + } + else if ( !usbhid->urbin ) + { + printk( KERN_INFO "sis_cdev_open : usbhid->urbin is not initialized yet" ); + return -1; + } + else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS2_TOUCH) + { + usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe, + usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length, + usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval); + + clear_bit( HID_STARTED, &usbhid->iofl ); + set_bit( HID_DISCONNECTED, &usbhid->iofl ); + + usb_kill_urb( usbhid->urbin ); + usb_free_urb( usbhid->urbin ); + usbhid->urbin = NULL; + return 0; + } + else + { + printk (KERN_INFO "This is not a SiS device"); + return -801; + } +} + +int sis_cdev_release(struct inode *inode, struct file *filp) +{ + //20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it + int ret; + struct usbhid_device *usbhid; + unsigned long flags; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_release" ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( !hid_dev_backup ) + { + printk( KERN_INFO "sis_cdev_release : hid_dev_backup is not initialized yet" ); + return -1; + } + + usbhid = hid_dev_backup->driver_data; + + printk( KERN_INFO "sys_sis_HID_start" ); + + if( !usbhid ) + { + printk( KERN_INFO "sis_cdev_release : usbhid is not initialized yet" ); + return -1; + } + + if( !backup_urb ) + { + printk( KERN_INFO "sis_cdev_release : urb_backup is not initialized yet" ); + return -1; + } + + clear_bit( HID_DISCONNECTED, &usbhid->iofl ); + usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL ); + + if( !backup_urb->interval ) + { + printk( KERN_INFO "sis_cdev_release : urb_backup->interval does not exist" ); + return -1; + } + + usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe, + backup_urb->transfer_buffer, backup_urb->transfer_buffer_length, + backup_urb->complete, backup_urb->context, backup_urb->interval); + usbhid->urbin->transfer_dma = usbhid->inbuf_dma; + usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + set_bit( HID_STARTED, &usbhid->iofl ); + + //method at hid_start_in + spin_lock_irqsave( &usbhid->lock, flags ); + ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC ); + spin_unlock_irqrestore( &usbhid->lock, flags ); + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_release : ret = %d", ret ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + return ret; +} + +//SiS 817 only +ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + int actual_length = 0, timeout = 0; + u8 *rep_data = NULL; + u16 size = 0; + long rep_ret; + struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_read\n"); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + + (((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff); + timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + + (((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff); + + rep_data = kzalloc(size, GFP_KERNEL); + if (!rep_data) + return -12; + + if ( copy_from_user( rep_data, (void*)buf, size) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + + rep_ret = usb_interrupt_msg(dev, backup_urb->pipe, + rep_data, size, &actual_length, timeout); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "sis_cdev_read : rep_data = "); + for (i=0; i<8; i++) + { + printk ("%02X ", rep_data[i]); + } + printk ("\n"); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if( rep_ret == 0 ) + { + rep_ret = actual_length; + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + } + + //free allocated data + kfree( rep_data ); + rep_data = NULL; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_read : rep_ret = %ld\n", rep_ret ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + return rep_ret; +} + +ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos ) +{ + int i, actual_length = 0; + u8 *tmp_data = NULL; //include report id + u8 *rep_data = NULL; + long rep_ret; + struct usb_interface *intf = to_usb_interface( hid_dev_backup->dev.parent ); + struct usb_device *dev = interface_to_usbdev( intf ); + struct usbhid_device *usbhid = hid_dev_backup->driver_data; + + if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS817_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_SISF817_TOUCH ) //817 method + { + u16 size = (((u16)(buf[64] & 0xff)) << 24) + (((u16)(buf[65] & 0xff)) << 16) + + (((u16)(buf[66] & 0xff)) << 8) + (u16)(buf[67] & 0xff); + int timeout = (((int)(buf[68] & 0xff)) << 24) + (((int)(buf[69] & 0xff)) << 16) + + (((int)(buf[70] & 0xff)) << 8) + (int)(buf[71] & 0xff); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_write : 817 method\n"); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + rep_data = kzalloc(size, GFP_KERNEL); + if (!rep_data) + return -12; + + if ( copy_from_user( rep_data, (void*)buf, size) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + + rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe, + rep_data, size, &actual_length, timeout ); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "sis_cdev_write : rep_data = "); + for (i=0; i<size-1; i++) + { + printk ("%02X ", rep_data[i]); + } + if (i == size-1) + printk ("%02X\n", rep_data[i]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if( rep_ret == 0 ) + { + rep_ret = actual_length; + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + } + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_write : rep_ret = %ld\n", rep_ret ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + } + else //816 method + { + + u8 request = buf[0]; + u8 dir = buf[1]; + u16 value = (((u16)(buf[2] & 0xff)) << 24) + (((u16)(buf[3] & 0xff)) << 16) + (((u16)(buf[4] & 0xff)) << 8) + (u16)(buf[5] & 0xff); + u16 index = (((u16)(buf[6] & 0xff)) << 24) + (((u16)(buf[7] & 0xff)) << 16) + (((u16)(buf[8] & 0xff)) << 8) + (u16)(buf[9] & 0xff); + + + u16 size = (((u16)(buf[29] & 0xff)) << 24) + (((u16)(buf[30] & 0xff)) << 16) + (((u16)(buf[31] & 0xff)) << 8) + (u16)(buf[32] & 0xff); + int timeout = (((int)(buf[33] & 0xff)) << 24) + (((int)(buf[34] & 0xff)) << 16) + (((int)(buf[35] & 0xff)) << 8) + (int)(buf[36] & 0xff); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "sis_cdev_write : 816 method\n"); + printk (KERN_INFO "dir = %d, value = %d, index = %d, timeout = %d\n", dir, value, index, timeout); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + rep_data = kzalloc( size , GFP_KERNEL ); + if ( rep_data == 0 ) + { + return -12; + } + + for( i = 0; i < size; i++) + { + rep_data[i] = buf[10+i]; + } + + tmp_data = kzalloc( size + 1, GFP_KERNEL ); //include report id, so size +1 + + for( i = 0; i < size; i++ ) + { + tmp_data[i+1] = rep_data[i]; + } + + buf += 10; + + if( dir & DIR_IN ) + { + if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS2_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_NEW_SIS2_TOUCH ) + { + //20110510, Yuger, for correcting intr data send into interrupt msg(receive, in, endp=2) + tmp_data[0] = 0x0A;//in + + rep_ret = usb_interrupt_msg( dev, backup_urb->pipe, tmp_data, size+1, &actual_length, timeout ); + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "(INT_IN)rep_ret = %ld, actual_length = %d", rep_ret, actual_length); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if( rep_ret == 0 ) + { + rep_ret = actual_length; + } + + //20110510, Yuger, for recovering rep_data + for( i = 0; i < size; i++ ) + { + rep_data[i] = tmp_data[i+1]; + } + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "(INT_IN)size = %u, dir = %u, rep_ret = %ld, rep_data = %X %X %X", size, dir, rep_ret, rep_data[0], rep_data[1], rep_data[2]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + kfree( tmp_data ); + rep_data = NULL; + tmp_data = NULL; + return -19; + } + } + else + { + //control message + rep_ret = usb_control_msg( dev, usb_rcvctrlpipe( dev, CTRL ), + request, (USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE), + value, index, rep_data, size, timeout ); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk ("(CTRL) size = %d, dir = %d, rep_ret = %ld, rep_data = ", size, dir, rep_ret); + for (i=0; i<size-1; i++) + { + printk ("%02X ", rep_data[i]); + } + if (i == size-1) + printk ("%02X\n", rep_data[i]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + } + } + else + { + if ( hid_dev_backup->product == USB_PRODUCT_ID_SIS2_TOUCH || hid_dev_backup->product == USB_PRODUCT_ID_NEW_SIS2_TOUCH ) + { + //20110510, Yuger, for correcting intr data send into interrupt msg(send, out, endp=1) + tmp_data[0] = 0x09;//out + + rep_ret = usb_interrupt_msg( dev, usbhid->urbout->pipe, tmp_data, size + 1, &actual_length, timeout ); + + //just return success or not(no need to return actual_length if succeed) + + //20110510, Yuger, for recovering rep_data + for( i = 0; i < size; i++ ) + { + rep_data[i] = tmp_data[i+1]; + } + //yy + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk(KERN_INFO "(INT_OUT)size = %u, actual_length = %d, rep_ret = %ld, rep_data = %x %x %x", size, actual_length, rep_ret, rep_data[0], rep_data[1], rep_data[2]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( copy_to_user( (void*)buf, rep_data, actual_length-1 ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + kfree( tmp_data ); + rep_data = NULL; + tmp_data = NULL; + return -19; + } + } + else + { + //control message + rep_ret = usb_control_msg( dev, usb_sndctrlpipe( dev, CTRL ), + request, (USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE), + value, index, rep_data, 16, timeout ); + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk ("(CTRL) size = %d, dir = %d, rep_ret = %ld, rep_data = ", size, dir, rep_ret); + for (i=0; i<size-1; i++) + { + printk ("%02X ", rep_data[i]); + } + if (i == size-1) + printk ("%02X\n", rep_data[i]); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + if ( copy_to_user( (void*)buf, rep_data, rep_ret ) ) + { + printk( KERN_INFO "copy_to_user fail\n" ); + //free allocated data + kfree( rep_data ); + rep_data = NULL; + return -19; + } + } + } + //free allocated data + kfree( tmp_data ); + tmp_data = NULL; + } + //free allocated data + kfree( rep_data ); + rep_data = NULL; + +#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW + printk( KERN_INFO "End of sis_cdev_write\n" ); +#endif //CONFIG_DEBUG_HID_SIS_UPDATE_FW + + return rep_ret; +} + +//~TT + +//for ioctl +static const struct file_operations sis_cdev_fops = { + .owner = THIS_MODULE, + .read = sis_cdev_read, + .write = sis_cdev_write, + .open = sis_cdev_open, + .release= sis_cdev_release, +}; + +//for ioctl +static int sis_setup_chardev(struct hid_device *hdev, struct sis_data *nd) +{ + + dev_t dev = MKDEV(sis_char_major, 0); + int alloc_ret = 0; + int cdev_err = 0; + int input_err = 0; + struct device *class_dev = NULL; + void *ptr_err; + + printk("sis_setup_chardev.\n"); + + if (nd == NULL) + { + input_err = -ENOMEM; + goto error; + } + + // dynamic allocate driver handle + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, BRIDGE_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS817_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SISF817_DEVICE_NAME); + else + alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, INTERNAL_DEVICE_NAME); + + if (alloc_ret) + goto error; + + sis_char_major = MAJOR(dev); + cdev_init(&sis_char_cdev, &sis_cdev_fops); + sis_char_cdev.owner = THIS_MODULE; + cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count); + if (cdev_err) + goto error; + + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + printk(KERN_INFO "%s driver(major %d) installed.\n", BRIDGE_DEVICE_NAME, sis_char_major); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + printk(KERN_INFO "%s driver(major %d) installed.\n", SIS817_DEVICE_NAME, sis_char_major); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + printk(KERN_INFO "%s driver(major %d) installed.\n", SISF817_DEVICE_NAME, sis_char_major); + else + printk(KERN_INFO "%s driver(major %d) installed.\n", INTERNAL_DEVICE_NAME, sis_char_major); + + // register class + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + sis_char_class = class_create(THIS_MODULE, BRIDGE_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + sis_char_class = class_create(THIS_MODULE, SIS817_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + sis_char_class = class_create(THIS_MODULE, SISF817_DEVICE_NAME); + else + sis_char_class = class_create(THIS_MODULE, INTERNAL_DEVICE_NAME); + + if(IS_ERR(ptr_err = sis_char_class)) + { + goto err2; + } + + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, BRIDGE_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SIS817_TOUCH) + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS817_DEVICE_NAME); + else if (hdev->product == USB_PRODUCT_ID_SISF817_TOUCH) + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SISF817_DEVICE_NAME); + else + class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, INTERNAL_DEVICE_NAME); + + if(IS_ERR(ptr_err = class_dev)) + { + goto err; + } + + return 0; +error: + if (cdev_err == 0) + cdev_del(&sis_char_cdev); + if (alloc_ret == 0) + unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count); + if(input_err != 0) + { + printk("sis_ts_bak error!\n"); + } +err: + device_destroy(sis_char_class, MKDEV(sis_char_major, 0)); +err2: + class_destroy(sis_char_class); + return -1; +} +#endif //CONFIG_HID_SIS_UPDATE_FW + +static int sis_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + struct sis_data *nd; + u8 *rep_data = NULL; + +#ifdef CONFIG_HID_SIS_UPDATE_FW + hid_dev_backup = hdev; +#endif //CONFIG_HID_SIS_UPDATE_FW + + printk(KERN_INFO "sis_probe\n"); + +#ifdef CONFIG_HID_SIS_UPDATE_FW + backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test + if (!backup_urb) { + dev_err(&hdev->dev, "cannot allocate backup_urb\n"); + return -ENOMEM; + } +#endif //CONFIG_HID_SIS_UPDATE_FW + +// command Set_Feature for changing device from mouse to touch device + rep_data = kmalloc(3,GFP_KERNEL); //return value will be 0xabcd + if (hdev->product == USB_PRODUCT_ID_SIS9200_TOUCH) + { + if(!rep_data) + return -ENOMEM; + rep_data[0] = 0x07; + rep_data[1] = 0x02; + rep_data[2] = 0xA9; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, (USB_DIR_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE), 0x0307, 0, rep_data, 3, 1000); + } + +// allocate memory for sis_data struct + nd = kzalloc(sizeof(struct sis_data), GFP_KERNEL); + if (!nd) { + dev_err(&hdev->dev, "cannot allocate SiS 9200 data\n"); + kfree(rep_data); + rep_data = NULL; + return -ENOMEM; + } + + hid_set_drvdata(hdev, nd); + +#ifdef CONFIG_HID_SIS_UPDATE_FW + //for ioctl + ret = sis_setup_chardev(hdev, nd); + if(ret) + { + printk( KERN_INFO "sis_setup_chardev fail\n"); + } +#endif //CONFIG_HID_SIS_UPDATE_FW + + //set noget for not init reports (speed improvement) + hdev->quirks |= HID_QUIRK_NOGET; + hdev->quirks &= ~HID_QUIRK_MULTITOUCH; //only hid-multitouch cat use this flag! + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + +err_free: + kfree(rep_data); + rep_data = NULL; + return ret; +} + +static void sis_remove(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_SIS_UPDATE_FW + //for ioctl + dev_t dev = MKDEV(sis_char_major, 0); + + printk(KERN_INFO "sis_remove\n"); + + cdev_del(&sis_char_cdev); + unregister_chrdev_region(dev, sis_char_devs_count); + device_destroy(sis_char_class, MKDEV(sis_char_major, 0)); + class_destroy(sis_char_class); +#else //CONFIG_HID_SIS_UPDATE_FW + + printk(KERN_INFO "sis_remove\n"); + +#endif //CONFIG_HID_SIS_UPDATE_FW + +#ifdef CONFIG_HID_SIS_UPDATE_FW + usb_kill_urb( backup_urb ); + usb_free_urb( backup_urb ); + backup_urb = NULL; +#endif + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id sis_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS2_TOUCH) }, //0x0457, 0x0151 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS_TOUCH) }, //0x0457, 0x0810 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_NEW_SIS2_TOUCH) }, //0x0457, 0x0816 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS9200_TOUCH) }, //0x0457, 0x9200 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SIS817_TOUCH) }, //0x0457, 0x0817 + { HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_PRODUCT_ID_SISF817_TOUCH) }, //0x0457, 0xF817 + { } +}; +MODULE_DEVICE_TABLE(hid, sis_devices); + + + +static struct hid_driver sis_driver = { + .name = "sis", + .id_table = sis_devices, + .probe = sis_probe, + .remove = sis_remove, + .raw_event = sis_raw_event, + .input_mapped = sis_input_mapped, + .input_mapping = sis_input_mapping, + .event = sis_event, +}; + +static int __init sis_init(void) +{ + printk(KERN_INFO "sis_init\n"); + return hid_register_driver(&sis_driver); +} + +static void __exit sis_exit(void) +{ + printk(KERN_INFO "sis_exit\n"); + hid_unregister_driver(&sis_driver); +} + +module_init(sis_init); +module_exit(sis_exit); +MODULE_DESCRIPTION("SiS 817 Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig new file mode 100755 index 00000000..eb37231f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_SITRONIX + tristate "Sitronix ST1xx series Capacity Touchscreen Device Support" + default m + depends on ARCH_WMT + ---help--- + Say Y here if you have an WMT based board with touchscreen + attached to it. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_sitronix.ko. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile new file mode 100755 index 00000000..b38deb74 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_ts_sitronix + +#obj-$(CONFIG_TOUCHSCREEN_SITRONIX) := $(MY_MODULE_NAME).o +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := sitronix_i2c.o irq_gpio.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + @rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers + +clean: + @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c new file mode 100755 index 00000000..bf57ff92 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.c @@ -0,0 +1,148 @@ +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include "irq_gpio.h" + +int wmt_enable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num < 4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) |= 1<<((num-12)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(int num) +{ + if(num > 15) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else if(num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x030C) &= ~(1<<((num-12)*8+7)); //enable interrupt + + return 0; +} + +int wmt_is_tsirq_enable(int num) +{ + int val = 0; + + if(num > 15) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else if(num >= 8 && num < 12) + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x030C) & (1<<((num-12)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(int num) +{ + if (num > 15) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(int num) +{ + if (num > 15) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +int wmt_set_gpirq(int num, int type) +{ + int shift; + int offset; + unsigned long reg; + + if(num >15) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num);//|=(1<<num);// //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else if(num >= 8 && num < 12){//[8,11] + shift = num-8; + offset = 0x0308; + }else{// [12,15] + shift = num-12; + offset = 0x030C; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.h b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.h new file mode 100755 index 00000000..0232bd04 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/irq_gpio.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_IRQ_GPIO_H +#define _LINUX_IRQ_GPIO_H + + +extern int wmt_enable_gpirq(int num); +extern int wmt_disable_gpirq(int num); +extern int wmt_is_tsirq_enable(int num); +extern int wmt_is_tsint(int num); +extern void wmt_clr_int(int num); +extern int wmt_set_gpirq(int num, int type); + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.c b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.c new file mode 100755 index 00000000..7b79aaf4 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.c @@ -0,0 +1,817 @@ +/* drivers/input/touchscreen/sis_i2c.c + * + * Copyright (C) 2009 SiS, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/linkage.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <mach/hardware.h> +#include <asm/uaccess.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include "sitronix_i2c.h" +#include "irq_gpio.h" + +struct sitronix_data *pContext=NULL; +struct i2c_client *l_client=NULL; + +#ifdef TOUCH_KEY + +#define MENU_IDX 0 +#define HOME_IDX 1 +#define BACK_IDX 2 +#define SEARCH_IDX 3 +#define NUM_KEYS 4 + +static int virtual_keys[NUM_KEYS] ={ + KEY_BACK, + KEY_HOME, + KEY_MENU, + KEY_SEARCH +}; +#endif + +#define I2C_BUS1 1 + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sitronix_early_suspend(struct early_suspend *h); +static void sitronix_late_resume(struct early_suspend *h); +#endif + +static int sitronix_read(struct sitronix_data *sitronix, u8 *rxdata, int length) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = sitronix->addr; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = rxdata; + + msg[1].addr = sitronix->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = rxdata; + + //ret = wmt_i2c_xfer_continue_if_4(msg, 2, I2C_BUS1); + ret = i2c_transfer(l_client->adapter, msg, 2); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +#ifdef SITRONIX_DEBUG +static int sitronix_write(struct sitronix_data *sitronix, u8 *txdata, int length) +{ + int ret; + struct i2c_msg msg[1]; + + msg[0].addr = sitronix->addr; + msg[0].flags = 0; + msg[0].len = length; + msg[0].buf = txdata; + + //ret = wmt_i2c_xfer_continue_if_4(msg, 1, I2C_BUS1); + ret = i2c_transfer(l_client->adapter, msg, 1); + if (ret <= 0) + dbg_err("msg i2c read error: %d\n", ret); + + return ret; +} + +static int sitronix_get_fw_revision(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[4]={FIRMWARE_REVISION_3,0}; + + ret = sitronix_read(sitronix, buffer, 4); + if (ret < 0){ + dbg_err("read fw revision error (%d)\n", ret); + return ret; + } + + memcpy(sitronix->fw_revision, buffer, 4); + printk("Fw Revision (hex): %x%x%x%x\n", buffer[0], buffer[1], buffer[2], buffer[3]); + + return 0; +} + +static int sitronix_get_max_touches(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[1]={MAX_NUM_TOUCHES}; + + ret = sitronix_read(sitronix, buffer, 1); + if (ret < 0){ + dbg_err("read max touches error (%d)\n", ret); + return ret; + } + + sitronix->max_touches = buffer[0]; + printk("max touches = %d \n",sitronix->max_touches); + + return 0; +} + +static int sitronix_get_protocol(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[1]={I2C_PROTOCOL}; + + ret = sitronix_read(sitronix, buffer, 1); + if (ret < 0){ + dbg_err("read i2c protocol error (%d)\n", ret); + return ret; + } + + sitronix->touch_protocol_type = buffer[0] & I2C_PROTOCOL_BMSK; + sitronix->sensing_mode = (buffer[0] & (ONE_D_SENSING_CONTROL_BMSK << ONE_D_SENSING_CONTROL_SHFT)) >> ONE_D_SENSING_CONTROL_SHFT; + printk("i2c protocol = %d ,sensing mode = %d \n", sitronix->touch_protocol_type, sitronix->sensing_mode); + + return 0; +} + +static int sitronix_get_resolution(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[3]={XY_RESOLUTION_HIGH}; + + ret = sitronix_read(sitronix, buffer, 3); + if (ret < 0){ + dbg_err("read resolution error (%d)\n", ret); + return ret; + } + + sitronix->resolution_x = ((buffer[0] & (X_RES_H_BMSK << X_RES_H_SHFT)) << 4) | buffer[1]; + sitronix->resolution_y = ((buffer[0] & Y_RES_H_BMSK) << 8) | buffer[2]; + printk("Resolution: %d x %d\n", sitronix->resolution_x, sitronix->resolution_y); + + return 0; +} + +static int sitronix_get_chip_id(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buffer[3]={CHIP_ID}; + + ret = sitronix_read(sitronix, buffer, 3); + if (ret < 0){ + dbg_err("read Chip ID error (%d)\n", ret); + return ret; + } + + if(buffer[0] == 0){ + if(buffer[1] + buffer[2] > 32) + sitronix->chip_id = 2; + else + sitronix->chip_id = 0; + }else + sitronix->chip_id = buffer[0]; + + sitronix->Num_X = buffer[1]; + sitronix->Num_Y = buffer[2]; + printk("Chip ID = %d, Num_X = %d, Num_Y = %d\n", sitronix->chip_id, sitronix->Num_X, sitronix->Num_Y); + + return 0; +} + +static int sitronix_get_device_status(struct sitronix_data *sitronix) +{ + int ret = 0; + uint8_t buf[3]={FIRMWARE_VERSION,0}; + + ret = sitronix_read(sitronix, buf, 3); + if (ret < 0){ + dbg_err("read resolution error (%d)\n", ret); + return ret; + } + + printk("Firmware version:%02x, Status Reg:%02x,Ctrl Reg:%02x\n", buf[0], buf[1],buf[2]); + return 0; + +} + +static int sitronix_get_device_info(struct sitronix_data *sitronix) +{ + int ret = 0; + + ret = sitronix_get_resolution(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_chip_id(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_fw_revision(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_protocol(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_max_touches(sitronix); + if(ret < 0) return ret; + + ret = sitronix_get_device_status(sitronix); + if(ret < 0) return ret; + + if((sitronix->fw_revision[0] == 0) && (sitronix->fw_revision[1] == 0)){ + if(sitronix->touch_protocol_type == SITRONIX_RESERVED_TYPE_0){ + sitronix->touch_protocol_type = SITRONIX_B_TYPE; + printk("i2c protocol (revised) = %d \n", sitronix->touch_protocol_type); + } + } + + if(sitronix->touch_protocol_type == SITRONIX_A_TYPE) + sitronix->pixel_length = PIXEL_DATA_LENGTH_A; + else if(sitronix->touch_protocol_type == SITRONIX_B_TYPE){ + sitronix->pixel_length = PIXEL_DATA_LENGTH_B; + sitronix->max_touches = 2; + printk("max touches (revised) = %d \n", sitronix->max_touches); + } + + return 0; +} +#endif + +static void sitronix_read_work(struct work_struct *work) +{ + struct sitronix_data *sitronix= container_of(work, struct sitronix_data, read_work); + int ret = -1; + u8 buf[22] = {FINGERS,0}; + u8 i = 0, fingers = 0, tskey = 0; + u16 px = 0, py = 0; + u16 x = 0, y = 0; + + ret = sitronix_read(sitronix, buf,sizeof(buf)); + if(ret <= 0){ + dbg_err("get raw data failed!\n"); + goto err_exit; + } + + fingers = buf[0]&0x0f; + if( fingers ){ + /* Report co-ordinates to the multi-touch stack */ + for(i=0; i < fingers; i++){ + if(sitronix->swap){ + y = ((buf[i*4+2]<<4)&0x0700)|buf[i*4+3]; + x = ((buf[i*4+2]<<8)&0x0700)|buf[i*4+4]; + }else{ + x = ((buf[i*4+2]<<4)&0x0700)|buf[i*4+3]; + y = ((buf[i*4+2]<<8)&0x0700)|buf[i*4+4]; + } + + if(!(buf[i*4+2]&0x80)) continue; /*check valid bit */ + + + if(x > sitronix->xresl ) x = sitronix->xresl ; + if(y > sitronix->yresl ) y = sitronix->yresl ; + + px = x; + py = y; + if(sitronix->xch) px = sitronix->xresl - x; + if(sitronix->ych) py = sitronix->yresl - y; + + if (sitronix->lcd_exchg) { + int tmp; + tmp = px; + px = py; + py = sitronix->xresl - tmp; + } + + input_report_abs(sitronix->input_dev, ABS_MT_POSITION_X, px); + input_report_abs(sitronix->input_dev, ABS_MT_POSITION_Y, py); + input_report_abs(sitronix->input_dev, ABS_MT_TRACKING_ID, i+1); + input_mt_sync(sitronix->input_dev); + sitronix->penup = 0; + if(sitronix->dbg) printk("F%d,raw data: x=%-4d, y=%-4d; report data: px=%-4d, py=%-4d\n", i, x, y, px, py); + } + input_sync(sitronix->input_dev); + + } + else if(!sitronix->penup){ + dbg("pen up.\n"); + sitronix->penup = 1; + input_mt_sync(sitronix->input_dev); + input_sync(sitronix->input_dev); + } + + /* virtual keys */ + tskey = buf[1]; + if(tskey){ + if(!sitronix->tkey_idx){ + sitronix->tkey_idx = tskey; + input_report_key(sitronix->input_dev,virtual_keys[sitronix->tkey_idx>>1] , 1); + input_sync(sitronix->input_dev); + dbg("virtual key down, idx=%d\n",sitronix->tkey_idx); + } + }else{ + if(sitronix->tkey_idx){ + dbg("virtual key up , idx=%d\n",sitronix->tkey_idx); + input_report_key(sitronix->input_dev,virtual_keys[sitronix->tkey_idx>>1] , 0); + input_sync(sitronix->input_dev); + sitronix->tkey_idx = tskey; + } + } + +err_exit: + wmt_enable_gpirq(sitronix->irqgpio); + return; +} + + +static irqreturn_t sitronix_isr_handler(int irq, void *dev) +{ + struct sitronix_data *sitronix = dev; + + if (wmt_is_tsint(sitronix->irqgpio)) + { + wmt_clr_int(sitronix->irqgpio); + if (wmt_is_tsirq_enable(sitronix->irqgpio)) + { + wmt_disable_gpirq(sitronix->irqgpio); + if(!sitronix->earlysus) queue_work(sitronix->workqueue, &sitronix->read_work); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void sitronix_reset(struct sitronix_data *sitronix) +{ + + gpio_set_value(sitronix->rstgpio, 1); + mdelay(5); + gpio_set_value(sitronix->rstgpio, 0); + mdelay(5); + gpio_set_value(sitronix->rstgpio, 1); + mdelay(5); + + return; +} + +static int sitronix_auto_clb(struct sitronix_data *sitronix) +{ + return 1; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sitronix_early_suspend(struct early_suspend *handler) +{ + struct sitronix_data *sitronix = container_of(handler, struct sitronix_data, early_suspend); + sitronix->earlysus = 1; + wmt_disable_gpirq(sitronix->irqgpio); + return; +} + +static void sitronix_late_resume(struct early_suspend *handler) +{ + struct sitronix_data *sitronix = container_of(handler, struct sitronix_data, early_suspend); + + sitronix->earlysus = 0; + sitronix_reset(sitronix); + msleep(200); + + wmt_set_gpirq(sitronix->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(sitronix->irqgpio); + + return; +} +#endif //CONFIG_HAS_EARLYSUSPEND + + +static int sitronix_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + sitronix->earlysus = 1; + wmt_disable_gpirq(sitronix->irqgpio); + return 0; +} + +static int sitronix_resume(struct platform_device *pdev) +{ + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + + sitronix->earlysus = 0; + sitronix_reset(sitronix); + msleep(200); + + wmt_set_gpirq(sitronix->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(sitronix->irqgpio); + return 0; +} + +static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "dbg \n"); +} + +static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct sitronix_data *sitronix = pContext; + + sscanf(buf,"%d",&sitronix->dbg); + + return count; +} +static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg); + +static ssize_t cat_clb(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "calibrate --echo 1 >clb \n"); +} + +static ssize_t echo_clb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int cal ; + struct sitronix_data *sitronix = pContext; + + sscanf(buf, "%d", &cal); + if(cal){ + if(sitronix_auto_clb(sitronix) <= 0) printk("Auto calibrate failed.\n"); + } + + return count; +} +static DEVICE_ATTR(clb, S_IRUGO | S_IWUSR, cat_clb, echo_clb); + +static struct attribute *sitronix_attributes[] = { + &dev_attr_clb.attr, + &dev_attr_dbg.attr, + NULL +}; + +static const struct attribute_group sitronix_group = { + .attrs = sitronix_attributes, +}; + +static int sitronix_sysfs_create_group(struct sitronix_data *sitronix, const struct attribute_group *group) +{ + int err; + + sitronix->kobj = kobject_create_and_add("wmtts", NULL) ; + if(!sitronix->kobj){ + dbg_err("kobj create failed.\n"); + return -ENOMEM; + } + + /* Register sysfs hooks */ + err = sysfs_create_group(sitronix->kobj, group); + if (err < 0){ + kobject_del(sitronix->kobj); + dbg_err("Create sysfs group failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void sitronix_sysfs_remove_group(struct sitronix_data *sitronix, const struct attribute_group *group) +{ + sysfs_remove_group(sitronix->kobj, group); + kobject_del(sitronix->kobj); + return; +} + +static int sitronix_probe(struct platform_device *pdev) +{ + int i; + int err = 0; + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + + INIT_WORK(&sitronix->read_work, sitronix_read_work); + sitronix->workqueue = create_singlethread_workqueue(sitronix->name); + if (!sitronix->workqueue) { + err = -ESRCH; + goto exit_create_singlethread; + } + + err = sitronix_sysfs_create_group(sitronix, &sitronix_group); + if(err < 0){ + dbg("create sysfs group failed.\n"); + goto exit_create_group; + } + + sitronix->input_dev = input_allocate_device(); + if (!sitronix->input_dev) { + err = -ENOMEM; + dbg("failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + + sitronix->input_dev->name = sitronix->name; + sitronix->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, sitronix->input_dev->propbit); + + if (sitronix->lcd_exchg) { + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_X, 0, sitronix->yresl, 0, 0); + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_Y, 0, sitronix->xresl, 0, 0); + } else { + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_X, 0, sitronix->xresl, 0, 0); + input_set_abs_params(sitronix->input_dev, + ABS_MT_POSITION_Y, 0, sitronix->yresl, 0, 0); + } + input_set_abs_params(sitronix->input_dev, + ABS_MT_TRACKING_ID, 0, 20, 0, 0); +#ifdef TOUCH_KEY + for (i = 0; i <NUM_KEYS; i++) + set_bit(virtual_keys[i], sitronix->input_dev->keybit); + + sitronix->input_dev->keycode = virtual_keys; + sitronix->input_dev->keycodesize = sizeof(unsigned int); + sitronix->input_dev->keycodemax = NUM_KEYS; +#endif + + err = input_register_device(sitronix->input_dev); + if (err) { + dbg_err("sitronix_ts_probe: failed to register input device.\n"); + goto exit_input_register_device_failed; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + sitronix->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + sitronix->early_suspend.suspend = sitronix_early_suspend; + sitronix->early_suspend.resume = sitronix_late_resume; + register_early_suspend(&sitronix->early_suspend); +#endif + + if(request_irq(sitronix->irq, sitronix_isr_handler, IRQF_SHARED, sitronix->name, sitronix) < 0){ + dbg_err("Could not allocate irq for ts_sitronix !\n"); + err = -1; + goto exit_register_irq; + } + + wmt_set_gpirq(sitronix->irqgpio, IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(sitronix->irqgpio); + sitronix_reset(sitronix); + msleep(200); +#ifdef SITRONIX_DEBUG + sitronix_get_device_info(sitronix); +#endif + + return 0; + +exit_register_irq: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&sitronix->early_suspend); +#endif +exit_input_register_device_failed: + input_free_device(sitronix->input_dev); +exit_input_dev_alloc_failed: + sitronix_sysfs_remove_group(sitronix, &sitronix_group); +exit_create_group: + cancel_work_sync(&sitronix->read_work); + destroy_workqueue(sitronix->workqueue); +exit_create_singlethread: + //kfree(sitronix); + return err; +} + +static int sitronix_remove(struct platform_device *pdev) +{ + struct sitronix_data *sitronix = platform_get_drvdata(pdev); + + cancel_work_sync(&sitronix->read_work); + flush_workqueue(sitronix->workqueue); + destroy_workqueue(sitronix->workqueue); + + free_irq(sitronix->irq, sitronix); + wmt_disable_gpirq(sitronix->irqgpio); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&sitronix->early_suspend); +#endif + input_unregister_device(sitronix->input_dev); + + sitronix_sysfs_remove_group(sitronix, &sitronix_group); + //kfree(sitronix); + + dbg("remove...\n"); + return 0; +} + +static void sitronix_release(struct device *device) +{ + return; +} + +static struct platform_device sitronix_device = { + .name = DEV_SITRONIX, + .id = 0, + .dev = {.release = sitronix_release}, +}; + +static struct platform_driver sitronix_driver = { + .driver = { + .name = DEV_SITRONIX, + .owner = THIS_MODULE, + }, + .probe = sitronix_probe, + .remove = sitronix_remove, + .suspend = sitronix_suspend, + .resume = sitronix_resume, +}; + +static int check_touch_env(struct sitronix_data *sitronix) +{ + int len = 96; + int Enable; + char retval[96] = {0}; + char *p=NULL; + int ret; + + // Get u-boot parameter + if(wmt_getsyspara("wmt.io.touch", retval, &len)) return -EIO; + + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0) return -ENODEV; + + p = strchr(retval,':'); + p++; + + if(strncmp(p,"st1536",6)) return -ENODEV; + + sitronix->name = DEV_SITRONIX; + sitronix->addr = SITRONIX_ADDR; + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d", + &sitronix->xresl, &sitronix->yresl, &sitronix->irqgpio, &sitronix->rstgpio, &sitronix->swap, &sitronix->xch, &sitronix->ych); + + sitronix->irq = IRQ_GPIO; + printk("%s reslx=%d, resly=%d, irqgpio_num=%d, rstgpio_num=%d, XYswap=%d, Xdirch=%d, Ydirch=%d\n", sitronix->name, + sitronix->xresl, sitronix->yresl, sitronix->irqgpio, sitronix->rstgpio, sitronix->swap, sitronix->xch, sitronix->ych); + + sitronix->penup = 1; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + sitronix->lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = DEV_SITRONIX, + .flags = 0x00, + .addr = SITRONIX_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(I2C_BUS1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + + +static int __init sitronix_init(void) +{ + int ret = -ENOMEM; + struct sitronix_data *sitronix=NULL; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + sitronix = kzalloc(sizeof(struct sitronix_data), GFP_KERNEL); + if(!sitronix){ + dbg_err("mem alloc failed.\n"); + return -ENOMEM; + } + + pContext = sitronix; + ret = check_touch_env(sitronix); + if(ret < 0) + goto exit_free_mem; + + ret = gpio_request(sitronix->irqgpio, "ts_irq"); + if (ret < 0) { + printk("gpio(%d) touchscreen irq request fail\n", sitronix->irqgpio); + goto exit_free_mem; + } + + ret = gpio_request(sitronix->rstgpio, "ts_rst"); + if (ret < 0) { + printk("gpio(%d) touchscreen reset request fail\n", sitronix->rstgpio); + goto exit_free_irqgpio; + } + gpio_direction_output(sitronix->rstgpio, 1); + + + ret = platform_device_register(&sitronix_device); + if(ret){ + dbg_err("register platform drivver failed!\n"); + goto exit_free_gpio; + } + platform_set_drvdata(&sitronix_device, sitronix); + + ret = platform_driver_register(&sitronix_driver); + if(ret){ + dbg_err("register platform device failed!\n"); + goto exit_unregister_pdev; + } + + return ret; + +exit_unregister_pdev: + platform_device_unregister(&sitronix_device); +exit_free_gpio: + + gpio_free(sitronix->rstgpio); +exit_free_irqgpio: + gpio_free(sitronix->irqgpio); + +exit_free_mem: + kfree(sitronix); + pContext = NULL; + ts_i2c_unregister_device(); + return ret; +} + +static void sitronix_exit(void) +{ + struct sitronix_data *sitronix; + + if(!pContext) return; + + sitronix = pContext; + + gpio_free(sitronix->irqgpio); + gpio_free(sitronix->rstgpio); + + + platform_driver_unregister(&sitronix_driver); + platform_device_unregister(&sitronix_device); + kfree(pContext); + + ts_i2c_unregister_device(); + return; +} + +late_initcall(sitronix_init); +module_exit(sitronix_exit); + +MODULE_DESCRIPTION("Sitronix Multi-Touch Driver"); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h new file mode 100755 index 00000000..8d3df91d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/sitronix/sitronix_i2c.h @@ -0,0 +1,137 @@ +#ifndef _LINUX_SIT_I2C_H +#define _LINUX_SIT_I2C_H + +#define SITRONIX_ADDR 0x60 +#define DEV_SITRONIX "touch_sitronix" +#define SITRONIX_MAX_SUPPORTED_POINT 5 +#define TOUCH_KEY + +struct sitronix_data { + u16 addr; + const char *name; + + struct input_dev *input_dev; + struct work_struct read_work; + struct workqueue_struct *workqueue; + struct kobject *kobj; + #ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int earlysus; + + int xresl; + int yresl; + + int irq; + int irqgpio; + + int rstgpio; + + int xch; + int ych; + int swap; + int lcd_exchg; + + int penup; + int dbg; +#ifdef TOUCH_KEY + //int tkey_pressed; + int tkey_idx; +#endif + u8 fw_revision[4]; + int resolution_x; + int resolution_y; + u8 max_touches; + u8 touch_protocol_type; + u8 chip_id; + + u8 Num_X; + u8 Num_Y; + u8 sensing_mode; + u8 pixel_length; +}; + +typedef enum{ + FIRMWARE_VERSION, + STATUS_REG, + DEVICE_CONTROL_REG, + TIMEOUT_TO_IDLE_REG, + XY_RESOLUTION_HIGH, + X_RESOLUTION_LOW, + Y_RESOLUTION_LOW, + FIRMWARE_REVISION_3 = 0x0C, + FIRMWARE_REVISION_2, + FIRMWARE_REVISION_1, + FIRMWARE_REVISION_0, + FINGERS, + KEYS_REG, + XY0_COORD_H, + X0_COORD_L, + Y0_COORD_L, + I2C_PROTOCOL = 0x3E, + MAX_NUM_TOUCHES, + DATA_0_HIGH, + DATA_0_LOW, + CHIP_ID = 0xF4, + + PAGE_REG = 0xff, +}RegisterOffset; + + +typedef enum{ + XY_COORD_H, + X_COORD_L, + Y_COORD_L, + PIXEL_DATA_LENGTH_B, + PIXEL_DATA_LENGTH_A, +}PIXEL_DATA_FORMAT; + +#define X_RES_H_SHFT 4 +#define X_RES_H_BMSK 0xf +#define Y_RES_H_SHFT 0 +#define Y_RES_H_BMSK 0xf +#define FINGERS_SHFT 0 +#define FINGERS_BMSK 0xf +#define X_COORD_VALID_SHFT 7 +#define X_COORD_VALID_BMSK 0x1 +#define X_COORD_H_SHFT 4 +#define X_COORD_H_BMSK 0x7 +#define Y_COORD_H_SHFT 0 +#define Y_COORD_H_BMSK 0x7 + +typedef enum{ + SITRONIX_RESERVED_TYPE_0, + SITRONIX_A_TYPE, + SITRONIX_B_TYPE, +}I2C_PROTOCOL_TYPE; + +#define I2C_PROTOCOL_SHFT 0x0 +#define I2C_PROTOCOL_BMSK 0x3 + +typedef enum{ + SENSING_BOTH, + SENSING_X_ONLY, + SENSING_Y_ONLY, + SENSING_BOTH_NOT, +}ONE_D_SENSING_CONTROL_MODE; + +#define ONE_D_SENSING_CONTROL_SHFT 0x2 +#define ONE_D_SENSING_CONTROL_BMSK 0x3 + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + +//#define SITRONIX_DEBUG + +#undef dbg +#ifdef SITRONIX_DEBUG + #define dbg(fmt,args...) printk("DBG:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) +#else + #define dbg(fmt,args...) +#endif + +#undef dbg_err +#define dbg_err(fmt,args...) printk("ERR:%s_%d:"fmt,__FUNCTION__,__LINE__,##args) + +#endif /* _LINUX_SIS_I2C_H */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig new file mode 100755 index 00000000..a5d9aa73 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Kconfig @@ -0,0 +1,16 @@ +# +# SSD253x capacity touch screen driver configuration +# +config TOUCHSCREEN_SSD253X + tristate "SSD253X I2C Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_ssd253x. + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile new file mode 100755 index 00000000..d78c8466 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_ssd253x
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := ssd253x-ts.o wmt_ts.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c new file mode 100755 index 00000000..c02392cb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.c @@ -0,0 +1,1827 @@ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/input.h> +//#include <asm/gpio.h> +#include <asm/irq.h> +#include <linux/irq.h> +#include <asm/io.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <mach/hardware.h> +#include <linux/platform_device.h> +#include <linux/suspend.h> +#include <linux/slab.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + +#include "ssd253x-ts.h" +#include "wmt_ts.h" + +//#define CONFIG_TOUCHSCREEN_SSL_DEBUG +#undef CONFIG_TOUCHSCREEN_SSL_DEBUG + +#define DEVICE_ID_REG 2 +#define VERSION_ID_REG 3 +#define AUTO_INIT_RST_REG 68 +#define EVENT_STATUS 121 +#define EVENT_MSK_REG 122 +#define IRQ_MSK_REG 123 +#define FINGER01_REG 124 +#define EVENT_STACK 128 +#define EVENT_FIFO_SCLR 135 +#define TIMESTAMP_REG 136 +#define SELFCAP_STATUS_REG 185 + +#define ON_TOUCH_INT INT_EI11 //GPIO :set the interrupt +#define DEVICE_NAME "touch_ssd253x" +#define SSD253X_I2C_ADDR 0x48 //0x48 + +// SSD2533 Setting +// Touch Panel Example +static struct ChipSetting* ssd253xcfgTable = NULL; +static int l_cfglen = 0; + +static struct ChipSetting ssd253xcfgTable_default[]={ +{2,0x06,0x1B,0x28}, +{2,0xd7,0x00,0x00}, +{2,0xd8,0x00,0x07}, +{2,0xdb,0x00,0x01}, +{2,0x30,0x03,0x08}, +{2,0x34,0xd4,0x1e}, +{2,0x57,0x00,0x06}, +{2,0x40,0x00,0xc8}, +{2,0x41,0x00,0x30}, +{2,0x42,0x00,0xc0}, +{2,0x43,0x00,0x30}, +{2,0x44,0x00,0xc0}, +{2,0x45,0x00,0xc0}, +{2,0x46,0x00,0x0f}, +{2,0x5f,0x00,0x00}, +{2,0x2d,0x00,0x00}, +{2,0x66,0x1F,0x38}, +{2,0x67,0x1c,0x92}, +{2,0x25,0x00,0x02}, +}; + + +// For SSD2533 Bug Version Only // +//#define SSD2533FIXEDCODE + struct ChipSetting ssd253xcfgTable1[]={ +{ 1, 0xA4, 0x00, 0x00}, //MCU prescaler default=01 +{ 1, 0xD4, 0x08, 0x00}, //Dummy Code +{ 1, 0xD4, 0x08, 0x00}, //Set Osc frequency default=8, range 0 to F +}; + + struct ChipSetting Reset[]={ +{ 0, 0x04, 0x00, 0x00}, // SSD2533 +}; + + struct ChipSetting Resume[]={ +{ 0, 0x04, 0x00, 0x00}, // SSD2533 +{ 1, 0x25, 0x12, 0x00}, // Set Operation Mode //Set from int setting +}; + + struct ChipSetting Suspend[] ={ +{ 1, 0x25, 0x00, 0x00}, // Set Operation Mode +{ 0, 0x05, 0x00, 0x00}, // SSD2533 +}; + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssd253x_ts_early_suspend(struct early_suspend *h); +static void ssd253x_ts_late_resume(struct early_suspend *h); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static irqreturn_t ssd253x_ts_isr(int irq, void *dev_id); +static enum hrtimer_restart ssd253x_ts_timer(struct hrtimer *timer); +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); + + +static int SSDS53X_SCREEN_MAX_X = 800; +static int SSDS53X_SCREEN_MAX_Y = 480; + + + +enum{ + IC_SSD2533 = 1, + IC_SSD2543, + IC_SSD2531 +}; + +static int ic_flag; + +static struct workqueue_struct *ssd253x_wq; + +int Ssd_Timer1,Ssd_Timer2,Ssd_Timer_flag; + +struct ssl_ts_priv { + struct input_dev *input; + struct hrtimer timer; + struct work_struct ssl_work; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + + int irq; + int use_irq; + int FingerNo; + int earlysus; + + int FingerX[FINGERNO]; + int FingerY[FINGERNO]; + int FingerP[FINGERNO]; + + int Resolution; + int EventStatus; + int FingerDetect; + + int sFingerX[FINGERNO]; + int sFingerY[FINGERNO]; + int pFingerX[FINGERNO]; + int pFingerY[FINGERNO]; +}; + +static struct ssl_ts_priv* l_ts = NULL; +struct wmtts_device ssd253x_tsdev; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +#define SD_INIT +#ifdef SD_INIT +#define TP_CHR "tp_chr" + +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> + +static long tp_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int tp_open(struct inode *inode, struct file *file); +static int tp_release(struct inode *inode, struct file *file); +static ssize_t tp_read(struct file *file, char __user *buf, size_t count,loff_t *offset); +static ssize_t tp_write(struct file *file, const char __user *buf,size_t count, loff_t *offset); + +//void InitFromSD(struct i2c_client *client); + +//struct ChipSetting _ssd253xcfgTable[200]; +//int sd_init_size=0; + + +//struct i2c_client *g_tp_client; + +#endif + + + +static int ReadRegister(/*struct i2c_client *client,*/uint8_t reg,int ByteNo) +{ + unsigned char buf[4]; + struct i2c_msg msg[2]; + int ret; + struct i2c_client* client = ts_get_i2c_client(); + + memset(buf, 0xFF, sizeof(buf)); + msg[0].addr = SSD253X_I2C_ADDR; + msg[0].flags = 0 | I2C_M_NOSTART; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = SSD253X_I2C_ADDR; + msg[1].flags = I2C_M_RD; + msg[1].len = ByteNo; + msg[1].buf = buf; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret <= 0) + { + printk("read the address (0x%x) of the ssd253x fail, ret=%d.\n", reg, ret); + return -1; + } + + if(ByteNo==1) return (int)((unsigned int)buf[0]<<0); + if(ByteNo==2) return (int)((unsigned int)buf[1]<<0)|((unsigned int)buf[0]<<8); + if(ByteNo==3) return (int)((unsigned int)buf[2]<<0)|((unsigned int)buf[1]<<8)|((unsigned int)buf[0]<<16); + if(ByteNo==4) return (int)((unsigned int)buf[3]<<0)|((unsigned int)buf[2]<<8)|((unsigned int)buf[1]<<16)|(buf[0]<<24); + return 0; +} + +static int WriteRegister(/*struct i2c_client *client,*/uint8_t Reg,unsigned char Data1,unsigned char Data2,int ByteNo) +{ + struct i2c_msg msg; + unsigned char buf[4]; + int ret; + struct i2c_client* client = ts_get_i2c_client(); + + buf[0]=Reg; + buf[1]=Data1; + buf[2]=Data2; + buf[3]=0; + + msg.addr = SSD253X_I2C_ADDR; + msg.flags = 0; + msg.len = ByteNo+1; + msg.buf = (char *)buf; + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret <= 0) + { + printk(KERN_ERR "write the address (0x%x) of the ssd25xx fail, ret=%d.\n", buf[0], ret); + return -1; + } + return 0; + +} + +int SSD253xdeviceInit1(void) +{ +#ifdef SSD2533FIXEDCODE + int i; + mdelay(600); //SSD2533 ESD2 EEPROM VERSION + for(i=0;i<sizeof(ssd253xcfgTable1)/sizeof(ssd253xcfgTable1[0]);i++) + { + if (WriteRegister(ssd253xcfgTable1[i].Reg, + ssd253xcfgTable1[i].Data1,ssd253xcfgTable1[i].Data2, + ssd253xcfgTable1[i].No)) + { + return -1; + } + } +#endif + return 0; +} + +int SSD253xdeviceInit(void) +{ + int i; + + for(i=0;i<l_cfglen/*sizeof(ssd253xcfgTable)/sizeof(ssd253xcfgTable[0])*/;i++) + { + if (WriteRegister(ssd253xcfgTable[i].Reg, + ssd253xcfgTable[i].Data1,ssd253xcfgTable[i].Data2, + ssd253xcfgTable[i].No)) + { + return -1; + } + if (0 == i) + { + msleep(300); + } + } + msleep(300); + return 0; +} + +int deviceReset(void) +{ + int i; + + i = 0;//just for remove warning message + wmt_rst_output(1); + mdelay(5); + wmt_rst_output(0); + mdelay(10); + wmt_rst_output(1); + msleep(200); + + //if(ic_flag == IC_SSD2533){ + for(i=0;i<sizeof(Reset)/sizeof(Reset[0]);i++) + { + if (WriteRegister(Reset[i].Reg, + Reset[i].Data1,Reset[i].Data2, + Reset[i].No)) + { + return -1; + } + } + //} + + mdelay(100); + if (SSD253xdeviceInit1()) + { + return -1; + } + return 0; +} + +int deviceResume(void) +{ + int i; + for(i=0;i<sizeof(Resume)/sizeof(Resume[0]);i++) + { + if (WriteRegister(Resume[i].Reg, + Resume[i].Data1,Resume[i].Data2, + Resume[i].No)) + { + return -1; + } + mdelay(100); + } + return 0; +} + +int deviceSuspend(void) +{ + int i; + //int timeout=10; + //int status; + + for(i=0;i<sizeof(Suspend)/sizeof(Suspend[0]);i++) + { + if (WriteRegister(Suspend[i].Reg, + Suspend[i].Data1,Suspend[i].Data2, + Suspend[i].No)) + { + return -1; + } + mdelay(100); + } + return 0; +} + +#define Mode RunningAverageMode +#define Dist RunningAverageDist +void RunningAverage(unsigned short *xpos,unsigned short *ypos,int No,struct ssl_ts_priv *ssl_priv) +{ + int FilterMode[4][2]={{0,8},{5,3},{6,2},{7,1}}; + int dx,dy; + int X,Y; + + X=*xpos; + Y=*ypos; + if((ssl_priv->pFingerX[No]!=0x0FFF)&&(X!=0x0FFF)) + { + dx=abs(ssl_priv->pFingerX[No]-X); + dy=abs(ssl_priv->pFingerY[No]-Y); + if(dx+dy<Dist*64) + { + ssl_priv->pFingerX[No]=(FilterMode[Mode][0]*ssl_priv->pFingerX[No]+FilterMode[Mode][1]*X)/8; + ssl_priv->pFingerY[No]=(FilterMode[Mode][0]*ssl_priv->pFingerY[No]+FilterMode[Mode][1]*Y)/8; + } + else + { + ssl_priv->pFingerX[No]=X; + ssl_priv->pFingerY[No]=Y; + } + } + else + { + ssl_priv->pFingerX[No]=X; + ssl_priv->pFingerY[No]=Y; + } + *xpos=ssl_priv->pFingerX[No]; + *ypos=ssl_priv->pFingerY[No]; +} + +void FingerCheckSwap(int *FingerX,int *FingerY,int *FingerP,int FingerNo,int *sFingerX,int *sFingerY) +{ + int i,j; + int index1,index2; + int Vx,Vy; + int Ux,Uy; + int R1x,R1y; + int R2x,R2y; + for(i=0;i<FingerNo;i++) + { + index1=i; + if( FingerX[index1]!=0xFFF) + if(sFingerX[index1]!=0xFFF) + { + for(j=i+1;j<FingerNo+3;j++) + { + index2=j%FingerNo; + if( FingerX[index2]!=0xFFF) + if(sFingerX[index2]!=0xFFF) + { + Ux=sFingerX[index1]-sFingerX[index2]; + Uy=sFingerY[index1]-sFingerY[index2]; + Vx= FingerX[index1]- FingerX[index2]; + Vy= FingerY[index1]- FingerY[index2]; + + R1x=Ux-Vx; + R1y=Uy-Vy; + R2x=Ux+Vx; + R2y=Uy+Vy; + + R1x=R1x*R1x; + R1y=R1y*R1y; + R2x=R2x*R2x; + R2y=R2y*R2y; + + if(R1x+R1y>R2x+R2y) + { + Ux=FingerX[index1]; + Uy=FingerY[index1]; + Vx=FingerP[index1]; + + FingerX[index1]=FingerX[index2]; + FingerY[index1]=FingerY[index2]; + FingerP[index1]=FingerP[index2]; + + FingerX[index2]=Ux; + FingerY[index2]=Uy; + FingerP[index2]=Vx; + } + break; + } + } + } + } + for(i=0;i<FingerNo;i++) + { + sFingerX[i]=FingerX[i]; + sFingerY[i]=FingerY[i]; + } +} + +#ifdef USE_TOUCH_KEY +static void ssd2533_ts_send_keyevent(struct ssl_ts_priv *ssl_priv,u8 btn_status, int downup) +{ + + switch(btn_status & 0x0f) + { + case 0x01: + input_report_key(ssl_priv->input, KEY_SEARCH, downup); + break; + case 0x02: + input_report_key(ssl_priv->input, KEY_BACK, downup); + break; + case 0x04: + input_report_key(ssl_priv->input, KEY_HOME, downup); + break; + case 0x08: + input_report_key(ssl_priv->input, KEY_MENU, downup); + break; + default: + break; + } + dbg("send %x %x\n", btn_status, downup); +} +#endif + +// for ssd2533(no test) +static int ssd253x_ts_cut_edge0(unsigned short pos,unsigned short x_y) +{ + u8 cut_value = 26; //26 cut_value < 32 + if(pos == 0xfff) + { + return pos; + } + //printk("X: rude data %d\n",pos); + if(x_y) //xpos + { + + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (XPOS_MAX - 16) ) + pos = XPOS_MAX + 16 + (pos - (XPOS_MAX -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + + pos = SSDS53X_SCREEN_MAX_X * pos / (DRIVENO * 64); + //printk("X: changed data %d\n",pos); + return pos; + } + else //ypos + { + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (YPOS_MAX - 16) ) + pos = YPOS_MAX + 16 + (pos - (YPOS_MAX -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + //printk("Y: rude data %d\n",pos); + pos = SSDS53X_SCREEN_MAX_Y* pos / (SENSENO * 64); + //printk("Y: changed data %d\n",pos); + return pos; + } + + +} + +// for ssd2532 +static int ssd253x_ts_cut_edge1(unsigned short pos,unsigned short x_y) +{ + u8 cut_value = 15; //cut_value < 32 + + if(pos == 0xfff){ + return pos; + } + + if(x_y){ //xpos 64-->96 //MAX=896 + pos = pos + cut_value;//????????Ôµ + pos = SSDS53X_SCREEN_MAX_X * pos / (790+cut_value*2);//SSDS53X_SCREEN_MAX_X?????Ò±?Ôµ + return pos; + }else{ //ypos //MAX=576 + pos = pos + cut_value;//?????ϱ?Ôµ + pos = SSDS53X_SCREEN_MAX_Y* pos / (470+cut_value*2);//SSDS53X_SCREEN_MAX_Y?????±?Ôµ + return pos; + } +} + +// for ssd2532,8" ssd253x_pydctp80a1.ts +// x_y:1--x,0--y +static int ssd253x_ts_cut_edge2(unsigned short pos,unsigned short x_y) +{ + int tpos; + + if (pos == 0xfff){ + return pos; + } + + tpos = pos; + if (x_y) + { + if (tpos<20) + { + tpos= tpos+18; + } else if (tpos>585) + { + tpos = tpos-18; + } else { + tpos = (tpos-20)*565/575+30; + } + pos = tpos; + return pos; + } else { + if (tpos <10) + { + tpos = tpos+10; + } else if (tpos >795) + { + tpos = 795; + } else { + tpos = (tpos-10)*775/785+20; + } + pos = tpos; + return pos; + } + +} +// for ssd2532 +static int ssd253x_ts_cut_edge3(unsigned short pos,unsigned short x_y) +{ + u8 cut_value = 15; + + if(pos == 0xfff){ + return pos; + } + + if(x_y){ + pos = pos + cut_value; + pos = SSDS53X_SCREEN_MAX_X * pos / (896+cut_value*2); + return pos; + }else{ + pos = pos + cut_value; + pos = SSDS53X_SCREEN_MAX_Y* pos / (576+cut_value*2); + return pos; + } +} + +// for jun feng TP +static int ssd253x_ts_cut_edge4(unsigned short pos,unsigned short x_y) +{ + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + int cut_value = 5; //cut_value < 32 + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + dbg("X: Raw data %d\n",pos); + if (pos >=XPOS_MAX) + { + pos = XPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_X* pos / (790 + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + dbg("X: Cut edge data %d\n",pos); + return pos; + } + else //ypos + { + + dbg("Y: Raw data %d\n",pos); + if (pos >=YPOS_MAX) + { + pos = YPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_Y* pos / (470 + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + //tpos = pos; + //tpos = /*SSDS53X_SCREEN_MAX_Y*/ (800* pos) / (470 + cut_value*2); + dbg("XPOS_MAX=%d,\n", XPOS_MAX); + dbg("YPOS_MAX=%d,\n",YPOS_MAX); + dbg("Y: Cut edge data pos= %d,tpos=%d\n",pos,tpos); + } + + return pos; + } + + +} + +static int ssd253x_ts_cut_edge5(unsigned short pos,unsigned short x_y) +{ + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + u8 cut_value = 20; //cut_value < 32 + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + dbg("X: Raw data %d\n",pos); + if (pos >=XPOS_MAX) + { + pos = XPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_X * pos / (XPOS_MAX + cut_value*2);//SSD253X_SCREEN_MAX_X|??????????|? } + dbg("X: Cut edge data %d\n",pos); + return pos; + } + } + else //ypos + { + + dbg("Y: Raw data %d\n",pos); + if (pos >=YPOS_MAX) + { + pos = YPOS_MAX; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSDS53X_SCREEN_MAX_Y * pos / (YPOS_MAX + cut_value*2);//SSD253X_SCREEN_MAX_X|??????????|? } + dbg("Y: Cut edge data %d\n",pos); + return pos; + } + } + return -1; +} + +static int ssd253x_ts_cut_edge6(unsigned short pos,unsigned short x_y) +{ + + #define XPOS_MAX_D (DRIVENO -EdgeDisable) *64 + #define YPOS_MAX_D (SENSENO -EdgeDisable) *64 + #undef SSD253X_SCREEN_MAX_X + #define SSD253X_SCREEN_MAX_X 800 + #define SSD253X_SCREEN_MAX_Y 480 + + u8 cut_value = 20; //cut_value < 32 + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + + + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Raw data %d\n",pos); + //#endif + if (pos >=XPOS_MAX_D) + { + pos = XPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX_D - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_X * pos / (XPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Cut edge data %d\n",pos); + //#endif + return pos; + } + else //ypos + { + + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Raw data %d\n",pos); + //#endif + if (pos >=YPOS_MAX_D) + { + pos = YPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX_D - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_Y * pos / (YPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Cut edge data %d\n",pos); + //#endif + return pos; + } + return -1; +} + +static int ssd253x_ts_cut_edge8(unsigned short pos,unsigned short x_y) +{ + + #define XPOS_MAX_D (DRIVENO -EdgeDisable) *64 + #define YPOS_MAX_D (SENSENO -EdgeDisable) *64 + #undef SSD253X_SCREEN_MAX_X + #define SSD253X_SCREEN_MAX_X 780 + #undef SSD253X_SCREEN_MAX_Y + #define SSD253X_SCREEN_MAX_Y 470 + + u8 cut_value = 10;//30; //cut_value < 32 + unsigned short Cut_Edge_XLeft[64]={ + 0x0008,0x0009,0x000B,0x000C,0x000D,0x000E,0x0010,0x0011, + 0x0012,0x0013,0x0015,0x0016,0x0017,0x0018,0x001A,0x001B, + 0x001C,0x001D,0x001F,0x0020,0x0021,0x0022,0x0024,0x0025, + 0x0026,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C, + 0x002C,0x002D,0x002E,0x002F,0x0030,0x0031,0x0032,0x0032, + 0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0038,0x0039, + 0x003A,0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040, + 0x0041,0x0042,0x0043,0x0044,0x0044,0x0045,0x0046,0x0047 + }; + + unsigned short Cut_Edge_XRight[64]={ + 0x0318,0x0317,0x0315,0x0314,0x0313,0x0312,0x0310,0x030F, + 0x030E,0x030D,0x030B,0x030A,0x0309,0x0308,0x0306,0x0305, + 0x0304,0x0303,0x0301,0x0300,0x02FF,0x02FE,0x02FC,0x02FB, + 0x02FA,0x02FA,0x02F9,0x02F8,0x02F7,0x02F6,0x02F5,0x02F4, + 0x02F4,0x02F3,0x02F2,0x02F1,0x02F0,0x02EF,0x02EE,0x02EE, + 0x02ED,0x02EC,0x02EB,0x02EA,0x02E9,0x02E8,0x02E8,0x02E7, + 0x02E6,0x02E5,0x02E4,0x02E3,0x02E2,0x02E2,0x02E1,0x02E0, + 0x02DF,0x02DE,0x02DD,0x02DC,0x02DC,0x02DB,0x02DA,0x02D9 + }; + + unsigned short Cut_Edge_YUp[64]={ + 0x0006,0x0007,0x0008,0x000A,0x000B,0x000C,0x000D,0x000F, + 0x0010,0x0011,0x0012,0x0014,0x0015,0x0016,0x0017,0x0018, + 0x001A,0x001B,0x001C,0x001D,0x001F,0x0020,0x0021,0x0022, + 0x0022,0x0023,0x0024,0x0025,0x0025,0x0026,0x0027,0x0028, + 0x0029,0x0029,0x002A,0x002B,0x002C,0x002C,0x002D,0x002E, + 0x002F,0x0030,0x0030,0x0031,0x0032,0x0033,0x0033,0x0034, + 0x0035,0x0036,0x0037,0x0037,0x0038,0x0039,0x003A,0x003A, + 0x003B,0x003C,0x003D,0x003E,0x003E,0x003F,0x0040,0x0041 + }; + + unsigned short Cut_Edge_YDown[64]={ + 0x01DA,0x01D9,0x01D8,0x01D6,0x01D5,0x01D4,0x01D3,0x01D1, + 0x01D0,0x01CF,0x01CE,0x01CC,0x01CB,0x01CA,0x01C9,0x01C8, + 0x01C6,0x01C5,0x01C4,0x01C3,0x01C1,0x01C0,0x01BF,0x01BE, + 0x01BE,0x01BD,0x01BC,0x01BB,0x01BB,0x01BA,0x01B9,0x01B8, + 0x01B7,0x01B7,0x01B6,0x01B5,0x01B4,0x01B4,0x01B3,0x01B2, + 0x01B1,0x01B0,0x01B0,0x01AF,0x01AE,0x01AD,0x01AD,0x01AC, + 0x01AB,0x01AA,0x01A9,0x01A9,0x01A8,0x01A7,0x01A6,0x01A6, + 0x01A5,0x01A4,0x01A3,0x01A2,0x01A2,0x01A1,0x01A0,0x019F + }; + + + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Raw data %d\n",pos); + //#endif + if (pos >=XPOS_MAX_D) + { + pos = XPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_XLeft[pos]; //Left cut edge + } + else + if ((XPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_XRight[XPOS_MAX_D - pos]; //Right cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_X * pos / (XPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("X: Cut edge data %d\n",pos); + //#endif + return pos; + } + else //ypos + { + + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Raw data %d\n",pos); + //#endif + if (pos >=YPOS_MAX_D) + { + pos = YPOS_MAX_D; + } + if (pos<64) + { + pos = Cut_Edge_YUp[pos]; //Up cut edge + } + else + if ((YPOS_MAX_D - pos) <64) + { + pos = Cut_Edge_YDown[YPOS_MAX_D - pos]; //Down cut edge + } + else + { + pos = pos + cut_value; // + pos = SSD253X_SCREEN_MAX_Y * pos / (YPOS_MAX_D + cut_value*2);//SSD253X_SCREEN_MAX_X|?????2????????|? + } + //#ifdef CONFIG_TS_CUTEDGE_DEBUG + dbg("Y: Cut edge data %d\n",pos); + //#endif + return pos; + } +} + +static int ssd253x_ts_cut_edge7(unsigned short pos,unsigned short x_y) +{ + unsigned short SENSENO_7 = 15; + unsigned short DRIVENO_7 = 20; + unsigned short EdgeDisable_7 = 1; // if Edge Disable, set it to 1, else reset to 0, OR SSD2533 set 0 + unsigned short XPOS_MAX_7 = (DRIVENO_7 -EdgeDisable_7) *64; + unsigned short YPOS_MAX_7 = (SENSENO_7 -EdgeDisable_7) *64; + + u8 cut_value = 10; //cut_value < 32 + dbg("enter...\n"); + + if(pos == 0xfff) + { + return pos; + } + if(x_y) //xpos + { + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (XPOS_MAX_7 - 16) ) + pos = XPOS_MAX_7 + 16 + (pos - (XPOS_MAX_7 -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + dbg("xpos_b:%d\n", pos); + pos = SSDS53X_SCREEN_MAX_X * pos / (DRIVENO_7 * 64); + dbg("xpos_a:%d\n", pos); + return pos; + } + else //ypos + { + if(pos < 16) + pos = cut_value + pos*(48 - cut_value) / 16; + else if(pos > (YPOS_MAX_7 - 16) ) + pos = YPOS_MAX_7 + 16 + (pos - (YPOS_MAX_7 -16))*(48 - cut_value) / 16; + else + pos = pos + 32; + dbg("ypos_b:%d\n", pos); + pos = SSDS53X_SCREEN_MAX_Y* pos / (SENSENO_7 * 64); + dbg("ypos_a:%d\n", pos); + return pos; + } + + +} + + +static int ssd253x_ts_cut_edge(unsigned short pos,unsigned short x_y) +{ + switch (wmt_ts_get_cutedge()) + { + case 0: + return ssd253x_ts_cut_edge0(pos,x_y); + break; + case 1: + return ssd253x_ts_cut_edge1(pos,x_y); + break; + case 2: + return ssd253x_ts_cut_edge2(pos,x_y); + break; + case 3: + return ssd253x_ts_cut_edge3(pos,x_y); + break; + case 4: + return ssd253x_ts_cut_edge4(pos,x_y); + break; + case 5: + return ssd253x_ts_cut_edge5(pos,x_y); + break; + case 6: + return ssd253x_ts_cut_edge6(pos,x_y); + break; + case 7: + return ssd253x_ts_cut_edge7(pos,x_y); + break; + case 8: + return ssd253x_ts_cut_edge8(pos,x_y); + break; + default: + return -1; + }; +} + +#ifdef USE_TOUCH_KEY +static u8 btn_status_last = 0; +#endif + +static void ssd253x_ts_work(struct work_struct *work) +{ + int i; + unsigned short xpos=0, ypos=0; + int tx,ty; + //width=0; + int FingerInfo; + int EventStatus; + int FingerX[FINGERNO]; + int FingerY[FINGERNO]; + int FingerP[FINGERNO]; + int clrFlag=0; + int Ssd_Timer; + #ifdef USE_TOUCH_KEY + u8 btn_status; + u8 btn_status_last = 0; + #endif + + struct ssl_ts_priv *ssl_priv = l_ts; + + #ifdef USE_TOUCH_KEY + btn_status = ReadRegister(ssl_priv->client,SELFCAP_STATUS_REG, 1); + //#ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG + dbg("btn pressed:%x\n", btn_status & 0x0f); + //#endif + if (btn_status_last != btn_status){ + if(btn_status){ + btn_status_last = btn_status; + ssd2533_ts_send_keyevent(ssl_priv,btn_status, 1); + dbg("send %x btn_status_last%d \n", btn_status,btn_status_last); + } + else{ + ssd2533_ts_send_keyevent(ssl_priv,btn_status_last, 0); + btn_status_last = 0; + dbg("btn_status_last %x \n", btn_status_last); + } + return ; + } + #endif + + Ssd_Timer = 0; + if(ic_flag == IC_SSD2533){ + if(!Ssd_Timer_flag){ + Ssd_Timer = ReadRegister(TIMESTAMP_REG,2); + if(!Ssd_Timer1){ + Ssd_Timer1 = Ssd_Timer/1000; + } + + Ssd_Timer2 = Ssd_Timer/1000; + + + if((Ssd_Timer2 - Ssd_Timer1) > 10){ + WriteRegister(AUTO_INIT_RST_REG,0x00,0x00,1); + Ssd_Timer_flag = 1; + } + } + } + + EventStatus = ReadRegister(EVENT_STATUS,2)>>4; + ssl_priv->FingerDetect=0; + for(i=0;i<ssl_priv->FingerNo;i++){ + if((EventStatus>>i)&0x1){ + FingerInfo=ReadRegister(FINGER01_REG+i,4); + xpos = ((FingerInfo>>4)&0xF00)|((FingerInfo>>24)&0xFF); + ypos = ((FingerInfo>>0)&0xF00)|((FingerInfo>>16)&0xFF); + dbg("raw data before cut, F%d:(%d,%d)\n",i,xpos,ypos); + if(xpos!=0xFFF){ + ssl_priv->FingerDetect++; + if (wmt_ts_get_cutedge()>=0){ + xpos = ssd253x_ts_cut_edge(xpos, 1); + ypos = ssd253x_ts_cut_edge(ypos, 0); + } + }else { + EventStatus=EventStatus&~(1<<i); + clrFlag=1; + } + }else{ + xpos=ypos=0xFFF; + clrFlag=1; + } + FingerX[i]=xpos; + FingerY[i]=ypos; + } + + if(ssl_priv->use_irq==1) wmt_enable_gpirq(); + if(ssl_priv->use_irq==2) + { + if(ssl_priv->FingerDetect==0) + { + wmt_enable_gpirq(); + } else { + hrtimer_start(&ssl_priv->timer, ktime_set(0, MicroTimeTInterupt), HRTIMER_MODE_REL); + } + } + if(ic_flag == IC_SSD2533){ + if(clrFlag) WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); + } + + if(ssl_priv->input->id.product==0x2533) + if(ssl_priv->input->id.version==0x0101) + FingerCheckSwap(FingerX,FingerY,FingerP,ssl_priv->FingerNo,ssl_priv->sFingerX,ssl_priv->sFingerY); + + // report data + for(i=0;i<ssl_priv->FingerNo;i++) + { + xpos=FingerX[i]; + ypos=FingerY[i]; + if(ssl_priv->input->id.product==0x2533){ + if(ssl_priv->input->id.version==0x0101) RunningAverage(&xpos,&ypos,i,ssl_priv); + if(ssl_priv->input->id.version==0x0102) RunningAverage(&xpos,&ypos,i,ssl_priv); + } + + if(xpos!=0xFFF) + { + dbg("raw data after cut, F%d:(%d,%d)\n",i,xpos,ypos); + switch (wmt_ts_get_xaxis()) + { + case 1: + tx = ypos; + break; + case 0: + default: + tx = xpos; + break; + } + + switch (wmt_ts_get_xdir()) + { + case 1: + break; + case -1: + tx = SSDS53X_SCREEN_MAX_Y - tx; + break; + default: + break; + }; + + if (tx <0){ + tx = 0; + } else if (tx >= SSDS53X_SCREEN_MAX_Y){ + tx = SSDS53X_SCREEN_MAX_Y-1; + } + switch (wmt_ts_get_yaxis()) + { + + case 0: + ty = xpos; + break; + case 1: + default: + ty = ypos; + break; + } + + switch (wmt_ts_get_ydir()) + { + case 1: + break; + case -1: + ty = SSDS53X_SCREEN_MAX_X - ty; + default: + break; + } + + if (ty < 0){ + ty = 0; + } else if (ty >=SSDS53X_SCREEN_MAX_X){ + ty = SSDS53X_SCREEN_MAX_X-1; + } + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = tx; + tx = ty; + ty = wmt_ts_get_resolvX() - tmp; + } + + ssd253x_tsdev.penup = 0; + input_report_abs(ssl_priv->input, ABS_MT_POSITION_X, tx); + input_report_abs(ssl_priv->input, ABS_MT_POSITION_Y, ty); + /*input_report_abs(ssl_priv->input, ABS_MT_POSITION_X, ty); + input_report_abs(ssl_priv->input, ABS_MT_POSITION_Y, tx);*/ + input_mt_sync(ssl_priv->input); + dbg("report data x=%d,y=%d\n", tx, ty); + + } + else if(ssl_priv->FingerX[i]!=0xFFF){ + input_mt_sync(ssl_priv->input); + //printk("pen up...\n"); + ssd253x_tsdev.penup = 1; + } + + ssl_priv->FingerX[i]=FingerX[i]; + ssl_priv->FingerY[i]=FingerY[i]; + } + + ssl_priv->EventStatus=EventStatus; + input_sync(ssl_priv->input); + if (1 == ssd253x_tsdev.penup){ + wake_up(&ts_penup_wait_queue); + } + +} + + +#define TPIC_INT_PLLLING 0 +#define TPIC_INT_INTERUPT 1 +#define TPIC_INT_HYBRID 2 + + +static int ssd253x_probe(struct platform_device *pdev) +{ + struct ssl_ts_priv *ssl_priv; + struct input_dev *ssl_input; + int error; + int i; + //unsigned int prescale; + + //#ifdef SD_INIT + // g_tp_client = l_client; + //#endif + + SSDS53X_SCREEN_MAX_X = wmt_ts_get_resolvY(); + SSDS53X_SCREEN_MAX_Y = wmt_ts_get_resolvX(); + + ssl_priv = kzalloc(sizeof(*ssl_priv), GFP_KERNEL); + if (!ssl_priv) + { + errlog(" kzalloc Error!\n"); + error=-ENODEV; + goto err0; + } + l_ts = ssl_priv; + + ssl_input = input_allocate_device(); + if (!ssl_input) + { + errlog(" ssd253x_ts_probe: input_allocate_device Error\n"); + error=-ENODEV; + goto freealloc; + } + ssl_input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_SYN) ; + set_bit(INPUT_PROP_DIRECT,ssl_input->propbit); + ssl_input->name = DEVICE_NAME; + ssl_input->id.bustype = BUS_I2C; + ssl_input->id.vendor = 0x2878; // Modify for Vendor ID + + ssl_priv->input = ssl_input; + + ssl_priv->FingerNo=wmt_ts_get_fingernum();//FINGERNO; + ssl_priv->Resolution=64; + + for(i=0;i<ssl_priv->FingerNo;i++) + { + ssl_priv->sFingerX[i]=0xFFF; + ssl_priv->sFingerY[i]=0xFFF; + + // For Adaptive Running Average + ssl_priv->pFingerX[i]=0xFFF; + ssl_priv->pFingerY[i]=0xFFF; + } + + deviceReset(); + ssl_input->id.product = ReadRegister(DEVICE_ID_REG,2); + ssl_input->id.version = ReadRegister(VERSION_ID_REG,2); + ssl_input->id.product = ReadRegister(DEVICE_ID_REG,2); + + ssl_input->id.version = ReadRegister(VERSION_ID_REG,2); + klog("SSL Touchscreen Device ID : 0x%04X\n",ssl_input->id.product); + klog("SSL Touchscreen Version ID : 0x%04X\n",ssl_input->id.version); + + if(ssl_input->id.product == 0x2531){ + ic_flag = IC_SSD2531; + }else if(ssl_input->id.product == 0x2533) { + ic_flag = IC_SSD2533; + }else if(ssl_input->id.product == 0x2543) { + ic_flag = IC_SSD2543; + } + + if(ic_flag == IC_SSD2533) { + ssl_priv->use_irq = TPIC_INT_HYBRID; + }else if(ic_flag == IC_SSD2543) { + ssl_priv->use_irq = TPIC_INT_INTERUPT; + } + + SSD253xdeviceInit(); + if(ic_flag == IC_SSD2533) { + WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); // clear Event FiFo + } + + + if(ssl_priv->input->id.product==0x2531) + ssl_priv->Resolution=32; + else if(ssl_priv->input->id.product==0x2533) + ssl_priv->Resolution=64; + + + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(ssl_input, ABS_MT_POSITION_X, 0,wmt_ts_get_resolvY(), 0, 0); + input_set_abs_params(ssl_input, ABS_MT_POSITION_Y, 0,wmt_ts_get_resolvX(), 0, 0); + } else { + input_set_abs_params(ssl_input, ABS_MT_POSITION_X, 0,wmt_ts_get_resolvX(), 0, 0); + input_set_abs_params(ssl_input, ABS_MT_POSITION_Y, 0,wmt_ts_get_resolvY(), 0, 0); + } + +#ifdef USE_TOUCH_KEY + set_bit(KEY_MENU, ssl_input->keybit); + set_bit(KEY_HOME, ssl_input->keybit); + set_bit(KEY_BACK, ssl_input->keybit); + set_bit(KEY_SEARCH, ssl_input->keybit); + #endif + error = input_register_device(ssl_input); + if(error) + { + errlog("input_register_device input Error!\n"); + error=-ENODEV; + goto panel_init_fail; + } + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) + { + hrtimer_init(&ssl_priv->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ssl_priv->timer.function = ssd253x_ts_timer; + //#ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG + dbg(" ssd253x_ts_probe: timer_init OK!\n"); + //#endif + } + + ssd253x_wq = create_singlethread_workqueue("ssd253x_wq"); + INIT_WORK(&ssl_priv->ssl_work, ssd253x_ts_work); + error = request_irq(wmt_get_tsirqnum(), ssd253x_ts_isr, IRQF_SHARED, "ssd253x_ts_q", l_ts); + if(error){ + errlog("request_irq Error!\n"); + error=-ENODEV; + goto freeque; + } + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_disable_gpirq(); + + +#ifdef CONFIG_HAS_EARLYSUSPEND + ssl_priv->early_suspend.suspend = ssd253x_ts_early_suspend; + ssl_priv->early_suspend.resume = ssd253x_ts_late_resume; + ssl_priv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN+2; + register_early_suspend(&ssl_priv->early_suspend); +#endif + deviceResume(); + wmt_enable_gpirq(); + dbg("SSD253X init ok!\n"); + return 0; + +freeque: + destroy_workqueue(ssd253x_wq); + input_unregister_device(ssl_input); +panel_init_fail: + input_free_device(ssl_input); +freealloc: + kfree(ssl_priv); +err0: + //dev_set_drvdata(&client->dev, NULL); + return error; +} + +static int ssd253x_remove(struct platform_device *pdev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer); + + //disable int + wmt_disable_gpirq(); + //free irq + free_irq(wmt_get_tsirqnum(), l_ts); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ssl_priv->early_suspend); +#endif + // free queue + cancel_work_sync (&ssl_priv->ssl_work); + flush_workqueue(ssd253x_wq); + destroy_workqueue(ssd253x_wq); + input_unregister_device(ssl_priv->input); + input_free_device(ssl_priv->input); + kfree(ssl_priv); + l_ts = NULL; + return 0; +} + + +/* +static int ssd253x_ts_open(struct input_dev *dev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + deviceResume(); + if(ssl_priv->use_irq) + { + wmt_enable_gpirq(); //(ssl_priv->irq); + } else { + hrtimer_start(&ssl_priv->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + return 0; +} + + +static void ssd253x_ts_close(struct input_dev *dev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + // disable interrupt + deviceSuspend(); + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) + hrtimer_cancel(&ssl_priv->timer); + if((ssl_priv->use_irq==1)||(ssl_priv->use_irq==2)) + wmt_disable_gpirq();//(ssl_priv->irq); +} +*/ +static int ssd253x_resume(struct platform_device *pdev) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + deviceReset(); + SSD253xdeviceInit(); + if(ic_flag == IC_SSD2533){ + WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); // clear Event FiFo + } + deviceResume(); + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(); + + if(! ssl_priv->use_irq) + { + hrtimer_start(&ssl_priv->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + ssl_priv->earlysus = 0; + return 0; +} + +static int ssd253x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer); + // disable irq + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + if(ic_flag == IC_SSD2533){ + deviceSuspend(); + }else if(ic_flag == IC_SSD2543){ + deviceReset(); + } + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssd253x_ts_late_resume(struct early_suspend *h) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + dbg("...\n"); + if (ssl_priv->earlysus != 0) + { + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + deviceReset(); + SSD253xdeviceInit(); + WriteRegister(EVENT_FIFO_SCLR,0x01,0x00,1); // clear Event FiFo + deviceResume(); + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(); + + if(! ssl_priv->use_irq) + { + hrtimer_start(&ssl_priv->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + ssl_priv->earlysus = 0; + } +} +static void ssd253x_ts_early_suspend(struct early_suspend *h) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + ssl_priv->earlysus = 1; + if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer); + // disable irq + wmt_disable_gpirq(); + Ssd_Timer_flag = 0; + deviceSuspend(); + + return; +} +#endif + + +static irqreturn_t ssd253x_ts_isr(int irq, void *dev_id) +{ + struct ssl_ts_priv *ssl_priv = l_ts; + + if (wmt_is_tsint()) + { + wmt_clr_int(); + if (wmt_is_tsirq_enable()) + { + wmt_disable_gpirq(); + dbg("begin..\n"); + if(!ssl_priv->earlysus) + { + queue_work(ssd253x_wq, &ssl_priv->ssl_work); + } + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static enum hrtimer_restart ssd253x_ts_timer(struct hrtimer *timer) +{ + struct ssl_ts_priv *ssl_priv = container_of(timer, struct ssl_ts_priv, timer); + #ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG + printk("+-----------------------------------------+\n"); + printk("| ssd253x_ts_timer! |\n"); + printk("+-----------------------------------------+\n"); + #endif + queue_work(ssd253x_wq, &ssl_priv->ssl_work); + if(ssl_priv->use_irq==0) hrtimer_start(&ssl_priv->timer, ktime_set(0, MicroTimeTInterupt), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#ifdef SD_INIT +static const struct file_operations tp_fops = { + .owner = THIS_MODULE, + .read = tp_read, + .write = tp_write, + .unlocked_ioctl = tp_ioctl, + .open = tp_open, + .release = tp_release, +}; + +static struct miscdevice misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = TP_CHR, + .fops = &tp_fops, +}; +#endif + + +static int ssd253x_init(void) +{ + char firmwname[60]; + int i; + + if (deviceReset() != 0) + return -1; + memset(firmwname,0,sizeof(firmwname)); + wmt_ts_get_firmwname(firmwname); + i = read_firmwarefile(firmwname,&ssd253xcfgTable,0x100); + if (i <= 0) + { + l_cfglen = sizeof(ssd253xcfgTable_default)/sizeof(ssd253xcfgTable_default[0]); + ssd253xcfgTable = ssd253xcfgTable_default; + dbg("Using the default configure!\n"); + } else { + l_cfglen = i; + } + Resume[1].No = ssd253xcfgTable[l_cfglen-1].No; + Resume[1].Reg = ssd253xcfgTable[l_cfglen-1].Reg; + Resume[1].Data1 = ssd253xcfgTable[l_cfglen-1].Data1; + Resume[1].Data2 = ssd253xcfgTable[l_cfglen-1].Data2; + if (SSD253xdeviceInit()!= 0) + { + if (i > 0) + { + kfree(ssd253xcfgTable); + } + return -1; + } + // init hardware + +#ifdef SD_INIT + misc_register(&misc); +#endif + + + return 0; +} + +static void ssd253x_exit(void) +{ + klog("remove the module\n"); + +#ifdef SD_INIT + misc_deregister(&misc); +#endif + + + if (ssd253xcfgTable != ssd253xcfgTable_default) + { + kfree(ssd253xcfgTable); + } + +} + +static int ssd253x_wait_penup(struct wmtts_device*tsdev) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==tsdev->penup)); + return ret; +} + + +struct wmtts_device raysen_tsdev = { + .driver_name = "ssd253x_ts", + .ts_id = "SSD253X", + .init = ssd253x_init, + .exit = ssd253x_exit, + .probe = ssd253x_probe, + .remove = ssd253x_remove, + .suspend = ssd253x_suspend, + .resume = ssd253x_resume, + .wait_penup = ssd253x_wait_penup, + .penup = 1, +}; + +#ifdef SD_INIT +static long tp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int tp_open(struct inode *inode, struct file *file) +{ + return 0; +} +static int tp_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t tp_read(struct file *file, char __user *buf, size_t count,loff_t *offset) +{ + char *kbuf; + uint8_t reg; + int ByteNo; + int readValue; + int i; + + kbuf = kmalloc(count,GFP_KERNEL); + + if(copy_from_user(kbuf,buf,1)) { + printk("no enough memory!\n"); + return -1; + } + + reg = (uint8_t)kbuf[0]; + ByteNo = count; + + readValue = ReadRegister( /*g_tp_client, */reg, ByteNo); + + for(i = 0;i < ByteNo;i++){ + kbuf[i] = (readValue>>(8*i)) & 0xff; + } + + if(copy_to_user(buf,kbuf,count)) { + printk("no enough memory!\n"); + return -1; + } + + kfree(kbuf); + + return count; +} + +static ssize_t tp_write(struct file *file, const char __user *buf,size_t count, loff_t *offset) +{ + char *kbuf; + + kbuf = kmalloc(count,GFP_KERNEL); + + if(copy_from_user(kbuf,buf,count)) { + printk("no enough memory!\n"); + return -1; + } + + if(kbuf[1] == 0x01){ + wmt_rst_output(0); + mdelay(5); + wmt_rst_output(1); + mdelay(20); + } + else + { + WriteRegister(/*g_tp_client,*/kbuf[1],kbuf[2],kbuf[3],kbuf[0]); + } + + kfree(kbuf); + + return count; +} + +#endif + + + + +MODULE_AUTHOR("Solomon Systech Ltd - Design Technology, Icarus Choi"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ssd253x Touchscreen Driver 1.3"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h new file mode 100755 index 00000000..fe6edeae --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/ssd253x-ts.h @@ -0,0 +1,28 @@ +/************************************************************** +ʹÓÃÇ°×¢ÒâͨµÀÊý£¬Çý¶¯Ä¬ÈÏʹÓÃͨµÀÊÇsense +´óÓÚdrive·ñÔòÐèÒª½«Ê¹Óõ½µÄDRIVENOÓëSENSENOµ÷»» +´ËÇé¿ö°üÀ¨0x66ºÍ0x67¼Ä´æÆ÷£¬µ«²»±ØÐ޸ġ£ +***************************************************************/ +#ifndef __SSD253X_20125181742_TS_H__ +#define __SSD253X_20125181742_TS_H__ +#define DRIVENO 15 +#define SENSENO 10 +#define EdgeDisable 1 // if Edge Disable, set it to 1, else reset to 0 +#define RunningAverageMode 2 //{0,8},{5,3},{6,2},{7,1} +#define RunningAverageDist 4 // Threshold Between two consecutive points +#define MicroTimeTInterupt 10000000 //20000000// 100Hz - 10,000,000us +#define FINGERNO 10 + +//#define USE_TOUCH_KEY + +#define USE_CUT_EDGE //0x8b must be 0x00; EdgeDisable set 0 +//#undef USE_CUT_EDGE + +#ifdef USE_CUT_EDGE + #define XPOS_MAX 576 //(DRIVENO - EdgeDisable) *64 + #define YPOS_MAX 896 //(SENSENO - EdgeDisable) *64 +#endif + + + +#endif diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c new file mode 100755 index 00000000..cf63ca13 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.c @@ -0,0 +1,810 @@ +#include <linux/unistd.h> +#include <linux/time.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +//#include <asm/semaphore.h> +#include <linux/proc_fs.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/suspend.h> +#include <linux/proc_fs.h> +#include <linux/input.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <asm/uaccess.h> +#include <linux/i2c.h> +#include <linux/irq.h> + +#include <asm/uaccess.h> +#include <linux/fs.h> +#include <linux/syscalls.h> + + +#include "wmt_ts.h" +#include "ssd253x-ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int lcd_exchg = 0; +static int irq_gpio; +static int rst_gpio; +static int panelres_x; +static int panelres_y; +static int l_xaxis=0; +static int l_xdirect=1; +static int l_yaxis=1; +static int l_ydirect=1; +static int l_cutedge=-1; +static DECLARE_WAIT_QUEUE_HEAD(queue); +static CALIBRATION_PARAMETER g_CalcParam; +static TS_EVENT g_evLast; +static struct mutex cal_mutex; +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +extern struct wmtts_device raysen_tsdev; +static struct wmtts_device* l_tsdev = &raysen_tsdev; +static struct i2c_client *l_client=NULL; +static int l_penup = 0; // 1-pen up,0-pen down +static char l_firmid[21]; + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +/////////////////////////////////////////////////////////////////////// +void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ) +{ + int x, y; + mutex_lock(&cal_mutex); + x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + + g_CalcParam.c2) / g_CalcParam.delta; + +//klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); + if ( x < 0 ) + x = 0; + + if ( y < 0 ) + y = 0; + if (x >= panelres_x) + x = panelres_x-1; + if (y >= panelres_y) + y = panelres_y-1; + + *pCalX = x; + *pCalY = y; + mutex_unlock(&cal_mutex); + return; +} + +static int parse_firmwarefile(const char* filedata, struct ChipSetting** firmarr, int maxlen) +{ + char endflag[]="/* End flag */"; + const char* p = filedata; + int val[4]; + int i = 0; + int j = 0; + const char* s = NULL; + + // the first { + while (*p!='{') p++; + p++; + s = p; + // calculate the number of array + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + i++; + } + p++; + }; + dbg("the number of arry:0x%x\n", i); + // alloc the memory for array + *firmarr = kzalloc(sizeof(struct ChipSetting)*i, GFP_KERNEL); + // parse the value of array + p = s; + j = 0; + while (strncmp(p,endflag,strlen(endflag))) + { + if (*p=='{') + { + memset(val,0,sizeof(val)); + sscanf(p,"{%x,%x,%x,%x}",val,val+1,val+2,val+3); + (*firmarr)[j].No = val[0]&0x00FF; + (*firmarr)[j].Reg = val[1]&0x00FF; + (*firmarr)[j].Data1 = val[2]&0x00FF; + (*firmarr)[j].Data2 = val[3]&0x00FF; + dbg("arry[0x%x]:%x,%x,%x,%x\n",j,(*firmarr)[j].No,(*firmarr)[j].Reg,(*firmarr)[j].Data1, + (*firmarr)[j].Data2); + j++; + } + //p = strchr(p,'}'); + p++; + if (j>=i-2) + { + dbg("%s",p); + } + + }; + if (i != j) + { + errlog("Error parsing file(the number of arry not match)!\n"); + return -1; + }; + dbg("paring firmware file end.\n"); + return i; +} + + +static struct device* get_tp_device(void){ + if(l_client == NULL){ + errlog("l_client is NULL\n"); + } + return &l_client->dev; +} + + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the number of firmware data,negative-parsing error. +int read_firmwarefile(char* filepath, struct ChipSetting** firmdata, int maxlen) +{ + const u8 *data = NULL; + int i = 0; + int ret = -1; + const struct firmware* tpfirmware = NULL; + + klog("ts config file:%s\n",filepath); + + + ret = request_firmware(&tpfirmware, filepath, get_tp_device()); + if (ret < 0) { + errlog("Failed load tp firmware: %s ret=%d\n", filepath,ret); + goto err_end; + } + + data = tpfirmware->data; + + i = parse_firmwarefile(data,firmdata,maxlen); + if (i <= 0) + { + errlog("error to parse firmware file.\n"); + ret = -1; + goto error_parse_fw; + } + ret = i; + + + dbg("success to read firmware file!\n");; + +error_parse_fw: + if(tpfirmware){ + release_firmware(tpfirmware); + tpfirmware = NULL; + } +err_end: + return ret; +} + + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +int wmt_ts_get_xaxis(void) +{ + return l_xaxis; +} + +int wmt_ts_get_xdir(void) +{ + return l_xdirect; +} + +int wmt_ts_get_yaxis(void) +{ + return l_yaxis; +} + +int wmt_ts_get_ydir(void) +{ + return l_ydirect; +} + +int wmt_ts_get_cutedge(void) +{ + return l_cutedge; +} + +void wmt_ts_get_firmwname(char* firmname) +{ + sprintf(firmname,"ssd253x_%s_cfg.tpf",l_firmid); +} + +int wmt_ts_get_fingernum(void) +{ + if (!strcmp(l_firmid,"10rs10f1609043psy1")) + { + return 10; + } + return 5; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +void wmt_tsreset_init(void) +{ + int num = rst_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num);//&= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<num); // out low + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //output enable + msleep(10); + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); // out high +} + +// enable:0-disable,1-enable +void wmt_enable_rst_pull(int enable) +{ + if (enable) + { + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<rst_gpio); //enable pull up/down + } else { + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<rst_gpio); //disable pull up/down + } +} + +// up:0-pull down,1-pull up +void wmt_set_rst_pull(int up) +{ + if (up) + { + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<rst_gpio); //pull up + } else { + REG32_VAL(__GPIO_BASE+0x04c0) &= ~(1<<rst_gpio); //pull down + } +} + +// high:0-low level,1-high level +void wmt_rst_output(int high) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + if (high) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<rst_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<rst_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<rst_gpio); //set output +} + +void wmt_rst_input(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<rst_gpio); //set input +} + +void wmt_set_intasgp(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio +} + +// val:1--high,0-low +void wmt_intgp_out(int val) +{ + if (val) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<irq_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<irq_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set output +} + +void wmt_ts_set_irqinput(void) +{ + int num = irq_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input +} + +unsigned int wmt_ts_irqinval(void) +{ + return REG32_VAL(__GPIO_BASE+0x0000)&(1<<irq_gpio); +} + +int wmt_set_gpirq(int type) +{ + int shift; + int offset; + unsigned long reg; + int num = irq_gpio; + + if(num >11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + +int wmt_enable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + + +int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) +{ + g_evLast.x = x; + g_evLast.y = y; + //dbg("raw(%d,%d)*\n", x, y); + return 0; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + return l_tsdev->suspend(pdev, state); +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + return l_tsdev->resume(pdev); +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 150; + char retval[150] = {0},*p=NULL; + int Enable=0,Gpio=0,PX=0,PY=0; + char* s=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID + errlog("[WMTENV] %s is not found\n", l_tsdev->ts_id); + return -ENODEV; + } + // get firmwareid + s = p+strlen(l_tsdev->ts_id)+1; //point to firmware id + p = strchr(p,':'); + memset(l_firmid,0,sizeof(l_firmid)); + len = p-s; + if (len>=20) + { + len = 19; + } + strncpy(l_firmid,s,len); + p++; + sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d",&Gpio,&PX,&PY,&rst_gpio, + &l_xaxis,&l_xdirect, + &l_yaxis,&l_ydirect, + &l_cutedge); + + irq_gpio = Gpio; + panelres_x = PX; + panelres_y = PY; + dbg("p.x=%d,p.y=%d,gpio=%d,resetgpio=%d,\nx-axis=%d,x_dir=%d,y-axis=%d,y_dir=%d,cutedge=%d\nfirmwareid:%s\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_xaxis,l_xdirect,l_yaxis,l_ydirect,l_cutedge, + l_firmid); + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + mutex_init(&cal_mutex); + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + // Create device node +/* if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { + printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, TS_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create touch device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); + return ret; + } +*/ + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + //device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); + //unregister_chrdev(TS_MAJOR, TS_NAME); + //class_destroy(l_dev_class); + mutex_destroy(&cal_mutex); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h new file mode 100755 index 00000000..3506773a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/ssd253x_ts/wmt_ts.h @@ -0,0 +1,116 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/suspend.h> +#include <linux/i2c.h> +#include <linux/firmware.h> + + +//#define DEBUG_WMT_TS +#undef dbg +#ifdef DEBUG_WMT_TS +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "ssd253x-ts" +#define WMT_TS_I2C_ADDR 0x01 + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +struct ChipSetting { + char No; + char Reg; + char Data1; + char Data2; +}; + + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_ts_set_rawcoord(unsigned short x, unsigned short y); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern int wmt_ts_get_xaxis(void); +extern int wmt_ts_get_xdir(void); +extern int wmt_ts_get_yaxis(void); +extern int wmt_ts_get_ydir(void); +extern int wmt_ts_get_cutedge(void); +extern void wmt_ts_get_firmwname(char* firmname); +extern int wmt_ts_get_fingernum(void); + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the number of firmware data,negative-parsing error. +extern int read_firmwarefile(char* filepath, struct ChipSetting** firmdata, int maxlen); + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile new file mode 100755 index 00000000..b3e5b2d3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/Makefile @@ -0,0 +1,4 @@ + +obj-$(CONFIG_TOUCHSCREEN_VT1609) := vt1609_dual.o vt1609_ts.o + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c new file mode 100755 index 00000000..c88872e5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c @@ -0,0 +1,692 @@ +#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+//#include <linux/spinlock.h>
+#include <linux/input.h>
+#include <linux/cdev.h>
+#include <linux/time.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/wmt_iomux.h>
+#include "vt1609_ts.h"
+
+
+//#define _DEBUG_
+
+#undef dbg
+#ifdef _DEBUG_
+#define dbg(fmt, args...) printk(KERN_ERR "[%s][%d]: " fmt, __func__ , __LINE__, ## args)
+#else
+#define dbg(fmt, args...)
+#endif
+
+#undef dbg_err
+#define dbg_err(fmt, args...) printk(KERN_ERR "[%s][%d]##ERROR##: " fmt, __func__ , __LINE__, ## args)
+
+#define VT1609_DUAL_VERSION "1.1"
+
+#define DUAL_BUF_LENGTH 17
+#define SINGLE_BUF_LEN 5
+#define MAX_SAMPLE_NUM 5
+#define POLL_TOUT 100
+#define DX_DETLA 4
+#define DX_NUM 5
+
+#define VXY 17
+#define SCALE_X 4
+#define SCALE_Y 2
+#define FILTER_COUNT_T1 2
+#define FILTER_COUNT_T2 5
+#define FILTER_COUNT_2T1 5
+#define SAMPLE_COUNT 4
+#define THRESHOLD_DX 256
+#define THRESHOLD_XY 1300
+#define THRESHOLD_DUAL_CNT 1
+
+#define CHL_X1 0x01
+#define CHL_X2 0x02
+#define CHL_X3 0x03
+#define CHL_Y1 0x04
+#define CHL_Y2 0x05
+#define CHL_Y3 0x06
+
+static int vxy_max_updated = 0;
+static int vx_max = 0;
+static int vy_max = 0;
+
+static int dual_cnt = 0;
+static int prv_dx = 0;
+static int dx1 = 0, dx2 = 0;
+
+static int TwoCT = 0;
+static int FirstCT = 0;
+static int TouchCT = 0 ;
+static int OneTCAfter2 = 0;
+static int TwoTouchFlag = 0;
+static struct vt1603_ts_pos pre,fixpos;
+
+//extern struct vt1603_ts_drvdata *pContext;
+
+struct dual_avg_buf {
+ int num;
+ u32 data[DUAL_BUF_LENGTH];
+};
+
+static struct dual_avg_buf x_buf;
+static struct dual_avg_buf y_buf;
+static struct dual_avg_buf avg_buf;
+
+static int vt1603_ts_get_ux(int *para);
+static int vt1603_ts_get_uy(int *para);
+static int vt1603_ts_get_vx(int *para);
+static int vt1603_ts_get_vy(int *para);
+
+static inline void dual_buf_fill(struct dual_avg_buf *dual_buf, u32 data, int len)
+{
+ dual_buf->data[dual_buf->num % len] = data;
+ dual_buf->num++;
+
+ return ;
+}
+
+static inline u32 dual_buf_avg(struct dual_avg_buf *dual_buf, int len)
+{
+ int i, num;
+ u32 avg = 0;
+ int max, min;
+
+ num = (dual_buf->num < len)? dual_buf->num : len;
+
+ if(num == 1)
+ return dual_buf->data[0];
+ if(num == 2)
+ return (dual_buf->data[0]+dual_buf->data[1])/2;
+
+ max = dual_buf->data[0];
+ min = dual_buf->data[0];
+ for (i = 0; i < num; i++){
+ avg += dual_buf->data[i];
+
+ if(dual_buf->data[i] > max)
+ max = dual_buf->data[i];
+
+ if(dual_buf->data[i] < min)
+ min = dual_buf->data[i];
+ }
+
+ return (avg-max-min )/ (num-2);
+}
+
+static void dual_buf_init(struct dual_avg_buf *dual_buf)
+{
+ memset(dual_buf, 0x00, sizeof(struct dual_avg_buf));
+ return ;
+}
+
+static inline void vt1603_ts_report_dual_pos(struct vt1603_ts_drvdata *ts_drv,
+ struct vt1603_ts_pos *fst,struct vt1603_ts_pos *lst)
+{
+ struct vt1603_ts_pos p1 = *fst;
+ struct vt1603_ts_pos p2 = *lst;
+
+ vt1603_ts_pos_calibration(ts_drv,&p1);
+ vt1603_ts_pos_calibration(ts_drv,&p2);
+ //dbg("Caled pos1 (%d, %d), pos2 (%d, %d)\n", p1.x, p1.y, p2.x, p2.y);
+
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_X, p1.x);
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, p1.y);
+ input_mt_sync(ts_drv->input);
+
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_X, p2.x);
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, p2.y);
+ input_mt_sync(ts_drv->input);
+
+ input_sync(ts_drv->input);
+
+ return;
+}
+
+static inline void vt1603_ts_auto_mode(struct vt1603_ts_drvdata *ts_drv)
+{
+ vt1603_set_reg8(ts_drv, VT1603_PWC_REG, 0x08);
+ /* auto position conversion mode and panel type config */
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1);
+ /* disable pen up/down detection, it is a MUST opearetion */
+ vt1603_set_reg8(ts_drv, 0xC8, 0x7F);
+
+ return;
+}
+
+static inline int select_channel(struct vt1603_ts_drvdata *ts_drv,int chl)
+{
+ switch(chl){
+ case CHL_X1://select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+ break;
+ case CHL_X2://select x2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x04);
+ break;
+ case CHL_X3://select x3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x00);
+ break;
+ case CHL_Y1://select y1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x07);
+ break;
+ case CHL_Y2://select y2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x06);
+ break;
+ case CHL_Y3://select y3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x03);
+ break;
+ default://default select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int select_x_channel(struct vt1603_ts_drvdata *ts_drv,int chl)
+{
+ switch(chl){
+ case CHL_X1://select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x07);
+ break;
+ case CHL_X2://select x2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x06);
+ break;
+ case CHL_X3://select x3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x03);
+ break;
+ case CHL_Y1://select y1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+
+ break;
+ case CHL_Y2://select y2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x04);
+ break;
+ case CHL_Y3://select y3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x00);
+ break;
+ default://default select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int get_channel_data(struct vt1603_ts_drvdata *ts_drv,int chl)
+{
+ int i = 0;
+ int sum = 0;
+ int buf[MAX_SAMPLE_NUM] = {0};
+ u32 now = 0;
+ u8 tmp = 0;
+
+ if(ts_drv->dual_dev.exch)
+ select_x_channel(ts_drv,chl);
+ else
+ select_channel(ts_drv,chl);
+
+ for (i = 0; i < ts_drv->dual_dev.SAMPLE_CNT; i++) {
+ vt1603_clrbits(ts_drv, VT1603_INTS_REG, 0x0f);
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x10);
+ udelay(100);
+ now = jiffies;
+ while (time_before(jiffies, now + msecs_to_jiffies(POLL_TOUT))) {
+ tmp = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ if (tmp & BIT0) {
+ buf[i] = vt1603_get_reg8(ts_drv, 0xce);
+ tmp = (vt1603_get_reg8(ts_drv, 0xcf) & 0x0f);
+ buf[i] |= (tmp << 8);
+ sum += buf[i];
+ goto next;
+ }
+ }
+ printk("VT1609 %s timeout!\n", __func__);
+ return 0;
+
+ next:
+ ;//printk("CHL %d buf[%d] is %d\n", chl, i, buf[i]);
+ }
+
+ return sum/ts_drv->dual_dev.SAMPLE_CNT;
+
+}
+
+
+static inline int vt1603_get_paramters(struct vt1603_ts_drvdata *ts_drv, int *para)
+{
+ /* change to manual mode now */
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x00);
+ /* set prechare to 0x10 */
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10);
+ /* get parameters now */
+ para[0] = get_channel_data(ts_drv, CHL_X1);
+ para[1] = get_channel_data(ts_drv, CHL_X2);
+ para[2] = get_channel_data(ts_drv, CHL_Y1);
+ para[3] = get_channel_data(ts_drv, CHL_Y2);
+
+ para[4] = get_channel_data(ts_drv, CHL_X3);
+ para[5] = get_channel_data(ts_drv, CHL_Y3);
+
+ /* reset adc, this is a MUST operation */
+ vt1603_set_reg8(ts_drv, 0xc8, 0x8f);
+ vt1603_set_reg8(ts_drv, 0xc0, BIT6 | BIT5 | BIT0);
+
+ return 0;
+}
+
+static int vt1603_get_vxy(struct vt1603_ts_drvdata *ts_drv, int *vx, int *vy)
+{
+ int i;
+ int xbuf[5] ={0}, ybuf[5] ={0};
+ int sum_vx = 0,sum_vy = 0;
+ int max_vx = 0,min_vx = 0;
+ int max_vy = 0,min_vy = 0;
+
+ /* change to manual mode now */
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x00);
+ /* set prechare to 0x10 */
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10);
+ for(i=0; i<5; i++){
+ xbuf[i] = get_channel_data(ts_drv,CHL_X3);
+ ybuf[i] = get_channel_data(ts_drv,CHL_Y3);
+ sum_vx += xbuf[i];
+ sum_vy += ybuf[i];
+ }
+
+ max_vx = min_vx = xbuf[0];
+ max_vy = min_vy = ybuf[0];
+
+ for(i=0; i<5; i++){
+ if(xbuf[i] > max_vx)
+ max_vx = xbuf[i];
+
+ if(xbuf[i] < min_vx)
+ min_vx = xbuf[i];
+
+ if(ybuf[i] > max_vy)
+ max_vy = ybuf[i];
+
+ if(ybuf[i] < min_vy)
+ min_vy = ybuf[i];
+ }
+ *vx = (sum_vx - max_vx - min_vx)/3;
+ *vy = (sum_vy - max_vy - min_vy)/3;
+ dbg("updated vx_max=%d; vy_max=%d\n",*vx, *vy);
+ /* reset adc, this is a MUST operation */
+ vt1603_set_reg8(ts_drv, 0xc8, 0x8f);
+ vt1603_set_reg8(ts_drv, 0xc0, BIT6 | BIT5 | BIT0);
+
+ return 0;
+}
+
+static inline int vt1603_ts_get_ux(int *para)
+{
+ return abs(para[1] - para[0]);
+}
+
+static inline int vt1603_ts_get_uy(int *para)
+{
+ return abs(para[3] - para[2]);
+}
+
+static inline int vt1603_ts_get_vx(int *para)
+{
+ return abs(vx_max - para[4]);
+}
+
+static inline int vt1603_ts_get_vy(int *para)
+{
+ return abs(vy_max - para[5]);
+}
+
+static inline int vt1603_ts_nTouch(struct vt1603_ts_drvdata *ts_drv, int *para)
+{
+ int ux, uy, vx, vy;
+
+ ux = vt1603_ts_get_ux(para);
+ uy = vt1603_ts_get_uy(para);
+ vx = vt1603_ts_get_vx(para);
+ vy = vt1603_ts_get_vy(para);
+ //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy);
+
+ if ((vx <= 5) && (vy <= 5)){
+ dual_cnt = 0;
+ return Single_TOUCH;
+ }else if ((vx >= ts_drv->dual_dev.vxy) || (vy >= ts_drv->dual_dev.vxy)){
+ dual_cnt++;
+ //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy);
+ return (dual_cnt > THRESHOLD_DUAL_CNT)? Multi_TOUCH : Single_TOUCH;
+ }else if (((vx > 5) || (vy > 5)) && ((ux >= 2 * ts_drv->dual_dev.vxy) || (uy >= 2 * ts_drv->dual_dev.vxy))){
+ dual_cnt++;
+ //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy);
+ return (dual_cnt > THRESHOLD_DUAL_CNT)? Multi_TOUCH : Single_TOUCH;
+ }else{
+ dual_cnt = 0;
+ return Single_TOUCH;
+ }
+
+}
+
+static int pos_fix(const int limit, int p)
+{
+ if (p > limit) p = limit;
+ if (p < 0) p = 0;
+
+ return (u16)(p & 0xffff);
+}
+
+static int vt1603_ts_update_vxy(struct vt1603_ts_drvdata *ts_drv, int *vx, int *vy)
+{
+ u8 val;
+ int timeout = 100;
+
+ val = vt1603_get_reg8(ts_drv, VT1603_CR_REG);
+ while (timeout-- && val != 0x02) {
+ msleep(20);
+ val = vt1603_get_reg8(ts_drv, VT1603_CR_REG);
+ }
+
+ if(!timeout){
+ dbg_err("get vx_max/vy_max failed!\n");
+ goto out;
+ }
+
+ vt1603_get_vxy(ts_drv, vx,vy);
+ dbg("update vx_max:%d, vy_max:%d\n", vx_max, vy_max);
+
+out:
+ vt1603_set_reg8(ts_drv, VT1603_INTS_REG, 0x0F);
+
+ return 0;
+}
+
+void vt1603_ts_dual_support(struct work_struct* dwork)
+{
+ int nTouch = 0;
+ int para[6] = { 0 };
+ //unsigned long flags = 0;
+ int vx = 0, vy = 0, dx = 0;
+ struct vt1603_ts_pos p,pos1, pos2;
+ struct vt1603_ts_drvdata *ts_drv = NULL;
+ u8 int_sts = 0;
+
+ ts_drv = container_of(dwork, struct vt1603_ts_drvdata, dual_work.work);
+
+ //spin_lock_irqsave(&ts_drv->spinlock, flags);
+ mutex_lock(&ts_drv->ts_mutex);
+
+ int_sts = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ if (int_sts & BIT4 || ts_drv->earlysus) {
+ if (jiffies_to_msecs(jiffies - ts_drv->ts_stamp) < TS_DEBOUNCE && !ts_drv->earlysus) {
+ dbg("vt1603 ts debouncing?...\n");
+ //vt1603_clr_ts_irq(ts_drv, int_sts & 0x0F);
+ goto next_loop;
+ }
+ dbg("======= penup ======\n");
+
+ /* update vx_max/vy_max only when first penup */
+ if(!vxy_max_updated){
+ vxy_max_updated ++;
+ vt1603_ts_update_vxy(ts_drv, &vx_max, &vy_max);
+ }
+ vt1603_ts_auto_mode(ts_drv);
+ /* vt1603 gpio1 as IRQ output */
+ vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);
+ input_mt_sync(ts_drv->input);
+ input_sync(ts_drv->input);
+ ts_drv->pen_state = TS_PENUP_STATE;
+ #ifdef TOUCH_KEY
+ vt1603_ts_report_key(ts_drv);
+ #endif
+ dual_buf_init(&avg_buf);
+ dual_buf_init(&x_buf);
+ dual_buf_init(&y_buf);
+
+ dx2 = 0;
+ dx1 = 0;
+ pre.x = 0;
+ pre.y = 0;
+ FirstCT = 0;
+ TwoCT = 0;
+ TouchCT = None_TOUCH;
+ OneTCAfter2 = 0;
+ TwoTouchFlag = 0;
+ vt1603_clr_ts_irq(ts_drv, int_sts & 0x0F);
+
+ if(!ts_drv->earlysus)
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return;
+ }
+
+ ts_drv->ts_stamp = jiffies;
+ ts_drv->pen_state = TS_PENDOWN_STATE;
+ vt1603_get_paramters(ts_drv, para);
+ vt1603_ts_auto_mode(ts_drv);
+ //vt1603_clr_ts_irq(ts_drv, 0x0F & int_sts);
+
+ nTouch = vt1603_ts_nTouch(ts_drv, para);
+ if(nTouch == Single_TOUCH){
+ p.x = (para[0] + para[1]) / 2;
+ p.y = (para[2] + para[3]) / 2;
+
+ if(TwoTouchFlag ==0 && FirstCT < ts_drv->dual_dev.F1_CNT){
+ FirstCT ++;
+ dbg("Filter First %d Single Touch\n",FirstCT);
+ goto next_loop;
+
+ }else if(TwoTouchFlag == 1 && OneTCAfter2 < ts_drv->dual_dev.F2T1_CNT){
+ dbg("Filter First %d pointer when back to single touch from dual touch\n",OneTCAfter2);
+ dx1 = 0;
+ dx2 = 0;
+ TwoCT = 0;
+ OneTCAfter2 ++;
+ dual_buf_init(&x_buf);
+ dual_buf_init(&y_buf);
+ dual_buf_init(&avg_buf);
+ goto next_loop;
+
+ }else if(p.x > vx_max || p.y > vy_max){
+ dbg("Pos (%d,%d) beyond vx_max or vy_max\n",p.x,p.y);
+ goto next_loop;
+
+ }else if((pre.x!=0 && pre.y!=0) && (abs(pre.x-p.x) > THRESHOLD_XY||abs(pre.y-p.y) > THRESHOLD_XY )){
+ dbg("Threhold Filter Pos (%-4d,%-4d) ,dx=%-4d,dy=%-4d\n",p.x,p.y,abs(pre.x-p.x),abs(pre.y-p.y));
+ pre.x = p.x;
+ pre.y = p.y;
+ goto next_loop;
+
+ }else{
+ dual_buf_fill(&x_buf, p.x, SINGLE_BUF_LEN);
+ dual_buf_fill(&y_buf, p.y, SINGLE_BUF_LEN);
+ p.x = dual_buf_avg(&x_buf, SINGLE_BUF_LEN);
+ p.y = dual_buf_avg(&y_buf, SINGLE_BUF_LEN);
+ dbg("Report PHY Pos (%-4d,%-4d)\n",p.x,p.y);
+ pre.x = p.x;
+ pre.y = p.y;
+ #ifdef TOUCH_KEY
+ if(vt1603_ts_get_key(ts_drv, p))
+ goto next_loop;
+ #endif
+
+ vt1603_ts_report_pos(ts_drv, &p);
+
+ TwoCT = 0;
+ TouchCT = Single_TOUCH;
+ OneTCAfter2 = 0;
+ TwoTouchFlag = 0;
+ goto next_loop;
+ }
+ }
+ else if(nTouch == Multi_TOUCH){
+ vx = vt1603_ts_get_vx(para);
+ vy = vt1603_ts_get_vy(para);
+ dx = ts_drv->dual_dev.scale_y * vy + ts_drv->dual_dev.scale_x * vx;
+
+ if(dx1 && dx2)
+ dx = (dx+dx1+dx2)/3;
+ dx2 = dx1;
+ dx1 = dx;
+ dbg("vx=%-3d, vy=%-3d, dx=%-d, Ddx=%-3d\n",vx,vy,dx,abs(prv_dx-dx));
+
+ if(TwoCT < ts_drv->dual_dev.F2_CNT){
+ TwoCT ++;
+ dual_buf_init(&avg_buf);
+ dbg("Filter The First %d Dual Touch\n",TwoCT);
+ goto next_loop;
+
+ }else if (prv_dx!=0 && (abs(prv_dx - dx) > ts_drv->dual_dev.THR_MAX_DX)){
+ dbg("Threhold Filter Dual Touch dx=%d\n",abs(prv_dx - dx) );
+ prv_dx = dx;
+ goto next_loop;
+
+ }else{
+ //process and report dual touch data
+ dual_buf_fill(&avg_buf, dx, DUAL_BUF_LENGTH);
+ dx = dual_buf_avg(&avg_buf, DUAL_BUF_LENGTH);
+
+ if(abs(prv_dx - dx) < ts_drv->dual_dev.THR_MIN_DX){
+ //printk("Replace with last dx Ddx=%d\n",abs(prv_dx - dx));
+ dx = prv_dx;
+ }
+
+ if(TwoTouchFlag==0 && TouchCT==Single_TOUCH){//Single Touch ->Multi Touch
+ fixpos = pre;
+ //printk("Touch(%-4d,%-4d) 1--->2\n",pre.x,pre.y);
+ }else if(TwoTouchFlag==0 && TouchCT==None_TOUCH){//Multi Touch from the beginning
+ fixpos.x = vx_max/2;
+ fixpos.y = vy_max/2;
+ //printk("Touch(%-4d,%-4d) 2--->2\n",pos1.x, pos1.y);
+ }
+
+ pos1 = fixpos;
+ pos2.x = fixpos.x;
+ if(fixpos.y > vy_max/2)
+ pos2.y = pos_fix(vy_max, (fixpos.y - 150 - dx*DX_DETLA/DX_NUM));
+ else
+ pos2.y = pos_fix(vy_max, (fixpos.y + 150 + dx*DX_DETLA/DX_NUM));
+
+ dbg("PHY dx=%d, pos1.y=%d, pos2.y=%d\n", dx, pos1.y, pos2.y);
+ vt1603_ts_report_dual_pos(ts_drv, &pos1, &pos2);
+
+ prv_dx = dx;
+ TouchCT = Multi_TOUCH;
+ TwoTouchFlag = 1;
+ OneTCAfter2 = 0;
+ #ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ set_key_led_gpio(ts_drv,HIGH);
+ #endif
+ goto next_loop;
+ }
+ }
+ else{
+ dbg_err("Main Loop Error!\n");
+ }
+
+next_loop:
+ queue_delayed_work(ts_drv->workqueue, &ts_drv->dual_work, msecs_to_jiffies(20));
+ vt1603_clr_ts_irq(ts_drv, 0x0f);
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return ;
+}
+
+int vt1603_dual_init(struct vt1603_ts_drvdata *ts_drv)
+{
+ int ret = 0;
+ //unsigned long flags = 0;
+ int retries = 20;
+ u8 val = 0;
+
+ if (ts_drv == NULL) {
+ printk(KERN_ERR "VT1609 TouchScreen Driver Does Not Exsit!\n");
+ ret = -1;
+ goto out;
+ }
+
+ //spin_lock_irqsave(&ts_drv->spinlock, flags);
+ mutex_lock(&ts_drv->ts_mutex);
+
+ while (retries--) {
+ val = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ if ((val & BIT4) == 0) {
+ printk(KERN_ERR "Do not keep in touching, when vt1609 driver to be installed!\n");
+ msleep(20);
+ continue ;
+ }
+
+ val = vt1603_get_reg8(ts_drv, VT1603_CR_REG);
+ if ( val != 0x02) {
+ printk(KERN_ERR "VT1609 is not working in TS mode now!reg: C1=0x%02x\n",val);
+ msleep(10);
+ continue;
+ }
+
+ break ;
+ }
+
+ if (retries == 0) {
+ printk(KERN_ERR "Enable VT1609 Dual Touch Support Failed!\n");
+ ret = -1;
+ goto out;
+ }
+
+
+ vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, 0x04);
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10);
+ vt1603_get_vxy(ts_drv, &vx_max, &vy_max);
+ vt1603_ts_auto_mode(ts_drv);
+ vt1603_clr_ts_irq(ts_drv, BIT0 | BIT2 | BIT3);
+
+ dual_buf_init(&avg_buf);
+ dual_buf_init(&x_buf);
+ dual_buf_init(&y_buf);
+
+ printk("VT1609 Dual Touch vx_max=%d,vy_max=%d, vxy=%d ver=%s\n",vx_max, vy_max,ts_drv->dual_dev.vxy,VT1609_DUAL_VERSION);
+out:
+ vt1603_clr_ts_irq(ts_drv, 0x0f);
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return ret;
+}
+
+void vt1603_dual_exit(struct vt1603_ts_drvdata *ts_drv)
+{
+ vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_drv->pdata->sclk_div);
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x20);
+ printk("VT1609 Dual Touch Support Disabled.\n");
+
+ return ;
+}
+
+
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c new file mode 100755 index 00000000..f41634fc --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c @@ -0,0 +1,1481 @@ +/* + * vt1603_mt_i2c.c: VT1603A Touch-Panel Controller and SAR-ADC Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: 2011.Jan.21st, version: 1.00 + * + */ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +//#include <linux/spinlock.h> +#include <linux/input.h> +#include <linux/random.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + +#include "vt1609_ts.h" + + +//#define VT1609_DEBUG + +#undef dbg +#ifdef VT1609_DEBUG +#define dbg(fmt, args...) printk(KERN_ERR "[%s][%d]: " fmt, __func__ , __LINE__, ##args) +#else +#define dbg(fmt, args...) +#endif + +static struct vt1603_fifo px; +static struct vt1603_fifo py; +static struct class *vt1603_ts_class; +static struct vt1603_ts_pos pre_pos; +static struct vt1603_ts_cal_info g_CalcParam; +struct vt1603_ts_drvdata *pContext = NULL; + +static int vt1603_ts_isPendown(struct vt1603_ts_drvdata *ts_drv); +static void vt1603_ts_dev_cleanup(struct vt1603_ts_drvdata *ts_drv); + +#ifdef TOUCH_KEY +static unsigned int key_codes[TOUCH_KEY_NUM] = { + [0] = KEY_SEARCH, + [1] = KEY_BACK, + [2] = KEY_HOME, + [3] = KEY_MENU, +}; +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void vt1603ts_early_suspend(struct early_suspend *h); +static void vt1603ts_late_resume(struct early_suspend *h); +#endif + +#ifdef TOUCH_KEY +static int setup_led_gpio(struct vt1603_ts_drvdata *ts_drv) +{ + if (ts_drv->ledgpio >= 0) + gpio_direction_output(ts_drv->ledgpio, 0); + + return 0; +} + +int set_key_led_gpio(struct vt1603_ts_drvdata *ts_drv, int val) +{ + if (ts_drv->ledgpio >= 0) { + if(val) + gpio_direction_output(ts_drv->ledgpio, 1); + else + gpio_direction_output(ts_drv->ledgpio, 0); + } + + return 0; +} + +static void led_timer_func(unsigned long data) +{ + set_key_led_gpio((struct vt1603_ts_drvdata *)data,LOW); + return; +} + +#endif + + +/* + * vt1603_set_reg8 - set register value of vt1603 + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + * @val: value register will be set + */ +inline int vt1603_set_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 val) +{ + int ret =0; + if (ts_drv->tdev) + ret = ts_drv->tdev->reg_write(ts_drv->tdev,reg,val); + + if(ret) + printk("vt1609 ts write error, errno%d\n", ret); + + return ret; +} + +/* + * vt1603_get_reg8 - get register value of vt1603 + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + */ +inline u8 vt1603_get_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg) +{ + u8 val = 0; + int ret = 0; + + if (ts_drv->tdev) + ret = ts_drv->tdev->reg_read(ts_drv->tdev,reg,&val); + + if (ret) + printk("vt1609 ts read error, errno%d\n", ret); + + return val; +} + + +#ifdef VT1609_DEBUG +/* + * vt1603_reg_dump - dubug function, for dump vt1603 related registers + * @ts_drv: vt1603 driver data + */ +static void vt1603_reg_dump(struct vt1603_ts_drvdata *ts_drv) +{ + u8 i; + for (i = 0; i < 15; i++) + dbg("reg[%d]:0x%02X, reg[%d]:0x%02X\n", + i, vt1603_get_reg8(ts_drv, i), i + 0xC0, vt1603_get_reg8(ts_drv, i + 0xC0)); +} +#endif + +/* + * vt1603_setbits - write bit1 to related register's bit + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + * @mask: bit setting mask + */ +inline void vt1603_setbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask) +{ + u8 tmp = 0; + tmp = vt1603_get_reg8(ts_drv, reg) | mask; + vt1603_set_reg8(ts_drv, reg, tmp); + + return; +} + + +/* + * vt1603_clrbits - write bit0 to related register's bit + * @ts_drv: vt1603 driver data + * @reg: vt1603 register address + * @mask:bit setting mask + */ +inline void vt1603_clrbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask) +{ + u8 tmp = vt1603_get_reg8(ts_drv, reg) & (~mask); + vt1603_set_reg8(ts_drv, reg, tmp); + + return; +} + +/* + * vt1603_clr_ts_irq - clear touch panel pen down/up and + * conversion end/timeout interrupts + * @ts_drv: vt1603 driver data + * @mask: which interrupt will be cleared + */ +inline int vt1603_clr_ts_irq(struct vt1603_ts_drvdata *ts_drv, u8 mask) +{ + vt1603_setbits(ts_drv, VT1603_INTS_REG, mask); + return 0; +} + + +/* + * Enable I2S CLK, wmt-i2s.c have done this. + */ +static void vt1603_ts_clk_enable(void) +{ +#if 0 + /* set to 11.288MHz */ + auto_pll_divisor(DEV_I2S, CLK_ENABLE , 0, 0); + auto_pll_divisor(DEV_I2S, SET_PLLDIV, 1, 11288); + /*clock = auto_pll_divisor(DEV_I2S, GET_FREQ , 0, 0); + info("%s : clock=%d \n" , __func__, clock);*/ + + /* Enable BIT4:ARFP clock, BIT3:ARF clock */ + PMCEU_VAL |= (BIT4 | BIT3); + + /* Enable BIT2:AUD clock */ + PMCE3_VAL |= BIT2; + + /* disable GPIO and Pull Down mode */ + GPIO_CTRL_GP10_I2S_BYTE_VAL &= ~0xFF; + GPIO_CTRL_GP27_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2); + + GPIO_PULL_EN_GP10_I2S_BYTE_VAL &= ~0xFF; + GPIO_PULL_EN_GP27_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2); + + /* set to 2ch input, 2ch output */ + GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT3 | BIT17 | BIT19 | BIT20 | BIT22); + GPIO_PIN_SHARING_SEL_4BYTE_VAL |= (BIT0 | BIT2 | BIT16 | BIT18 | BIT21); +#endif + return; +} + +/* + * vt1603_setup_ts_mode - switch to VT1603 TS mode + * @ts_drv: vt1603 driver data + */ +static int vt1603_setup_ts_mode(struct vt1603_ts_drvdata *ts_drv) +{ + int ret = 0; + struct vt1603_ts_platform_data *ts_pdata; + + ts_pdata = ts_drv->pdata; + ret |= vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_pdata->sclk_div); + if (ts_pdata->panel_type == PANEL_TYPE_4WIRED) + ret |= vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1); + else + ret |= vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1 | BIT0); + + vt1603_clr_ts_irq(ts_drv, 0x0f); + + return (ret < 0)? -1 : 0; + +} + + +static int vt1603_fifo_push(struct vt1603_fifo *Fifo, int Data) +{ + Fifo->buf[Fifo->head] = Data; + Fifo->head++; + if(Fifo->head >= VT1603_FIFO_LEN){ + Fifo->head = 0; + Fifo->full = 1; + } + + return 0; +} + +static int vt1603_fifo_avg(struct vt1603_fifo Fifo, int *Data) +{ + int i=0; + int Sum=0,Max=0,Min=0; + + if(!Fifo.full && !Fifo.head)//FIFO is empty + return 0; + + if(!Fifo.full ){ + for(i=0; i<Fifo.head; i++) + Sum += Fifo.buf[i]; + + *Data = Sum/Fifo.head; + return 0; + } + + Max = Fifo.buf[0]; + Min = Fifo.buf[0]; + for(i=0; i<VT1603_FIFO_LEN; i++){ + Sum += Fifo.buf[i]; + + if(Max < Fifo.buf[i]) + Max = Fifo.buf[i]; + + if(Min > Fifo.buf[i]) + Min = Fifo.buf[i]; + } + Sum -= Max; + Sum -= Min; + *Data = Sum/(VT1603_FIFO_LEN-2); + + return 0; + +} + + +inline int vt1603_ts_pos_calibration(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *to_cal) +{ + int x, y; + + x = (g_CalcParam.a1 * to_cal->x + g_CalcParam.b1 * to_cal->y + + g_CalcParam.c1) / g_CalcParam.delta; + y = (g_CalcParam.a2 * to_cal->x + g_CalcParam.b2 * to_cal->y + + g_CalcParam.c2) / g_CalcParam.delta; + + /* pos check */ + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (x > ts_drv->resl_x) + x = ts_drv->resl_x - 1; + if (y > ts_drv->resl_y) + y = ts_drv->resl_y - 1; + + if (ts_drv->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ts_drv->resl_x - tmp; + } + + to_cal->x = x; + to_cal->y = y; + + return 0; +} + +static inline void vt1603_ts_set_rawdata(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *pos) +{ + ts_drv->raw_x = pos->x; + ts_drv->raw_y = pos->y; + + return; +} + +inline void vt1603_ts_report_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos) +{ + vt1603_ts_set_rawdata(ts_drv,pos); + vt1603_ts_pos_calibration(ts_drv,pos); + + input_report_abs(ts_drv->input, ABS_MT_POSITION_X, pos->x); + input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, pos->y); + input_mt_sync(ts_drv->input); + input_sync(ts_drv->input); + + return; +} + +#ifdef TOUCH_KEY +void vt1603_ts_report_key(struct vt1603_ts_drvdata *ts_drv) +{ + if(ts_drv->touch_key_used ){ + + if(ts_drv->ledgpio >= 0 ) + mod_timer(&ts_drv->led_timer, jiffies+10*HZ); + + if(ts_drv->key_pressed && ts_drv->key_idx < _MAX_NUM ){ + input_report_key(ts_drv->input, key_codes[ts_drv->key_idx], 1); + input_sync(ts_drv->input); + input_report_key(ts_drv->input, key_codes[ts_drv->key_idx], 0); + input_sync(ts_drv->input); + dbg("report as key event %d \n",ts_drv->key_idx); + } + } + + return; +} + +inline int vt1603_ts_get_key(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos pos) +{ + if(ts_drv->touch_key_used){ + + if(pos.y > ts_drv->tsc_key.low && pos.y < ts_drv->tsc_key.upper){ + + ts_drv->key_pressed = 1; + if(pos.x>(ts_drv->tsc_key.key[_SEARCH].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_SEARCH].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_SEARCH].idx; + } + else if(pos.x>(ts_drv->tsc_key.key[_BACK].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_BACK].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_BACK].idx; + } + else if(pos.x>(ts_drv->tsc_key.key[_HOME].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_HOME].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_HOME].idx; + } + else if(pos.x>(ts_drv->tsc_key.key[_MENU].pos-ts_drv->tsc_key.delta) && + pos.x<(ts_drv->tsc_key.key[_MENU].pos+ts_drv->tsc_key.delta)){ + ts_drv->key_idx = ts_drv->tsc_key.key[_MENU].idx; + } + else{ + ts_drv->key_idx = _MAX_NUM; + } + + if(ts_drv->key_idx < _MAX_NUM && ts_drv->ledgpio >= 0) + set_key_led_gpio(ts_drv,HIGH); + + return 1; + } + + if(ts_drv->ledgpio >= 0) + set_key_led_gpio(ts_drv,HIGH); + } + + ts_drv->key_pressed= 0; + + return 0 ; +} + +#endif + + +/* + * vt1603_ts_get_pos - get touch panel touched position from vt1603 + * conversion register + * @ts_drv: vt1603 driver data + * @pos: vt1603 touch panel touched point conversion data + */ +static inline void vt1603_ts_get_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos) +{ + u8 datal, datah; + + /* get x-position */ + datal = vt1603_get_reg8(ts_drv, VT1603_XPL_REG); + datah = vt1603_get_reg8(ts_drv, VT1603_XPH_REG); + pos->x = ADC_DATA(datal, datah); + + /* get y-positin */ + datal = vt1603_get_reg8(ts_drv, VT1603_YPL_REG); + datah = vt1603_get_reg8(ts_drv, VT1603_YPH_REG); + pos->y = ADC_DATA(datal, datah); + vt1603_clr_ts_irq(ts_drv, BIT0); + + return; +} + +/* + * vt1603_ts_isPendown - get touch panel pen state from vt1603 + * interrup status register + * @ts_drv: vt1603 driver data + */ +static inline int vt1603_ts_isPendown(struct vt1603_ts_drvdata *ts_drv) +{ + u8 state = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + + if (state & BIT4) + return TS_PENUP_STATE; + else + return TS_PENDOWN_STATE; +} + + +static inline int vt1603_pos_avg(struct vt1603_ts_pos *pos) +{ + vt1603_fifo_push(&px, pos->x); + vt1603_fifo_push(&py, pos->y); + vt1603_fifo_avg(px, &pos->x); + vt1603_fifo_avg(py, &pos->y); + + return 0; +} + +static int vt1603_pos_cleanup(void) +{ + px.full = 0; + px.head = 0; + + py.full = 0; + py.head = 0; + + return 0; +} + +static void vt1603_read_loop(struct work_struct* dwork) +{ + struct vt1603_ts_drvdata *ts_drv=NULL; + struct vt1603_ts_pos pos; + + ts_drv = container_of(dwork, struct vt1603_ts_drvdata, read_work.work); + ts_drv->pen_state= vt1603_ts_isPendown(ts_drv); + if((ts_drv->pen_state == TS_PENUP_STATE) ||ts_drv->earlysus){ + vt1603_clr_ts_irq(ts_drv, 0x0F); + if(jiffies_to_msecs(jiffies - ts_drv->ts_stamp) < 80 && !ts_drv->earlysus){ + //dbg("Debounceing@@@@@@@@\n"); + goto next_loop; + } + + dbg("============== penup ==============\n"); + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);/* vt1603 gpio1 as IRQ output */ + input_mt_sync(ts_drv->input); + input_sync(ts_drv->input); + #ifdef TOUCH_KEY + vt1603_ts_report_key(ts_drv); + #endif + pre_pos.x = 0; + pre_pos.y = 0; + ts_drv->hcnt = 0; + vt1603_pos_cleanup(); + + if(!ts_drv->earlysus) + wmt_gpio_unmask_irq(ts_drv->intgpio); + + return; + } + + ts_drv->ts_stamp = jiffies; + vt1603_ts_get_pos(ts_drv, &pos); + + //Filter the first N point + if(ts_drv->hcnt < VT1603_FILTER_HEAD_COUNT){ + ts_drv->hcnt++; + goto next_loop; + } + + /* ƽ»¬Â˲¨*/ + if((pre_pos.x != 0 && pre_pos.y != 0)&&(abs(pre_pos.x-pos.x) > VT1603_JITTER_THRESHOLD||abs(pre_pos.y-pos.y) > VT1603_JITTER_THRESHOLD)){ + pre_pos.x = pos.x; + pre_pos.y = pos.y; + goto next_loop; + } +#ifdef TOUCH_KEY + if(vt1603_ts_get_key(ts_drv,pos)) + goto next_loop; +#endif + + vt1603_pos_avg(&pos); + pre_pos.x = pos.x; + pre_pos.y = pos.y; + + dbg("x=%d, y=%d\n",pos.x,pos.y); + vt1603_ts_report_pos(ts_drv, &pos); + +next_loop: + queue_delayed_work(ts_drv->workqueue, &ts_drv->read_work, 20*HZ/1000); + + return; +} + + +static void vt1603_ts_work(struct work_struct *work) +{ + int int_sts; + //unsigned long flags; + struct vt1603_ts_drvdata *ts_drv=pContext; + + //spin_lock_irqsave(&ts_drv->spinlock, flags); + mutex_lock(&ts_drv->ts_mutex); + int_sts = vt1603_get_reg8(ts_drv, VT1603_INTS_REG); + dbg("+++++++ ts int status 0x%02x +++++++\n",int_sts); + + if ((int_sts & BIT4) == 0 || (int_sts & BIT1) == BIT1){ + if(ts_drv->pen_state == TS_PENUP_STATE){ + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x03);/* vt1603 gpio1 as logic high output */ + ts_drv->pen_state = TS_PENDOWN_STATE; + ts_drv->ts_stamp = jiffies; + vt1603_setup_ts_mode(ts_drv); + dbg("============= pendown =============\n"); + vt1603_pos_cleanup(); + if(ts_drv->dual_enable) + vt1603_ts_dual_support(&ts_drv->dual_work.work); + else + vt1603_read_loop(&ts_drv->read_work.work); + + vt1603_clr_ts_irq(ts_drv, int_sts&0x0f); + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + + return; + } + } + + vt1603_clr_ts_irq(ts_drv, int_sts&0x0f); + //spin_unlock_irqrestore(&ts_drv->spinlock, flags); + mutex_unlock(&ts_drv->ts_mutex); + wmt_gpio_unmask_irq(ts_drv->intgpio); + + return ; +} + + +static irqreturn_t vt1603_ts_isr(int irq, void *dev_id) +{ + struct vt1603_ts_drvdata *ts_drv = dev_id; + + if(!gpio_irqstatus(ts_drv->intgpio) || + !is_gpio_irqenable(ts_drv->intgpio)) + return IRQ_NONE; + + wmt_gpio_ack_irq(ts_drv->intgpio); + wmt_gpio_mask_irq(ts_drv->intgpio); + schedule_work(&ts_drv->work); + dbg("@@@@@@@ touch irq @@@@@@@\n"); + + return IRQ_HANDLED; +} + +static int vt1603_register_input(struct vt1603_ts_drvdata * ts_drv) +{ + if(strcmp(ts_drv->dev_id,"VT1609")) + ts_drv->input->name = "vt1603-touch"; + else + ts_drv->input->name = "vt1609-touch"; + + ts_drv->input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + ts_drv->input->propbit[0] = BIT_MASK(INPUT_PROP_DIRECT); + +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used){ + int i; + for (i = 0; i < TOUCH_KEY_NUM; i++) + set_bit(key_codes[i], ts_drv->input->keybit); + + ts_drv->input->keycode = key_codes; + ts_drv->input->keycodesize = sizeof(unsigned int); + ts_drv->input->keycodemax = TOUCH_KEY_NUM; + } +#endif + if (ts_drv->lcd_exchg) { + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_X, 0, ts_drv->resl_y, 0, 0); + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_Y, 0, ts_drv->resl_x, 0, 0); + } else { + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_X, 0, ts_drv->resl_x, 0, 0); + input_set_abs_params(ts_drv->input, ABS_MT_POSITION_Y, 0, ts_drv->resl_y, 0, 0); + } + + input_register_device(ts_drv->input); + return 0; +} + + +/* + * vt1603_ts_calibration - vt1603 self calibration routine + * @ts_drv: vt1603 driver data + */ +static void vt1603_ts_calibration(struct vt1603_ts_drvdata *ts_drv) +{ + unsigned char i, j, tmp; + unsigned char cal[5][8] = {{0}}; + unsigned int cal_sum[8] = {0}; + struct vt1603_ts_platform_data *ts_pdata; + + dbg("Enter\n"); + ts_pdata = ts_drv->pdata; + for (j = 0; j < 5; j++) { + tmp = BIT6 | BIT0 | (ts_pdata->cal_sel << 4); + vt1603_set_reg8(ts_drv, VT1603_CCCR_REG, tmp); + msleep(100); + for (i = 0; i < 8; i++) + cal[j][i] = vt1603_get_reg8(ts_drv, VT1603_ERR8_REG + i); + } + for (i = 0; i < 8; i++) { + for (j = 0; j < 5; j++) + cal_sum[i] += cal[j][i]; + tmp = (u8)cal_sum[i]/5; + vt1603_set_reg8(ts_drv, VT1603_DBG8_REG + i, tmp); + } + + dbg("Exit\n"); + return ; +} + +/* + * vt1603_ts_reset - reset vt1603, auto postition conversion mode, + * do self calibration if enable + * @ts_drv: vt1603 driver data + */ +static void vt1603_ts_reset(struct vt1603_ts_drvdata * ts_drv) +{ + struct vt1603_ts_platform_data *ts_pdata; + ts_pdata = ts_drv->pdata; + + /* power control enable */ + vt1603_set_reg8(ts_drv, VT1603_PWC_REG, 0x18); + /* begin calibrate if calibration enable */ + if ((ts_pdata != NULL) && (ts_pdata->cal_en == CALIBRATION_ENABLE)) { + vt1603_ts_calibration(ts_drv); + } + + /* clock divider */ + vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_pdata->sclk_div); + + /* clean debug register,for some 2 layer PCB machine enter debug mode unexpected */ + vt1603_set_reg8(ts_drv, VT1603_DCR_REG, 0x00); + + vt1603_set_reg8(ts_drv, VT1603_INTEN_REG, BIT1);//Just Enable pendown IRQ + + /* auto position conversion mode and panel type config */ + if (ts_pdata->panel_type== PANEL_TYPE_4WIRED) + vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1); + else + vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1 | BIT0); + + /* interrupt control, pen up/down detection enable */ + vt1603_set_reg8(ts_drv, VT1603_INTCR_REG, 0xff); + + /* mask other module interrupts */ + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG27, 0xff); + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG28, 0xFF); + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG29, 0xFF); + /* reset headphone detect irq */ + vt1603_set_reg8(ts_drv, VT1603_IMASK_REG27, 0xfd); + + if (ts_pdata->irq_type == HIGH_ACTIVE|| ts_pdata->irq_type == RISING_EDGE_ACTIVE) + vt1603_clrbits(ts_drv, VT1603_IPOL_REG33, BIT5); + else + vt1603_setbits(ts_drv, VT1603_IPOL_REG33, BIT5); + + vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);/* vt1603 gpio1 as IRQ output */ + /* clear irq */ + vt1603_clr_ts_irq(ts_drv, 0x0F); + + return; +} + + +static struct vt1603_ts_platform_data vt1603_ts_pdata = { + .panel_type = PANEL_TYPE_4WIRED, + .cal_en = CALIBRATION_DISABLE, + .cal_sel = 0x00, + .shift = 0x00, + .sclk_div = 0x08, + .irq_type = LOW_ACTIVE, +}; + +struct delayed_work resume_work; +static void vt1603_resume_work(struct work_struct* dwork) +{ + struct vt1603_ts_drvdata *ts_drv = pContext; + ts_drv->pen_state = TS_PENUP_STATE; + + /* must ensure mclk is available */ + vt1603_ts_clk_enable(); + /* vt1603 ts hardware resume */ + vt1603_ts_reset(ts_drv); + /* clear irq before enale gpio irq */ + vt1603_clr_ts_irq(ts_drv, 0x0f ); + + gpio_direction_input(ts_drv->intgpio); + wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); +#endif +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif +} +static __devinit int +vt1603_ts_probe(struct platform_device *pdev) +{ + int ret = 0; + struct vt1603_ts_drvdata *ts_drv = pContext; + struct vt1603_ts_platform_data *ts_pdata = NULL; + + ts_pdata = &vt1603_ts_pdata; + + ts_drv->pdata = ts_pdata; + ts_drv->pen_state = TS_PENUP_STATE; + ts_drv->tdev = dev_get_platdata(&pdev->dev); + + //spin_lock_init(&ts_drv->spinlock); + mutex_init(&ts_drv->ts_mutex); + + dev_set_drvdata(&pdev->dev, ts_drv); +#ifdef CONFIG_HAS_EARLYSUSPEND + ts_drv->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts_drv->earlysuspend.suspend = vt1603ts_early_suspend; + ts_drv->earlysuspend.resume = vt1603ts_late_resume; + register_early_suspend(&ts_drv->earlysuspend); +#endif + /* 1. mclk enable */ + vt1603_ts_clk_enable(); + /* 2.vt1603 touch-panel and sar-adc module reset */ + vt1603_ts_reset(ts_drv); + +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif + /* initial battery if battery detection enable */ + /* initial temperature if temperature detection enable */ + + /* request iuput device */ + ts_drv->input = input_allocate_device(); + if (!ts_drv->input) { + printk("vt1603_ts: alloc input device failed"); + ret = -ENOMEM; + goto release_driver_data; + } + vt1603_register_input(ts_drv); + + INIT_DELAYED_WORK(&ts_drv->read_work, vt1603_read_loop); + INIT_DELAYED_WORK(&ts_drv->dual_work, vt1603_ts_dual_support); + INIT_DELAYED_WORK(&resume_work, vt1603_resume_work); + ts_drv->workqueue = create_singlethread_workqueue("vt160x-touch"); + if(!ts_drv->workqueue){ + printk("vt160x create singlethread work queue failed!\n"); + goto release_driver_data; + } + + INIT_WORK(&ts_drv->work, vt1603_ts_work); + + if (request_irq(ts_drv->gpio_irq, vt1603_ts_isr, IRQF_SHARED, "vt160x-touch", ts_drv)) { + printk("vt160x_ts: request IRQ %d failed\n", ts_drv->gpio_irq); + ret = -ENODEV; + } + + wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); +#endif + + dbg("%s Touch Screen Driver Installed!\n",ts_drv->dev_id); + return ret; + +release_driver_data: + kfree(ts_drv); + ts_drv = NULL; + + return ret; +} + +static __devexit int +vt1603_ts_remove(struct platform_device *pdev) +{ + struct vt1603_ts_drvdata *ts_drv; + ts_drv = dev_get_drvdata(&pdev->dev); + + dbg("Enter\n"); + + wmt_gpio_mask_irq(ts_drv->intgpio); + if(ts_drv->dual_enable) + vt1603_dual_exit(ts_drv); + + /* input unregister */ + input_unregister_device(ts_drv->input); + cancel_work_sync(&ts_drv->work); + cancel_delayed_work_sync(&ts_drv->dual_work); + cancel_delayed_work_sync(&ts_drv->read_work); + destroy_workqueue(ts_drv->workqueue); + vt1603_ts_dev_cleanup(ts_drv); +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + del_timer_sync(&ts_drv->led_timer); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts_drv->earlysuspend); +#endif + /* free vt1603 driver data */ + dev_set_drvdata(&pdev->dev, NULL); + mutex_destroy(&ts_drv->ts_mutex); + free_irq(ts_drv->gpio_irq,ts_drv); + kfree(ts_drv); + ts_drv = NULL; + + dbg("Exit\n"); + return 0; +} + +#ifdef CONFIG_PM + +#ifdef CONFIG_HAS_EARLYSUSPEND + +static void +vt1603ts_early_suspend(struct early_suspend *h) +{ + struct vt1603_ts_drvdata *ts_drv = pContext; + + dbg("Enter\n"); + + wmt_gpio_mask_irq(ts_drv->intgpio); +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0){ + del_timer_sync(&ts_drv->led_timer); + set_key_led_gpio(ts_drv,LOW); + } +#endif + + ts_drv->earlysus = 1; + dbg("Exit\n"); + return; +} + +static void +vt1603ts_late_resume(struct early_suspend *h) +{ + struct vt1603_ts_drvdata *ts_drv = pContext; + + dbg("Enter\n"); + ts_drv->pen_state = TS_PENUP_STATE; + + /* must ensure mclk is available */ + vt1603_ts_clk_enable(); + /* vt1603 ts hardware resume */ + vt1603_ts_reset(ts_drv); + /* clear irq before enale gpio irq */ + vt1603_clr_ts_irq(ts_drv, 0x0f ); + + ts_drv->earlysus = 0; + //wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); + dbg("Exit\n"); +#endif + + return; +} + +#endif + +static int +vt1603_ts_suspend(struct platform_device *pdev, pm_message_t message) +{ + struct vt1603_ts_drvdata *ts_drv = dev_get_drvdata(&pdev->dev); + + dbg("Enter\n"); +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif + + ts_drv = dev_get_drvdata(&pdev->dev); + + wmt_gpio_mask_irq(ts_drv->intgpio); +#ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0){ + set_key_led_gpio(ts_drv,LOW); + del_timer_sync(&ts_drv->led_timer); + } +#endif + + dbg("Exit\n"); + return 0; +} + +static int +vt1603_ts_resume(struct platform_device *pdev) +{ + //struct vt1603_ts_drvdata *ts_drv = dev_get_drvdata(&pdev->dev); + + dbg("Enter\n"); + //delay resume work because some resources were closed by audio driver. + schedule_delayed_work(&resume_work, HZ); +#if 0 + ts_drv->pen_state = TS_PENUP_STATE; + + /* must ensure mclk is available */ + vt1603_ts_clk_enable(); + /* vt1603 ts hardware resume */ + vt1603_ts_reset(ts_drv); + /* clear irq before enale gpio irq */ + vt1603_clr_ts_irq(ts_drv, 0x0f ); + + gpio_direction_input(ts_drv->intgpio); + wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts_drv->intgpio); + #ifdef TOUCH_KEY + if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0) + setup_led_gpio(ts_drv); +#endif +#ifdef VT1609_DEBUG + /* 4. dump vt1603 to ensure setting ok */ + vt1603_reg_dump(ts_drv); +#endif +#endif + dbg("Exit\n"); + + return 0; +} + +#else +#define vt1603_ts_suspend NULL +#define vt1603_ts_resume NULL +#endif + + +static struct platform_driver vt1603_driver = { + .driver = { + .name = VT1603_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = vt1603_ts_probe, + .remove = vt1603_ts_remove, + .suspend = vt1603_ts_suspend, + .resume = vt1603_ts_resume, +}; + +static int vt1603_ts_dev_open(struct inode *inode, struct file *filp) +{ + struct vt1603_ts_drvdata *ts_drv; + + dbg("Enter\n"); + + ts_drv = container_of(inode->i_cdev, struct vt1603_ts_drvdata , cdev); + if (ts_drv == NULL) { + printk("can not get vt1603_ts driver data\n"); + return -ENODATA; + } + filp->private_data = ts_drv; + + dbg("Exit\n"); + return 0; +} + +static int vt1603_ts_dev_close(struct inode *inode, struct file *filp) +{ + struct vt1603_ts_drvdata *ts_drv; + + dbg("Enter\n"); + + ts_drv = container_of(inode->i_cdev, struct vt1603_ts_drvdata , cdev); + if (ts_drv == NULL) { + printk("can not get vt1603_ts driver data\n"); + return -ENODATA; + } + + dbg("Exit\n"); + return 0; +} + +static long vt1603_ts_dev_ioctl(struct file *filp,unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int nBuff[7] = { 0 }; + char env_val[96] = { 0 }; + struct vt1603_ts_drvdata *ts_drv; + + dbg("Enter\n"); + /* check type and command number */ + if (_IOC_TYPE(cmd) != VT1603_TS_IOC_MAGIC) + return -ENOTTY; + + ts_drv = filp->private_data; + switch (cmd) { + case VT1603_TS_IOC_CAL_DONE: + copy_from_user(nBuff, (unsigned int *)arg, 7 * sizeof(int)); + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if (g_CalcParam.delta == 0) + g_CalcParam.delta = 1; + + sprintf(env_val, "%d %d %d %d %d %d %d", + nBuff[0], nBuff[1], nBuff[2], nBuff[3], nBuff[4], nBuff[5], nBuff[6]); + + wmt_setsyspara("wmt.io.ts.2dcal", env_val); + printk("TOUCH CAL DONE: [%s]\n", env_val); + break; + + case VT1603_TS_IOC_CAL_RAWDATA: + nBuff[0] = ts_drv->raw_x; + nBuff[1] = ts_drv->raw_y; + copy_to_user((unsigned int *)arg, nBuff, 2 * sizeof(int)); + printk("TOUCH CAL RAWDATA: x=%-4d, y=%-4d \n", nBuff[0], nBuff[1]); + break; + default: + ret = -EINVAL; + break; + } + + dbg("Exit\n"); + return ret; +} + +static struct file_operations vt1603_ts_fops = { + .owner = THIS_MODULE, + .open = vt1603_ts_dev_open, + .unlocked_ioctl = vt1603_ts_dev_ioctl, + .release = vt1603_ts_dev_close, +}; + + +static int vt1603_ts_dev_setup(struct vt1603_ts_drvdata *ts_drv) +{ + dev_t dev_no = 0; + int ret = 0; + struct device *dev = NULL; + + dbg("Enter\n"); + if (VT1603_TS_DEV_MAJOR) { + ts_drv->major = VT1603_TS_DEV_MAJOR; + ts_drv->minor = 0; + dev_no = MKDEV(ts_drv->major, ts_drv->minor); + ret = register_chrdev_region(dev_no, VT1603_TS_NR_DEVS, DEV_NAME); + } else { + ret = alloc_chrdev_region(&dev_no, 0, VT1603_TS_NR_DEVS, DEV_NAME); + ts_drv->major = MAJOR(dev_no); + ts_drv->minor = MINOR(dev_no); + dbg("vt1603_ts device major = %d, minor = %d \n", ts_drv->major,ts_drv->minor); + } + + if (ret < 0) { + printk("can not get major %d\n", ts_drv->major); + goto out; + } + + cdev_init(&ts_drv->cdev, &vt1603_ts_fops); + + ts_drv->cdev.owner = THIS_MODULE; + ts_drv->cdev.ops = &vt1603_ts_fops; + ret = cdev_add(&ts_drv->cdev, dev_no, VT1603_TS_NR_DEVS); + if (ret) { + printk("add char dev for vt1603 ts failed\n"); + goto release_region; + } + + vt1603_ts_class = class_create(THIS_MODULE, ts_drv->dev_id); + if (IS_ERR(vt1603_ts_class)) { + printk("create vt1603_ts class failed\n"); + ret = PTR_ERR(vt1603_ts_class); + goto release_cdev; + } + + dev = device_create(vt1603_ts_class, NULL, dev_no, NULL, DEV_NAME); + if (IS_ERR(dev)) { + printk("create device for vt160x ts failed\n"); + ret = PTR_ERR(dev); + goto release_class; + } + + dbg("Exit\n"); + return ret; + +release_class: + class_destroy(vt1603_ts_class); + vt1603_ts_class = NULL; +release_cdev: + cdev_del(&ts_drv->cdev); +release_region: + unregister_chrdev_region(dev_no, VT1603_TS_NR_DEVS); +out: + return ret; +} + +static void vt1603_ts_dev_cleanup(struct vt1603_ts_drvdata *ts_drv) +{ + dev_t dev_no = MKDEV(ts_drv->major, ts_drv->minor); + + dbg("Enter\n"); + cdev_del(&ts_drv->cdev); + unregister_chrdev_region(dev_no, VT1603_TS_NR_DEVS); + device_destroy(vt1603_ts_class, dev_no); + class_destroy(vt1603_ts_class); + dbg("Exit\n"); +} + +#ifdef TOUCH_KEY +static int parse_touch_key_env(struct vt1603_ts_drvdata *ts_drv) +{ + int i = 0; + int ret = 0; + int len = 96; + char retval[96] = {0}; + char *p = NULL; + + ret = wmt_getsyspara("wmt.ts.vkey", retval, &len); + if(ret){ + printk("Read wmt.ts.vkey Failed.\n"); + return -EIO; + } + + sscanf(retval,"%d:%d:%d:%d", &ts_drv->tsc_key.key_num, + &ts_drv->tsc_key.low, &ts_drv->tsc_key.upper, &ts_drv->tsc_key.delta); + + if(!ts_drv->tsc_key.key_num){ + printk("tsc key number is zero!\n"); + return -EIO; + } + + p = retval; + i = 4; + while(i--){ + p = strchr(p,':'); + p++; + } + + for(i = 0; i < ts_drv->tsc_key.key_num; i++){ + sscanf(p,"%d_%d",&ts_drv->tsc_key.key[i].pos,&ts_drv->tsc_key.key[i].idx ); + p = strchr(p,':'); + p++; + } + + dbg("%d:%d:%d:%d:%d_%d:%d_%d:%d_%d:%d_%d\n", + ts_drv->tsc_key.key_num, + ts_drv->tsc_key.low, + ts_drv->tsc_key.upper, + ts_drv->tsc_key.delta, + ts_drv->tsc_key.key[0].pos, + ts_drv->tsc_key.key[0].idx, + ts_drv->tsc_key.key[1].pos, + ts_drv->tsc_key.key[1].idx, + ts_drv->tsc_key.key[2].pos, + ts_drv->tsc_key.key[2].idx, + ts_drv->tsc_key.key[3].pos, + ts_drv->tsc_key.key[3].idx); + + return 0; + +} +#endif + +static int parse_dual_env(struct vt1603_ts_drvdata *ts_drv) +{ + int ret = 0; + int len = 96; + char retval[96] = {0}; + + len = sizeof(retval); + ret = wmt_getsyspara("wmt.io.vt1609", retval, &len); + if(ret){ + //printk("wmt.io.vt1609 not set, use default parameter.\n"); + ts_drv->dual_dev.vxy = 17; + ts_drv->dual_dev.scale_x = 4; + ts_drv->dual_dev.scale_y = 2; + ts_drv->dual_dev.F1_CNT = 2; + ts_drv->dual_dev.F2_CNT = 7; + ts_drv->dual_dev.F2T1_CNT = 15; + ts_drv->dual_dev.SAMPLE_CNT = 1; + ts_drv->dual_dev.THR_MIN_DX = 13; + ts_drv->dual_dev.THR_MAX_DX = 256; + ts_drv->dual_dev.exch = 0; + + return 0; + } + + sscanf(retval,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &ts_drv->dual_dev.vxy, + &ts_drv->dual_dev.scale_x, + &ts_drv->dual_dev.scale_y, + &ts_drv->dual_dev.F1_CNT, + &ts_drv->dual_dev.F2_CNT, + &ts_drv->dual_dev.F2T1_CNT, + &ts_drv->dual_dev.SAMPLE_CNT, + &ts_drv->dual_dev.THR_MIN_DX, + &ts_drv->dual_dev.THR_MAX_DX, + &ts_drv->dual_dev.exch); + /* + printk("%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + ts_drv->dual_dev.vxy, + ts_drv->dual_dev.scale_x, + ts_drv->dual_dev.scale_y, + ts_drv->dual_dev.F1_CNT, + ts_drv->dual_dev.F2_CNT , + ts_drv->dual_dev.F2T1_CNT , + ts_drv->dual_dev.SAMPLE_CNT , + ts_drv->dual_dev.THR_MIN_DX , + ts_drv->dual_dev.THR_MAX_DX), + ts_drv->dual_dev.exch; + */ + return 0; +} + +static int vt1603_uboot_env_check(struct vt1603_ts_drvdata *ts_drv) +{ + int nBuff[7] = {0}; + int i = 0, Enable = 0; + int intgpio=0; + int ledgpio=-1; + int reslx=480,resly=800; + int ret=0,len = 96; + char retval[96] = {0}; + char *p=NULL; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + printk("Read wmt.io.touch Failed.\n"); + return -EIO; + } + + sscanf(retval,"%d:",&Enable); + //check touch enable + if(Enable == 0){ + printk("System touchscreen is disbaled.\n"); + return -ENODEV; + } + + p = strchr(retval,':'); + p++; + if(strncmp(p,"vt1603",6) == 0){//check touch ID + strcpy(ts_drv->dev_id, "VT1603A"); + } + else if(strncmp(p,"vt1609",6) == 0){//check touch ID + ts_drv->dual_enable = 1; + strcpy(ts_drv->dev_id, "VT1609"); + parse_dual_env(ts_drv); + } + else{ + printk("Vt1609 touchscreen driver disabled.\n"); + return -ENODEV; + } + + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d",&reslx, &resly, &intgpio, &ledgpio); + + ts_drv->resl_x = reslx; + ts_drv->resl_y = resly; + + ts_drv->intgpio = intgpio; + + ts_drv->ledgpio = ledgpio; + + ts_drv->gpio_irq = IRQ_GPIO; + + printk("%s-Touch: reslx=%d resly=%d, Interrupt GPIO%d , Virtual Touch Key Led GPIO%d\n",ts_drv->dev_id, + ts_drv->resl_x, ts_drv->resl_y, ts_drv->intgpio, ts_drv->ledgpio); + + len = sizeof(retval); + memset(retval, 0, sizeof(retval)); + + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + printk("Read env wmt.io.ts.2dcal Failed.\n"); + //return -EIO; + } + + for (i = 0; i < sizeof(retval); i++) { + if (retval[i] == ' ' || retval[i] == ',' || retval[i] == ':') + retval[i] = '\0'; + } + + p = retval; + for (i = 0; (i < 7) && (p < (retval + sizeof(retval))); ) { + if (*p == '\0') + p++; + else { + sscanf(p, "%d", &nBuff[i]); + p = p + strlen(p); + i++; + } + } + dbg("Touchscreen Calibrate Data: [%d %d %d %d %d %d %d]\n", + nBuff[0], nBuff[1], nBuff[2], nBuff[3], nBuff[4], nBuff[5], nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta = 1; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + ts_drv->lcd_exchg = 1; + } + + return 0; +} + +static int gpio_resource_request(void) +{ + if (gpio_request(pContext->intgpio, "ts_irq") < 0) { + printk("gpio(%d) touchscreen interrupt request fail\n", pContext->intgpio); + return -EIO; + } + gpio_direction_input(pContext->intgpio); + + if (pContext->ledgpio >= 0) { + if (gpio_request(pContext->ledgpio, "ts_led") < 0) { + printk("gpio(%d) touchscreen led gpio request fail\n", pContext->ledgpio); + gpio_free(pContext->intgpio); + return -EIO; + } + gpio_direction_output(pContext->ledgpio, 0); + } + + return 0; +} +static void gpio_resource_free(void) +{ + gpio_free(pContext->intgpio); + if (pContext->ledgpio >= 0) + gpio_free(pContext->ledgpio); +} + + +static int __init vt1603_ts_init(void) +{ + int ret = 0; + struct vt1603_ts_drvdata *ts_drv = NULL; + + dbg("Enter\n"); + ts_drv = kzalloc(sizeof(struct vt1603_ts_drvdata), GFP_KERNEL); + if (!ts_drv) { + printk("vt160x ts: alloc driver data failed\n"); + return -ENOMEM; + } + pContext = ts_drv; + ret = vt1603_uboot_env_check(ts_drv); + if (ret) {//vt1603 touch disabled + goto out; + }else{//vt1603 touch enabled + if (gpio_resource_request()) + goto out; + ret = vt1603_ts_dev_setup(ts_drv);//only touch calibrate need dev node + if (ret) { + printk("##ERR## vt160x ts create device node failed.\n"); + goto freegpio; + } + +#ifdef TOUCH_KEY + if(!parse_touch_key_env(ts_drv)){ + ts_drv->touch_key_used = 1; + if(ts_drv->ledgpio >= 0){//touch virtual key back light led enabled + init_timer(&ts_drv->led_timer); + ts_drv->led_timer.function = led_timer_func; + ts_drv->led_timer.data = (unsigned long) ts_drv; + } + } +#endif + } + + ret = platform_driver_register(&vt1603_driver); + if(ret){ + printk("vt160x platform driver register failed!.\n"); + goto release_dev; + } + + if(ts_drv->dual_enable) + vt1603_dual_init(ts_drv); + + dbg("Exit\n"); + return ret; + +release_dev: + vt1603_ts_dev_cleanup(ts_drv); +freegpio: + gpio_resource_free(); +out: + kfree(ts_drv); + + return ret; +} +//module_init(vt1603_ts_init); +late_initcall(vt1603_ts_init); +static void __exit vt1603_ts_exit(void) +{ + dbg("Enter\n"); + + platform_driver_unregister(&vt1603_driver); + gpio_resource_free(); + + dbg("Exit\n"); +} +module_exit(vt1603_ts_exit); + +MODULE_DESCRIPTION("VT1603A/VT1609 TouchScreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h new file mode 100755 index 00000000..31210579 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h @@ -0,0 +1,301 @@ +#ifndef __VT1603_TS_H__ +#define __VT1603_TS_H__ +#include <linux/mfd/vt1603/core.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif + +#define DEV_NAME "wmtts" +#define VT1603_DRIVER_NAME "vt1603-touch" + +#undef abs +#define abs(x) (((x)>0)?(x):(-(x))) + +#define FALSE 0 +#define TRUE 1 +#define VT1603_TS_NR_DEVS 1 +#define VT1603_TS_DEV_MAJOR 160 +#define TS_DEBOUNCE 50 +#define VT1603_FILTER_HEAD_COUNT 2 +#define VT1603_JITTER_THRESHOLD 1200//µ¥µãÇ°ºó2µãÖ®¼äµÄx/y ±ä»¯×î´óÈÝÐíÖµ + +#define None_TOUCH 0x00 +#define Single_TOUCH 0x01 +#define Multi_TOUCH 0x02 + +#define ADC_DATA(low, high) ((((high) & 0x0F) << 8) + (low)) + +/* touch panel type config */ +#define PANEL_TYPE_4WIRED 0x10 +#define PANEL_TYPE_5WIRED 0x11 + +/* enable calibration or not */ +#define CALIBRATION_ENABLE 0x01 +#define CALIBRATION_DISABLE 0x00 + +/* VT1603 working mode */ +#define VT1603_TS_MODE BIT1 +#define VT1603_TEMP_MODE BIT2 +#define VT1603_BAT_MODE BIT3 + +/* VT1603 touch panel state */ +#define TS_PENDOWN_STATE 0x00 +#define TS_PENUP_STATE 0x01 + +struct vt1603_ts_pos { + int x; + int y; +}; + +#define VT1603_FIFO_LEN 3 +struct vt1603_fifo{ + int head; + int full; + int buf[VT1603_FIFO_LEN]; +}; + +#define I2C_BUS 0x00 +#define SPI_BUS 0x01 + +#define VT1603_SPI_FIX_CS 0x00 +#define VT1603_SPI_FAKE_CS 0x03 +#define VT1603_SPI_BUS_0 0x00 +#define VT1603_SPI_BUS_1 0x01 +#define VT1603_MAX_SPI_CLK (20*1000*1000) +#define SPI_DEFAULT_CLK (4*1000*1000) +#define IDLE_DATA_NUM 5 + +#define VT1603_I2C_FIX_ADDR 0x1A +#define VT1603_I2C_FAKE_ADDR 0xFF +#define VT1603_TS_I2C_WCMD 0x00 +#define VT1603_TS_I2C_RCMD 0x01 +#define VT1603_TS_I2C_RWCMD 0x02 +#define VT1603_I2C_BUS_0 0x00 +#define VT1603_I2C_BUS_1 0x01 + +/////////////////////////////// +//#define TOUCH_KEY +#define KEY_DETLA 300 +#define TOUCH_KEY_NUM 4 +#define TOUCH_KEY_LED_GPIO 4 + +#define HIGH 1 +#define LOW 0 + +struct tsc_key{ + int pos; + int idx; +}; + +struct tsc_key_st{ + int key_num; + int low; + int upper; + int delta; + struct tsc_key key[TOUCH_KEY_NUM]; +}; + +enum key_idx{ + _SEARCH, + _BACK, + _HOME, + _MENU, + _MAX_NUM, +}; +///////////////////////// + +enum gpio_irq_type { + HIGH_ACTIVE = 0, + LOW_ACTIVE = 1, + RISING_EDGE_ACTIVE = 3, + FALLING_EDGE_ACTIVE = 4, + UNKOWN_TYPE = 0xFF +}; + +/* + * vt1603_ts_platform_data - vt1603 configuration data + * @panel_type: touch panel type: 4-wired or 5-wired + * @cal_en: enable calibration circuit or not + * @cal_sel: calibratin capacitor control bits + * @shfit: conversion data shfit + * @sclk_div: initial value of sclk dividor if mclk = 12.288MHZ 0x04 = 200ksps 0x08 = 100ksps + * @soc_gpio_irq: soc gpio interrupts, connect with vt1603 gpio1 + */ +struct vt1603_ts_platform_data { + u8 panel_type; + u8 cal_en; + u8 cal_sel:2; + u8 shift; + u8 sclk_div; + int soc_gpio_irq; + int gpio_num; + enum gpio_irq_type irq_type; +}; + +struct vt1609_dual_st{ + int vxy; + + int scale_x; + int scale_y; + + int F1_CNT; + int F2_CNT; + int F2T1_CNT; + int SAMPLE_CNT; + + int THR_MIN_DX; + int THR_MAX_DX; + + int exch; +}; + +struct vt1603_ts_drvdata { + struct vt1603 *tdev; + //spinlock_t spinlock; + struct mutex ts_mutex; + struct input_dev *input; + struct work_struct work; + struct delayed_work read_work; + struct delayed_work dual_work; + struct workqueue_struct *workqueue; + struct vt1603_ts_platform_data *pdata; + + int earlysus; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + char dev_id[32]; + + struct cdev cdev; + int major; + int minor; + + int gpio_irq; + + int intgpio; + + u8 pen_state; + int ts_stamp; + int hcnt; + + int resl_x; + int resl_y; + int lcd_exchg; + + int raw_x; + int raw_y; + + int dual_enable; + struct vt1609_dual_st dual_dev; + + int ledgpio; +#ifdef TOUCH_KEY + int key_idx; + int key_pressed; + int touch_key_used; + struct timer_list led_timer; + struct tsc_key_st tsc_key; +#endif + +}; + +/* VT1603 Register address */ +#define VT1603_BTHD_REG 0x78 +#define VT1603_BCLK_REG 0x88 +#define VT1603_BAEN_REG 0x04 + +#define VT1603_PWC_REG 0xC0 +#define VT1603_CR_REG 0xC1 +#define VT1603_CCCR_REG 0xC2 +#define VT1603_CDPR_REG 0xC3 +#define VT1603_TSPC_REG 0xC4 +#define VT1603_AMCR_REG 0xC7 +#define VT1603_INTCR_REG 0xC8 +#define VT1603_INTEN_REG 0xC9 +#define VT1603_INTS_REG 0xCA +#define VT1603_DCR_REG 0xCB + +#define VT1603_TODCL_REG 0xCC +#define VT1603_TODCH_REG 0xCD + +#define VT1603_DATL_REG 0xCE +#define VT1603_DATH_REG 0xCF + +#define VT1603_XPL_REG 0xD0 +#define VT1603_XPH_REG 0xD1 +#define VT1603_YPL_REG 0xD2 +#define VT1603_YPH_REG 0xD3 + +#define VT1603_BATL_REG 0xD4 +#define VT1603_BATH_REG 0xD5 + +#define VT1603_TEMPL_REG 0xD6 +#define VT1603_TEMPH_REG 0xD7 + +#define VT1603_ERR8_REG 0xD8 +#define VT1603_ERR7_REG 0xD9 +#define VT1603_ERR6_REG 0xDA +#define VT1603_ERR5_REG 0xDB +#define VT1603_ERR4_REG 0xDC +#define VT1603_ERR3_REG 0xDD +#define VT1603_ERR2_REG 0xDE +#define VT1603_ERR1_REG 0xDF + +#define VT1603_DBG8_REG 0xE0 +#define VT1603_DBG7_REG 0xE1 +#define VT1603_DBG6_REG 0xE2 +#define VT1603_DBG5_REG 0xE3 +#define VT1603_DBG4_REG 0xE4 +#define VT1603_DBG3_REG 0xE5 +#define VT1603_DBG2_REG 0xE6 +#define VT1603_DBG1_REG 0xE7 + +/* for VT1603 GPIO1 interrupt setting */ +#define VT1603_IMASK_REG27 27 +#define VT1603_IMASK_REG28 28 +#define VT1603_IMASK_REG29 29 +#define VT1603_IPOL_REG33 33 +#define VT1603_ISEL_REG36 36 + +struct vt1603_ts_cal_info { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}; + +/* VT1603 TS and SAR-ADC IOCTL */ +#define VT1603_TS_IOC_MAGIC 't' + +/* for touch screen calibration */ +#define VT1603_TS_IOC_CAL_START _IO(VT1603_TS_IOC_MAGIC, 1) +#define VT1603_TS_IOC_CAL_DONE _IOW(VT1603_TS_IOC_MAGIC, 2, int *) +#define VT1603_TS_IOC_CAL_RAWDATA _IOR(VT1603_TS_IOC_MAGIC, 3, int *) +#define VT1603_TS_IOC_CAL_QUIT _IOW(VT1603_TS_IOC_MAGIC, 4, int *) + +extern int wmt_setsyspara(char *varname, unsigned char *varval); +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlenex); + +int vt1603_clr_ts_irq(struct vt1603_ts_drvdata *ts_drv, u8 mask); +int vt1603_set_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 val); +u8 vt1603_get_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg); +void vt1603_setbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask); +void vt1603_clrbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask); + +void vt1603_ts_report_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos); +int vt1603_ts_pos_calibration(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *to_cal); + +#ifdef TOUCH_KEY +void vt1603_ts_report_key(struct vt1603_ts_drvdata *ts_drv); +int vt1603_ts_get_key(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos pos); +int set_key_led_gpio(struct vt1603_ts_drvdata *ts_drv,int val); +#endif + +int vt1603_dual_init(struct vt1603_ts_drvdata *ts_drv); +void vt1603_dual_exit(struct vt1603_ts_drvdata *ts_drv); +void vt1603_ts_dual_support(struct work_struct* work); + +#endif /* __VT1603_TS_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig new file mode 100755 index 00000000..3bf6dcc3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Kconfig @@ -0,0 +1,16 @@ +# +# ZET6221 capacity touch screen driver configuration +# +config TOUCHSCREEN_ZET6221 + tristate "ZEITEC ZET6221 I2C Capacitive Touchscreen Input Driver Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with touchscreen + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_ts_zet6221 + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile new file mode 100755 index 00000000..102fb212 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/Makefile @@ -0,0 +1,32 @@ +KERNELDIR=../../../../
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_ts_zet6221
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := zet6221_i2c.o wmt_ts.o zet6221_downloader.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions *.order *.symvers modules.builtin
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c new file mode 100755 index 00000000..bfc65e7f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.c @@ -0,0 +1,833 @@ +#include <linux/unistd.h> +#include <linux/time.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +//#include <asm/semaphore.h> +#include <linux/proc_fs.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/suspend.h> +#include <linux/input.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/firmware.h> + +#include <asm/uaccess.h> +#include <linux/fs.h> +#include <linux/syscalls.h> + +#include "wmt_ts.h" +#include "zet6221_ts.h" + +///////////////////////////////////////////////////////////////// + +// commands for ui +#define TS_IOC_MAGIC 't' + +#define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) +#define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) +#define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) +#define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) +#define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) +#define TS_IOC_MAXNR 5 + +#define TP_INFOR_ARRAY_SIZE (sizeof(l_tpinfor)/sizeof(l_tpinfor[1])) +// +#define TS_MAJOR 11 +#define TS_DRIVER_NAME "wmtts_touch" +#define TS_NAME "wmtts" +#define WMTTS_PROC_NAME "wmtts_config" + +#define EXT_GPIO0 0 +#define EXT_GPIO1 1 +#define EXT_GPIO2 2 +#define EXT_GPIO3 3 +#define EXT_GPIO4 4 +#define EXT_GPIO5 5 +#define EXT_GPIO6 6 +#define EXT_GPIO7 7 + + + +typedef struct { + int a1; + int b1; + int c1; + int a2; + int b2; + int c2; + int delta; +}CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; + + +static int irq_gpio; +static int rst_gpio; +static int panelres_x; +static int panelres_y; +static int s_download_option; +static int s_high_Impendence_mode; +static int lcd_exchg = 0; + + +static DECLARE_WAIT_QUEUE_HEAD(queue); +static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); + +extern struct wmtts_device zet6221_tsdev; +static struct wmtts_device* l_tsdev = &zet6221_tsdev; +struct proc_dir_entry* l_tsproc = NULL; +static struct i2c_client *l_client=NULL; +static int l_penup = 1; // 1-pen up,0-pen down +int earlysus_en = 0; + +struct tp_infor +{ + //enum tp_type type; + char name[64]; + //unsigned int i2caddr; + unsigned int xaxis; //0: x,1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; +}; + +static int l_tpindex = -1; +static struct tp_infor l_tpinfor[1]; + +///////////////////////////////////////////////////// +// function declare +///////////////////////////////////////////////////// +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ); +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data); +/////////////////////////////////////////////////////////////////////// + +void wmt_ts_get_firmwname(char* firmname) +{ + int offset = 0; + offset = strlen(l_tsdev->ts_id); + switch(ic_model){ + case ZET6223: + l_tpinfor[l_tpindex].name[offset] = '2'; + l_tpinfor[l_tpindex].name[offset+1] = '3'; + break; + case ZET6231: + l_tpinfor[l_tpindex].name[offset] = '3'; + l_tpinfor[l_tpindex].name[offset+1] = '1'; + break; + case ZET6251: + l_tpinfor[l_tpindex].name[offset] = '5'; + l_tpinfor[l_tpindex].name[offset+1] = '1'; + break; + case ZET6221: + default: + l_tpinfor[l_tpindex].name[offset] = '2'; + l_tpinfor[l_tpindex].name[offset+1] = '1'; + break; + } + sprintf(firmname,"%s_fw.bin",l_tpinfor[l_tpindex].name); +} + +unsigned int wmt_ts_get_xaxis(void) +{ + return l_tpinfor[l_tpindex].xaxis; +} + +unsigned int wmt_ts_get_xdir(void) +{ + return l_tpinfor[l_tpindex].xdir; +} + +unsigned int wmt_ts_get_ydir(void) +{ + return l_tpinfor[l_tpindex].ydir; +} + +unsigned int wmt_ts_get_maxfingernum(void) +{ + return l_tpinfor[l_tpindex].max_finger_num; +} + + +int wmt_ts_load_firmware(char* firmwarename, unsigned char** firmdata, int* fwlen) +{ + const struct firmware *fw_entry; + if(request_firmware(&fw_entry, firmwarename, &l_client->dev)!=0) { + printk(KERN_ERR "cat't request firmware\n"); + return -1; + } + if (fw_entry->size <= 0) { + printk(KERN_ERR "load firmware error\n"); + release_firmware(fw_entry); + return -1; + } + + //*firmdata = kzalloc(fw_entry->size + 1, GFP_KERNEL); + memcpy(*firmdata, fw_entry->data, fw_entry->size); + *fwlen = fw_entry->size; + release_firmware(fw_entry); + + return 0; +} + + + + int wmt_ts_get_gpionum(void) +{ + return irq_gpio; +} + +int wmt_ts_get_resetgpnum(void) +{ + return rst_gpio; +} + +int wmt_ts_get_lcdexchg(void) +{ + return lcd_exchg; +} + +int wmt_ts_get_resolvX(void) +{ + return panelres_x; +} + +int wmt_ts_get_resolvY(void) +{ + return panelres_y; +} + +//up:1-pen up,0-pen down +void wmt_ts_set_penup(int up) +{ + l_penup = up; +} + +// +int wmt_ts_wait_penup(void) +{ + int ret = wait_event_interruptible( + ts_penup_wait_queue, + (1==l_penup)); + return ret; +} + +// return:1-pen up,0-pen dwon +int wmt_ts_ispenup(void) +{ + return l_penup; +} + + +void wmt_ts_wakeup_penup(void) +{ + wake_up(&ts_penup_wait_queue); +} + +int wmt_is_tsirq_enable(void) +{ + int val = 0; + int num = irq_gpio; + + if(num > 11) + return 0; + + if(num<4) + val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); + else if(num >= 4 && num < 8) + val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); + else + val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); + + return val?1:0; + +} + +int wmt_is_tsint(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return 0; + } + return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} + +void wmt_clr_int(void) +{ + int num = irq_gpio; + + if (num > 11) + { + return; + } + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; +} + +void wmt_tsreset_init(void) +{ + int num = rst_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num);//&= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<num); // out low + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //output enable + msleep(10); + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); // out high +} + +// enable:0-disable,1-enable +void wmt_enable_rst_pull(int enable) +{ + if (enable) + { + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<rst_gpio); //enable pull up/down + } else { + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<rst_gpio); //disable pull up/down + } +} + +// up:0-pull down,1-pull up +void wmt_set_rst_pull(int up) +{ + if (up) + { + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<rst_gpio); //pull up + } else { + REG32_VAL(__GPIO_BASE+0x04c0) &= ~(1<<rst_gpio); //pull down + } +} + +// high:0-low level,1-high level +void wmt_rst_output(int high) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + if (high) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<rst_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<rst_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<rst_gpio); //set output +} + +void wmt_rst_input(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<rst_gpio); //set input +} + +void wmt_set_intasgp(void) +{ + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio +} + +// val:1--high,0-low +void wmt_intgp_out(int val) +{ + if (val) + { + REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<irq_gpio); // high + } else { + REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<irq_gpio); // low + } + REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set output +} + +void wmt_ts_set_irqinput(void) +{ + int num = irq_gpio; + + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input +} + +unsigned int wmt_ts_irqinval(void) +{ + return REG32_VAL(__GPIO_BASE+0x0000)&(1<<irq_gpio); +} + +int wmt_set_gpirq(int type) +{ + int shift; + int offset; + unsigned long reg; + int num = irq_gpio; + + if(num >11) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num);//|=(1<<num);// //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down + REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else{// [8,11] + shift = num-8; + offset = 0x0308; + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status + msleep(5); + return 0; +} + +int wmt_enable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > 11) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + + return 0; +} + + +int wmt_get_tsirqnum(void) +{ + return IRQ_GPIO; +} + +static void wmt_ts_platform_release(struct device *device) +{ + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +// .num_resources = ARRAY_SIZE(wm9715_ts_resources), +// .resource = wm9715_ts_resources, +}; + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("ts suspend....\n"); + return l_tsdev->suspend(pdev, state); +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + dbg("ts resume....\n"); + return l_tsdev->resume(pdev); +} + +static int wmt_ts_probe(struct platform_device *pdev) +{ + l_tsproc= create_proc_entry(WMTTS_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_tsproc != NULL) + { + l_tsproc->read_proc = ts_readproc; + l_tsproc->write_proc = ts_writeproc; + } + + if (l_tsdev->probe != NULL) + return l_tsdev->probe(pdev); + else + return 0; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + if (l_tsproc != NULL) + { + remove_proc_entry(WMTTS_PROC_NAME, NULL); + l_tsproc = NULL; + } + + if (l_tsdev->remove != NULL) + return l_tsdev->remove(pdev); + else + return 0; +} + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + +static int ts_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + int calibrate = 0; + int val = 0; + + if (sscanf(buffer, "calibrate=%d\n", &calibrate)) + { + if (1 == calibrate) + { + if((l_tsdev->capacitance_calibrate != NULL) && + (0 == l_tsdev->capacitance_calibrate())) + { + printk(KERN_ALERT "%s calibration successfully!\n", l_tsdev->ts_id); + } else { + printk(KERN_ALERT "%s calibration failed!\n", l_tsdev->ts_id); + } + } + } else if (sscanf(buffer, "reset=%d\n", &val)) + { + + } + return count; +} + +static int ts_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "echo calibrate=1 > /proc/wmtts_config to calibrate ts.\n"); + return len; +} + + +int is_high_impendence_mode(void) +{ + return s_high_Impendence_mode; +} + +int get_download_option(void) +{ + return s_download_option; +} + + +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 96, i = 0; + char retval[200] = {0},*p=NULL,*s=NULL; + int Enable=0; + int val,val1; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(l_tpinfor,0,sizeof(l_tpinfor[0])); + + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':');p++; + s = strchr(p,':'); + strncpy(l_tpinfor[0].name,p, (s-p)); + p = s+1; + dbg("ts_name=%s\n", l_tpinfor[0].name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &irq_gpio,&panelres_x,&panelres_y,&rst_gpio, + &(l_tpinfor[0].xaxis),&(l_tpinfor[0].xdir),&(l_tpinfor[0].ydir), + &(l_tpinfor[0].max_finger_num),&s_high_Impendence_mode,&s_download_option); + + if (ret < 8) + { + dbg("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + + + /*p = strchr(retval,':'); + p++; + if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID + //errlog(" %s!=====\n", l_tsdev->ts_id); + return -ENODEV; + }*/ + + //sscanf(p,"%s:", ); + if (strstr(l_tpinfor[0].name, l_tsdev->ts_id) == NULL) + { + errlog("Can't find %s%s!\n", l_tsdev->ts_id,"xx"); + return -ENODEV; + } + l_tpindex = 0; + +/* + p = strchr(p,':'); + p++; + sscanf(p,"%d:%d:%d:%d",&irq_gpio,&panelres_x,&panelres_y,&rst_gpio); + + */ + klog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d,high_Impendence_mode=%d,s_download_option=%d\n", + panelres_x, panelres_y, irq_gpio, rst_gpio, + l_tpinfor[0].xaxis,l_tpinfor[0].xdir,l_tpinfor[0].ydir, + l_tpinfor[0].max_finger_num,s_high_Impendence_mode,s_download_option); + + // parse touch key param + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.tskeyindex", retval, &len); + if(ret){ + dbg("no touch key!\n"); + //return -EIO; + } else { + p = retval; + // the number of touch key + sscanf(retval,"%d:", &val); + dbg("tskey num:%d\n",val); + p = strchr(p,':'); + p++; + // touch key range + for (i=0;i<val;i++) + { + sscanf(p,"%d:",&val1); + p = strchr(p,':'); + p++; + zet6221_set_tskey(i, val1); + dbg("key%d:(%d)\n",i,val1); + }; + } + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len); + if(!ret) { + p = retval; + sscanf(p, "%d", &earlysus_en); + } + + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + lcd_exchg = 1; + } + +/* memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len); + if(ret){ + errlog("Read env wmt.io.ts.2dcal Failed.\n "); + //return -EIO; + } + i = 0; + while(i < sizeof(retval)){ + if(retval[i]==' ' || retval[i]==',' || retval[i]==':') + retval[i] = '\0'; + i++; + } + + i = 0; + p = retval; + while(i<7 && p < (retval + sizeof(retval))){ + if(*p == '\0') + p++; + else{ + sscanf(p,"%d",&nBuff[i]); + //printk("%d\n",nBuff[i]); + p=p+strlen(p); + i++; + } + } + //sscanf(retval,"%d %d %d %d %d %d %d %d",&nBuff[0],&nBuff[1],&nBuff[2],&nBuff[3],&nBuff[4],&nBuff[5],&nBuff[6]); + dbg("Tsc calibrate init data: [%d %d %d %d %d %d %d]\n",nBuff[0],nBuff[1],nBuff[2],nBuff[3],nBuff[4],nBuff[5],nBuff[6]); + + g_CalcParam.a1 = nBuff[0]; + g_CalcParam.b1 = nBuff[1]; + g_CalcParam.c1 = nBuff[2]; + g_CalcParam.a2 = nBuff[3]; + g_CalcParam.b2 = nBuff[4]; + g_CalcParam.c2 = nBuff[5]; + g_CalcParam.delta = nBuff[6]; + + if(g_CalcParam.delta == 0) + g_CalcParam.delta =1;//avoid divide by zero +*/ + return 0; +} + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .addr = WMT_TS_I2C_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +struct i2c_client* ts_get_i2c_client(void) +{ + return l_client; +} + +static int __init wmt_ts_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + //ts_i2c_board_info.addr = l_tpinfor[l_tpindex].i2caddr; + if (ts_i2c_register_device()<0) + { + dbg("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + if (l_tsdev->init() < 0){ + dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); + ret = -1; + goto err_init; + } + + // register device and driver of platform + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + + klog("%s driver init ok!\n",l_tsdev->ts_id); + return 0; +err_init: + ts_i2c_unregister_device(); + return ret; +} + +static void __exit wmt_ts_exit(void) +{ + dbg("%s\n",__FUNCTION__); + + l_tsdev->exit(); + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + ts_i2c_unregister_device(); +} + + +module_init(wmt_ts_init); +module_exit(wmt_ts_exit); + +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h new file mode 100755 index 00000000..cab70586 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/wmt_ts.h @@ -0,0 +1,149 @@ + +#ifndef WMT_TSH_201010191758 +#define WMT_TSH_201010191758 + +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/suspend.h> +#include <linux/i2c.h> + + +//#define DEBUG_WMT_TS +#ifdef DEBUG_WMT_TS +#undef dbg +#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +//#define dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#else +#define dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk("[%s]: " fmt, __FUNCTION__, ## args) + +#define WMT_TS_I2C_NAME "zet6221-ts" +#define WMT_TS_I2C_ADDR 0x76 + + +#ifndef dim +#define dim(x) (sizeof(x) / sizeof(x[0])) +#endif + +extern int earlysus_en; + +//////////////////////////////data type/////////////////////////// +typedef struct { + short pressure; + short x; + short y; + //short millisecs; +} TS_EVENT; + +struct wmtts_device +{ + //data + char* driver_name; + char* ts_id; + //function + int (*init)(void); + int (*probe)(struct platform_device *platdev); + int (*remove)(struct platform_device *pdev); + void (*exit)(void); + int (*suspend)(struct platform_device *pdev, pm_message_t state); + int (*resume)(struct platform_device *pdev); + int (*capacitance_calibrate)(void); + int (*wait_penup)(struct wmtts_device*tsdev); // waiting untill penup + int penup; // 0--pendown;1--penup + +}; + +enum { + ZET6221 = 0, + ZET6231, + ZET6223, + ZET6251, +}; +extern u8 ic_model; +extern unsigned char* flash_buffer; +extern int l_fwlen; + + +//////////////////////////function interface///////////////////////// +extern int wmt_ts_get_gpionum(void); +extern int wmt_ts_iscalibrating(void); +extern int wmt_ts_get_resolvX(void); +extern int wmt_ts_get_resolvY(void); +extern int wmt_set_gpirq(int type); +extern int wmt_get_tsirqnum(void); +extern int wmt_disable_gpirq(void); +extern int wmt_enable_gpirq(void); +extern int wmt_is_tsirq_enable(void); +extern int wmt_is_tsint(void); +extern void wmt_clr_int(void); +extern void wmt_tsreset_init(void); +extern int wmt_ts_get_resetgpnum(void); +extern int wmt_ts_get_lcdexchg(void); +extern void wmt_enable_rst_pull(int enable); +extern void wmt_set_rst_pull(int up); +extern void wmt_rst_output(int high); +extern void wmt_rst_input(void); +extern void wmt_set_intasgp(void); +extern void wmt_intgp_out(int val); +extern void wmt_ts_set_irqinput(void); +extern unsigned int wmt_ts_irqinval(void); +extern void wmt_ts_set_penup(int up); +extern int wmt_ts_wait_penup(void); +extern void wmt_ts_wakeup_penup(void); +extern struct i2c_client* ts_get_i2c_client(void); +extern int wmt_ts_ispenup(void); +extern unsigned int wmt_ts_get_maxfingernum(void); +extern unsigned int wmt_ts_get_ictype(void); +extern unsigned int wmt_ts_get_xaxis(void); +extern unsigned int wmt_ts_get_xdir(void); +extern unsigned int wmt_ts_get_ydir(void); +// short +extern unsigned int wmt_ts_get_touchheight(void); +// long +extern unsigned int wmt_ts_get_touchwidth(void); +extern void wmt_ts_get_firmwname(char* firmname); +extern int wmt_ts_load_firmware(char* firmwarename, unsigned char** firmdata, int* fwlen); + + + + +extern void TouchPanelCalibrateAPoint( + int UncalX, //@PARM The uncalibrated X coordinate + int UncalY, //@PARM The uncalibrated Y coordinate + int *pCalX, //@PARM The calibrated X coordinate + int *pCalY //@PARM The calibrated Y coordinate + ); + +//filepath:the path of firmware file; +//firmdata:store the data from firmware file; +//maxlen: the max len of firmdata; +//return:the length of firmware data,negative-parsing error. +//extern +u8 zet6221_ts_sfr(struct i2c_client *client); +int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + + +#define HIGH_IMPENDENCE_MODE 0 +#define NOT_HIGH_IMPENDENCE_MODE 1 + +extern int is_high_impendence_mode(void); + + +#define FORCE_DOWNLOAD 1 +#define FORCE_CANCEL_DOWNLOAD 2 +extern int get_download_option(void); + + + +#endif + + + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c new file mode 100755 index 00000000..ac51aa21 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_downloader.c @@ -0,0 +1,1209 @@ +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/slab.h> +//#include "zet6221_fw.h" + +#include "wmt_ts.h" + +#define ZET6221_DOWNLOADER_NAME "zet6221_downloader" +#define FEATURE_FW_CHECK_SUM 1 +//#define High_Impendence_Mode + +#define TS_INT_GPIO S3C64XX_GPN(9) /*s3c6410*/ +#define TS_RST_GPIO S3C64XX_GPN(10) /*s3c6410*/ +#define RSTPIN_ENABLE + +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +//static u8 fw_version0; +//static u8 fw_version1; + +//#define debug_mode 1 +//#define DPRINTK(fmt,args...) do { if (debug_mode) printk(KERN_EMERG "[%s][%d] "fmt"\n", __FUNCTION__, __LINE__, ##args);} while(0) + +static unsigned char zeitec_zet6221_page[131] __initdata; +static unsigned char zeitec_zet6221_page_in[131] __initdata; +unsigned char* flash_buffer = NULL; +int l_fwlen = 0; + +//static u16 fb[8] = {0x3EEA,0x3EED,0x3EF0,0x3EF3,0x3EF6,0x3EF9,0x3EFC,0x3EFF}; +static u16 fb[8] = {0x3DF1,0x3DF4,0x3DF7,0x3DFA,0x3EF6,0x3EF9,0x3EFC,0x3EFF}; +static u16 fb21[8] = {0x3DF1,0x3DF4,0x3DF7,0x3DFA,0x3EF6,0x3EF9,0x3EFC,0x3EFF}; +static u16 fb23[8] = {0x7BFC,0x7BFD,0x7BFE,0x7BFF,0x7C04,0x7C05,0x7C06,0x7C07}; +u8 ic_model = 0; + +extern int zet6221_i2c_write_tsdata(struct i2c_client *client, u8 *data, u8 length); +extern int zet6221_i2c_read_tsdata(struct i2c_client *client, u8 *data, u8 length); +extern u8 pc[]; + + + + +/************************load firmwre data from file************************/ +int zet6221_load_fw(void) +{ + char fwname[256] = {0}; + int ret = -1; + wmt_ts_get_firmwname(fwname); + ret = wmt_ts_load_firmware(fwname, &flash_buffer, &l_fwlen); + if(!ret) { + printk("Success load fw_file: %s, length %d\n", fwname, l_fwlen); + printk("%x,%x,%x,%x\n", flash_buffer[0], flash_buffer[1], flash_buffer[2], flash_buffer[3]); + printk("%x,%x,%x,%x\n", flash_buffer[l_fwlen-4], flash_buffer[l_fwlen-3], flash_buffer[l_fwlen-2], flash_buffer[l_fwlen-1]); + } + return ret; +} + +/***********************free firmware memory*******************************/ +int zet6221_free_fwmem(void) +{ + if (l_fwlen > 0 && flash_buffer != NULL ) + { + kfree(flash_buffer); + flash_buffer = NULL; + l_fwlen = 0; + } + return 0; +} +//#define I2C_CTPM_ADDRESS (0x76) + +/*********************************************************************** +[function]: + callback: write data to ctpm by i2c interface,implemented by special user; +[parameters]: + client[in] :i2c client structure; + bt_ctpm_addr[in] :the address of the ctpm; + pbt_buf[in] :data buffer; + dw_lenth[in] :the length of the data buffer; +[return]: + 1 :success; + 0 :fail; +************************************************************************/ +int i2c_write_interface(struct i2c_client *client, u8 bt_ctpm_addr, u8* pbt_buf, u16 dw_lenth) +{ + struct i2c_msg msg; + msg.addr = bt_ctpm_addr; + msg.flags = 0; + msg.len = dw_lenth; + msg.buf = pbt_buf; + return i2c_transfer(client->adapter,&msg, 1); +} + +/*********************************************************************** +[function]: + callback: read data from ctpm by i2c interface,implemented by special user; +[parameters]: + client[in] :i2c client structure; + bt_ctpm_addr[in] :the address of the ctpm; + pbt_buf[out] :data buffer; + dw_lenth[in] :the length of the data buffer; +[return]: + 1 :success; + 0 :fail; +************************************************************************/ +int i2c_read_interface(struct i2c_client *client, u8 bt_ctpm_addr, u8* pbt_buf, u16 dw_lenth) +{ + struct i2c_msg msg; + msg.addr = bt_ctpm_addr; + msg.flags = I2C_M_RD; + msg.len = dw_lenth; + msg.buf = pbt_buf; + return i2c_transfer(client->adapter,&msg, 1); +} + +/*********************************************************************** + [function]: + callback: check version; + [parameters]: + void + + [return]: + 0: different 1: same; +************************************************************************/ +u8 zet6221_ts_version(void) +{ + int i; + + if(pc == NULL){ + errlog(" pc is NULL\n"); + return 0; + } + if( flash_buffer == NULL ){ + errlog("flash_buffer \n"); + return 0; + } + +#if 1 + dbg("pc: "); + for(i=0;i<8;i++){ + dbg("%02x ",pc[i]); + } + dbg("\n"); + + dbg("src: "); + for(i=0;i<8;i++){ + dbg("%02x ", flash_buffer[fb[i]]); + } + dbg("\n"); +#endif + + mdelay(20); + + for(i=0;i<8;i++) + if(pc[i]!= flash_buffer[fb[i]]) + return 0; + return 1; +} + + +/*********************************************************************** + [function]: + callback: send password 1K (ZET6223) + [parameters]: + client[in]: struct i2c_client — represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_sndpwd_1k(struct i2c_client *client) +{ + u8 ts_sndpwd_cmd[3] = {0x20,0xB9,0xA3}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_sndpwd_cmd, 3); +#else + ret=zet6221_i2c_write_tsdata(client, ts_sndpwd_cmd, 3); +#endif + + + return 1; +} + + +/*********************************************************************** + [function]: + callback: send password; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_sndpwd(struct i2c_client *client) +{ + u8 ts_sndpwd_cmd[3] = {0x20,0xC5,0x9D}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_sndpwd_cmd, 3); +#else + ret=zet6221_i2c_write_tsdata(client, ts_sndpwd_cmd, 3); +#endif + + return 1; +} + +u8 zet622x_ts_option(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x27}; + u8 ts_cmd_erase[1] = {0x28}; + u8 ts_in_data[16] = {0}; + u8 ts_out_data[18] = {0}; + int ret; + u16 model; + int i; + u8 high_impendence_data = 0; + const u8 HIGH_IMPENDENCE_MODE_DATA = 0xf1; + const u8 NOT_HIGH_IMPENDENCE_MODE_DATA = 0xf2; + + + dbg("zet622x_ts_option++\n"); + + wmt_rst_output(0); + msleep(10); + //send password + zet6221_ts_sndpwd(client); + msleep(100); + + + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, dim(ts_cmd)); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, dim(ts_cmd)); +#endif + msleep(2); + + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, ts_in_data, dim(ts_in_data)); +#else + ret=zet6221_i2c_read_tsdata(client, ts_in_data, dim(ts_in_data)); +#endif + //msleep(2); + + dbg("command %02x recv:\n",ts_cmd[0]); + for(i=0;i<16;i++) + { + dbg("%02x ",ts_in_data[i]); + } + dbg("\n"); + // zet6231 recv: ff ff fc 30 ff 80 31 62 ff ff ff ff ff ff ff ff + + model = 0x0; + model = ts_in_data[7]; + model = (model << 8) | ts_in_data[6]; + + switch(model) { + case 0xFFFF: + ret = 1; + ic_model = ZET6221; + for(i=0;i<8;i++) + { + fb[i]=fb21[i]; + } + + if( is_high_impendence_mode() == HIGH_IMPENDENCE_MODE ){ + high_impendence_data = HIGH_IMPENDENCE_MODE_DATA; + }else if( is_high_impendence_mode() == NOT_HIGH_IMPENDENCE_MODE ) { + high_impendence_data = NOT_HIGH_IMPENDENCE_MODE_DATA; + } + + //#if defined(High_Impendence_Mode) + if(ts_in_data[2] != high_impendence_data) + { + + if(zet6221_ts_sfr(client)==0) + { + return 0; + } + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd_erase, dim(ts_cmd_erase)); + #else + ret=zet6221_i2c_write_tsdata(client, ts_cmd_erase, dim(ts_cmd_erase)); + #endif + + msleep(100); + dbg("erase ret=%d \n",ret); + + + for(i=2;i<18;i++) + { + ts_out_data[i]=ts_in_data[i-2]; + } + ts_out_data[0] = 0x21; + ts_out_data[1] = 0xc5; + ts_out_data[4] = high_impendence_data; + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_out_data, 18); + #else + ret=zet6221_i2c_write_tsdata(client, ts_out_data, 18); + #endif + + msleep(100); + dbg("write out data, ret=%d\n",ret); + + + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); + #else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); + #endif + + msleep(2); + + dbg("send %02x\n",ts_cmd[0]); + + + #if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, ts_in_data, 16); + #else + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 16); + #endif + //msleep(2); + dbg("command %02x recv:\n",ts_cmd[0]); + for(i=0;i<16;i++) + { + dbg("%02x ",ts_in_data[i]); + } + dbg("\n"); + + } + + //#endif + + + + break; + case 0x6223: + ret = 1; + ic_model = ZET6223; + for(i=0;i<8;i++) + { + fb[i]=fb23[i]; + } + break; + case 0x6231: + ret = 1; + ic_model = ZET6231; + for(i=0;i<8;i++) + { + fb[i]=fb23[i]; + } + break; + case 0x6251: + ic_model = ZET6251; + for(i=0;i<8;i++) + { + fb[i] = fb23[i]; + } + break; + default: + errlog("Notice: can't detect the TP IC,use ZET6231 default\n"); + ret = 1; + ic_model = ZET6231; + for(i=0;i<8;i++) + { + fb[i]=fb23[i]; + } + break; + + } + + wmt_rst_output(1); + msleep(10); + + dbg("zet622x_ts_option-- ret:%d\n",ret); + return ret; +} +/*********************************************************************** + [function]: + callback: set/check sfr information; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_sfr(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x2C}; + u8 ts_in_data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + u8 ts_cmd17[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + //u8 ts_sfr_data[16] = {0x18,0x76,0x27,0x27,0xFF,0x03,0x8E,0x14,0x00,0x38,0x82,0xEC,0x00,0x00,0x7d,0x03}; + int ret; + int i; + + dbg("zet6221_ts_sfr++"); +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + msleep(10); + dbg("sfr cmd : 0x%02x \n",ts_cmd[0]); + + + + dbg("sfr rcv : \n"); + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, ts_in_data, 16); +#else + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 16); +#endif + msleep(10); + + if(ts_in_data[14]!=0x3D && ts_in_data[14]!=0x7D) + { + return 0; + } + + for(i=0;i<16;i++) + { + ts_cmd17[i+1]=ts_in_data[i]; + dbg("[%d]%02x\n",i,ts_in_data[i]); + } + + dbg("\n"); + + // need to check 0x3D to open write function + if(ts_in_data[14]!=0x3D) + { + ts_cmd17[15]=0x3D; + + ts_cmd17[0]=0x2B; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd17, 17); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd17, 17); +#endif + + if(ret<0) + { + errlog("enable sfr(0x3D) failed!\n"); + return 0; + } + + } + dbg("zet6221_ts_sfr--"); + return 1; +} + +/*********************************************************************** + [function]: + callback: mass erase flash; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_masserase(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x24}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + + return 1; +} + +/*********************************************************************** + [function]: + callback: erase flash by page; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_pageerase(struct i2c_client *client,int npage) +{ + u8 ts_cmd[3] = {0x23,0x00,0x00}; + u8 len = 0; + int ret; + + switch(ic_model) + { + case ZET6221: + ts_cmd[1]=npage; + len=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + ts_cmd[1]=npage & 0xff; + ts_cmd[2]=npage >> 8; + len=3; + break; + default: + ts_cmd[1]=npage & 0xff; + ts_cmd[2]=npage >> 8; + len=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, len); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, len); +#endif + msleep(2); + + return 1; +} + +/*********************************************************************** + [function]: + callback: reset mcu; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_resetmcu(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0x29}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + + return 1; +} + + +#define CMD_PROG_CHECK_SUM (0x36) +#define CMD_PROG_GET_CHECK_SUM (0x37) +///*********************************************************************** +/// [function]: zet622x_cmd_read_check_sum +/// [parameters]: client, page_id, buf +/// [return]: int +///************************************************************************ +int zet622x_cmd_read_check_sum(struct i2c_client *client, int page_id, u8 * buf) +{ + int ret; + int cmd_len = 3; + + buf[0]= CMD_PROG_CHECK_SUM; + buf[1]= (u8)(page_id) & 0xff; + buf[2]= (u8)(page_id >> 8); + ret=zet6221_i2c_write_tsdata(client, buf, cmd_len); + if(ret<=0) + { + printk("[ZET]: Read check sum fail"); + return ret; + } + + buf[0]= CMD_PROG_GET_CHECK_SUM; + cmd_len = 1; + ret=zet6221_i2c_write_tsdata(client, buf, cmd_len); + if(ret<=0) + { + printk("[ZET]: Read check sum fail"); + return ret; + } + + cmd_len = 1; + ret = zet6221_i2c_read_tsdata(client, buf, cmd_len); + if(ret<=0) + { + printk("[ZET]: Read check sum fail"); + return ret; + } + return 1; +} + + +/*********************************************************************** + [function]: + callback: start HW function; + [parameters]: + client[in]: struct i2c_client ???represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_hwcmd(struct i2c_client *client) +{ + u8 ts_cmd[1] = {0xB9}; + + int ret; + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, ts_cmd, 1); +#else + ret=zet6221_i2c_write_tsdata(client, ts_cmd, 1); +#endif + + return 1; +} + +/*********************************************************************** +update FW +************************************************************************/ +int __init zet6221_downloader( struct i2c_client *client ) +{ + int BufLen=0; + int BufPage=0; + int BufIndex=0; + int ret; + int i; + + int nowBufLen=0; + int nowBufPage=0; + int nowBufIndex=0; + int retryCount=0; + int retryTimes = 0; + + int i2cLength=0; + int bufOffset=0; + + dbg("zet6221_downloader++\n"); + +begin_download: + +#if defined(RSTPIN_ENABLE) + //reset mcu + //gpio_direction_output(TS_RST_GPIO, GPIO_LOW); + wmt_rst_output(0); + msleep(5); +#else + zet6221_ts_hwcmd(client); + msleep(200); +#endif + //send password + //send password + ret = zet6221_ts_sndpwd(client); + dbg("zet6221_ts_sndpwd ret=%d\n",ret); + msleep(100); + +/*****compare version*******/ + + //0~3 + memset(zeitec_zet6221_page_in,0x00,131); + switch(ic_model) + { + case ZET6221: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[0] >> 7);//(fb[0]/128); + + i2cLength=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + default: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[0] >> 7) & 0xff; //(fb[0]/128); + zeitec_zet6221_page_in[2]=(fb[0] >> 7) >> 8; //(fb[0]/128); + + i2cLength=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, i2cLength); + dbg("write_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + msleep(2); + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; + zeitec_zet6221_page_in[2]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); + dbg("read_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + + //printk("page=%d ",(fb[0] >> 7)); //(fb[0]/128)); + for(i=0;i<4;i++) + { + pc[i]=zeitec_zet6221_page_in[(fb[i] & 0x7f)]; //[(fb[i]%128)]; + dbg("offset[%d]=%d ",i,(fb[i] & 0x7f)); //(fb[i]%128)); + } + dbg("\n"); + + + // 4~7 + memset(zeitec_zet6221_page_in,0x00,131); + switch(ic_model) + { + case ZET6221: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[4] >> 7);//(fb[4]/128); + + i2cLength=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=(fb[4] >> 7) & 0xff; //(fb[4]/128); + zeitec_zet6221_page_in[2]=(fb[4] >> 7) >> 8; //(fb[4]/128); + + i2cLength=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, i2cLength); + dbg("write_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; + zeitec_zet6221_page_in[2]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); + dbg("read_ret =%d, i2caddr=0x%x\n", ret, client->addr); +#endif + + //printk("page=%d ",(fb[4] >> 7)); //(fb[4]/128)); + for(i=4;i<8;i++) + { + pc[i]=zeitec_zet6221_page_in[(fb[i] & 0x7f)]; //[(fb[i]%128)]; + dbg("offset[%d]=%d ",i,(fb[i] & 0x7f)); //(fb[i]%128)); + } + dbg("\n"); + +#if 1 // need to check + //page 127 + memset(zeitec_zet6221_page_in,0x00,130); + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=127; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 2); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, 2); +#endif + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); +#endif + + for(i=0;i<128;i++) + { + // 0x3F80 = 16256 = 128x127, means skipped the first 127 page (0-126) ,use the page 127. + if(0x3F80+i < l_fwlen/*sizeof(flash_buffer)/sizeof(char)*/) //l_fwlen: the bytes of data read from firmware file + { + if(zeitec_zet6221_page_in[i]!=flash_buffer[0x3F80+i]) + { + errlog("page 127 [%d] doesn't match! continue to download! retry times:%d\n",i,retryTimes); + if( retryTimes++ >= 20){ // retry 20 times ,quit + errlog("May be I2C comunication is error\n"); + goto exit_download; + } + goto proc_sfr; + } + } + } + +#endif + + if( get_download_option() == FORCE_DOWNLOAD ){ + errlog("FORCE_DOWNLOAD\n"); + goto proc_sfr; + } + if( get_download_option() == FORCE_CANCEL_DOWNLOAD ){ + errlog("FORCE_CANCEL_DOWNLOAD\n"); + goto exit_download; + } + if(zet6221_ts_version()!=0){ + klog("tp version is the same,no need to download\n"); + goto exit_download; + } + + + +/*****compare version*******/ +proc_sfr: + //sfr + if(zet6221_ts_sfr(client)==0) + { + +#if 1 + +#if defined(RSTPIN_ENABLE) + + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_LOW); + wmt_rst_output(0); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); +#else + zet6221_ts_resetmcu(client); +#endif + msleep(20); + errlog("zet6221_ts_sfr error, download again\n"); + goto begin_download; + +#endif + + } + msleep(20); + + /// Fix the bug that page#504~#512 failed to write + if(ic_model == ZET6223) + { + zet6221_ts_sndpwd_1k(client); + } + + //erase + if(BufLen==0) + { + //mass erase + dbg( "mass erase\n"); + zet6221_ts_masserase(client); + msleep(200); + + BufLen=l_fwlen;/*sizeof(flash_buffer)/sizeof(char)*/; + }else + { + zet6221_ts_pageerase(client,BufPage); + msleep(200); + } + + + while(BufLen>0) + { +download_page: + + memset(zeitec_zet6221_page,0x00,131); + + klog( "Start: write page%d\n",BufPage); + nowBufIndex=BufIndex; + nowBufLen=BufLen; + nowBufPage=BufPage; + + switch(ic_model) + { + case ZET6221: + bufOffset = 2; + i2cLength=130; + + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage; + break; + case ZET6231: + case ZET6223: + case ZET6251: + default: + bufOffset = 3; + i2cLength=131; + + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage & 0xff; + zeitec_zet6221_page[2]=BufPage >> 8; + break; + } + if(BufLen>128) + { + for(i=0;i<128;i++) + { + zeitec_zet6221_page[i+bufOffset]=flash_buffer[BufIndex]; + BufIndex+=1; + } + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage; + BufLen-=128; + } + else + { + for(i=0;i<BufLen;i++) + { + zeitec_zet6221_page[i+bufOffset]=flash_buffer[BufIndex]; + BufIndex+=1; + } + zeitec_zet6221_page[0]=0x22; + zeitec_zet6221_page[1]=BufPage; + BufLen=0; + } + +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page, i2cLength); +#endif + //msleep(200); + msleep(2); + +#if 1 + + memset(zeitec_zet6221_page_in,0x00,131); + switch(ic_model) + { + case ZET6221: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=BufPage; + + i2cLength=2; + break; + case ZET6231: + case ZET6223: + case ZET6251: + default: + zeitec_zet6221_page_in[0]=0x25; + zeitec_zet6221_page_in[1]=BufPage & 0xff; + zeitec_zet6221_page_in[2]=BufPage >> 8; + + i2cLength=3; + break; + } +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_write_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, i2cLength); +#else + ret=zet6221_i2c_write_tsdata(client, zeitec_zet6221_page_in, i2cLength); +#endif + msleep(2); + + zeitec_zet6221_page_in[0]=0x0; + zeitec_zet6221_page_in[1]=0x0; + zeitec_zet6221_page_in[2]=0x0; +#if defined(I2C_CTPM_ADDRESS) + ret=i2c_read_interface(client, I2C_CTPM_ADDRESS, zeitec_zet6221_page_in, 128); +#else + ret=zet6221_i2c_read_tsdata(client, zeitec_zet6221_page_in, 128); +#endif + + for(i=0;i<128;i++) + { + if(i < nowBufLen) + { + if(zeitec_zet6221_page[i+bufOffset]!=zeitec_zet6221_page_in[i]) + { + BufIndex=nowBufIndex; + BufLen=nowBufLen; + BufPage=nowBufPage; + + if(retryCount < 5) + { + retryCount++; + goto download_page; + }else + { + //BufIndex=0; + //BufLen=0; + //BufPage=0; + retryCount=0; + +#if defined(RSTPIN_ENABLE) + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_LOW); + wmt_rst_output(0); + msleep(20); + + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); +#else + zet6221_ts_resetmcu(client); +#endif + msleep(20); + goto begin_download; + } + + } + } + } + +#endif + retryCount=0; + BufPage+=1; + } + +exit_download: + +#if defined(RSTPIN_ENABLE) + //gpio_direction_output(TS_RST_GPIO, GPIO_HIGH); + wmt_rst_output(1); + msleep(100); +#endif + + zet6221_ts_resetmcu(client); + msleep(100); + + dbg("zet6221_downloader--\n"); + return 1; + + +} + +int zet622x_resume_downloader(struct i2c_client *client) +{ + int ret = 0; + + int BufLen=0; + int BufPage=0; + int BufIndex=0; + int bufOffset = 0; + + int nowBufLen=0; + int nowBufPage=0; + int nowBufIndex=0; + + int i2cLength = 0; + + int i = 0; + + u8 bPageBuf[256]; + +#ifdef FEATURE_FW_CHECK_SUM + u8 get_check_sum = 0; + u8 check_sum = 0; + int retry_count = 0; + u8 tmp_data[16]; +#endif ///< for FEATURE_FW_CHECK_SUM + + + ///-------------------------------------------------------------/// + /// 1. Set RST=LOW + ///-------------------------------------------------------------/// + wmt_rst_output(0); + msleep(20); + //printk("RST = LOW\n"); + + ///-------------------------------------------------------------/// + /// Send password + ///-------------------------------------------------------------/// + ret = zet6221_ts_sndpwd(client); + if(ret<=0) + { + return ret; + } + + //printk("AAA\n"); + BufLen=l_fwlen;/*sizeof(flash_buffer)/sizeof(char)*/; + //printk("BBB%d\n",BufLen); + + while(BufLen>0) + { + /// memset(zeitec_zet622x_page, 0x00, 131); + nowBufIndex=BufIndex; + nowBufLen=BufLen; + nowBufPage=BufPage; + + switch(ic_model) + { + case ZET6251: + bufOffset = 3; + i2cLength=131; + + bPageBuf[0]=0x22; + bPageBuf[1]=BufPage & 0xff; + bPageBuf[2]=BufPage >> 8; + break; + } + + if(BufLen>128) + { + for(i=0;i<128;i++) + { + bPageBuf[i + bufOffset] = flash_buffer[BufIndex]; + BufIndex += 1; + } + + BufLen = BufLen - 128; + } + else + { + for(i=0;i<BufLen;i++) + { + bPageBuf[i+bufOffset]=flash_buffer[BufIndex]; + BufIndex+=1; + } + + BufLen=0; + } + +#ifdef FEATURE_FW_CHECK_SUM +LABEL_RETRY_DOWNLOAD_PAGE: +#endif ///< for FEATURE_FW_CHECK_SUM + + ret=zet6221_i2c_write_tsdata(client, bPageBuf, i2cLength); + + if(ic_model!= ZET6251) + { + msleep(50); + } + +#ifdef FEATURE_FW_CHECK_SUM + ///---------------------------------/// + /// Get check sum + ///---------------------------------/// + for(i=0;i<128;i++) + { + if(i == 0) + { + check_sum = bPageBuf[i + bufOffset]; + } + else + { + check_sum = check_sum ^ bPageBuf[i + bufOffset]; + } + } + + ///---------------------------------/// + /// Read check sum + ///---------------------------------/// + memset(tmp_data, 0, 16); + ret = zet622x_cmd_read_check_sum(client, BufPage, &tmp_data[0]); + if(ret<=0) + { + return ret; + } + get_check_sum = tmp_data[0]; + + //printk("[ZET]: page=%3d ,Check sum : %x ,get check sum : %x\n", BufPage, check_sum, get_check_sum); + if(check_sum != get_check_sum) + { + + if(retry_count < 5) + { + retry_count++; + goto LABEL_RETRY_DOWNLOAD_PAGE; + } + else + { + retry_count = 0; + wmt_rst_output(1); + msleep(20); + wmt_rst_output(0); + msleep(20); + wmt_rst_output(1); + msleep(20); + printk("[ZET] zet622x_resume_downloader fail\n"); + return ret; + } + + } + retry_count = 0; +#endif ///< for FEATURE_FW_CHECK_SUM + + BufPage+=1; + } + + printk("[ZET] zet622x_resume_downloader OK\n"); + //printk("RST = HIGH\n"); + + ///-------------------------------------------------------------/// + /// reset_mcu command + ///-------------------------------------------------------------/// + zet6221_ts_resetmcu(client); + msleep(10); + + ///-------------------------------------------------------------/// + /// SET RST=HIGH + ///-------------------------------------------------------------/// + wmt_rst_output(1); + msleep(20); + + ///-------------------------------------------------------------/// + /// RST toggle + ///-------------------------------------------------------------/// + wmt_rst_output(0); + msleep(2); + + wmt_rst_output(1); + msleep(2); + + return ret; +} + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_i2c.c b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_i2c.c new file mode 100755 index 00000000..31818510 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_i2c.c @@ -0,0 +1,2786 @@ +/* drivers/input/touchscreen/zet6221_i2c.c + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ZEITEC Semiconductor Co., Ltd + * Tel: +886-3-579-0045 + * Fax: +886-3-579-9960 + * http://www.zeitecsemi.com + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/jiffies.h> +#include <linux/io.h> +#include <linux/kthread.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/wakelock.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <asm/uaccess.h> + +#include <linux/input/mt.h> +#include "wmt_ts.h" +#include <linux/power/wmt_battery.h> +#include "../../../video/backlight/wmt_bl.h" + + +//fw update. +//#include "zet6221_fw.h" + +/* -------------- global variable definition -----------*/ +#define _MACH_MSM_TOUCH_H_ + +#define ZET_TS_ID_NAME "zet6221-ts" + +#define MJ5_TS_NAME "touch_zet6221" + +//#define TS_INT_GPIO S3C64XX_GPN(9) /*s3c6410*/ +//#define TS1_INT_GPIO AT91_PIN_PB17 /*AT91SAM9G45 external*/ +//#define TS1_INT_GPIO AT91_PIN_PA27 /*AT91SAM9G45 internal*/ +//#define TS_RST_GPIO S3C64XX_GPN(10) + +//#define MT_TYPE_B + +#define TS_RST_GPIO +#define X_MAX 800 //1024 +#define Y_MAX 480 //576 +#define FINGER_NUMBER 5 +#define KEY_NUMBER 3 //0 +//#define P_MAX 1 +#define P_MAX 255 //modify 2013-1-1 +#define D_POLLING_TIME 25000 +#define U_POLLING_TIME 25000 +#define S_POLLING_TIME 100 +#define REPORT_POLLING_TIME 3 +#define RETRY_DOWNLOAD_TIMES 2 + +#define MAX_KEY_NUMBER 8 +#define MAX_FINGER_NUMBER 16 +#define TRUE 1 +#define FALSE 0 + +//#define debug_mode 1 +//#define DPRINTK(fmt,args...) do { if (debug_mode) printk(KERN_EMERG "[%s][%d] "fmt"\n", __FUNCTION__, __LINE__, ##args);} while(0) + +//#define TRANSLATE_ENABLE 1 +#define TOPRIGHT 0 +#define TOPLEFT 1 +#define BOTTOMRIGHT 2 +#define BOTTOMLEFT 3 +#define ORIGIN BOTTOMRIGHT + +#define TIME_CHECK_CHARGE 3000 + +#define I2C_MAJOR 126 +#define I2C_MINORS 256 + + +///=============================================================================================/// +/// IOCTL control Definition +///=============================================================================================/// +#define ZET_IOCTL_CMD_FLASH_READ (20) +#define ZET_IOCTL_CMD_FLASH_WRITE (21) +#define ZET_IOCTL_CMD_RST (22) +#define ZET_IOCTL_CMD_RST_HIGH (23) +#define ZET_IOCTL_CMD_RST_LOW (24) + +#define ZET_IOCTL_CMD_DYNAMIC (25) + +#define ZET_IOCTL_CMD_FW_FILE_PATH_GET (26) +#define ZET_IOCTL_CMD_FW_FILE_PATH_SET (27) + +#define ZET_IOCTL_CMD_MDEV (28) +#define ZET_IOCTL_CMD_MDEV_GET (29) + +#define ZET_IOCTL_CMD_TRAN_TYPE_PATH_GET (30) +#define ZET_IOCTL_CMD_TRAN_TYPE_PATH_SET (31) + +#define ZET_IOCTL_CMD_IDEV (32) +#define ZET_IOCTL_CMD_IDEV_GET (33) + +#define ZET_IOCTL_CMD_MBASE (34) +#define ZET_IOCTL_CMD_MBASE_GET (35) + +#define ZET_IOCTL_CMD_INFO_SET (36) +#define ZET_IOCTL_CMD_INFO_GET (37) + +#define ZET_IOCTL_CMD_TRACE_X_SET (38) +#define ZET_IOCTL_CMD_TRACE_X_GET (39) + +#define ZET_IOCTL_CMD_TRACE_Y_SET (40) +#define ZET_IOCTL_CMD_TRACE_Y_GET (41) + +#define ZET_IOCTL_CMD_IBASE (42) +#define ZET_IOCTL_CMD_IBASE_GET (43) + +#define ZET_IOCTL_CMD_DRIVER_VER_GET (44) +#define ZET_IOCTL_CMD_MBASE_EXTERN_GET (45) + +#define IOCTL_MAX_BUF_SIZE (1024) + +///----------------------------------------------------/// +/// IOCTL ACTION +///----------------------------------------------------/// +#define IOCTL_ACTION_NONE (0) +#define IOCTL_ACTION_FLASH_DUMP (1<<0) + +static int ioctl_action = IOCTL_ACTION_NONE; + +///=============================================================================================/// +/// Transfer type +///=============================================================================================/// +#define TRAN_TYPE_DYNAMIC (0x00) +#define TRAN_TYPE_MUTUAL_SCAN_BASE (0x01) +#define TRAN_TYPE_MUTUAL_SCAN_DEV (0x02) +#define TRAN_TYPE_INIT_SCAN_BASE (0x03) +#define TRAN_TYPE_INIT_SCAN_DEV (0x04) +#define TRAN_TYPE_KEY_MUTUAL_SCAN_BASE (0x05) +#define TRAN_TYPE_KEY_MUTUAL_SCAN_DEV (0x06) +#define TRAN_TYPE_KEY_DATA (0x07) +#define TRAN_TYPE_MTK_TYPE (0x0A) +#define TRAN_TYPE_FOCAL_TYPE (0x0B) + +///=============================================================================================/// +/// TP Trace +///=============================================================================================/// +#define TP_DEFAULT_ROW (10) +#define TP_DEFAULT_COL (15) + +#define DRIVER_VERSION "$Revision: 44 $" +//static char const *revision="$Revision: 44 $"; + +///=============================================================================================/// +/// Macro Definition +///=============================================================================================/// +#define MAX_FLASH_BUF_SIZE (0x10000) + +///---------------------------------------------------------------------------------/// +/// 18. IOCTRL Debug +///---------------------------------------------------------------------------------/// +#define FEATURE_IDEV_OUT_ENABLE +#define FEATURE_MBASE_OUT_ENABLE +#define FEATURE_MDEV_OUT_ENABLE +#define FEATURE_INFO_OUT_EANBLE +#define FEATURE_IBASE_OUT_ENABLE + + + +///-------------------------------------/// +/// firmware save / load +///-------------------------------------/// +u32 data_offset = 0; +struct inode *inode = NULL; +mm_segment_t old_fs; + +char driver_version[128]; + +//#define FW_FILE_NAME "/vendor/modules/zet62xx.bin" +char fw_file_name[128]; +///-------------------------------------/// +/// Transmit Type Mode Path parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/" +/// "/mnt/extsd/" +///-------------------------------------/// + +// It should be the path where adb tools can push files in +#define TRAN_MODE_FILE_PATH "/data/local/tmp/" +char tran_type_mode_file_name[128]; +u8 *tran_data = NULL; + +///-------------------------------------/// +/// Mutual Dev Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetmdev" +/// "/mnt/extsd/zetmdev" +///-------------------------------------/// +#ifdef FEATURE_MDEV_OUT_ENABLE + #define MDEV_FILE_NAME "zetmdev" + #define MDEV_MAX_FILE_ID (10) + #define MDEV_MAX_DATA_SIZE (2048) +///-------------------------------------/// +/// mutual dev variables +///-------------------------------------/// + u8 *mdev_data = NULL; + int mdev_file_id = 0; +#endif ///< FEATURE_MDEV_OUT_ENABLE + +///-------------------------------------/// +/// Initial Base Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetibase" +/// "/mnt/extsd/zetibase" +///-------------------------------------/// +#ifdef FEATURE_IBASE_OUT_ENABLE + #define IBASE_FILE_NAME "zetibase" + #define IBASE_MAX_FILE_ID (10) + #define IBASE_MAX_DATA_SIZE (512) + +///-------------------------------------/// +/// initial base variables +///-------------------------------------/// + u8 *ibase_data = NULL; + int ibase_file_id = 0; +#endif ///< FEATURE_IBASE_OUT_ENABLE + +///-------------------------------------/// +/// Initial Dev Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetidev" +/// "/mnt/extsd/zetidev" +///-------------------------------------/// +#ifdef FEATURE_IDEV_OUT_ENABLE + #define IDEV_FILE_NAME "zetidev" + #define IDEV_MAX_FILE_ID (10) + #define IDEV_MAX_DATA_SIZE (512) + +///-------------------------------------/// +/// initial dev variables +///-------------------------------------/// + u8 *idev_data = NULL; + int idev_file_id = 0; +#endif ///< FEATURE_IDEV_OUT_ENABLE + +///-------------------------------------/// +/// Mutual Base Mode parameters +///-------------------------------------/// +/// External SD-Card could be +/// "/mnt/sdcard/zetmbase" +/// "/mnt/extsd/zetmbase" +///-------------------------------------/// +#ifdef FEATURE_MBASE_OUT_ENABLE + #define MBASE_FILE_NAME "zetmbase" + #define MBASE_MAX_FILE_ID (10) + #define MBASE_MAX_DATA_SIZE (2048) + +///-------------------------------------/// +/// mutual base variables +///-------------------------------------/// + u8 *mbase_data = NULL; + int mbase_file_id = 0; +#endif ///< FEATURE_MBASE_OUT_ENABLE + +///-------------------------------------/// +/// infomation variables +///-------------------------------------/// +#ifdef FEATURE_INFO_OUT_EANBLE + #define INFO_MAX_DATA_SIZE (64) + #define INFO_DATA_SIZE (17) + #define ZET6221_INFO (0x00) + #define ZET6231_INFO (0x0B) + #define ZET6223_INFO (0x0D) + #define ZET6251_INFO (0x0C) + #define UNKNOW_INFO (0xFF) + u8 *info_data = NULL; +#endif ///< FEATURE_INFO_OUT_EANBLE +///-------------------------------------/// +/// Default transfer type +///-------------------------------------/// +u8 transfer_type = TRAN_TYPE_DYNAMIC; + +///-------------------------------------/// +/// Default TP TRACE +///-------------------------------------/// +int row = TP_DEFAULT_ROW; +int col = TP_DEFAULT_COL; + +struct msm_ts_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +struct zet6221_tsdrv { + struct i2c_client *i2c_ts; + struct work_struct work1; + struct input_dev *input; + struct timer_list polling_timer; + struct delayed_work work; // for polling + struct workqueue_struct *queue; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + unsigned int gpio; /* GPIO used for interrupt of TS1*/ + unsigned int irq; + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +struct i2c_dev +{ + struct list_head list; + struct i2c_adapter *adap; + struct device *dev; +}; + +static struct i2c_dev *zet_i2c_dev; +static struct class *i2c_dev_class; +static LIST_HEAD (i2c_dev_list); +static DEFINE_SPINLOCK(i2c_dev_list_lock); + +struct zet6221_tsdrv * l_ts = NULL; +static int l_suspend = 0; // 1:suspend, 0:normal state + +//static int resetCount = 0; //albert++ 20120807 + + +//static u16 polling_time = S_POLLING_TIME; + +static int l_powermode = -1; +static struct mutex i2c_mutex; +static struct wake_lock downloadWakeLock; + + +//static int __devinit zet6221_ts_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int __devexit zet6221_ts_remove(struct i2c_client *dev); +extern int register_bl_notifier(struct notifier_block *nb); + +extern int unregister_bl_notifier(struct notifier_block *nb); + +extern int zet6221_downloader( struct i2c_client *client/*, unsigned short ver, unsigned char * data */); +extern int zet622x_resume_downloader(struct i2c_client *client); +extern u8 zet6221_ts_version(void); +extern u8 zet6221_ts_get_report_mode_t(struct i2c_client *client); +extern u8 zet622x_ts_option(struct i2c_client *client); +extern int zet6221_load_fw(void); +extern int zet6221_free_fwmem(void); + +void zet6221_ts_charger_mode_disable(void); +void zet6221_ts_charger_mode(void); +static int zet_fw_size(void); +static void zet_fw_save(char *file_name); +static void zet_fw_load(char *file_name); +static void zet_fw_init(void); +#ifdef FEATURE_MDEV_OUT_ENABLE +static void zet_mdev_save(char *file_name); +#endif ///< FEATURE_MDEV_OUT_ENABLE +#ifdef FEATURE_IDEV_OUT_ENABLE +static void zet_idev_save(char *file_name); +#endif ///< FEATURE_IDEV_OUT_ENABLE +#ifdef FEATURE_IBASE_OUT_ENABLE +static void zet_ibase_save(char *file_name); +#endif ///< FEATURE_IBASE_OUT_ENABLE +#ifdef FEATURE_MBASE_OUT_ENABLE +static void zet_mbase_save(char *file_name); +#endif ///< FEATURE_MBASE_OUT_ENABLE +static void zet_information_save(char *file_name); + +static struct task_struct *resume_download_task; + + + +//static int filterCount = 0; +//static u32 filterX[MAX_FINGER_NUMBER][2], filterY[MAX_FINGER_NUMBER][2]; + +//static u8 key_menu_pressed = 0x1; +//static u8 key_back_pressed = 0x1; +//static u8 key_search_pressed = 0x1; + +static u16 ResolutionX=X_MAX; +static u16 ResolutionY=Y_MAX; +static u16 FingerNum=0; +static u16 KeyNum=0; +static int bufLength=0; +static u8 xyExchange=0; +static u16 inChargerMode = 0; +static struct i2c_client *this_client; +struct workqueue_struct *ts_wq = NULL; +static int l_tskey[4][2] = { + {KEY_BACK,0}, + {KEY_MENU,0}, + {KEY_HOME,0}, + {KEY_SEARCH,0}, +}; + +u8 pc[8]; +// {IC Model, FW Version, FW version,Codebase Type=0x08, Customer ID, Project ID, Config Board No, Config Serial No} + +//Touch Screen +/*static const struct i2c_device_id zet6221_ts_idtable[] = { + { ZET_TS_ID_NAME, 0 }, + { } +}; + +static struct i2c_driver zet6221_ts_driver = { + .driver = { + .owner = THIS_MODULE, + .name = ZET_TS_ID_NAME, + }, + .probe = zet6221_ts_probe, + .remove = __devexit_p(zet6221_ts_remove), + .id_table = zet6221_ts_idtable, +}; +*/ + +void zet6221_set_tskey(int index,int key) +{ + l_tskey[index][0] = key; +} + + +void check_charger(void) +{ + mutex_lock(&i2c_mutex); + if (!wmt_charger_is_dc_plugin()) + { + klog("disable_mode\n"); + zet6221_ts_charger_mode_disable(); + } else { + klog("charge mode\n"); + zet6221_ts_charger_mode(); + } + mutex_unlock(&i2c_mutex); + l_powermode = wmt_charger_is_dc_plugin(); +} + + +void check_charger_polling(void) +{ + if(l_suspend == 1) + { + return; + } + + if (wmt_charger_is_dc_plugin() != l_powermode) + { + check_charger(); + } + + ///-------------------------------------------------------------------/// + /// IOCTL Action + ///-------------------------------------------------------------------/// + if(ioctl_action & IOCTL_ACTION_FLASH_DUMP) + { + printk("[ZET]: IOCTL_ACTION: Dump flash\n"); + zet_fw_save(fw_file_name); + ioctl_action &= ~IOCTL_ACTION_FLASH_DUMP; + } + + return; +} + + + +//extern unsigned int wmt_bat_is_batterypower(void); +/*********************************************************************** + [function]: + callback: Timer Function if there is no interrupt fuction; + [parameters]: + arg[in]: arguments; + [return]: + NULL; +************************************************************************/ + +static void polling_timer_func(struct work_struct *work) +{ + struct zet6221_tsdrv *ts = l_ts; + //schedule_work(&ts->work1); + //queue_work(ts_wq,&ts->work1); + //dbg("check mode!\n"); +/* + if (wmt_bat_is_batterypower() != l_powermode) + { + mutex_lock(&i2c_mutex); + if (wmt_bat_is_batterypower()) + { + klog("disable_mode\n"); + zet6221_ts_charger_mode_disable(); + } else { + klog("charge mode\n"); + zet6221_ts_charger_mode(); + } + mutex_unlock(&i2c_mutex); + l_powermode = wmt_bat_is_batterypower(); + } +*/ + + check_charger_polling(); + queue_delayed_work(ts->queue, &ts->work, msecs_to_jiffies(TIME_CHECK_CHARGE)); + + + //mod_timer(&ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); +} + + + +///********************************************************************** +/// [function]: zet622x_i2c_get_free_dev +/// [parameters]: adap +/// [return]: void +///********************************************************************** +static struct i2c_dev *zet622x_i2c_get_free_dev(struct i2c_adapter *adap) +{ + struct i2c_dev *i2c_dev; + + if (adap->nr >= I2C_MINORS) + { + printk("[ZET] : i2c-dev:out of device minors (%d) \n",adap->nr); + return ERR_PTR (-ENODEV); + } + + i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + { + return ERR_PTR(-ENOMEM); + } + i2c_dev->adap = adap; + + spin_lock(&i2c_dev_list_lock); + list_add_tail(&i2c_dev->list, &i2c_dev_list); + spin_unlock(&i2c_dev_list_lock); + + return i2c_dev; +} + +///********************************************************************** +/// [function]: zet622x_i2c_dev_get_by_minor +/// [parameters]: index +/// [return]: i2c_dev +///********************************************************************** +static struct i2c_dev *zet622x_i2c_dev_get_by_minor(unsigned index) +{ + struct i2c_dev *i2c_dev; + spin_lock(&i2c_dev_list_lock); + + list_for_each_entry(i2c_dev, &i2c_dev_list, list) + { + printk(" [ZET] : line = %d ,i2c_dev->adapt->nr = %d,index = %d.\n",__LINE__,i2c_dev->adap->nr,index); + if(i2c_dev->adap->nr == index) + { + goto LABEL_FOUND; + } + } + i2c_dev = NULL; + +LABEL_FOUND: + spin_unlock(&i2c_dev_list_lock); + + return i2c_dev ; +} + + + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num,int bus_id); +/*********************************************************************** + [function]: + callback: read data by i2c interface; + [parameters]: + client[in]: struct i2c_client �represent an I2C slave device; + data [out]: data buffer to read; + length[in]: data length to read; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int zet6221_i2c_read_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int rc = 0; + + memset(data, 0, length); + rc = i2c_master_recv(client, data, length); + if (rc <= 0) + { + errlog("error!\n"); + return -EINVAL; + } else if (rc != length) + { + dbg("want:%d,real:%d\n", length, rc); + } + return rc;*/ +} + +/*********************************************************************** + [function]: + callback: write data by i2c interface; + [parameters]: + client[in]: struct i2c_client �represent an I2C slave device; + data [out]: data buffer to write; + length[in]: data length to write; + [return]: + Returns negative errno, else the number of messages executed; +************************************************************************/ +int zet6221_i2c_write_tsdata(struct i2c_client *client, u8 *data, u8 length) +{ + struct i2c_msg msg; + msg.addr = client->addr; + msg.flags = 0; + msg.len = length; + msg.buf = data; + return i2c_transfer(client->adapter,&msg, 1); + + /*int ret = i2c_master_recv(client, data, length); + if (ret <= 0) + { + errlog("error!\n"); + } + return ret; + */ +} + +/*********************************************************************** + [function]: + callback: coordinate traslating; + [parameters]: + px[out]: value of X axis; + py[out]: value of Y axis; + p [in]: pressed of released status of fingers; + [return]: + NULL; +************************************************************************/ +void touch_coordinate_traslating(u32 *px, u32 *py, u8 p) +{ + int i; + u8 pressure; + + #if ORIGIN == TOPRIGHT + for(i=0;i<MAX_FINGER_NUMBER;i++){ + pressure = (p >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + } + } + #elif ORIGIN == BOTTOMRIGHT + for(i=0;i<MAX_FINGER_NUMBER;i++){ + pressure = (p >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + px[i] = X_MAX - px[i]; + py[i] = Y_MAX - py[i]; + } + } + #elif ORIGIN == BOTTOMLEFT + for(i=0;i<MAX_FINGER_NUMBER;i++){ + pressure = (p >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + if(pressure) + { + py[i] = Y_MAX - py[i]; + } + } + #endif +} + +/*********************************************************************** + [function]: + callback: reset function; + [parameters]: + void; + [return]: + void; +************************************************************************/ +void ctp_reset(void) +{ +#if defined(TS_RST_GPIO) + //reset mcu + /* gpio_direction_output(TS_RST_GPIO, 1); + msleep(1); + gpio_direction_output(TS_RST_GPIO, 0); + msleep(10); + gpio_direction_output(TS_RST_GPIO, 1); + msleep(20);*/ + wmt_rst_output(1); + msleep(1); + wmt_rst_output(0); + msleep(10); + wmt_rst_output(1); + msleep(5); + dbg("has done\n"); +#else + u8 ts_reset_cmd[1] = {0xb0}; + zet6221_i2c_write_tsdata(this_client, ts_reset_cmd, 1); +#endif + +} + + +///********************************************************************** +/// [function]: zet622x_ts_parse_mutual_dev +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_MDEV_OUT_ENABLE +u8 zet622x_ts_parse_mutual_dev(struct i2c_client *client) +{ + int mdev_packet_size = (row+2) * (col + 2); + int ret = 0; + int idx = 0; + int len = mdev_packet_size; + char mdev_file_name_out[128]; + + int step_size = col + 2; + + while(len > 0) + { + if(len < step_size) + { + step_size = len; + } + + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + idx += step_size; + } + + sprintf(mdev_file_name_out, "%s%s%02d.bin", tran_type_mode_file_name, MDEV_FILE_NAME, mdev_file_id); + zet_mdev_save(mdev_file_name_out); + mdev_file_id = (mdev_file_id +1)% (MDEV_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_MDEV_OUT_ENABLE + +///********************************************************************** +/// [function]: zet622x_ts_parse_initial_base +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_IBASE_OUT_ENABLE +u8 zet622x_ts_parse_initial_base(struct i2c_client *client) +{ + int ibase_packet_size = (row + col) * 2; + int ret = 0; + int idx = 0; + int len = ibase_packet_size; + char ibase_file_name_out[128]; + + int step_size = ibase_packet_size; + + while(len > 0) + { + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + } + sprintf(ibase_file_name_out, "%s%s%02d.bin", tran_type_mode_file_name, IBASE_FILE_NAME, ibase_file_id); + zet_ibase_save(ibase_file_name_out); + ibase_file_id = (ibase_file_id +1)% (IBASE_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_IBASE_OUT_ENABLE + +///********************************************************************** +/// [function]: zet622x_ts_parse_initial_dev +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_IDEV_OUT_ENABLE +u8 zet622x_ts_parse_initial_dev(struct i2c_client *client) +{ + int idev_packet_size = (row + col); + int ret = 0; + int idx = 0; + int len = idev_packet_size; + char idev_file_name_out[128]; + + int step_size = idev_packet_size; + + while(len > 0) + { + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + } + sprintf(idev_file_name_out, "%s%s%02d.bin", tran_type_mode_file_name, IDEV_FILE_NAME, idev_file_id); + zet_idev_save(idev_file_name_out); + idev_file_id = (idev_file_id +1)% (IDEV_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_IDEV_OUT_ENABLE + +///********************************************************************** +/// [function]: zet622x_ts_parse_mutual_base +/// [parameters]: client +/// [return]: u8 +///********************************************************************** +#ifdef FEATURE_MBASE_OUT_ENABLE +u8 zet622x_ts_parse_mutual_base(struct i2c_client *client) +{ + int mbase_packet_size = (row * col * 2); + int ret = 0; + int idx = 0; + int len = mbase_packet_size; + char mbase_file_name_out[128]; + + int step_size = col*2; + + while(len > 0) + { + if(len < step_size) + { + step_size = len; + } + + ret = zet6221_i2c_read_tsdata(client, &tran_data[idx], step_size); + len -= step_size; + idx += step_size; + } + sprintf(mbase_file_name_out, "%s%s%02d.bin",tran_type_mode_file_name, MBASE_FILE_NAME, mbase_file_id); + zet_mbase_save(mbase_file_name_out); + mbase_file_id = (mbase_file_id +1)% (MBASE_MAX_FILE_ID); + return ret; +} +#endif ///< FEATURE_MBASE_OUT_ENABLE + +/*********************************************************************** + [function]: + callback: read finger information from TP; + [parameters]: + client[in]: struct i2c_client �represent an I2C slave device; + x[out]: values of X axis; + y[out]: values of Y axis; + z[out]: values of Z axis; + pr[out]: pressed of released status of fingers; + ky[out]: pressed of released status of keys; + [return]: + Packet ID; +************************************************************************/ +u8 zet6221_ts_get_xy_from_panel(struct i2c_client *client, u32 *x, u32 *y, u32 *z, u32 *pr, u32 *ky) +{ + u8 ts_data[70]; + int ret; + int i; + + memset(ts_data,0,70); + + ret=zet6221_i2c_read_tsdata(client, ts_data, bufLength); + + *pr = ts_data[1]; + *pr = (*pr << 8) | ts_data[2]; + + for(i=0;i<FingerNum;i++) + { + x[i]=(u8)((ts_data[3+4*i])>>4)*256 + (u8)ts_data[(3+4*i)+1]; + y[i]=(u8)((ts_data[3+4*i]) & 0x0f)*256 + (u8)ts_data[(3+4*i)+2]; + z[i]=(u8)((ts_data[(3+4*i)+3]) & 0x0f); + } + + //if key enable + if(KeyNum > 0) + *ky = ts_data[3+4*FingerNum]; + + return ts_data[0]; +} + +/*********************************************************************** + [function]: + callback: get dynamic report information; + [parameters]: + client[in]: struct i2c_client �represent an I2C slave device; + + [return]: + 1; +************************************************************************/ +u8 zet6221_ts_get_report_mode(struct i2c_client *client) +{ + u8 ts_report_cmd[1] = {0xb2}; + //u8 ts_reset_cmd[1] = {0xb0}; + u8 ts_in_data[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + int ret; + int i; + int count=0; + + ret=zet6221_i2c_write_tsdata(client, ts_report_cmd, 1); + + if (ret > 0) + { + while(1) + { + msleep(1); + + //if (gpio_get_value(TS_INT_GPIO) == 0) + if (wmt_ts_irqinval() == 0) + { + dbg( "int low\n"); + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 17); + + if(ret > 0) + { + + for(i=0;i<8;i++) + { + pc[i]=ts_in_data[i] & 0xff; + } + + if(pc[3] != 0x08) + { + errlog("=============== zet6221_ts_get_report_mode report error ===============\n"); + return 0; + } + + xyExchange = (ts_in_data[16] & 0x8) >> 3; + if(xyExchange == 1) + { + ResolutionY= ts_in_data[9] & 0xff; + ResolutionY= (ResolutionY << 8)|(ts_in_data[8] & 0xff); + ResolutionX= ts_in_data[11] & 0xff; + ResolutionX= (ResolutionX << 8) | (ts_in_data[10] & 0xff); + } + else + { + ResolutionX = ts_in_data[9] & 0xff; + ResolutionX = (ResolutionX << 8)|(ts_in_data[8] & 0xff); + ResolutionY = ts_in_data[11] & 0xff; + ResolutionY = (ResolutionY << 8) | (ts_in_data[10] & 0xff); + } + + FingerNum = (ts_in_data[15] & 0x7f); + KeyNum = (ts_in_data[15] & 0x80); + + if(KeyNum==0) + bufLength = 3+4*FingerNum; + else + bufLength = 3+4*FingerNum+1; + + //DPRINTK( "bufLength=%d\n",bufLength); + + break; + + }else + { + errlog ("=============== zet6221_ts_get_report_mode read error ===============\n"); + return 0; + } + + }else + { + //DPRINTK( "int high\n"); + if(count++ > 30) + { + errlog ("=============== zet6221_ts_get_report_mode time out ===============\n"); + return 0; + } + + } + } + + } + return 1; +} + +#if 0 +static int zet6221_is_ts(struct i2c_client *client) +{ + /*u8 ts_in_data[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + ctp_reset(); + if (zet6221_i2c_read_tsdata(client, ts_in_data, 17) <= 0) + { + return 0; + } + return 1;*/ + return 1; +} +#endif + +/*********************************************************************** + [function]: + callback: get dynamic report information with timer delay; + [parameters]: + client[in]: struct i2c_client represent an I2C slave device; + + [return]: + 1; +************************************************************************/ + +u8 zet6221_ts_get_report_mode_t(struct i2c_client *client) +{ + u8 ts_report_cmd[1] = {0xb2}; + u8 ts_in_data[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + int ret; + int i; + + ret=zet6221_i2c_write_tsdata(client, ts_report_cmd, 1); + msleep(10); + + dbg("ret=%d,i2c_addr=0x%x\n", ret, client->addr); + if (ret > 0) + { + //mdelay(10); + //msleep(10); + dbg("=============== zet6221_ts_get_report_mode_t ===============\n"); + ret=zet6221_i2c_read_tsdata(client, ts_in_data, 17); + + if(ret > 0) + { + + for(i=0;i<8;i++) + { + pc[i]=ts_in_data[i] & 0xff; + } + + if(pc[3] != 0x08) + { + errlog("=============== zet6221_ts_get_report_mode_t report error ===============\n"); + return 0; + } + + xyExchange = (ts_in_data[16] & 0x8) >> 3; + if(xyExchange == 1) + { + ResolutionY= ts_in_data[9] & 0xff; + ResolutionY= (ResolutionY << 8)|(ts_in_data[8] & 0xff); + ResolutionX= ts_in_data[11] & 0xff; + ResolutionX= (ResolutionX << 8) | (ts_in_data[10] & 0xff); + } + else + { + ResolutionX = ts_in_data[9] & 0xff; + ResolutionX = (ResolutionX << 8)|(ts_in_data[8] & 0xff); + ResolutionY = ts_in_data[11] & 0xff; + ResolutionY = (ResolutionY << 8) | (ts_in_data[10] & 0xff); + } + + FingerNum = (ts_in_data[15] & 0x7f); + KeyNum = (ts_in_data[15] & 0x80); + inChargerMode = (ts_in_data[16] & 0x2) >> 1; + + if(KeyNum==0) + bufLength = 3+4*FingerNum; + else + bufLength = 3+4*FingerNum+1; + + }else + { + errlog ("=============== zet6221_ts_get_report_mode_t READ ERROR ===============\n"); + return 0; + } + + }else + { + errlog("=============== zet6221_ts_get_report_mode_t WRITE ERROR ===============\n"); + return 0; + } + return 1; +} + +/*********************************************************************** + [function]: + callback: interrupt function; + [parameters]: + irq[in]: irq value; + dev_id[in]: dev_id; + + [return]: + NULL; +************************************************************************/ +static irqreturn_t zet6221_ts_interrupt(int irq, void *dev_id) +{ + struct zet6221_tsdrv *ts_drv = dev_id; + int j = 0; + if (wmt_is_tsint()) + { + wmt_clr_int(); + if (wmt_is_tsirq_enable() && l_suspend == 0) + { + wmt_disable_gpirq(); + dbg("begin..\n"); + //if (!work_pending(&l_tsdata.pen_event_work)) + if (wmt_ts_irqinval() == 0) + { + queue_work(ts_wq, &ts_drv->work1); + } else { + if(KeyNum > 0) + { + //if (0 == ky) + { + for (j=0;j<4;j++) + { + if (l_tskey[j][1] != 0) + { + l_tskey[j][1] = 0; + } + } + dbg("finish one key report!\n"); + } + } + wmt_enable_gpirq(); + } + } + return IRQ_HANDLED; + } + + return IRQ_NONE; + + /*//polling_time = D_POLLING_TIME; + + if (gpio_get_value(TS_INT_GPIO) == 0) + { + // IRQ is triggered by FALLING code here + struct zet6221_tsdrv *ts_drv = dev_id; + schedule_work(&ts_drv->work1); + //DPRINTK("TS1_INT_GPIO falling\n"); + }else + { + //DPRINTK("TS1_INT_GPIO raising\n"); + } + + return IRQ_HANDLED;*/ +} + +/*********************************************************************** + [function]: + callback: touch information handler; + [parameters]: + _work[in]: struct work_struct; + + [return]: + NULL; +************************************************************************/ +static void zet6221_ts_work(struct work_struct *_work) +{ + u32 x[MAX_FINGER_NUMBER], y[MAX_FINGER_NUMBER], z[MAX_FINGER_NUMBER], pr, ky, points; + u32 px,py,pz; + u8 ret; + u8 pressure; + int i,j; + int tx,ty; + int xmax,ymax; + int realnum = 0; + struct zet6221_tsdrv *ts = + container_of(_work, struct zet6221_tsdrv, work1); + + struct i2c_client *tsclient1 = ts->i2c_ts; + + if(l_suspend == 1) + { + return; + } + + if (bufLength == 0) + { + wmt_enable_gpirq(); + return; + } + /*if(resetCount == 1) + { + resetCount = 0; + wmt_enable_gpirq(); + return; + }*/ + + //if (gpio_get_value(TS_INT_GPIO) != 0) + if (wmt_ts_irqinval() != 0) + { + /* do not read when IRQ is triggered by RASING*/ + //DPRINTK("INT HIGH\n"); + dbg("INT HIGH....\n"); + wmt_enable_gpirq(); + return; + } + + ///-------------------------------------------/// + /// Transfer Type : Mutual Dev Mode + ///-------------------------------------------/// +#ifdef FEATURE_MDEV_OUT_ENABLE + if(transfer_type == TRAN_TYPE_MUTUAL_SCAN_DEV) + { + zet622x_ts_parse_mutual_dev(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< FEATURE_MDEV_OUT_ENABLE + + ///-------------------------------------------/// + /// Transfer Type : Initial Base Mode + ///-------------------------------------------/// +#ifdef FEATURE_IBASE_OUT_ENABLE + if(transfer_type == TRAN_TYPE_INIT_SCAN_BASE) + { + zet622x_ts_parse_initial_base(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< FEATURE_IBASE_OUT_ENABLE + + ///-------------------------------------------/// + /// Transfer Type : Initial Dev Mode + ///-------------------------------------------/// +#ifdef FEATURE_IDEV_OUT_ENABLE + if(transfer_type == TRAN_TYPE_INIT_SCAN_DEV) + { + zet622x_ts_parse_initial_dev(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< TRAN_TYPE_INIT_SCAN_DEV + + ///-------------------------------------------/// + /// Transfer Type : Mutual Base Mode + ///-------------------------------------------/// +#ifdef FEATURE_MBASE_OUT_ENABLE + if(transfer_type == TRAN_TYPE_MUTUAL_SCAN_BASE) + { + zet622x_ts_parse_mutual_base(tsclient1); + wmt_enable_gpirq(); + return; + } +#endif ///< FEATURE_MBASE_OUT_ENABLE + + mutex_lock(&i2c_mutex); + ret = zet6221_ts_get_xy_from_panel(tsclient1, x, y, z, &pr, &ky); + mutex_unlock(&i2c_mutex); + + if(ret == 0x3C) + { + + dbg( "x1= %d, y1= %d x2= %d, y2= %d [PR] = %d [KY] = %d\n", x[0], y[0], x[1], y[1], pr, ky); + + points = pr; + + #if defined(TRANSLATE_ENABLE) + touch_coordinate_traslating(x, y, points); + #endif + realnum = 0; + + for(i=0;i<FingerNum;i++){ + pressure = (points >> (MAX_FINGER_NUMBER-i-1)) & 0x1; + dbg( "valid=%d pressure[%d]= %d x= %d y= %d\n",points , i, pressure,x[i],y[i]); + + if(pressure) + { + px = x[i]; + py = y[i]; + pz = z[i]; + + dbg("raw%d(%d,%d) xaxis:%d ResolutionX:%d ResolutionY:%d\n", i, px, py,wmt_ts_get_xaxis(),ResolutionX,ResolutionY); + + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, i); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, P_MAX); + //input_report_abs(ts->input, ABS_MT_POSITION_X, x[i]); + //input_report_abs(ts->input, ABS_MT_POSITION_Y, y[i]); + if (wmt_ts_get_xaxis() == 0) + { + tx = px; + ty = py; + xmax = ResolutionX; + ymax = ResolutionY; + } else { + tx = py; + ty = px; + xmax = ResolutionY; + ymax = ResolutionX; + } + if (wmt_ts_get_xdir() == -1) + { + tx = xmax - tx; + } + if (wmt_ts_get_ydir() == -1) + { + ty = ymax - ty; + } + //tx = ResolutionY - py; + //ty = px; + dbg("rpt%d(%d,%d)\n", i, tx, ty); + //add for cross finger 2013-1-10 + #ifdef MT_TYPE_B + input_mt_slot(ts->input, i); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,true); + #endif + input_report_abs(ts->input, ABS_MT_TRACKING_ID, i); + //input_report_key(ts->input, BTN_TOUCH, 1); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pz); + //******************************* + + if (wmt_ts_get_lcdexchg()) { + int tmp; + tmp = tx; + tx = ty; + ty = ResolutionY - tmp; + } + + input_report_abs(ts->input, ABS_MT_POSITION_X, tx /*px*/); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ty /*py*/); + + #ifndef MT_TYPE_B + input_mt_sync(ts->input); + #endif + realnum++; + if (wmt_ts_ispenup()) + { + wmt_ts_set_penup(0); + } + + }else + { + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, i); + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0); + //input_mt_sync(ts->input); + #ifdef MT_TYPE_B + input_mt_slot(ts->input, i); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,false); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + #endif //add cross finger 2013-1-10 + dbg("p%d not pen down\n",i); + } + } + + #ifdef MT_TYPE_B + input_mt_report_pointer_emulation(ts->input, true); + #endif //add finger cross 2013-1-10 + //printk("<<<realnum %d\n", realnum); + if (realnum != 0) + { + input_sync(ts->input); + dbg("report one point group\n"); + } else if (!wmt_ts_ispenup()) + {//********here no finger press 2013-1-10 + //add 2013-1-10 cross finger issue! + #ifdef MT_TYPE_B + for(i=0;i<FingerNum;i++){ + input_mt_slot(ts->input, i); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,false); + input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + } + input_mt_report_pointer_emulation(ts->input, true); + #else + //input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0); + //input_mt_sync(ts->input); + //input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); + //input_report_key(ts->input, BTN_TOUCH, 0); + #endif + //********************************** + input_mt_sync(ts->input); + input_sync(ts->input); + dbg("real pen up!\n"); + wmt_ts_set_penup(1); + } + + if(KeyNum > 0) + { + //for(i=0;i<MAX_KEY_NUMBER;i++) + if (0 == ky) + { + for (j=0;j<4;j++) + { + if (l_tskey[j][1] != 0) + { + l_tskey[j][1] = 0; + } + } + dbg("finish one key report!\n"); + } else { + for(i=0;i<4;i++) + { + pressure = ky & ( 0x01 << i ); + if (pressure) + { + dbg("key%d\n", i); + if (0 == l_tskey[i][1]) + { + l_tskey[i][1] = 1; // key down + input_report_key(ts->input, l_tskey[i][0], 1); + input_report_key(ts->input, l_tskey[i][0], 0); + input_sync(ts->input); + dbg("report key_%d\n", l_tskey[i][0]); + break; + } + } + + } + } + } + + dbg("normal end...\n"); + }else { + dbg("do nothing!\n"); + if(KeyNum > 0) + { + //if (0 == ky) + { + for (j=0;j<4;j++) + { + if (l_tskey[j][1] != 0) + { + l_tskey[j][1] = 0; + } + } + dbg("finish one key report!\n"); + } + } + } + wmt_enable_gpirq(); + +} + +/*********************************************************************** + [function]: + callback: charger mode enable; + [parameters]: + void + + [return]: + void +************************************************************************/ +void zet6221_ts_charger_mode() +{ + //struct zet6221_tsdrv *zet6221_ts; + u8 ts_write_charge_cmd[1] = {0xb5}; + int ret=0; + ret=zet6221_i2c_write_tsdata(this_client, ts_write_charge_cmd, 1); +} +EXPORT_SYMBOL_GPL(zet6221_ts_charger_mode); + +/*********************************************************************** + [function]: + callback: charger mode disable; + [parameters]: + void + + [return]: + void +************************************************************************/ +void zet6221_ts_charger_mode_disable(void) +{ + //struct zet6221_tsdrv *zet6221_ts; + u8 ts_write_cmd[1] = {0xb6}; + int ret=0; + ret=zet6221_i2c_write_tsdata(this_client, ts_write_cmd, 1); +} +EXPORT_SYMBOL_GPL(zet6221_ts_charger_mode_disable); + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ts_early_suspend(struct early_suspend *handler) +{ + //Sleep Mode +/* u8 ts_sleep_cmd[1] = {0xb1}; + int ret=0; + ret=zet6221_i2c_write_tsdata(this_client, ts_sleep_cmd, 1); + return; + */ + wmt_disable_gpirq(); + l_suspend = 1; + //del_timer(&l_ts->polling_timer); + +} + +static void ts_late_resume(struct early_suspend *handler) +{ + resetCount = 1; + //if (l_suspend != 0) + { + //wmt_disable_gpirq(); + //ctp_reset(); + //wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_enable_gpirq(); + l_suspend = 0; + } + //l_powermode = -1; + //mod_timer(&l_ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); + +} +#endif +static int zet_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + wmt_disable_gpirq(); + l_suspend = 1; + return 0; +} + + +/*********************************************************************** + [function]: + resume_download_thread + [parameters]: + arg + + [return]: + int; +************************************************************************/ +int resume_download_thread(void *arg) +{ + char fw_name[64]; + wake_lock(&downloadWakeLock); + sprintf(fw_name, "%szet62xx.bin", tran_type_mode_file_name); + zet_fw_load(fw_name); + //printk("Thread : Enter\n"); +// if((iRomType == ROM_TYPE_SRAM) || +// (iRomType == ROM_TYPE_OTP)) //SRAM,OTP + // { + zet622x_resume_downloader(this_client); + check_charger(); + l_suspend = 0; + //printk("zet622x download OK\n"); + // } + //printk("Thread : Leave\n"); + wake_unlock(&downloadWakeLock); + return 0; +} + +static int zet_ts_resume(struct platform_device *pdev) +{ + wmt_disable_gpirq(); + ctp_reset(); + + if(ic_model == ZET6251) { + //upload bin to flash_buffer, just for debug + resume_download_task = kthread_create(resume_download_thread, NULL , "resume_download"); + if(IS_ERR(resume_download_task)) { + errlog("cread thread failed\n"); + } + wake_up_process(resume_download_task); + } else { + check_charger(); + l_suspend = 0; + } + + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + if (!earlysus_en) + wmt_enable_gpirq(); + + ///--------------------------------------/// + /// Set transfer type to dynamic mode + ///--------------------------------------/// + transfer_type = TRAN_TYPE_DYNAMIC; + + return 0; +} + + +///********************************************************************** +/// [function]: zet622x_ts_set_transfer_type +/// [parameters]: void +/// [return]: void +///********************************************************************** +int zet622x_ts_set_transfer_type(u8 bTransType) +{ + u8 ts_cmd[10] = {0xC1, 0x02, TRAN_TYPE_DYNAMIC, 0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00}; + int ret = 0; + ts_cmd[2] = bTransType; + ret = zet6221_i2c_write_tsdata(this_client, ts_cmd, 10); + return ret; +} + + +///********************************************************************** +/// [function]: zet622x_ts_set_transfer_type +/// [parameters]: void +/// [return]: void +///********************************************************************** +#ifdef FEATURE_INFO_OUT_EANBLE +int zet622x_ts_set_info_type(void) +{ + int ret = 1; + char info_file_name_out[128]; + + /// ic type + switch(ic_model) + { + case ZET6221: + tran_data[0] = ZET6221_INFO; + break; + case ZET6223: + tran_data[0] = ZET6223_INFO; + break; + case ZET6231: + tran_data[0] = ZET6231_INFO; + break; + case ZET6251: + tran_data[0] = ZET6251_INFO; + break; + default: + tran_data[0] = UNKNOW_INFO; + break; + } + + /// resolution + if(xyExchange== 1) + { + tran_data[16] = 0x8; + tran_data[9] = ((ResolutionY >> 8)&0xFF); + tran_data[8] = (ResolutionY &0xFF); + tran_data[11] = ((ResolutionX >> 8)&0xFF); + tran_data[10] = (ResolutionX &0xFF); + } + else + { + tran_data[16] = 0x00; + tran_data[9] = ((ResolutionX >> 8)&0xFF); + tran_data[8] = (ResolutionX &0xFF); + tran_data[11] = ((ResolutionY >> 8)&0xFF); + tran_data[10] = (ResolutionY &0xFF); + } + + /// trace X + tran_data[13] = TP_DEFAULT_COL; ///< trace x + /// trace Y + tran_data[14] = TP_DEFAULT_ROW; ///< trace y + + if(KeyNum > 0) + { + tran_data[15] = (0x80 | FingerNum); + } + else + { + tran_data[15] = FingerNum; + } + + sprintf(info_file_name_out, "%sinfo.bin",tran_type_mode_file_name); + zet_information_save(info_file_name_out); + + printk("[ZET] : ic:%d, traceX:%d, traceY:%d\n", tran_data[0],tran_data[13],tran_data[14]); + return ret; +} +#endif ///< FEATURE_INFO_OUT_EANBLE + +///*********************************************************************** +/// [function]: zet_mdev_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +static void zet_mdev_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row+2) * (col + 2); + + ///-------------------------------------------------------/// + /// create the file that stores the mutual dev data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(mdev_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} + +///*********************************************************************** +/// [function]: zet_idev_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_IDEV_OUT_ENABLE +static void zet_idev_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row + col); + + ///-------------------------------------------------------/// + /// create the file that stores the initial dev data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(idev_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_IDEV_OUT_ENABLE + +///*********************************************************************** +/// [function]: zet_ibase_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_IBASE_OUT_ENABLE +static void zet_ibase_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row + col) * 2; + + ///-------------------------------------------------------/// + /// create the file that stores the initial base data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(ibase_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_IBASE_OUT_ENABLE + +///*********************************************************************** +/// [function]: zet_mbase_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_MBASE_OUT_ENABLE +static void zet_mbase_save(char *file_name) +{ + struct file *fp; + int data_total_len = (row * col * 2); + + ///-------------------------------------------------------/// + /// create the file that stores the mutual base data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(mbase_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_MBASE_OUT_ENABLE + +///*********************************************************************** +/// [function]: zet_information_save +/// [parameters]: char * +/// [return]: void +///************************************************************************ +#ifdef FEATURE_INFO_OUT_EANBLE +static void zet_information_save(char *file_name) +{ + struct file *fp; + int data_total_len = INFO_DATA_SIZE; + + ///-------------------------------------------------------/// + /// create the file that stores the mutual base data + ///-------------------------------------------------------/// + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, tran_data, data_total_len, &(fp->f_pos)); + memcpy(info_data, tran_data, data_total_len); + set_fs(old_fs); + filp_close(fp, 0); + + return; +} +#endif ///< FEATURE_INFO_OUT_EANBLE + +///************************************************************************ +/// [function]: zet_dv_set_file_name +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_dv_set_file_name(char *file_name) +{ + strcpy(driver_version, file_name); +} + +///************************************************************************ +/// [function]: zet_fw_set_file_name +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_fw_set_file_name(void)//char *file_name) +{ + char fwname[256] = {0}; + wmt_ts_get_firmwname(fwname); + sprintf(fw_file_name,"/system/etc/firmware/%s",fwname); + //strcpy(fw_file_name, file_name); +} + +///************************************************************************ +/// [function]: zet_mdev_set_file_name +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_tran_type_set_file_name(char *file_name) +{ + strcpy(tran_type_mode_file_name, file_name); +} + + +///*********************************************************************** +/// [function]: zet_fw_size +/// [parameters]: void +/// [return]: void +///************************************************************************ +static int zet_fw_size(void) +{ + int flash_total_len = 0x8000; + + switch(ic_model) + { + case ZET6221: + flash_total_len = 0x4000; + break; + case ZET6223: + flash_total_len = 0x10000; + break; + case ZET6231: + case ZET6251: + default: + flash_total_len = 0x8000; + break; + } + + return flash_total_len; +} + + +///*********************************************************************** +/// [function]: zet_fw_save +/// [parameters]: file name +/// [return]: void +///************************************************************************ +static void zet_fw_save(char *file_name) +{ + struct file *fp; + int flash_total_len = 0; + + fp = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if(IS_ERR(fp)) + { + printk("[ZET] : Failed to open %s\n", file_name); + return; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + flash_total_len = zet_fw_size(); + printk("[ZET] : flash_total_len = 0x%04x\n",flash_total_len ); + + vfs_write(fp, flash_buffer, flash_total_len, &(fp->f_pos)); + + set_fs(old_fs); + + filp_close(fp, 0); + + + return; +} + +///*********************************************************************** +/// [function]: zet_fw_load +/// [parameters]: file name +/// [return]: void +///************************************************************************ +static void zet_fw_load(char *file_name) +{ + int file_length = 0; + struct file *fp; + loff_t *pos; + + //printk("[ZET]: find %s\n", file_name); + fp = filp_open(file_name, O_RDONLY, 0644); + if(IS_ERR(fp)) + { + //printk("[ZET]: No firmware file detected\n"); + return; + } + + ///----------------------------/// + /// Load from file + ///----------------------------/// + printk("[ZET]: Load from %s\n", file_name); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + /// Get file size + inode = fp->f_dentry->d_inode; + file_length = (int)inode->i_size; + //l_fwlen = file_length; + + pos = &(fp->f_pos); + + vfs_read(fp, &flash_buffer[0], file_length, pos); + + //file_length + set_fs(old_fs); + filp_close(fp, 0); + + +} + +///************************************************************************ +/// [function]: zet_fw_init +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_fw_init(void) +{ + //int i; + + if(flash_buffer == NULL) + { + flash_buffer = kmalloc(MAX_FLASH_BUF_SIZE, GFP_KERNEL); + } + + ///---------------------------------------------/// + /// Init the mutual dev buffer + ///---------------------------------------------/// + if(mdev_data== NULL) + { + mdev_data = kmalloc(MDEV_MAX_DATA_SIZE, GFP_KERNEL); + } + if(idev_data== NULL) + { + idev_data = kmalloc(IDEV_MAX_DATA_SIZE, GFP_KERNEL); + } + + if(mbase_data== NULL) + { + mbase_data = kmalloc(MBASE_MAX_DATA_SIZE, GFP_KERNEL); + } + if(ibase_data== NULL) + { + ibase_data = kmalloc(IBASE_MAX_DATA_SIZE, GFP_KERNEL); + } + + if(tran_data == NULL) + { + tran_data = kmalloc(MBASE_MAX_DATA_SIZE, GFP_KERNEL); + } + + if(info_data == NULL) + { + info_data = kmalloc(INFO_MAX_DATA_SIZE, GFP_KERNEL); + } + + /*printk("[ZET]: Load from header\n"); + + if(ic_model == ZET6221) + { + for(i = 0 ; i < sizeof(zeitec_zet6221_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6221_firmware[i]; + } + } + else if(ic_model == ZET6223) + { + for(i = 0 ; i < sizeof(zeitec_zet6223_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6223_firmware[i]; + } + } + else if(ic_model == ZET6231) + { + for(i = 0 ; i < sizeof(zeitec_zet6231_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6231_firmware[i]; + } + } + else if(ic_model == ZET6251) + { + for(i = 0 ; i < sizeof(zeitec_zet6251_firmware) ; i++) + { + flash_buffer[i] = zeitec_zet6251_firmware[i]; + } + } + + /// Load firmware from bin file + zet_fw_load(fw_file_name);*/ +} + +///************************************************************************ +/// [function]: zet_fw_exit +/// [parameters]: void +/// [return]: void +///************************************************************************ +static void zet_fw_exit(void) +{ + ///---------------------------------------------/// + /// free mdev_data + ///---------------------------------------------/// + if(mdev_data!=NULL) + { + kfree(mdev_data); + mdev_data = NULL; + } + + if(idev_data!=NULL) + { + kfree(idev_data); + idev_data = NULL; + } + + if(mbase_data!=NULL) + { + kfree(mbase_data); + mbase_data = NULL; + } + + if(ibase_data!=NULL) + { + kfree(ibase_data); + ibase_data = NULL; + } + + if(tran_data != NULL) + { + kfree(tran_data); + tran_data = NULL; + } + + if(info_data != NULL) + { + kfree(info_data); + info_data = NULL; + } + + + ///---------------------------------------------/// + /// free flash buffer + ///---------------------------------------------/// + if(flash_buffer!=NULL) + { + kfree(flash_buffer); + flash_buffer = NULL; +} + +} + +///************************************************************************ +/// [function]: zet_fops_open +/// [parameters]: file +/// [return]: int +///************************************************************************ +static int zet_fops_open(struct inode *inode, struct file *file) +{ + int subminor; + int ret = 0; + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_dev *i2c_dev; + + subminor = iminor(inode); + printk("[ZET] : ZET_FOPS_OPEN , subminor=%d\n",subminor); + + i2c_dev = zet622x_i2c_dev_get_by_minor(subminor); + if (!i2c_dev) + { + printk("error i2c_dev\n"); + return -ENODEV; + } + + adapter = i2c_get_adapter(i2c_dev->adap->nr); + if(!adapter) + { + return -ENODEV; + } + + client = kzalloc(sizeof(*client), GFP_KERNEL); + + if(!client) + { + i2c_put_adapter(adapter); + ret = -ENOMEM; + } + snprintf(client->name, I2C_NAME_SIZE, "pctp_i2c_ts%d", adapter->nr); + //client->driver = &zet622x_i2c_driver; + client->driver = this_client->driver; + client->adapter = adapter; + file->private_data = client; + + return 0; +} + + +///************************************************************************ +/// [function]: zet_fops_release +/// [parameters]: inode, file +/// [return]: int +///************************************************************************ +static int zet_fops_release (struct inode *inode, struct file *file) +{ + struct i2c_client *client = file->private_data; + + printk("[ZET] : zet_fops_release -> line : %d\n",__LINE__ ); + + i2c_put_adapter(client->adapter); + kfree(client); + file->private_data = NULL; + return 0; +} + +///************************************************************************ +/// [function]: zet_fops_read +/// [parameters]: file, buf, count, ppos +/// [return]: size_t +///************************************************************************ +static ssize_t zet_fops_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + int i; + int iCnt = 0; + char str[256]; + int len = 0; + + printk("[ZET] : zet_fops_read -> line : %d\n",__LINE__ ); + + ///-------------------------------/// + /// Print message + ///-------------------------------/// + sprintf(str, "Please check \"%s\"\n", fw_file_name); + len = strlen(str); + + ///-------------------------------/// + /// if read out + ///-------------------------------/// + if(data_offset >= len) + { + return 0; + } + + for(i = 0 ; i < count-1 ; i++) + { + buf[i] = str[data_offset]; + buf[i+1] = 0; + iCnt++; + data_offset++; + if(data_offset >= len) + { + break; + } + } + + ///-------------------------------/// + /// Save file + ///-------------------------------/// + if(data_offset == len) + { + zet_fw_save(fw_file_name); + } + return iCnt; +} + +///************************************************************************ +/// [function]: zet_fops_write +/// [parameters]: file, buf, count, ppos +/// [return]: size_t +///************************************************************************ +static ssize_t zet_fops_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + printk("[ZET]: zet_fops_write -> %s\n", buf); + data_offset = 0; + return count; +} + +///************************************************************************ +/// [function]: ioctl +/// [parameters]: file , cmd , arg +/// [return]: long +///************************************************************************ +static long zet_fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg ) +{ + u8 __user * user_buf = (u8 __user *) arg; + + u8 buf[IOCTL_MAX_BUF_SIZE]; + int data_size; + + if(copy_from_user(buf, user_buf, IOCTL_MAX_BUF_SIZE)) + { + printk("[ZET]: zet_ioctl: copy_from_user fail\n"); + return 0; + } + + printk("[ZET]: zet_ioctl -> cmd = %d, %02x, %02x\n", cmd, buf[0], buf[1]); + + if(cmd == ZET_IOCTL_CMD_FLASH_READ) + { + printk("[ZET]: zet_ioctl -> ZET_IOCTL_CMD_FLASH_DUMP cmd = %d, file=%s\n", cmd, (char *)buf); + ioctl_action |= IOCTL_ACTION_FLASH_DUMP; + } + else if(cmd == ZET_IOCTL_CMD_FLASH_WRITE) + { + printk("[ZET]: zet_ioctl -> ZET_IOCTL_CMD_FLASH_WRITE cmd = %d\n", cmd); + { //upload bin to flash_buffer + char fw_name[64]; + sprintf(fw_name, "%szet62xx.bin", tran_type_mode_file_name); + zet_fw_load(fw_name); + } + zet622x_resume_downloader(this_client); + } + else if(cmd == ZET_IOCTL_CMD_RST) + { + printk("[ZET]: zet_ioctl -> ZET_IOCTL_CMD_RST cmd = %d\n", cmd); + //ctp_reset(); + wmt_rst_output(1); + + wmt_rst_output(0); + msleep(20); + wmt_rst_output(1); + + transfer_type = TRAN_TYPE_DYNAMIC; + } + else if(cmd == ZET_IOCTL_CMD_RST_HIGH) + { + wmt_rst_output(1); + } + else if(cmd == ZET_IOCTL_CMD_RST_LOW) + { + wmt_rst_output(0); + } + else if(cmd == ZET_IOCTL_CMD_MDEV) + { + ///---------------------------------------------------/// + /// set mutual dev mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_MUTUAL_SCAN_DEV); + transfer_type = TRAN_TYPE_MUTUAL_SCAN_DEV; + + } + else if(cmd == ZET_IOCTL_CMD_IBASE) + { + ///---------------------------------------------------/// + /// set initial base mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_INIT_SCAN_BASE); + transfer_type = TRAN_TYPE_INIT_SCAN_BASE; + + } +#ifdef FEATURE_IDEV_OUT_ENABLE + else if(cmd == ZET_IOCTL_CMD_IDEV) + { + ///---------------------------------------------------/// + /// set initial dev mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_INIT_SCAN_DEV); + transfer_type = TRAN_TYPE_INIT_SCAN_DEV; + + } +#endif ///< FEATURE_IDEV_OUT_ENABLE +#ifdef FEATURE_MBASE_OUT_ENABLE + else if(cmd == ZET_IOCTL_CMD_MBASE) + { + ///---------------------------------------------------/// + /// set Mutual Base mode + ///---------------------------------------------------/// + zet622x_ts_set_transfer_type(TRAN_TYPE_MUTUAL_SCAN_BASE); + transfer_type = TRAN_TYPE_MUTUAL_SCAN_BASE; + + } +#endif ///< FEATURE_MBASE_OUT_ENABLE + else if(cmd == ZET_IOCTL_CMD_DYNAMIC) + { + zet622x_ts_set_transfer_type(TRAN_TYPE_DYNAMIC); + transfer_type = TRAN_TYPE_DYNAMIC; + } + else if(cmd == ZET_IOCTL_CMD_FW_FILE_PATH_GET) + { + memset(buf, 0x00, 64); + strcpy(buf, fw_file_name); + printk("[ZET]: zet_ioctl: Get FW_FILE_NAME = %s\n", buf); + } + else if(cmd == ZET_IOCTL_CMD_FW_FILE_PATH_SET) + { + strcpy(fw_file_name, buf); + printk("[ZET]: zet_ioctl: set FW_FILE_NAME = %s\n", buf); + + } + else if(cmd == ZET_IOCTL_CMD_MDEV_GET) + { + data_size = (row+2)*(col+2); + memcpy(buf, mdev_data, data_size); + printk("[ZET]: zet_ioctl: Get MDEV data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_TRAN_TYPE_PATH_SET) + { + strcpy(tran_type_mode_file_name, buf); + printk("[ZET]: zet_ioctl: Set ZET_IOCTL_CMD_TRAN_TYPE_PATH_ = %s\n", buf); + } + else if(cmd == ZET_IOCTL_CMD_TRAN_TYPE_PATH_GET) + { + memset(buf, 0x00, 64); + strcpy(buf, tran_type_mode_file_name); + printk("[ZET]: zet_ioctl: Get ZET_IOCTL_CMD_TRAN_TYPE_PATH = %s\n", buf); + } + else if(cmd == ZET_IOCTL_CMD_IDEV_GET) + { + data_size = (row + col); + memcpy(buf, idev_data, data_size); + printk("[ZET]: zet_ioctl: Get IDEV data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_IBASE_GET) + { + data_size = (row + col)*2; + memcpy(buf, ibase_data, data_size); + printk("[ZET]: zet_ioctl: Get IBASE data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_MBASE_GET) + { + data_size = (row*col*2); + if(data_size > IOCTL_MAX_BUF_SIZE) + { + data_size = IOCTL_MAX_BUF_SIZE; + } + memcpy(buf, mbase_data, data_size); + printk("[ZET]: zet_ioctl: Get MBASE data size=%d\n", data_size); + } + else if(cmd == ZET_IOCTL_CMD_INFO_SET) + { + printk("[ZET]: zet_ioctl: ZET_IOCTL_CMD_INFO_SET\n"); + zet622x_ts_set_info_type(); + } + else if(cmd == ZET_IOCTL_CMD_INFO_GET) + { + data_size = INFO_DATA_SIZE; + memcpy(buf, info_data, data_size); + printk("[ZET]: zet_ioctl: Get INFO data size=%d,IC: %x,X:%d,Y:%d\n", data_size, info_data[0], info_data[13], info_data[14]); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_X_SET) + { + printk("[ZET]: zet_ioctl: ZET_IOCTL_CMD_TRACE_X_SET\n"); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_X_GET) + { + printk("[ZET]: zet_ioctl: Get TRACEX data\n"); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_Y_SET) + { + printk("[ZET]: zet_ioctl: ZET_IOCTL_CMD_TRACE_Y_SET\n"); + } + else if(cmd == ZET_IOCTL_CMD_TRACE_Y_GET) + { + printk("[ZET]: zet_ioctl: Get TRACEY data \n"); + } + else if(cmd == ZET_IOCTL_CMD_DRIVER_VER_GET) + { + memset(buf, 0x00, 64); + strcpy(buf, driver_version); + printk("[ZET]: zet_ioctl: Get DRIVER_VERSION = %s\n", buf); + printk("[ZET]: zet_ioctl: Get SVN = %s\n", DRIVER_VERSION); + } + else if(cmd == ZET_IOCTL_CMD_MBASE_EXTERN_GET) + { + data_size = (row*col*2) - IOCTL_MAX_BUF_SIZE; + if(data_size < 1) + { + data_size = 1; + } + memcpy(buf, (mbase_data+IOCTL_MAX_BUF_SIZE), data_size); + printk("[ZET]: zet_ioctl: Get MBASE extern data size=%d\n", data_size); + } + + if(copy_to_user(user_buf, buf, IOCTL_MAX_BUF_SIZE)) + { + printk("[ZET]: zet_ioctl: copy_to_user fail\n"); + return 0; + } + + return 0; +} + +///************************************************************************ +/// file_operations +///************************************************************************ +static const struct file_operations zet622x_ts_fops = +{ + .owner = THIS_MODULE, + .open = zet_fops_open, + .read = zet_fops_read, + .write = zet_fops_write, + .unlocked_ioctl = zet_fops_ioctl, + .compat_ioctl = zet_fops_ioctl, + .release = zet_fops_release, +}; + +static int zet6221_ts_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int result = -1; + int count = 0; + int download_count = 0; + int download_ok = 0; + struct input_dev *input_dev; + struct device *dev; + + + struct zet6221_tsdrv *zet6221_ts; + + dbg( "[TS] zet6221_ts_probe \n"); + + zet6221_ts = kzalloc(sizeof(struct zet6221_tsdrv), GFP_KERNEL); + l_ts = zet6221_ts; + zet6221_ts->i2c_ts = client; + //zet6221_ts->gpio = TS_INT_GPIO; /*s3c6410*/ + //zet6221_ts->gpio = TS1_INT_GPIO; + + this_client = client; + + i2c_set_clientdata(client, zet6221_ts); + + //client->driver = &zet6221_ts_driver; + ts_wq = create_singlethread_workqueue("zet6221ts_wq"); + if (!ts_wq) + { + errlog("Failed to create workqueue!\n"); + goto err_create_wq; + } + + INIT_WORK(&zet6221_ts->work1, zet6221_ts_work); + + input_dev = input_allocate_device(); + if (!input_dev || !zet6221_ts) { + result = -ENOMEM; + goto fail_alloc_mem; + } + + //i2c_set_clientdata(client, zet6221_ts); + + input_dev->name = MJ5_TS_NAME; + input_dev->phys = "zet6221_touch/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0002; + input_dev->id.version = 0x0100; +//bootloader + zet622x_ts_option(client); + msleep(100); + + download_count = 0; + download_ok = 0; + zet_fw_init(); + do{ + if (zet6221_load_fw()) + { + errlog("Can't load the firmware of zet62xx!\n"); + } else { + zet6221_downloader(client); + //ctp_reset(); //cancel it? need to check + } + udelay(100); + + count=0; + do{ + ctp_reset(); + + if(zet6221_ts_get_report_mode_t(client)==0) //get IC info by delay + { + ResolutionX = X_MAX; + ResolutionY = Y_MAX; + FingerNum = FINGER_NUMBER; + KeyNum = KEY_NUMBER; + if(KeyNum==0) + bufLength = 3+4*FingerNum; + else + bufLength = 3+4*FingerNum+1; + errlog("[warning] zet6221_ts_get_report_mode_t report error!!use default value\n"); + }else + { + if(zet6221_ts_version()==1) // zet6221_ts_version() depends on zet6221_downloader() + // cancel download firmware, need to comment it. + { + dbg("get report mode ok!\n"); + download_ok = 1; + } + } + count++; + }while(count<REPORT_POLLING_TIME && download_ok != 1 ); + download_count++; + }while( download_count < RETRY_DOWNLOAD_TIMES && download_ok != 1 ); + + errlog( "ResolutionX=%d ResolutionY=%d FingerNum=%d KeyNum=%d\n",ResolutionX,ResolutionY,FingerNum,KeyNum); + + input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + if (wmt_ts_get_lcdexchg()) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ResolutionX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ResolutionY, 0, 0); + } else { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ResolutionY, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ResolutionX, 0, 0); + } + + set_bit(KEY_BACK, input_dev->keybit); + set_bit(KEY_HOME, input_dev->keybit); + set_bit(KEY_MENU, input_dev->keybit); + + //*******************************add 2013-1-10 + set_bit(ABS_MT_TRACKING_ID, input_dev->absbit); + //set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit); + input_set_abs_params(input_dev,ABS_MT_TRACKING_ID, 0, FingerNum, 0, 0); + //input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, P_MAX, 0, 0); + //set_bit(BTN_TOUCH, input_dev->keybit); + + #ifdef MT_TYPE_B + input_mt_init_slots(input_dev, FingerNum); + #endif + //set_bit(KEY_SEARCH, input_dev->keybit); + + //input_dev->evbit[0] = BIT(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + //input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + result = input_register_device(input_dev); + if (result) + goto fail_ip_reg; + + zet6221_ts->input = input_dev; + + input_set_drvdata(zet6221_ts->input, zet6221_ts); + mutex_init(&i2c_mutex); + wake_lock_init(&downloadWakeLock, WAKE_LOCK_SUSPEND, "resume_download"); + zet6221_ts->queue = create_singlethread_workqueue("ts_check_charge_queue"); + INIT_DELAYED_WORK(&zet6221_ts->work, polling_timer_func); + + //setup_timer(&zet6221_ts->polling_timer, polling_timer_func, (unsigned long)zet6221_ts); + //mod_timer(&zet6221_ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); + + + //s3c6410 + //result = gpio_request(zet6221_ts->gpio, "GPN"); + wmt_set_gpirq(IRQ_TYPE_EDGE_FALLING); + wmt_disable_gpirq(); + /*result = gpio_request(zet6221_ts->gpio, "GPN"); + if (result) + goto gpio_request_fail; + */ + + zet6221_ts->irq = wmt_get_tsirqnum();//gpio_to_irq(zet6221_ts->gpio); + dbg( "[TS] zet6221_ts_probe.gpid_to_irq [zet6221_ts->irq=%d]\n",zet6221_ts->irq); + + result = request_irq(zet6221_ts->irq, zet6221_ts_interrupt,IRQF_SHARED /*IRQF_TRIGGER_FALLING*/, + ZET_TS_ID_NAME, zet6221_ts); + if (result) + { + errlog("Can't alloc ts irq=%d\n", zet6221_ts->irq); + goto request_irq_fail; + } + + + ///-----------------------------------------------/// + /// Set the default firmware bin file name & mutual dev file name + ///-----------------------------------------------/// + zet_dv_set_file_name(DRIVER_VERSION); + zet_fw_set_file_name();//FW_FILE_NAME); + zet_tran_type_set_file_name(TRAN_MODE_FILE_PATH); + + ///---------------------------------/// + /// Set file operations + ///---------------------------------/// + result = register_chrdev(I2C_MAJOR, "zet_i2c_ts", &zet622x_ts_fops); + if(result) + { + printk(KERN_ERR "%s:register chrdev failed\n",__FILE__); + goto fail_register_chrdev; + } + ///---------------------------------/// + /// Create device class + ///---------------------------------/// + i2c_dev_class = class_create(THIS_MODULE,"zet_i2c_dev"); + if(IS_ERR(i2c_dev_class)) + { + result = PTR_ERR(i2c_dev_class); + goto fail_create_class; + } + ///--------------------------------------------/// + /// Get a free i2c dev + ///--------------------------------------------/// + zet_i2c_dev = zet622x_i2c_get_free_dev(client->adapter); + if(IS_ERR(zet_i2c_dev)) + { + result = PTR_ERR(zet_i2c_dev); + goto fail_get_free_dev; + } + dev = device_create(i2c_dev_class, &client->adapter->dev, + MKDEV(I2C_MAJOR,client->adapter->nr), NULL, "zet62xx_ts%d", client->adapter->nr); + if(IS_ERR(dev)) + { + result = PTR_ERR(dev); + goto fail_create_device; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + zet6221_ts->early_suspend.suspend = ts_early_suspend, + zet6221_ts->early_suspend.resume = ts_late_resume, + zet6221_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;//,EARLY_SUSPEND_LEVEL_DISABLE_FB + 2; + register_early_suspend(&zet6221_ts->early_suspend); +#endif + //disable_irq(zet6221_ts->irq); + ctp_reset(); + wmt_enable_gpirq(); + queue_delayed_work(zet6221_ts->queue, &zet6221_ts->work, msecs_to_jiffies(TIME_CHECK_CHARGE)); + //mod_timer(&zet6221_ts->polling_timer,jiffies + msecs_to_jiffies(TIME_CHECK_CHARGE)); + dbg("ok\n"); + return 0; + +fail_create_device: + kfree(zet_i2c_dev); +fail_get_free_dev: + class_destroy(i2c_dev_class); +fail_create_class: + unregister_chrdev(I2C_MAJOR, "zet_i2c_ts"); +fail_register_chrdev: + free_irq(zet6221_ts->irq, zet6221_ts); +request_irq_fail: + destroy_workqueue(zet6221_ts->queue); + cancel_delayed_work_sync(&zet6221_ts->work); + //gpio_free(zet6221_ts->gpio); +//gpio_request_fail: + free_irq(zet6221_ts->irq, zet6221_ts); + wake_lock_destroy(&downloadWakeLock); + input_unregister_device(input_dev); + input_dev = NULL; +fail_ip_reg: +fail_alloc_mem: + input_free_device(input_dev); + destroy_workqueue(ts_wq); + cancel_work_sync(&zet6221_ts->work1); + zet_fw_exit(); +err_create_wq: + kfree(zet6221_ts); + return result; +} + +static int zet6221_ts_remove(void /*struct i2c_client *dev*/) +{ + struct zet6221_tsdrv *zet6221_ts = l_ts;//i2c_get_clientdata(dev); + + //del_timer(&zet6221_ts->polling_timer); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&zet6221_ts->early_suspend); +#endif + wmt_disable_gpirq(); + device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR,this_client->adapter->nr)); + kfree(zet_i2c_dev); + class_destroy(i2c_dev_class); + unregister_chrdev(I2C_MAJOR, "zet_i2c_ts"); + free_irq(zet6221_ts->irq, zet6221_ts); + //gpio_free(zet6221_ts->gpio); + //del_timer_sync(&zet6221_ts->polling_timer); + destroy_workqueue(zet6221_ts->queue); + cancel_delayed_work_sync(&zet6221_ts->work); + input_unregister_device(zet6221_ts->input); + wake_lock_destroy(&downloadWakeLock); + cancel_work_sync(&zet6221_ts->work1); + destroy_workqueue(ts_wq); + zet_fw_exit(); + kfree(zet6221_ts); + + return 0; +} + +static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + //printk("get notify\n"); + switch (event) { + case BL_CLOSE: + l_suspend = 1; + //printk("\nclose backlight\n\n"); + //printk("disable irq\n\n"); + wmt_disable_gpirq(); + break; + case BL_OPEN: + l_suspend = 0; + //printk("\nopen backlight\n\n"); + //printk("enable irq\n\n"); + wmt_enable_gpirq(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block wmt_bl_notify = { + .notifier_call = wmt_wakeup_bl_notify, +}; + +static int zet6221_ts_init(void) +{ + //u8 ts_data[70]; + //int ret; + + /*ctp_reset(); + memset(ts_data,0,70); + ret=zet6221_i2c_read_tsdata(ts_get_i2c_client(), ts_data, 8); + if (ret <= 0) + { + dbg("Can't find zet6221!\n"); + return -1; + } + if (!zet6221_is_ts(ts_get_i2c_client())) + { + dbg("isn't zet6221!\n"); + return -1; + }*/ + if (zet6221_ts_probe(ts_get_i2c_client())) + { + return -1; + } + if (earlysus_en) + register_bl_notifier(&wmt_bl_notify); + //i2c_add_driver(&zet6221_ts_driver); + return 0; +} +//module_init(zet6221_ts_init); + +static void zet6221_ts_exit(void) +{ + zet6221_ts_remove(); + if (earlysus_en) + unregister_bl_notifier(&wmt_bl_notify); + //i2c_del_driver(&zet6221_ts_driver); +} +//module_exit(zet6221_ts_exit); + +void zet6221_set_ts_mode(u8 mode) +{ + dbg( "[Touch Screen]ts mode = %d \n", mode); +} +//EXPORT_SYMBOL_GPL(zet6221_set_ts_mode); + +struct wmtts_device zet6221_tsdev = { + .driver_name = WMT_TS_I2C_NAME, + .ts_id = "ZET62", + .init = zet6221_ts_init, + .exit = zet6221_ts_exit, + .suspend = zet_ts_suspend, + .resume = zet_ts_resume, +}; + + +MODULE_DESCRIPTION("ZET6221 I2C Touch Screen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h new file mode 100755 index 00000000..671bb29d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/zet6221_ts/zet6221_ts.h @@ -0,0 +1,6 @@ +#ifndef ZET6221_TSH_201010191758
+#define ZET6221_TSH_201010191758
+
+extern void zet6221_set_tskey(int index,int key);
+
+#endif
|