blob: 3f25233d04659b0ff5928a2515a3cb74ef818d90 [file] [log] [blame]
/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
*
* File Name : ftk.c
* Authors : Sensor & MicroActuators BU - Application Team
* : Bela Somaiah (bela.somaiah@st.com)
* Version : V 1.0
* Date : 29/06/2011
* Description : Capacitive touch screen controller (FingertipK)
*
********************************************************************************
*
* 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.
*
* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
*
********************************************************************************
* REVISON HISTORY
*
*VERSION | DATE | AUTHORS | DESCRIPTION
* 1.0 | 29/06/2011| Bela Somaiah| First Release(link to ftk_patch.h)
*
*******************************************************************************/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/hrtimer.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/i2c/ftk_patch.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/earlysuspend.h>
/*
* Definitions & global arrays.
*/
#define DRIVER_DESC "ftk i2c touchscreen driver"
#define ftk_TS_DRV_NAME "ftk"
#define X_AXIS_MAX 480
#define X_AXIS_MIN 0
#define Y_AXIS_MAX 800 // 272
#define Y_AXIS_MIN 0
#define PRESSURE_MIN 0
#define PRESSURE_MAX 256
#define LOAD_PATCH_FOR_FINGERTIPK 1 // 1
static struct i2c_driver stm_ts_driver;
static struct workqueue_struct *stmtouch_wq;
static int cor_xyz[10][3];
static int prev_xyz[10][3];
static u8 ID_Indx[10];
static u8 IDj = 0;
static u8 StylusTouchID=100;
struct B0_write {
u8 addr;
u8 val;
};
static unsigned char ftk_keycode[] = {
KEY_BACK,
KEY_SEARCH,
KEY_HOME,
KEY_1,
KEY_9,
};
//#define patch_file_path "/mnt/sdcard/ftk.patch"
//#define config_file_path "/mnt/sdcard/ftk.config"
// CMM elton pointers
#define patch_file_path "/system/etc/touchpad/ftk.patch"
#define config_file_path "/system/etc/touchpad/ftk.config"
// \CMM
//#define patch_file_path "/data/misc/wifi/ftk.patch"
//#define config_file_path "/data/misc/wifi/ftk.config"
static u32 strnum_to_digtial( char * inputStrData, int length) ;
#ifdef LOAD_PATCH_FOR_FINGERTIPK
extern u16 PatchDataSize;
//extern u8 PatchData[648]; //for patch 1
extern u8 PatchData[15984]; //for patch 7 of 169;
#define P70_PATCH_LEN PatchDataSize// 16*1024
#define WRITE_CHUNK_SIZE 64
#define P70_PATCH_ADDR_START 0x00420000
#endif
struct hrtimer test_timer;
struct ftk_ts {
struct device *dev;
struct i2c_client *client;
struct input_dev *input_dev;
struct hrtimer timer;
struct work_struct work;
spinlock_t lock;
int reported_finger_count;
int x;
int y;
int z;
int pendown;
int irq;
int (*power)(int on);
struct early_suspend early_suspend;
};
static int TouchID_EventXYZ[10][5] = {0}; //add by michael HU; 03Nov2011;
#ifdef CONFIG_HAS_EARLYSUSPEND
static void stm_ts_early_suspend(struct early_suspend *h);
static void stm_ts_late_resume(struct early_suspend *h);
#endif
static int init_ftk(struct ftk_ts *ftk_ts);
static void test_timer_func(void)
{
// printk("Michael: test_timer_func\n");
// ftk_gpio_test();
printk("In the test_timer_func!\n" );
// init_ftk(struct ftk_ts *ftk_ts);
hrtimer_start(&test_timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
static void start_test_timer(void)
{
printk("enter start_test_timer\n");
hrtimer_init(&test_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
test_timer.function = test_timer_func;
hrtimer_start(&test_timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
static void stop_test_timer(void)
{
hrtimer_cancel(&test_timer);
}
static int ftk_write_reg(struct ftk_ts *ftk_ts, unsigned char * reg, u16 num_com)
{
int ret, i;
struct i2c_msg xfer_msg[2];
xfer_msg[0].addr = ftk_ts->client->addr;
xfer_msg[0].len = num_com;
xfer_msg[0].flags = 0;
xfer_msg[0].buf = reg;
return i2c_transfer(ftk_ts->client->adapter, xfer_msg, 1);
return 0;
}
static int ftk_read_reg(struct ftk_ts *ftk_ts, unsigned char *reg, int cnum, u8 *buf, int num)
{
#if 1
struct i2c_msg xfer_msg[2];
xfer_msg[0].addr = ftk_ts->client->addr;
xfer_msg[0].len = cnum;
xfer_msg[0].flags = 0;
xfer_msg[0].buf = reg;
xfer_msg[1].addr = ftk_ts->client->addr;
xfer_msg[1].len = num;
xfer_msg[1].flags = I2C_M_RD;
xfer_msg[1].buf = buf;
return i2c_transfer(ftk_ts->client->adapter, xfer_msg, 2);
#endif
return 0;
}
#define B0_COMMAND_WRITES 75
static struct B0_write B0_command_writes[B0_COMMAND_WRITES] = {
{0x2E,0x10},//</Touch-In Hysteresis" />
{0x2C,0x5A},//</TVR" />
{0x2D,0x00},//</" />
{0x4E,0x10},//</EVR1" />
{0x4F,0x00},//</" />
{0x7F,0x40},//</EVR2" />
{0x80,0x00},//</" />
{0x13,0x15},//</Post Sync Noise Reduction" />
{0x15,0x09},//</TS FE settings - Triangular window enable" />
{0x16,0x83},//</FECONF: RTI selection and M-Cycle" />
{0x17,0x8F},//</C_int Sel and T-Cycle" />
{0x18,0x06},//</I-Cycle" />
{0x19,0x07},//</R-Cycle (min)" />
{0x1A,0x55},//</Protocol" />
{0x1B,0x55},//</Protocol" />
// {0x1C,0x04},//</X start Channel" />
//{0x1D,0x0F},//</X Length" />
//{0x1E,0x05},//</Y Start Channel" />
// {0x1F,0x09},//</Y Length" />
{0x1C,0x04},//</X start Channel" />
{0x1D,0x14},//</X Length" />
{0x1E,0x05},//</Y Start Channel" />
{0x1F,0x0C},//</Y Length" />
{0x30,0x10},//</Stylus Strength Hysteresis" />
{0x32,0x20},//</Finger Strength Hysteresis" />
{0x34,0xD1},//</Adaptive Filter - Rscan enable; Adaptive weight Enable; Sample count" />
{0x35,0x0A},//</Std dev base" />
{0x36,0x0A},//</Std dev threshold 1" />
{0x37,0x50},//</Std dev threshold 2" />
{0x3A,0x59},//</Frame Filter Weight (Noisy and Default)" />
{0x3B,0x8A},//</Co-ord Filter weight:Z,XY" />
{0x48,0x70},//</Stylus Strength Threshold" />
{0x4A,0x00},//</Stylus Area Threshold" />
{0x4B,0xA0},//</Finger Strength Threshold (Byte 0)" />
{0x4C,0x00},//</Finger Strength Threshold (Byte 1)" />
{0x4D,0x06},//</Finger Area Threshold" />
//{0x57,0x60},//</Display Screen Resolution X (Byte 0)" />
//{0x58,0x01},//</Display Screen Resolution X (Byte 1)" />
//{0x59,0xE6},//</Display Screen Resolution Y (Byte 0)" />
// {0x5A,0x00},//</Display Screen Resolution Y (Byte 1)" />
//{0x57,0x20},//Display Resolution for X //landscape mode;
//{0x58,0x3},//Display Resolution for X
//{0x59,0xE0},//Display Resolution for Y
//{0x5A,0x1},//Display Resolution for Y
{0x57,0x20},//Display Resolution for X //---0x 01 EO = 480;
{0x58,0x03},//Display Resolution for X
{0x59,0xE0},//Display Resolution for Y // ---0X 03 20 = 800
{0x5A,0x01},//Display Resolution for Y
{0x61,0x05},//</TS Active Frame Rate" />
{0x62,0x05},//</TS Idle Frame Rate" />
{0x63,0xC8},//</Auto Cal Interval (between cal cycles)" />
{0x64,0x05},//</Auto Cal Sampling Time (between samples)" />
{0x65,0x70},//</Tracking Radius (Byte 0)" />
{0x66,0x00},//</Tracking Radius (Byte 1)" />
{0x68,0x2F},//</Touch-In Delay" />
{0x69,0x1F},//</Touch-out Delay" />
{0x6E,0x05},//</Motion Tolerance X" />
{0x6F,0x05},//</Motion Tolerance Y" />
{0x70,0x94},//</SW Feature En: Auto Cal_Dis; Peak Det_En; Frame Reconstruction On" />
{0x7D,0x37},//</ACC and Bit shift (Active Mode)" />
{0x7E,0x37},//</ACC and Bit shift (Idle Mode)" />
{0x88,0x04},//</Comp Clk Count" />
{0x89,0x83},//</FE Cap sel (TSComp_Enable)" />
{0x8A,0x0F},//</C-Comp setting (default:20pF) " />
{0x8C,0xFF},//</Cs Offset (Byte 0)" />
{0x8D,0xC1},//</Cs Offset (Byte 1)" />
{0xAE,0x00},//</In-Cell Disable" />
{0xB6,0x02},//</Min Area for Touch reporting" />
{0xB7,0x00},//</Stationary Touch Reporting Interval" />
{0xB8,0x40},//</Merge In Threshold" />
{0xB9,0x10},//</Merge Out Hysteresis" />
{0xBA,0x6F},//</Touch-In delay 2" />
{0xBB,0x0D},//</Noisy Coordinate Filter" />
{0xBC,0x01},//</Senseline Compensation" />
{0xBD,0x12},//</Noise Monitoring TX - 19" />
{0xBE,0x01},//</Noise Reduction Step" />
{0xBF,0x10},//</Frame/Co-ordinate IIR Noise Threshold" />
{0xC0,0x10},//</R-start:03" />
{0xC1,0x9C},//</" />
{0xC2,0x05},//</R-end:21" />
{0xC3,0x00},//</" />
{0xC4,0x04},//</R1:03" />
{0xC5,0x0C},//</R2:08" />
{0xC6,0x10},//</R3:0D" />
{0xC7,0x12},//</R4:13" />
{0xC8,0x03},//</Standard Deviation Adaptive Threshold Slope" />
{0xCA,0x0F},//</Upper limit for Standard Deviation" />
};
static u8 SendConfigByFile(struct ftk_ts *ftk_ts,char * inputStrData, int iLength)
{
int i = 0;
u8 regAdd[8];
int rc;
//printk( "Enter SendConfigByFile \n");
for ( i = 0 ; i < iLength/2; i++ )
{
regAdd[i] = strnum_to_digtial( &inputStrData[i*2], 2 );
//printk("%02X ", regAdd[i]);
}
// printk("\n");
rc = ftk_write_reg(ftk_ts, &regAdd[0],iLength/2);
#if 1
if ( ( regAdd[0] == 0xB0 ) && ( regAdd[1] == 0x04 ))
{
printk("mdelay(55) after 0xB004 \n");
mdelay(50);
}
#endif
mdelay(5);
return 0;
}
static u8 LoadConfigFromFile(struct ftk_ts *ftk_ts)
{
u32 writeAddr, j = 0, iReadLen = 0, iDataPackLen = 0, iTemp = 0 ;
loff_t iPos = 0;
static char buf[WRITE_CHUNK_SIZE];
struct file *fp;
mm_segment_t fs;
u8 regAdd[8];
u8 val[8];
int rc;
printk("Michael HU 10Oct2011: Enter LoadConfigFromFile function\n");
//return -1;
fp = filp_open(config_file_path, O_RDONLY, 0644);
if (IS_ERR(fp)) {
printk("Open patch file error\n");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
iPos= 0;
iReadLen = vfs_read(fp, buf, sizeof(buf), &iPos);
if ( iReadLen == 0 )
{
printk("The file is an empty file!\n");
return -1;
}
iPos = 0;
while( iReadLen > 0 )
{
iReadLen = vfs_read(fp, buf, 2, &iPos);
//printk("buf[0] =%c, buf[1]=%c\n", buf[0], buf[1]);
//printk("iReadLen=%d\n", iReadLen);
if ( iReadLen == 2 )
iDataPackLen = strnum_to_digtial(buf, 2);
else if ( iReadLen == 0 )
{
printk("finish reading config file\n");
}
else
{
printk("Pack length is wrong!");
return -1;
}
// iPos = iPos + 2;
iTemp = iPos;
// printk("first iPos = %d\n!", iTemp );
iReadLen = vfs_read(fp, buf, iDataPackLen, &iPos);
if ( iReadLen == iDataPackLen )
SendConfigByFile(ftk_ts, buf,iDataPackLen);
else if ( iReadLen == 0 )
{
printk("finish reading config file\n");
}
else
{
printk("Pack Data is wrong!");
return -1;
}
// iPos = iPos + iDataPackLen;
iTemp = iPos;
// printk("Second iPos = %d\n!", iTemp );
}
#if 1
#ifdef LOAD_PATCH_FOR_FINGERTIPK
regAdd[0] = 0xB0; regAdd[1] = 0x03;
rc=ftk_read_reg(ftk_ts, regAdd, 2, val, 1);
mdelay(5);
printk("Patch loaded, Version =%X \n", val[0]);
#endif
regAdd[0]=0x83; //TS Sense on
regAdd[1]=0x00;
rc = ftk_write_reg(ftk_ts, &regAdd[0],1);
mdelay(5);
#endif
printk("finish LoadConfigFromFile function \n");
return 0;
}
static u8 LoadConfig(struct ftk_ts *ftk_ts)
{
u8 val[8];
u8 regAdd[7];
int rc;
u8 patchConfig = 0xC0;
int b0_i = 0;
int k;
for ( k = 0 ; k <2; k++)
{
regAdd[0] = 0xB0; // All writes below are 1 addr, 1 value
for (b0_i = 0; b0_i < B0_COMMAND_WRITES; ++b0_i ) {
regAdd[1] = B0_command_writes[b0_i].addr;
regAdd[2] = B0_command_writes[b0_i].val;
ftk_write_reg(ftk_ts, &regAdd[0], 3);
mdelay(5);
}
regAdd[0]=0xB3; // Set Upper byte Address
regAdd[1]=0xFF;
regAdd[2]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(5);
regAdd[0]=0xB1; // Set lower byte Address
regAdd[1]=0xFC;
regAdd[2]=0x2F;
regAdd[3]=patchConfig;
ftk_write_reg(ftk_ts, &regAdd[0],4);
mdelay(5);
regAdd[0]=0xB0; // Warm-Boot
regAdd[1]=0x04;
regAdd[2]=0x20;
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(12);
regAdd[1]=0x05; // Set Interrupt Polarity
regAdd[2]=0x01; //'0' - level interrupt '1' - edge interrupt
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(5);
regAdd[1]=0x06; // Enable Touch Detect Interrupt
regAdd[2]=0xC0;
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(5);
regAdd[1]=0x07; //Read 0x07 to clear ISR
rc=ftk_read_reg(ftk_ts, &regAdd[0], 2, &val[0], 1);
mdelay(5);
regAdd[0]=0x85; //Read 0x85 to clear the buffer
rc=ftk_read_reg(ftk_ts, &regAdd[0], 1, &val[0], 8);
mdelay(5);
regAdd[0]=0x85; //Read 0x85 to clear the buffer
rc=ftk_read_reg(ftk_ts, &regAdd[0], 1, &val[0], 8);
mdelay(5);
regAdd[0]=0x81; //TS Sleep out
regAdd[1]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],1);
mdelay(5);
regAdd[0]=0x8A; //Set Area Location
regAdd[1]=0x00; //Touch screen size
regAdd[2]=0x00;
regAdd[3]=0x00;
regAdd[4]=0xFF; //Full screen is used
regAdd[5]=0xFF;
regAdd[6]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],7);
mdelay(5);
regAdd[0]=0x8B; //Set Area layer
regAdd[1]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],2);
mdelay(5);
regAdd[0]=0x8C; //Set Area Event
regAdd[1]=0x00;
regAdd[2]=0x00;
regAdd[3]=0x00;
regAdd[4]=0x00;
regAdd[5]=0x0F;
regAdd[6]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],7);
mdelay(5);
regAdd[0]=0x8D; //Set Area Touches
regAdd[1]=0x00;
regAdd[2]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(5);
regAdd[0]=0x8F; //Touch screen orientation
// regAdd[1]=0xE0;// (Portrait mode)
// regAdd[1]=0x80; //(Landscape Mode)
// regAdd[1]=0x60;// (Portrait mode)
//regAdd[1]=0x00;// (Portrait mode)
regAdd[1]=0x20;// (Portrait mode)
ftk_write_reg(ftk_ts, &regAdd[0],2);
mdelay(5);
#ifdef LOAD_PATCH_FOR_FINGERTIPK
regAdd[0] = 0xB0; regAdd[1] = 0x03;
rc=ftk_read_reg(ftk_ts, regAdd, 2, val, 1);
mdelay(5);
printk("Patch loaded, Version =%X \n", val[0]);
#endif
regAdd[0]=0x83; //TS Sense on
regAdd[1]=0x00;
rc = ftk_write_reg(ftk_ts, &regAdd[0],1);
mdelay(5);
}
if(rc<0)
printk("ftk Not Initialised from loadconfig \n");
else
printk("ftk Initialised from loadconfig\n");
}
#ifdef LOAD_PATCH_FOR_FINGERTIPK
static u8 LoadPatch(struct ftk_ts *ftk_ts)
{
u32 writeAddr, j = 0;
u8 i, byteWork0[2], byteWork1[67], regAdd[3] ={0xB3, 0xB1,0};
while (j<P70_PATCH_LEN)
{
writeAddr = P70_PATCH_ADDR_START + j;
byteWork0[0] = (writeAddr >> 24) & 0xFF;
byteWork0[1] = (writeAddr >> 16) & 0xFF;
regAdd[0] =0xB3;
regAdd[1] =byteWork0[0];
regAdd[2] =byteWork0[1];
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(10);
byteWork1[0]= 0xB1;
byteWork1[1] = (writeAddr >> 8) & 0xFF;
byteWork1[2] = writeAddr & 0xFF;
i = 0;
while ((j<P70_PATCH_LEN) && (i<WRITE_CHUNK_SIZE))
{
byteWork1[i+3] = PatchData[j];
i++;
j++;
}
ftk_write_reg(ftk_ts, &byteWork1[0],67);
mdelay(10);
}
mdelay(10);
return 0;
}
static u8 Is_file_exist()
{
struct file *fp;
fp = filp_open(patch_file_path, O_RDONLY, 0644);
if (IS_ERR(fp)) {
printk("Patch file doesn't exist %s\n", patch_file_path);
return -1;
}
else
{
filp_close(fp, NULL);
printk("Patch file exist\n");
}
fp = filp_open(config_file_path, O_RDONLY, 0644);
if (IS_ERR(fp)) {
printk("Config file doesn't exist %s\n", config_file_path);
return -1;
}
else
{
filp_close(fp, NULL);
printk("Config file exist\n");
return 0;
}
}
//u32 ChangeNum(String str,int length)
static u32 strnum_to_digtial( char * inputStrData, int length)
{
// char revstr[16] = {'0'};
int num[16] = {0};
int count = 1;
int result = 0;
int i;
// wsprintfA(revstr, "%S", str);
for ( i=length-1;i>=0;i--)
{
if ((inputStrData[i] >= '0') && (inputStrData[i] <= '9'))
num[i] = inputStrData[i] - 48;
else if ((inputStrData[i] >= 'a') && (inputStrData[i] <= 'f'))
num[i] = inputStrData[i] - 'a' + 10;
else if ((inputStrData[i] >= 'A') && (inputStrData[i] <= 'F'))
num[i] = inputStrData[i] - 'A' + 10;
else
num[i] = 0;
result = result+num[i] * count;
count = count * 16;
}
return result;
}
u8 get_data_from_file(struct file *fp, char * buffer)
{
static char raw_data_buf[WRITE_CHUNK_SIZE*2];
u32 iReadLen = 0, i = 0, iTemp = 0;
u32 iValue = 0;
loff_t iPos = 0;
iReadLen = vfs_read(fp, raw_data_buf, sizeof(raw_data_buf), &iPos);
iTemp = iPos;
printk("get_data_from_file iPos = %d!\n", iTemp);
for ( i = 0; i < WRITE_CHUNK_SIZE; i++)
{
buffer[i] = strnum_to_digtial( &raw_data_buf[i*2], 2 );
//printk("%02X ",buffer[i]);
}
//printk("\n iReadLen = %d, div/6= %d\n", iReadLen, iReadLen/6);
return (iReadLen/2);
}
static u8 LoadPatchFromFile(struct ftk_ts *ftk_ts)
{
u32 writeAddr, j = 0, iReadLen = 0, iTemp = 0;
u8 i, byteWork0[2], byteWork1[67], regAdd[3] ={0xB3, 0xB1,0};
static char buf[WRITE_CHUNK_SIZE];
struct file *fp;
mm_segment_t fs;
loff_t iPos = 0;
printk("Enter LoadPatchFromFile function\n");
fp = filp_open(patch_file_path, O_RDONLY, 0644);
if (IS_ERR(fp)) {
printk("Open patch file error\n");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
iPos= 0;
iReadLen = vfs_read(fp, buf, sizeof(buf), &iPos);
if ( iReadLen == 0 )
{
printk("The file is an empty file!\n");
return -1;
}
iPos= 0;
while (1)
{
writeAddr = P70_PATCH_ADDR_START + j;
//printk("j = %d\n, ", j);
byteWork0[0] = (writeAddr >> 24) & 0xFF;
byteWork0[1] = (writeAddr >> 16) & 0xFF;
regAdd[0] =0xB3;
regAdd[1] =byteWork0[0];
regAdd[2] =byteWork0[1];
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(10);
byteWork1[0]= 0xB1;
byteWork1[1] = (writeAddr >> 8) & 0xFF;
byteWork1[2] = writeAddr & 0xFF;
i = 0;
//iReadLen = vfs_read(fp, buf, sizeof(buf), &iPos);
//iReadLen = get_data_from_file(fp, buf);
//printk("\niReadLen = %d!\n", iReadLen);
{
static char raw_data_buf[WRITE_CHUNK_SIZE*2];
u32 k = 0;
u32 iValue = 0;
iReadLen = vfs_read(fp, raw_data_buf, sizeof(raw_data_buf), &iPos);
iTemp = iPos;
//printk("get_data_from_file iPos = %d!\n", iTemp);
for ( k = 0; k < WRITE_CHUNK_SIZE; k++)
{
buf[k] = strnum_to_digtial( &raw_data_buf[k*2], 2 );
//printk("%02X ",buffer[i]);
}
iReadLen = iReadLen / 2;
}
if ( iReadLen < sizeof(buf) )
{
while (i < iReadLen )
{
byteWork1[i+3] = buf[i];
//printk("%02X, ", buf[i]);
//if ( buf[i] != PatchData[j] )
//printk("Read data is different: j=%d, data=%02X, patchData=%02X\n", j, buf[i], PatchData[j] );
i++;
j++;
}
ftk_write_reg(ftk_ts, &byteWork1[0],iReadLen+3);
mdelay(10);
printk("It is the last group of data!j =%d\n", j);
break;
}
while (i<WRITE_CHUNK_SIZE)
{
byteWork1[i+3] = buf[i];
//printk("%02X, ", buf[i]);
//if ( buf[i] != PatchData[j] )
//printk("Read data is different: j=%d, data=%02X, patchData=%02X\n", j, buf[i], PatchData[j] );
i++;
j++;
}
ftk_write_reg(ftk_ts, &byteWork1[0],WRITE_CHUNK_SIZE+3);
mdelay(10);
//printk("\n---------------------------------\n ");
}
filp_close(fp, NULL);
set_fs(fs);
//mdelay(10);
return 0;
}
#endif
static int write_config_file(struct ftk_ts *ftk_ts)
{
u8 regAdd[8];
int b0_i = 0;
regAdd[0] = 0xB0; // All writes below are 1 addr, 1 value
for (b0_i = 0; b0_i < B0_COMMAND_WRITES; ++b0_i ) {
regAdd[1] = B0_command_writes[b0_i].addr;
regAdd[2] = B0_command_writes[b0_i].val;
ftk_write_reg(ftk_ts, &regAdd[0], 3);
mdelay(5);
}
regAdd[0] = 0xB3;
regAdd[1] = 0xFF;
regAdd[2] = 0xFF;
ftk_write_reg(ftk_ts, &regAdd[0], 3);
mdelay(5);
regAdd[0] = 0xB1;
regAdd[1] = 0xFC;
regAdd[2] = 0x2F;
regAdd[3] = 0xC0;
ftk_write_reg(ftk_ts, &regAdd[0], 4);
mdelay(5);
regAdd[0] = 0xB0;
regAdd[1] = 0x04;
regAdd[2] = 0x20;
ftk_write_reg(ftk_ts, &regAdd[0], 3);
mdelay(5);
regAdd[0]=0x81; //TS Sleep out
regAdd[1]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],1);
mdelay(5);
regAdd[0]=0x8A; //Set Area Location
regAdd[1]=0x00; //Touch screen size
regAdd[2]=0x00;
regAdd[3]=0x00;
regAdd[4]=0xFF; //Full screen is used
regAdd[5]=0xFF;
regAdd[6]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],7);
mdelay(5);
regAdd[0]=0x8B; //Set Area layer
regAdd[1]=0x00;
regAdd[2]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(5);
regAdd[0]=0x8C; //Set Area Event
regAdd[1]=0x00;
regAdd[2]=0x00;
regAdd[3]=0x00;
regAdd[4]=0x00;
regAdd[5]=0x0F;
regAdd[6]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],7);
mdelay(5);
regAdd[0]=0x8D; //Set Area Touches
regAdd[1]=0x00;
regAdd[2]=0xFF;
ftk_write_reg(ftk_ts, &regAdd[0],3);
mdelay(5);
regAdd[0]=0x83; //Set Area layer
regAdd[1]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],2);
mdelay(5);
regAdd[0]=0x80; //Set Area layer
regAdd[1]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],2);
mdelay(5);
regAdd[0]=0x81; //Set Area layer
regAdd[1]=0x00;
ftk_write_reg(ftk_ts, &regAdd[0],2);
mdelay(5);
}
static int init_ftk(struct ftk_ts *ftk_ts)
{
u8 val[8];
u8 regAdd[7];
int rc;
u8 patchConfig = 0x80;
int b0_i = 0;
#if 1
regAdd[0]=0xB0;
regAdd[1]=0x00;
rc=ftk_read_reg(ftk_ts, regAdd, 2, val, 3);
if (rc < 0) {
printk(KERN_ERR " : i2c_transfer failed\n");
}
mdelay(5);
printk("Chip ID = %x %x %x\n" , val[0], val[1], val[2]);
printk(" Michael Hu 15Oct2011: Read Chip ID finished!\n");
#endif
#if 1
regAdd[0]=0x9E; //TS Soft Reset
ftk_write_reg(ftk_ts, &regAdd[0],1);
mdelay(5);
if( Is_file_exist() == 0 )
{
#ifdef LOAD_PATCH_FOR_FINGERTIPK
if ( LoadPatchFromFile(ftk_ts) == 0)
#endif
{
LoadConfigFromFile(ftk_ts);
mdelay(5);
// LoadConfigFromFile(ftk_ts);
// mdelay(5);
// LoadConfig(ftk_ts);
}
}
#ifdef LOAD_PATCH_FOR_FINGERTIPK
else if (LoadPatch(ftk_ts) == 0)
#endif
{
LoadConfig(ftk_ts);
}
if(rc<0)
printk("ftk Not Initialised\n");
else
printk("ftk Initialised\n");
#endif
return 0;
}
static void newdata(struct ftk_ts * ftkts, u8 id)
{
// printk("id=%d, x=%d, y=%d \n", id, ftkts->x, ftkts->y);
// input_report_abs(ftkts->input_dev, ABS_MT_TRACKING_ID, id);
input_report_abs(ftkts->input_dev, ABS_MT_POSITION_X, ftkts->x);
input_report_abs(ftkts->input_dev, ABS_MT_POSITION_Y, ftkts->y);
input_report_abs(ftkts->input_dev, ABS_MT_TOUCH_MAJOR, ftkts->z);
#if 0
if (ftkts->z){
input_report_abs(ftkts->input_dev, ABS_MT_TOUCH_MAJOR, 10);
}
else{
input_report_abs(ftkts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
}
#endif
input_mt_sync(ftkts->input_dev);
}
static enum hrtimer_restart st_ts_timer_func(struct hrtimer *timer)
{
struct ftk_ts *ftkts = container_of(timer, struct ftk_ts, timer);
queue_work(stmtouch_wq, &ftkts->work);
return HRTIMER_NORESTART;
}
static irqreturn_t ts_interrupt(int irq, void *handle)
{
struct ftk_ts *ftk_ts = handle;
disable_irq_nosync(ftk_ts->client->irq);
queue_work(stmtouch_wq, &ftk_ts->work);
return IRQ_HANDLED;
}
int iPrintTimes = 0; //add by ;
static void SendDataOut(struct ftk_ts *ftkts, int x, int y, int z, int EventID, int TouchID, int NumTouches )
{
int i,j ;
if ((EventID == 0x03)||(EventID == 0x05))
{
// printk("EventID=%d, IDj = %d, TouchID = %d, NumTouches = %d \n",EventID, IDj, TouchID, NumTouches);
if ( EventID == 0x03 )
{
ID_Indx[IDj] = TouchID; //Add New ID In
IDj=IDj+1;
}
//printk("num1= %d \n",IDj);
cor_xyz[TouchID][0] = x;
cor_xyz[TouchID][1] = y;
cor_xyz[TouchID][2] = z;
for( i = 0; i < IDj; i++ )
{
// printk("IDj = %d; i = %d; \n", IDj, i );
// printk("ID_Indx[i] = %d, x = %d, y = %d \n", ID_Indx[i], cor_xyz[ID_Indx[i]][0], cor_xyz[ID_Indx[i]][1]);
ftkts->x=cor_xyz[ID_Indx[i]][0];
ftkts->y=cor_xyz[ID_Indx[i]][1];
ftkts->z=cor_xyz[ID_Indx[i]][2];
newdata(ftkts, ID_Indx[i]);
//printk("EventID=%d, ID_Indx[%d] = %d, x = %d, y = %d \n",EventID, i, ID_Indx[i], cor_xyz[ID_Indx[i]][0], cor_xyz[ID_Indx[i]][1]);
}
input_sync(ftkts->input_dev);
}
else if (EventID == 0x04)
{
for (j = 0; j < IDj; j++)
{
if (ID_Indx[j]==TouchID)
{
do
{
ID_Indx[j]=ID_Indx[j+1]; //update the Indx
j++;
}while(j<10);
// j=IDj+1;
break;
}
}
if ( IDj > 0 )
IDj = IDj - 1;
#if 1
if ( IDj== 0)
{
input_mt_sync(ftkts->input_dev);
//input_sync(ftkts->input_dev);
}
for( i = 0; i < IDj; i++ )
{
//printk("EventID=%d, ID_Indx[%d] = %d, x = %d, y = %d \n",EventID, i, ID_Indx[i], cor_xyz[ID_Indx[i]][0], cor_xyz[ID_Indx[i]][1]);
ftkts->x=cor_xyz[ID_Indx[i]][0];
ftkts->y=cor_xyz[ID_Indx[i]][1];
ftkts->z=cor_xyz[ID_Indx[i]][2];
newdata(ftkts, ID_Indx[i]);
}
#endif
//input_mt_sync(ftkts->input_dev);
input_sync(ftkts->input_dev);
//printk("EventID=%d, IDj = %d, TouchID = %d \n",EventID, IDj, TouchID);
}
}
static void ts_tasklet_proc(struct work_struct *work)
{
// struct stmpe32m28_ts *stmpe32m28ts = container_of(work, struct stmpe32m28_ts, work);
struct ftk_ts *ftkts = container_of(work, struct ftk_ts, work);
unsigned char data[129];
int x, y,z;
int rc;
u8 status;
u8 regAdd;
u8 writeCMD[3];
u8 FoundFlag=0;
u8 LeftEvent = 0;
u8 FirstLeftEvent = 0;
u8 EventNum=0;
u8 NumTouches=0;
u8 EventNum2=0;
u8 TouchID, EventID;
u8 i,j;
//u8 regAdd2[2];
//u8 val[2];
writeCMD[0]=0xB0; //disable interrupt;
writeCMD[1]=0x06;
writeCMD[2]=0x00;
ftk_write_reg(ftkts, &writeCMD[0],3);
//mdelay(1);
data[0]=0xB0;
data[1]=0x07;
rc=ftk_read_reg(ftkts, &data[0], 2, &status, 1);
ftkts->pendown = 0;
EventNum=0;
do
{
regAdd=0x85;
data[0]=0;
rc=ftk_read_reg(ftkts, &regAdd, 1, data, 8);
FirstLeftEvent=data[7+EventNum*8]&0x0F;
NumTouches=(data[1+EventNum*8]&0xF0)>>4;
TouchID=data[1+EventNum*8]&0x0F;
EventID=data[EventNum*8]&0x0F;
x=((data[4+EventNum*8]&0xF0)>>4)|((data[2+EventNum*8])<<4);
y=((data[4+EventNum*8]&0x0F)|((data[3+EventNum*8])<<4));
z=data[5+EventNum*8];
// printk("FirstLeftEvent=%d, EventID=%d, TouchID = %d, NumTouches = %d, x=%d, y=%d \n", FirstLeftEvent, EventID, TouchID, NumTouches, x, y);
SendDataOut(ftkts, x, y, z, EventID, TouchID, NumTouches);
}while( FirstLeftEvent > 0);
writeCMD[0]=0xB0; //disable interrupt;
writeCMD[1]=0x06;
writeCMD[2]=0x50;
ftk_write_reg(ftkts, &writeCMD[0],3);
mdelay(1);
if (!ftkts->irq) {
hrtimer_start(&ftkts ->timer, ktime_set(0, 10000000), HRTIMER_MODE_REL);
}
else
{
enable_irq(ftkts->client->irq);
}
}
static int stm_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp)
{
struct ftk_ts *ftk_ts = NULL;
struct ftk_i2c_platform_data *pdata;
int ret = 0;
int err = 0;
int i;
printk( "++ftkts_probe:04Nov 09:13 2011\n");
#if 1
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){
printk(KERN_ERR " :err = EIO! \n");
err = EIO;
goto fail;
}
ftk_ts = kzalloc(sizeof(struct ftk_ts), GFP_KERNEL);
if (!ftk_ts){
printk(KERN_ERR " :err = ENOMEM! \n");
err = ENOMEM;
goto fail;
}
INIT_WORK(&ftk_ts->work, ts_tasklet_proc);
ftk_ts->client=client;
i2c_set_clientdata(client,ftk_ts);
#endif
//begin add by ; 02Aug2011;
#if 1
pdata = client->dev.platform_data;
if (pdata)
{
printk(" :Get pdata! \n");
ftk_ts->power = pdata->power; //remove for test the only power;
}
else
{
printk(" :not get pdata! \n");
}
if (ftk_ts->power) {
printk("Power affect tested!\n");
ret = ftk_ts->power(1);
pdata->power(1);
if (ret < 0) {
pr_err(" :ftk_probe power on failed\n");
goto fail;
}
else
printk(" :ftk_probe power on successfully! \n");
}
#else
printk("Power affect tested!\n");
pdata = client->dev.platform_data;
if (pdata)
{
printk(" :Get pdata! \n");
pdata->power(1);
if (ret < 0) {
pr_err(" :ftk_probe power on failed\n");
goto fail;
}
else
printk(" :ftk_probe power on successfully! \n");
}
else
{
printk(" :not get pdata! \n");
}
//end add by ; 02Aug2011;
#endif
#if 1
ftk_ts->dev = &ftk_ts->client->dev;
ftk_ts->input_dev = input_allocate_device();
ftk_ts->input_dev->dev.parent = &client->dev;
if(!ftk_ts->input_dev){
err = ENOMEM;
goto fail;
}
ftk_ts->input_dev->name = "ftk";
ftk_ts->input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
ftk_ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
set_bit(EV_SYN, ftk_ts->input_dev->evbit);
set_bit(EV_KEY,ftk_ts->input_dev->evbit);
set_bit(BTN_TOUCH,ftk_ts->input_dev->keybit);
set_bit(BTN_2,ftk_ts->input_dev->keybit);
set_bit(EV_ABS,ftk_ts->input_dev->evbit);
input_set_abs_params(ftk_ts->input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_MT_TRACKING_ID, 0, 10, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_MT_TOUCH_MAJOR, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_MT_WIDTH_MAJOR, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_MT_POSITION_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
input_set_abs_params(ftk_ts->input_dev, ABS_MT_POSITION_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
err=input_register_device(ftk_ts->input_dev);
if(err) {
goto fail;
}
err = init_ftk(ftk_ts);
if(err) {
goto fail;
}
ftk_ts->irq=client->irq;
#if 1
if (!ftk_ts->irq) {
hrtimer_init(&ftk_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ftk_ts->timer.function = st_ts_timer_func;
hrtimer_start(&ftk_ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
printk(KERN_INFO " : hrtimer_start\n");
}
else
{
printk(KERN_INFO " :ftk_ts->irq = %d! \n", ftk_ts->irq);
if(request_irq(ftk_ts->irq, ts_interrupt, IRQF_TRIGGER_FALLING, client->name, ftk_ts)) {
printk(KERN_INFO " :request_irq fail! \n");
err = -EBUSY;
goto fail;
}
printk(KERN_INFO " :request_irq successfully! \n");
}
#ifdef CONFIG_HAS_EARLYSUSPEND
ftk_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ftk_ts->early_suspend.suspend = stm_ts_early_suspend;
ftk_ts->early_suspend.resume =stm_ts_late_resume;
register_early_suspend(&ftk_ts->early_suspend);
#endif
#else
printk(KERN_INFO " :remove interrupt and timer handler \n");
#endif
#endif
return 0;
fail:
if(ftk_ts) {
if(ftk_ts->input_dev)
input_free_device(ftk_ts->input_dev);
kfree(ftk_ts);
}
printk("--ftkts_probe ret=%d\n", err);
return err;
}
static int stm_ts_remove(struct i2c_client *client)
{
// struct ftk_ts *priv = dev_get_drvdata(&client->dev);
struct ftk_ts *ts = i2c_get_clientdata(client);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&ts->early_suspend);
#endif
printk("Hello from Remove: 12Oct2011 \n");
// if (priv->irq)
// free_irq(priv->irq, priv);
if (ts->irq)
free_irq(client->irq, ts);
else
hrtimer_cancel(&ts->timer);
input_unregister_device(ts->input_dev);
//kfree(priv);
kfree(ts);
//dev_set_drvdata(&client->dev, NULL);
return 0;
}
static int stm_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
int ret;
u8 regAdd[2];
struct ftk_ts *ts = i2c_get_clientdata(client);
printk( "enter stm_ts_suspend\n");
if (ts->irq)
{
printk( "enter disable_irq\n");
disable_irq(client->irq);
}
else
{
printk( "enter hrtimer_cancel\n");
hrtimer_cancel(&ts->timer);
}
regAdd[0]=0x80; //TS Sleep in
regAdd[1]=0x00;
ret = ftk_write_reg(ts, &regAdd[0],1);
mdelay(5);
if (ret < 0)
printk( "stm_ts_suspend: i2c_smbus_write_byte_data failed\n");
return 0;
}
static int stm_ts_resume(struct i2c_client *client)
{
int ret;
u8 regAdd[2];
struct ftk_ts *ts = i2c_get_clientdata(client);
printk( "enter stm_ts_resume\n");
if (ts->irq)
{
printk( "enter disable_irq\n");
enable_irq(client->irq);
}
else
{
printk( "enter hrtimer_cancel\n");
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
regAdd[0]=0x81; //TS Sleep out
regAdd[1]=0x00;
ret = ftk_write_reg(ts, &regAdd[0],1);
mdelay(5);
if (ret < 0)
printk(KERN_ERR "stm_ts_suspend: i2c_smbus_write_byte_data failed\n");
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void stm_ts_early_suspend(struct early_suspend *h)
{
struct ftk_ts *ts;
ts = container_of(h, struct ftk_ts, early_suspend);
stm_ts_suspend(ts->client, PMSG_SUSPEND);
}
static void stm_ts_late_resume(struct early_suspend *h)
{
struct ftk_ts *ts;
ts = container_of(h, struct ftk_ts, early_suspend);
stm_ts_resume(ts->client);
}
#endif
static const struct i2c_device_id stm_ts_id[] = {
{ "ftk", 0 },
{ }
};
static struct i2c_driver stm_ts_driver = {
.driver = {
.name = "ftk",
},
.probe = stm_ts_probe,
.remove = stm_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = stm_ts_suspend,
.resume = stm_ts_resume,
#endif
.id_table = stm_ts_id,
};
static int __init stm_ts_init(void)
{
stmtouch_wq = create_singlethread_workqueue("stmtouch_wq");
if (!stmtouch_wq)
return -ENOMEM;
return i2c_add_driver(&stm_ts_driver);
}
static void __exit stm_ts_exit(void)
{
i2c_del_driver(&stm_ts_driver);
if (stmtouch_wq)
destroy_workqueue(stmtouch_wq);
}
MODULE_DESCRIPTION("STM MultiTouch IC Driver");
MODULE_AUTHOR("Bela Somaiah");
MODULE_LICENSE("GPL");
module_init(stm_ts_init);
module_exit(stm_ts_exit);