Example #1
0
static int touch_event_handler(void *unused)
{
    struct sched_param param = { .sched_priority = RTPM_PRIO_TPD }; 
    static int x1, y1, x2, y2, raw_x1, raw_y1, raw_x2, raw_y2;
    int temp_x1 = x1, temp_y1 = y1, temp_raw_x1 = raw_x1, temp_raw_y1 = raw_y1;
    int lastUp_x = 0, lastUp_y = 0;
    char buffer[10];
    int ret = -1, touching, oldtouching;//int pending = 0
    unsigned char Wrbuf[1] = {0};
    
    sched_setscheduler(current, SCHED_RR, &param); 
    do{
        set_current_state(TASK_INTERRUPTIBLE);
        while (tpd_halt) {tpd_flag = 0; msleep(20);}
        wait_event_interruptible(waiter, tpd_flag != 0);
        tpd_flag = 0;
        TPD_DEBUG_SET_TIME;
        set_current_state(TASK_RUNNING); 

        i2c_client->addr = ( i2c_client->addr & I2C_MASK_FLAG ) | I2C_ENEXT_FLAG;
        ret = i2c_master_send(i2c_client, Wrbuf, 1);
        if(ret != sizeof(Wrbuf))
        {
            TPD_DEBUG("[mtk-tpd] i2c write communcate error: 0x%x\n", ret);
            continue;
        }
        i2c_client->addr = ( ( i2c_client->addr & I2C_MASK_FLAG ) | I2C_DMA_FLAG ) | I2C_ENEXT_FLAG;
        ret = tpd_i2c_read(i2c_client, buffer, 7);
        buffer[7] = buffer[8] = buffer[9] = 0;
        if (ret != 7)//sizeof(buffer)
        {
            TPD_DEBUG("[mtk-tpd] i2c read communcate error: 0x%x\n", ret);
            continue;
        }
        i2c_client->addr = i2c_client->addr & I2C_MASK_FLAG;

        touching = buffer[0];
        if(touching > 0) 
        {
            raw_x1 = x1 = ((buffer[3] << 8) | buffer[2]);
            raw_y1 = y1 = ((buffer[5] << 8) | buffer[4]);
        }
        if(touching > 1)
        {
            raw_x2 = x2 = ((buffer[7] << 8) | buffer[6]);
            raw_y2 = y2 = ((buffer[9] << 8) | buffer[8]);
        }
        oldtouching = buffer[1]; 
        TPD_DEBUG("[mtk-tpd]:raw_x1:%d, raw_y1:%d, raw_x2:%d, raw_y2:%d\n", raw_x1, raw_y1, raw_x2, raw_y2);
        TPD_DEBUG("[mtk-tpd]:touch:%d, old_touch:%d\n", touching, oldtouching);
        switch(touching)
        {
        case 0:
            /* touching=0, oldtouching 0 is invalid */
            if(oldtouching > 0)
            {
                //tpd_up(raw_y1, raw_x1, y1, x1, 0);	
                //tpd_up(raw_x1, raw_y1, x1, y1, 0);
                lastUp_x = x1;
                lastUp_y = y1;
            }
            if(oldtouching > 1)
            {
                //tpd_up(raw_y2, raw_x2, y2, x2, 0);	
                //tpd_up(raw_x2, raw_y2, x2, y2, 0);
                //lastUp_x = x1;
                //lastUp_y = y1;
            }
            tpd_up(lastUp_x, lastUp_y, lastUp_x, lastUp_y, 0);
            break;
        case 1:
            tpd_calibrate(&x1, &y1);
            //tpd_down(raw_y1, raw_x1, y1, x1, 1);
            tpd_down(raw_x1, raw_y1, x1, y1, 1);
            if(oldtouching == 2)
            {
                if(abs(x1 - x2) < 2 && abs(y1 - y2) < 2) // need to adjust.
                {
                    //tpd_up(temp_raw_y1, temp_raw_x1, temp_y1, temp_x1, 0);
                    
                    //For ICS
                    //tpd_up(temp_raw_x1, temp_raw_y1, temp_x1, temp_y1, 0);
                }
                else
                {
                    //tpd_up(raw_y2, raw_x2, y2, x2, 0);
                    
                    //For ICS
                    //tpd_up(raw_x2, raw_y2, x2, y2, 0);
                }
            }
            break;
        case 2:
            tpd_calibrate(&x1, &y1);
            //tpd_down(raw_y1, raw_x1, y1, x1, 1);
            tpd_down(raw_x1, raw_y1, x1, y1, 1);
            //tpd_calibrate(&x2, &y2);
            //tpd_down(raw_y2, raw_x2, y2, x2, 1);
            //tpd_down(raw_x2, raw_y2, x2, y2, 1);
            break;
        default:
            TPD_DEBUG("[mtk-tpd] invalid touch num: 0x%x\n", touching);
            continue;
        }
        temp_x1 = x1;
        temp_y1 = y1;      
        temp_raw_x1 = raw_x1;
        temp_raw_y1 = raw_y1;
        input_sync(tpd->dev);
        
    } while (!kthread_should_stop()); 
    return 0;
}
static int touch_event_handler(void *unused) {
    struct sched_param param = { .sched_priority = RTPM_PRIO_TPD }; 
    int x1=0, y1=0, x2=0, y2=0, x3=0, y3=0, x4=0, y4=0, p1=0, p2=0, p3=0, p4=0, id1=0xf, id2=0xf, id3=0xf, id4 = 0xf, pre_id1 = 0xf, pre_id2 = 0xf, pre_id3 = 0xf, pre_id4 = 0xf, pre_tt_mode = 0, finger_num = 0, pre_num = 0;
    int raw_x1=0, raw_y1=0, raw_x2=0, raw_y2=0, raw_x3=0, raw_y3=0, raw_x4=0, raw_y4=0;
    static char toggle;
    static char buffer[32];//[16];
//    int pending = 0;
	u32 temp;
    sched_setscheduler(current, SCHED_RR, &param); 
    g_temptimerdiff=get_jiffies_64();//jiffies;
    do {
		if(tpd_debuglog==1) {
			TPD_DMESG("[mtk-tpd] %s\n", __FUNCTION__); 
		}	    	
        set_current_state(TASK_INTERRUPTIBLE);
	if(tpd_debuglog==1)
		TPD_DMESG("[mtk-tpd], %s, tpd_halt=%d\n", __FUNCTION__, tpd_halt);
        while (tpd_halt) {tpd_flag = 0; msleep(20);}
        #ifndef POLL_MODE
        wait_event_interruptible(waiter, tpd_flag != 0);
        tpd_flag = 0;
        #endif
        TPD_DEBUG_SET_TIME;
        set_current_state(TASK_RUNNING); 
	//	#ifndef CY8CTMA300_CHARGE
		#if 0			
		temp =  *(volatile u32 *)CHR_CON0;	
		temp &= (1<<13);
		if(temp!=0)
		{
			   if(tpd_debuglog==1)	
			   	TPD_DMESG("[mtk-tpd], write 0x01 to 0x1D register!!\n");
			   buffer[0] = 0x01;
			   buffer[0] = 0x01;
			   i2c_smbus_write_i2c_block_data(i2c_client, 0x1D, 1, &(buffer[0]));    		
		}
		else
		{
			   if(tpd_debuglog==1)			
			   	TPD_DMESG("[mtk-tpd], write 0x00 to 0x1D register!!\n");
			   buffer[0] = 0x00;
			   i2c_smbus_write_i2c_block_data(i2c_client, 0x1D, 1, &(buffer[0])); 			
		} 
		#endif	
		#ifndef TPD_NO_GPIO 	    // for mt6575T fpga early porting    
        if (tpd_show_version) {
            tpd_show_version = 0;
                        
            mt_set_gpio_mode(GPIO1, 0x00);
            mt_set_gpio_dir(GPIO1, GPIO_DIR_OUT);
            mt_set_gpio_pull_enable(GPIO1, GPIO_PULL_ENABLE);
            mt_set_gpio_pull_select(GPIO1, GPIO_PULL_UP);
            
            mt_set_gpio_out(GPIO1, GPIO_OUT_ZERO);
            msleep(100);            
                        
            buffer[0] = 0x01; // reset touch panel mode
            i2c_smbus_write_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0]));
            msleep(200);
            
            buffer[0] = 0x10; // swith to system information mode
            i2c_smbus_write_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0]));
            msleep(200);
            
            i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 8, &(buffer[0x0]));
            i2c_smbus_read_i2c_block_data(i2c_client, 0x08, 8, &(buffer[0x8]));
            i2c_smbus_read_i2c_block_data(i2c_client, 0x10, 8, &(buffer[0x10]));
            i2c_smbus_read_i2c_block_data(i2c_client, 0x18, 8, &(buffer[0x18]));
            printk("[mtk-tpd] Cypress Touch Panel ID %x.%x\n", buffer[0x07], buffer[0x08]);            
            printk("[mtk-tpd] Cypress Touch Panel Firmware Version %x.%x\n", buffer[0x15], buffer[0x16]); 
            buffer[0] = 0x04; // switch to operation mode
            i2c_smbus_write_i2c_block_data(i2c_client, 0x00, 1, &(buffer[0]));
            msleep(200);
                      
            mt_set_gpio_out(GPIO1, GPIO_OUT_ONE);            
            mt_set_gpio_mode(GPIO1, 0x01);
            mt_set_gpio_pull_enable(GPIO1, GPIO_PULL_ENABLE);
            mt_set_gpio_pull_select(GPIO1, GPIO_PULL_UP);           
            continue;
        }        
      #endif  
        i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 8, &(buffer[0]));
        i2c_smbus_read_i2c_block_data(i2c_client, 0x08, 8, &(buffer[8]));
        i2c_smbus_read_i2c_block_data(i2c_client, 0x10, 8, &(buffer[16]));
        i2c_smbus_read_i2c_block_data(i2c_client, 0x18, 8, &(buffer[24]));		
	if(tpd_debuglog==1)
	{
        TPD_DMESG("[mtk-tpd]HST_MODE  : %x\n", buffer[0]); 
        TPD_DMESG("[mtk-tpd]TT_MODE   : %x\n", buffer[1]); 
        TPD_DMESG("[mtk-tpd]TT_STAT   : %x\n", buffer[2]);
       // TPD_DEBUG("[mtk-tpd]TOUCH_ID  : %x\n", buffer[8]);
		TPD_DMESG("[mtk-tpd]TOUCH_12ID  : %x\n", buffer[8]);
		TPD_DMESG("[mtk-tpd]TOUCH_34ID  : %x\n", buffer[21]);
	}	
        
        finger_num = buffer[2] & 0x0f;
        
        if (finger_num == 0 && pre_num ==0) {
            msleep(10);
            tpd_flag = 0;
            pre_tt_mode = buffer[1];
            continue;   
        }
        
        if (pre_tt_mode == buffer[1]) {
            msleep(5);
            tpd_flag = 0;
            pre_tt_mode = buffer[1];
            continue;  
        }
        
        if (buffer[1] & 0x20) {
            TPD_DEBUG("buffer not ready\n");
            tpd_flag = 0;
            pre_tt_mode = buffer[1];
            continue; // buffer is not ready for use
        }
        
        id1 = (buffer[8] & 0xf0) >> 4;
        id2 = (buffer[8] & 0x0f);
		id3 = (buffer[21] & 0xf0) >> 4;
		id4 = (buffer[21] & 0x0f);
                
//        if (id1 != 0xf) { 
	   if(finger_num>=1) {
            x1 = (((int)buffer[3]) << 8) + buffer[4]; 
            y1 = (((int)buffer[5]) << 8) + buffer[6]; 
            if(x1>2048 || y1>2048) {
	            tpd_flag = 0;
	            pre_tt_mode = buffer[1];  
	            continue;          		
            	}
            p1 = buffer[7];
            raw_x1 = x1; raw_y1 = y1;
            tpd_calibrate(&x1, &y1);
            tpd_down(raw_x1, raw_y1, x1, y1, p1);
            if(counter_pointer==0)
            	g_temptimerdiff=get_jiffies_64();//jiffies;
            if(x_min==0&&y_min==0&&x_max==0&&y_max==0) {
            		x_min = x1;
            		y_min = y1;
            		x_max = x1;
            		y_max = y1;
            	}
            if(x1<x_min)
            	x_min = x1;
            if(x1>x_max)
            	x_max = x1;
            if(y1<y_min)
            	y_min = y1;
            if(y1>y_max)
            	y_max = y1;
            counter_pointer++;
            if (time_after(jiffies, g_temptimerdiff + 100)){	//1s
            	TPD_DMESG("[mtk-tpd], x_min=%d, y_min=%d, x_max=%d, y_max=%d, counter_pointer=%d!!\n", x_min, y_min, x_max, y_max, counter_pointer);
            	x_min=0;
            	y_min=0;
            	x_max=0;
            	y_max=0;
            	counter_pointer=0;
            }
        }
        
//        if (id2 != 0xf || finger_num==2) {
	    if(finger_num>=2) {
            x2 = (((int)buffer[9]) << 8) + buffer[10]; 
            y2 = (((int)buffer[11]) << 8) + buffer[12]; 
            p2 = buffer[13];
            raw_x2 = x2; raw_y2 = y2;
            tpd_calibrate(&x2, &y2);
            tpd_down(raw_x2, raw_y2, x2, y2, p2);
        }
//	if(id3 != 0xf || finger_num==3) {
	    if(finger_num>=3) {
            x3 = (((int)buffer[16]) << 8) + buffer[17]; 
            y3= (((int)buffer[18]) << 8) + buffer[19]; 
            p3= buffer[20];
            raw_x3 = x3; raw_y3 = y3;
            tpd_calibrate(&x3, &y3);
            tpd_down(raw_x3, raw_y3, x3, y3, p3); 
		}

//	if(id4 != 0xf || finger_num==4) {
	    if(finger_num>=4) {
            x4 = (((int)buffer[22]) << 8) + buffer[23]; 
            y4= (((int)buffer[24]) << 8) + buffer[25]; 
            p4= buffer[26];
            raw_x4 = x4; raw_y4 = y4;
            tpd_calibrate(&x4, &y4);
            tpd_down(raw_x4, raw_y4, x4, y4, p4); 
		}	
        
	if(pre_num>=1 && pre_id1==0xf) {
		if(finger_num>=1 && id1==0xf) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger1 is still down!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger1 is up!!\n");
			tpd_up(raw_x1, raw_y1, x1, y1, p1);
		}		
		
	} else if(pre_num>=1 && pre_id1 !=0xf) {
		if(id1==pre_id1) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger1 is still down!!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger1 is up!\n");
			tpd_up(raw_x1, raw_y1, x1, y1, p1);
		}
	}
	
	if(pre_num>=2 && pre_id2==0xf) {
		if((finger_num>=2 && id2==0xf) || (finger_num==1 && id1==0xf)) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger2 is still down!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger2 is up!!\n");
			tpd_up(raw_x2, raw_y2, x2, y2, p2);
		}		
		
	} else if(pre_num>=2 && pre_id2 !=0xf) {
		if(id2==pre_id2 || id1==pre_id2) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger2 is still down!!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger2 is up!\n");
			tpd_up(raw_x2, raw_y2, x2, y2, p2);
		}
	}

	
	if(pre_num>=3 && pre_id3==0xf) {
		if((finger_num>=3 && id3==0xf) || (finger_num==2 && id2==0xf) || (finger_num==1 && id1==0xf)) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger3 is still down!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger3 is up!!\n");
			tpd_up(raw_x3, raw_y3, x3, y3, p3);
		}		
		
	} else if(pre_num>=3 && pre_id3 !=0xf) {
		if(id3==pre_id3 || id2==pre_id3 || id1==pre_id3) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger3 is still down!!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger3 is up!\n");
			tpd_up(raw_x3, raw_y3, x3, y3, p3);
		}
	}

	if(pre_num==4 && pre_id4==0xf) {
		if((finger_num>=4 && id4==0xf) || (finger_num==3 && id3==0xf) || (finger_num==2 && id2==0xf) || (finger_num==1 && id1==0xf)) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger4 is still down!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger4 is up!!\n");
			tpd_up(raw_x4, raw_y4, x4, y4, p4);
		}		
		
	} else if(pre_num==4 && pre_id4 !=0xf) {
		if(id4==pre_id4 || id3==pre_id4 || id2==pre_id4 || id1==pre_id4) {
			if(tpd_debuglog==1)
				TPD_DMESG("finger4 is still down!!\n");
		} else {
			if(tpd_debuglog==1)
				TPD_DMESG("finger4 is up!\n");
			tpd_up(raw_x4, raw_y4, x4, y4, p4);
		}
	}
		if(tpd_debuglog==1)	
			TPD_DMESG("pre_id1=%d, pre_id2=%d, pre_id3=%d, pre_id4=%d, id1=%d, id2=%d, id3=%d, id4=%d\n", pre_id1, pre_id2, pre_id3, pre_id4, id1, id2, id3, id4);				
        pre_id1 = id1; pre_id2 = id2; pre_id3 = id3; pre_id4 = id4; pre_tt_mode = buffer[1];
	pre_num = finger_num;
       
	if(tpd && tpd->dev && tpd_register_flag==1) {      
	        input_sync(tpd->dev);
	}
        
        i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &toggle);
        if((toggle & 0x80) == 0) 
            toggle = toggle | 0x80;
        else 
            toggle = toggle & (~0x80);
        i2c_smbus_write_i2c_block_data(i2c_client, 0x00, 1, &toggle); // switch the read toggle bit to do next sampling 
        tpd_flag = 0;
    #ifndef POLL_MODE
    } while (!kthread_should_stop());
    #else 
    }while(1);
Example #3
0
static int touch_event_handler(void *unused) {
    struct sched_param param = { .sched_priority = RTPM_PRIO_TPD };
    char index;
    char buffer[14];
    int i, pre_touch1 = 0, pre_touch2 = 0, touch = 0, finger_num = 0;
    int x1, y1, p1, x2, y2, p2, raw_x1, raw_y1, raw_x2, raw_y2;
    struct i2c_msg msg[2];
    
    sched_setscheduler(current, SCHED_RR, &param);
    
    do {
        MT6516_EINTIRQUnmask(CUST_EINT_TOUCH_PANEL_NUM); // possibly to lose event?
        set_current_state(TASK_INTERRUPTIBLE);
        if (!kthread_should_stop()) {
            while (tpd_halt) {tpd_flag=0; msleep(20);}
            if (pre_touch1 || pre_touch2)
                wait_event_interruptible_timeout(waiter, tpd_flag!=0, HZ/8);
            else
                wait_event_interruptible_timeout(waiter, tpd_flag!=0, HZ*2);
            TPD_DEBUG_SET_TIME;
        }
        set_current_state(TASK_RUNNING);
        
        if (tpd_calibrate_en | tpd_show_version) {
            mt_set_gpio_mode(GPIO61, 0x00);
            mt_set_gpio_pull_enable(GPIO61, GPIO_PULL_ENABLE);
            mt_set_gpio_pull_select(GPIO61,GPIO_PULL_UP);
            mt_set_gpio_dir(GPIO61, GPIO_DIR_OUT);
            mt_set_gpio_out(GPIO61, GPIO_OUT_ZERO);
            
            hwPowerDown(TPD_POWER_SOURCE,"TP");
            hwPowerOn(TPD_POWER_SOURCE,VOL_3300,"TP");
            msleep(20);
    
            if (tpd_calibrate_en) {
                tpd_do_calibrate();
                tpd_calibrate_en = 0;
            } else {
                tpd_print_version();
                tpd_show_version = 0;
            }
                
            /* added in android 2.2, for configuring EINT2 to EINT mode */
            mt_set_gpio_mode(GPIO61, 0x01);
            mt_set_gpio_pull_enable(GPIO61, GPIO_PULL_ENABLE);
            mt_set_gpio_pull_select(GPIO61,GPIO_PULL_UP);
            continue;
        } 
        
        if (!tpd_flag) {
            if (pre_touch1==1) {
                tpd_up(raw_x1, raw_y1, x1,y1,p1); pre_touch1 = 0;
            }
            if (pre_touch2==1) {
                tpd_up(raw_x2, raw_y2, x2,y2,p2); pre_touch2 = 0;
            }
            input_sync(tpd->dev);
            continue;
        } else {
            tpd_flag = 0;
        }
        
        buffer[0] = 0x80;
        i2c_master_send(i2c_rs_client, &buffer[0], (1 << 8 | 1));
    
        touch = (buffer[0] & 0x08) >> 3; // finger up or finger down
        //printk("buffer[0] = %d\n", buffer[0]);
        
        if (buffer[0]&0x80) {
           
            buffer[6] = 0xc0;
            i2c_master_send(i2c_rs_client, &buffer[6], (8 << 8 | 1));
              
            buffer[0] = 0xe0;
            i2c_master_send(i2c_rs_client, &buffer[0], (6 << 8 | 1));
            
            if (finger_num == 0x03 && buffer[0] == 0x00) {
                TPD_DEBUG("[mtk-tpd] firmware bug. hold one finger, hold another finger, and then tap the first finger, it will happen.\n");
                continue;
            }
            
            if ((buffer[0] & 0xF0)) {
                TPD_DEBUG("[mtk-tpd] this is not a position information\n");
                continue;
            }
            
            if (buffer[1] == 0x01) {
                TPD_DEBUG("[mtk-tpd] fat touch detect\n");
                continue;
            }
            
            finger_num = buffer[0]&0x07;
            if (finger_num&1) {
                x1 = buffer[2]+((buffer[3]&0x0f)<<8);
                y1 = buffer[4]+((buffer[3]&0xf0)<<4);
                p1 = buffer[5]&0x0f;
                raw_x1 = x1; raw_y1 = y1;
                tpd_calibrate(&x1, &y1);
                tpd_down(raw_x1, raw_y1, x1, y1, p1);
                pre_touch1=1;
            } else {
                if (pre_touch1!=0) {
                    tpd_up(raw_x1, raw_y1, x1, y1, p1); 
                    pre_touch1 = 0;
                }
            }
                
            if (finger_num&2) {
                x2 = buffer[6]+((buffer[7]&0x0f)<<8);
                y2 = buffer[8]+((buffer[7]&0xf0)<<4);
                p2 = buffer[9]&0x0f;
                raw_x2 = x2; raw_y2 = y2;
                tpd_calibrate(&x2, &y2);
                tpd_down(raw_x2, raw_y2, x2, y2, p2);
                pre_touch2=1;
            } else {
                if (pre_touch2!=0) {
                    tpd_up(raw_x2, raw_y2, x2, y2, p2); 
                    pre_touch2 = 0;
                }
            }
            
            input_sync(tpd->dev);
        } else {
            msleep(10);
        }       
    } while (!kthread_should_stop());
    return 0;
}
static int touch_event_handler(void *unused) {
    struct sched_param param = { .sched_priority = RTPM_PRIO_TPD }; 
    static int x1, y1, raw_x1, raw_y1;
    int temp_x1, temp_y1, temp_raw_x1, temp_raw_y1, temp_touch_dir, temp_contact_id;
    int report_id, touch_valid, contact_id, touch_dir, touch_need_sync;
    char buffer[10];
    int ret = -1;
    
    sched_setscheduler(current, SCHED_RR, &param); 
    do {
        set_current_state(TASK_INTERRUPTIBLE);
        while (tpd_halt) {tpd_flag = 0; msleep(20);}
        wait_event_interruptible(waiter, tpd_flag != 0);
        tpd_flag = 0;
        TPD_DEBUG_SET_TIME;
        set_current_state(TASK_RUNNING); 
        TPD_DEBUG("[mtk-tpd] touch interrupt\n");
        touch_need_sync = 0;
        temp_x1 = 0xFFFFFFFF;
        temp_y1 = 0xFFFFFFFF;
        temp_raw_x1 = 0xFFFFFFFF;
        temp_raw_y1 = 0xFFFFFFFF;
        temp_touch_dir = 0xFFFFFFFF;
        temp_contact_id = 0xFFFFFFFF;
        do
        {
            i2c_client->addr = i2c_client->addr & I2C_MASK_FLAG | I2C_DMA_FLAG | I2C_ENEXT_FLAG;
            ret = tpd_i2c_read(i2c_client, buffer, 10);
            if (ret != sizeof(buffer))
            {
                TPD_DEBUG("[mtk-tpd] i2c read communcate error: 0x%x\n", ret);
                continue;
            }
            i2c_client->addr = i2c_client->addr & I2C_MASK_FLAG;
            report_id = buffer[0];
            if (0x4 == report_id)
            {
            	touch_valid = buffer[1]>>7;
            	if (touch_valid)
            	{
            	    contact_id = (buffer[1]&0x7C)>>2;
            	    touch_dir = buffer[1]&0x1;
            	    raw_x1 = x1 = ((buffer[3] << 8) | buffer[2]);
                    raw_y1 = y1 = ((buffer[5] << 8) | buffer[4]);
                    TPD_DEBUG("[mtk-tpd]:id:%d, raw_x1:%d, raw_y1:%d\n", contact_id, raw_x1, raw_y1);
                    tpd_calibrate(&x1, &y1);
                    
                    if (((temp_x1 != x1) || (temp_y1 != y1) || (temp_contact_id != contact_id))
                        && (0xFFFFFFFF != temp_x1) && (0xFFFFFFFF != temp_y1))
                    {
                    	touch_need_sync = 1;
                        if (temp_touch_dir)
                        {
                    	    tpd_down(temp_raw_y1, temp_raw_x1, temp_y1, temp_x1, 1);
                        }
                        else
                        {
                    	    tpd_up(temp_raw_y1, temp_raw_x1, temp_y1, temp_x1, 0);
                        }
                    }
                    temp_x1 = x1;
                    temp_y1 = y1;
                    temp_raw_x1 = raw_x1;
                    temp_raw_y1 = raw_y1;
                    temp_touch_dir = touch_dir;
                    temp_contact_id = contact_id;
            	}
            	else
            	{
            	    TPD_DEBUG("[mtk-tpd]:Touch Invalid\n");
            	}
            }
            else
            {
                TPD_DEBUG("[mtk-tpd]:Invalid report ID:%d\n", buffer);
            }
        }while(!mt_get_gpio_in(GPIO_CTP_EINT_PIN));
/* handle touch panel interrupt for down / up event */
void tpd_tasklet(unsigned long unused) {
    static int x1,y1,p1;//,d1,round=0;
    int cx=0, cy=0, cp=0, cd=0;               /* current point */
    int fx=0, fy=0, fp=0, fd=0;               /* foresee point */
    int ni=0, i =0;                           /* index         */
    static int lx=0, ly=0;                    /* latest  point */
    static int px=0, py=0;
    static struct touch_info buf_kp[3];
    static int buf_p=1, buf_c=2, buf_f=0, down = 0;
    int dx;

    TPD_DEBUG_SET_TIME;

    if (tpd_em_debounce_time != 0) {
        tpd_set_debounce_time(tpd_em_debounce_time);
        tpd_em_debounce_time = 0;
    }
    
    //struct timeval tv;
    //long t1, t2;
    //do_gettimeofday(&tv);
    //t1 = tv.tv_sec*1000000l+tv.tv_usec;

    //tpd_sampling(&cx, &cy, &cp, &cd);
    //tpd_calibrate(&cx, &cy);
    //printk("c [%5d %5d %5d %5d]\n", cx, cy, cp, cd);
    //mod_timer(&(tpd->timer),jiffies+TPD_DELAY);
    //return;
    tpd_sampling(&cx, &cy, &cp, &cd);
    tpd_calibrate(&cx, &cy);

    /* ============= boundary condition ============*/
    if(cx<0) cx=0;
    if(cy<0) cy=0;
    if(cx>TPD_RES_X) cx=TPD_RES_X;
    #if defined(TPD_HAVE_BUTTON) || defined(TPD_HAVE_VIRTUAL_KEY)
    if(cy>TPD_RES_Y && cy<TPD_BUTTON_HEIGHT) cp=TPD_PRESSURE_MAX+1,cd=0;
    #else
    if(cy>TPD_RES_Y) cy=TPD_RES_Y;
    #endif

    if(tpd_mode==TPD_MODE_KEYPAD &&
        ((cd==0 && down==1) || (tpd_mode_axis==0 && cy>=tpd_mode_min && cy<=tpd_mode_max) ||
         (tpd_mode_axis==1 && cx>=tpd_mode_min && cx<=tpd_mode_max))) {
        /* this segment of code should be refactorized with following drift elimination */
        #ifdef TPD_HAVE_DRIFT_ELIMINATION
        /* drift elimination */
        if(buf.count==0 || (cp>=TPD_PRESSURE_NICE && cd)) {
          TPD_DEBUG("drift eliminated (0) or Pressure filtering\n");
        #ifdef TPD_HAVE_ADV_DRIFT_ELIMINATION
        } else if (buf.count==1 && cp>TPD_ADE_P1) {
          TPD_DEBUG("drift eliminated (1)\n");
        } else if (buf.count==1) {
          /* queue first good point, discard it if 2nd pt is bad */
          TPD_BUF_QUEUE(cx,cy,cd,cp);
        } else if (buf.count==2 && cp>TPD_ADE_P2) {
          TPD_DEBUG("drift eliminated (2)\n");
          TPD_BUF_UNQUEUE(fx,fy,fd,fp);
        #endif
        #else
        if(0) {
        #endif
        } else {
            buf_f = ((buf_f+1)%3);
            buf_c = ((buf_f+2)%3);
            buf_p = ((buf_f+1)%3);
            buf_kp[buf_f].x1 = (cd?cx:buf_kp[buf_c].x1);
            buf_kp[buf_f].y1 = (cd?cy:buf_kp[buf_c].y1);
            dx = buf_kp[buf_f].x1 - buf_kp[buf_c].x1;
            buf_kp[buf_f].count = (cd?(dx*dx<tpd_mode_keypad_tolerance?buf_kp[buf_c].count+1:1):0);
            if(buf_kp[buf_c].count<2) { if(down) {
                down=0;
                tpd_up(buf_kp[buf_p].x1, buf_kp[buf_p].y1,1,0);
                input_sync(tpd->dev); 
            } }
            if(buf_kp[buf_c].count>1 ||
               (buf_kp[buf_c].count==1 && (
                buf_kp[buf_p].count==0 || buf_kp[buf_f].count==0
                || (buf_kp[buf_f].x1-buf_kp[buf_c].x1)*(buf_kp[buf_c].x1-buf_kp[buf_p].x1)<=0))) {
                tpd_down(buf_kp[buf_c].x1, buf_kp[buf_c].y1,1,1, &px, &py);
                input_sync(tpd->dev);
                down = 1;
            }
            if(cd==0) { if(down) {
                down=0;
                tpd_up(buf_kp[buf_p].x1, buf_kp[buf_p].y1,1,0);
                input_sync(tpd->dev); 
                buf.count = 0;
            }}
            else mod_timer(&(tpd->timer),jiffies+TPD_DELAY);
        } mod_timer(&(tpd->timer),jiffies+TPD_DELAY);
        buf.count++;
    } else {

    // to avoid miss of tpd down when press light to heavy
    if(tpd_sw_status==0) {
        if(tpd_hw_status==1) {
            if(cd==0) stop_timer(true);
        } else return;
    } tpd_sw_status = 1;
    

    /* ================= buffering =================*/
    /* save new point in ni, get point from index */
    ni=TPD_BUF_NP(); 
    buf.x[ni]=cx;
    buf.y[ni]=cy;
    buf.d[ni]=cd;
    buf.p[ni]=cp;
    fx=(cx=buf.x[buf.index]);
    fy=(cy=buf.y[buf.index]);
    fd=(cp=buf.p[buf.index]);
    fp=(cd=buf.d[buf.index]);
    buf.index = ni;

    tpd_lpfx[tpd_lpfc]=cx;
    tpd_lpfy[tpd_lpfc]=cy;
    x1 = 0, y1 = 0, p1 = 0;
    for(i=tpd_lpfc;i<tpd_lpfc+5;i++) {
      x1 += (tpd_lpfx[i%5]*tpd_lpfw[i-tpd_lpfc]);
      y1 += (tpd_lpfy[i%5]*tpd_lpfw[i-tpd_lpfc]);
      if(tpd_lpfx[i%5]!=0 || tpd_lpfy[i%5]!=0) p1+=tpd_lpfw[i-tpd_lpfc];
    } 
    cx=x1/(p1?p1:1); cy=y1/(p1?p1:1);

    TPD_DEBUG(">%d [%8d %8d %8d %8d] - ",buf.count,cx,cy,cp,cd);

    /* pressure thresholding */
    if(cp>TPD_PRESSURE_MAX || (cx==TPD_RES_X && cy==TPD_RES_Y)) 
        cd=0,cp=TPD_PRESSURE_MAX+1;

    if(cd==1) {
      #ifdef TPD_HAVE_DRIFT_ELIMINATION
      /* drift elimination */
      if(buf.count==0) {
        TPD_DEBUG("drift eliminated (0)\n");
      #ifdef TPD_HAVE_ADV_DRIFT_ELIMINATION
      } else if (buf.count==1 && cp>TPD_ADE_P1) {
        TPD_DEBUG("drift eliminated (1)\n");
      } else if (buf.count==1) {
        /* queue first good point, discard it if 2nd pt is bad */
        TPD_BUF_QUEUE(cx,cy,cd,cp);
      } else if (buf.count==2 && cp>TPD_ADE_P2) {
        TPD_DEBUG("drift eliminated (2)\n");
        TPD_BUF_UNQUEUE(fx,fy,fd,fp);
      #endif
      #else
      if(0) {
      #endif
      } else {
        /* if a point is already queued, pop and send it */
        if(buf.queued) {
          TPD_BUF_UNQUEUE(fx,fy,fd,fp);
          /* if the queued point is a bad point.. */
          #ifdef TPD_HAVE_BUTTON
          /* if point is for btn, don't process it */
          if(cy>=TPD_BUTTON_HEIGHT) {}
          #else
          if(0) {}
          #endif
          else if(fp>TPD_PRESSURE_NICE && buf.avg_count<2) {
            /* average current point and queued point */
            cx = (cx+fx)/2;
            cy = (cy+fy)/2;
            buf.avg_count++;
          } else {
            TPD_DEBUG("pop and down\n");
            tpd_down(fx,fy,fd,fp, &px, &py);
            lx=fx,ly=fy;
            buf.avg_count=0;
          }
        }
        #ifdef TPD_HAVE_BUTTON
        /* queue points near bottom btns, to prevent mis-touch of menu */
        if(cy>TPD_BUTTON_HEIGHT-20 && cy<TPD_BUTTON_HEIGHT) {
          TPD_DEBUG("queued\n");
          TPD_BUF_QUEUE(cx,cy,cd,cp);
        }
        #else
        if(0) {}
        #endif
        /* discontinuity elimination - queueing */
        /* also point averaging */
        else if(buf.d[ni]==0 || cp>TPD_PRESSURE_NICE) {
          TPD_DEBUG("queued\n");
          TPD_BUF_QUEUE(cx,cy,cd,cp);
        } else {
          TPD_DEBUG("down\n");
          tpd_down(cx,cy,cd,cp, &px, &py);
          lx=cx,ly=cy;
          buf.effective++;
          buf.last = buf.count+1;
        }
      }
      buf.count++;
      mod_timer(&(tpd->timer),jiffies+TPD_DELAY);
    } else {
      if(buf.queued) {
        if(buf.count-buf.last>TPD_COUNT_TOLERANCE) {
          /* single point elimination */
          TPD_BUF_UNQUEUE(cx,cy,cd,cp);
          TPD_DEBUG("unqueue : ");
          if(buf.effective==0) {
            TPD_DEBUG("sp eliminated.\n");
            stop_timer(false);
          } else {
            /* track extension */
            if(cp<TPD_PRESSURE_NICE) { /* only when end-point is good..*/
              tpd_down(cx,cy,cd,cp, &px, &py);
              #ifdef TPD_HAVE_TRACK_EXTENSION
              if(buf.effective>0) {
                cx=cx+cx-px,cy=cy+cy-py;
                tpd_down(cx,cy,cd,cp, &px, &py);
                TPD_DEBUG("track extend.\n");
              }
              lx=cx,ly=cy;
              #endif
            } else TPD_DEBUG("end point is not good, discard\n");
            tpd_up(lx,ly,cd,cp);
            stop_timer(false);
          }
        } else {
          /* waiting for next down event */
          TPD_DEBUG("delay handling.\n");
          buf.count++;
          mod_timer(&(tpd->timer),jiffies+TPD_DELAY);
        }
      } else {
        TPD_DEBUG("no queue.\n");
        /* since no queue and no touch, stop timer after specific times of trial */
        /* only increase buf.count after real first down. */
        //if(buf.effective) buf.count++;
        if(buf.count || !buf.last) buf.count++;
        if(buf.count-buf.last>TPD_COUNT_TOLERANCE || buf.count==0) {
          tpd_up(lx,ly,0,TPD_PRESSURE_MAX+1);
          stop_timer(true);
        } else mod_timer(&(tpd->timer),jiffies+TPD_DELAY);
      }
    }
    }
    //printk("\n");
    //do_gettimeofday(&tv);
    //t2 = tv.tv_sec*1000000l+tv.tv_usec;
    //printk("%ld\n", t2-t1);
    return;
}

//#ifdef CONFIG_HAS_EARLYSUSPEND
/* platform device functions */
void tpd_suspend(struct early_suspend *h) {

    /*MT6573_IRQClearInt(MT6573_WDT_IRQ_LINE);
    MT6573_IRQMask(MT6573_TOUCH_IRQ_LINE);
    if(hwDisableClock(MT6573_PDN_PERI_TP,"Touch")==FALSE)
        TPD_DMESG("entering suspend mode - hwDisableClock failed.");
    if(hwDisableClock(MT6573_PDN_PERI_ADC,"Touch")==FALSE)
        TPD_DMESG("entering suspend mode - hwDisableClock failed.");*/
    tpd_hw_status = 0;
}
void tpd_resume(struct early_suspend *h) {
    /*if(hwEnableClock(MT6573_PDN_PERI_ADC,"Touch")==FALSE)
        TPD_DMESG("resume from suspend mode - hwEnableClock ADC failed.");
    if(hwEnableClock(MT6573_PDN_PERI_TP,"Touch")==FALSE)
        TPD_DMESG("resume from suspend mode - hwEnableClock TP failed.");*/

    //MT6573_IRQUnmask(MT6573_TOUCH_IRQ_LINE);
}
static int tpd_gettouchinfo(struct touch_info *cinfo, struct touch_info *sinfo) {
    char data[6] = {0,0,0,0,0,0};
    static struct touch_elapse elapse;
    static struct touch_info oinfo;
    static int px = 0, py = 0;
    static int mapping[4] = {2,3,4,5};
    static int pdata[6] = {-1,-1,-1,-1,-1,-1};
    static int repeat[6] = { 0, 0, 0, 0, 0, 0};
    static int fat_touch = 0;
    int x, y, i, average, count;
    if(i2c_master_recv(i2c_client, data, 6)==6) {
        TPD_DEBUG("[%x %x %x %x %x %x]\n",data[0],data[1],data[2],data[3],data[4],data[5]);
        if(data[0]==0x81 || data[0]==0xc0 || data[0]==0x80) {
            x   = (((unsigned int)(data[1] & 0x0f))<<7)+((unsigned int)(data[2] & 0x7f));
            y   = (((unsigned int)(data[3] & 0x0f))<<7)+((unsigned int)(data[4] & 0x7f));
            raw_x1 = x; raw_y1 = y;
            cinfo->p   = data[5]+1;
            if(cinfo->p>TPD_FAT_TOUCH) fat_touch = 1; // don't react if too fat 
            tpd_calibrate(&x, &y);
            #ifdef TPD_HAVE_TREMBLE_ELIMINATION
            /*tremble elimination */
            if(data[0] & 0x01) {
                elapse.t2 = jiffies;
                if(!elapse.t1) elapse.t1 = elapse.t2;
                elapse.buf[elapse.i] = elapse.t2 - elapse.t1;
                elapse.i = ((elapse.i+1)%5);
                for(i=0,average=0,count=0;i<5;i++)
                    if(elapse.buf[i]) count++, average+=elapse.buf[i];
                if(count) average /= count;
								#ifdef TPD_CUSTOM_TREMBLE_TOLERANCE                	
                if(( (px-x)*(px-x)+(py-y)*(py-y)) < tpd_trembling_tolerance(average, cinfo->p)) {
                #else
                if(( (px-x)*(px-x)+(py-y)*(py-y)) < tpd_trembling_tolerance_defalut(average, cinfo->p)) {
                #endif	
                    x=px,y=py;
                } else px = x, py = y;
                elapse.t1 = elapse.t2;
            }
            #endif
            cinfo->x1 = x;
            cinfo->y1 = y;
            cinfo->count=1;
            if(data[0]==0x80) cinfo->count=0;
            #ifdef TPD_HAVE_BUTTON
            if(boot_mode!=NORMAL_BOOT && cinfo->y1>=TPD_RES_Y && cinfo->y1<TPD_BUTTON_HEIGHT) cinfo->count = 0;
            #endif
        } else if(data[0]==0x4a && data[1]==0x04) {
            
            for(i=2;i<6;i++) if(pdata[i]==-1) pdata[i]=(int)data[i];
            if(data[2]>7 || data[2]-pdata[2]>1) data[2]=pdata[2];
            if(data[3]>7 || data[3]-(int)pdata[3]<-1) data[3]=(char)pdata[3];
            if(data[4]>11 || data[4]-(int)pdata[4]<-1) data[4]=(char)pdata[4];
            if(data[5]>11 || data[5]-(int)pdata[5]>1) data[5]=(char)pdata[5];
            for(i=2;i<6;i++) {
                // trembling elimination - currently disabled
                //if(repeat[i]>2 && (data[i]-pdata[i]==1 || data[i]-pdata[i]==-1)) { data[i]=pdata[i]; repeat[i]-=2; }
                //if(pdata[i]==data[i]) repeat[i]++; else repeat[i]=0;
                pdata[i] = (int)data[i];
            }

            // ghost point resolving
            oinfo.count = sinfo->count;
            oinfo.x1 = (2048*(data[2]+1))/8;
            oinfo.x2 = (2048*(data[3]+1))/8;
            oinfo.y1 = (2048*(data[4]+1))/12;
            oinfo.y2 = (2048*(data[5]+1))/12;
            tpd_calibrate(&(oinfo.x1), &(oinfo.y1));
            tpd_calibrate(&(oinfo.x2), &(oinfo.y2));
            tpd_findmapping(cinfo, &oinfo, mapping);

            cinfo->x1 = (2048*(data[mapping[0]]+1))/8;
            cinfo->x2 = (2048*(data[mapping[1]]+1))/8;
            cinfo->y1 = (2048*(data[mapping[2]]+1))/12;
            cinfo->y2 = (2048*(data[mapping[3]]+1))/12;
            raw_x1 = cinfo->x1; raw_y1 = cinfo->y1;
            raw_x2 = cinfo->x2; raw_y2 = cinfo->y2;
            tpd_calibrate(&(cinfo->x1), &(cinfo->y1));
            tpd_calibrate(&(cinfo->x2), &(cinfo->y2));
            cinfo->count = 2;
        } else if(data[0]==0x0a && data[1]==0x03 && data[2]==0x38 && data[4]==0) {
            cinfo->count = 0;
        } else if(data[0]==0x0a && data[1]==0x04 && data[2]==0x44) {
            tpd_firmware_version[0] = data[3]-48;
            tpd_firmware_version[1] = ((data[4]-48)*10) + (data[5]-48);

            printk("[mt6516-tpd] EETI Touch Panel Firmware Version %d.%d\n", 
                tpd_firmware_version[0], tpd_firmware_version[1]);
            if(tpd_firmware_version[0]!=1 || tpd_firmware_version[1]!=15)
                printk("[mt6516-tpd] Panel Firmware Version Mismatched!");
        }
        if(cinfo->count!=1) memset(&elapse, 0, sizeof(elapse));
        if(data[0]==0xc0 || (cinfo->count==0 && sinfo->count==2)) {
            cinfo->pending = 0;
            cinfo->count = 0;
        }
        if(cinfo->count!=2) {
            // trembling elimination - currently disabled
            //repeat[2]= 0; repeat[3] =0; repeat[4]= 0; repeat[5]= 0;
            pdata[2]=-1;  pdata[3]=-1; pdata[4]=-1; pdata[5]=-1;
        }
    } else { 
        printk(TPD_DEVICE " - failed to retrieve touch data\n"); 
        return 1;
    }
    if(cinfo->count==0 && fat_touch==1) {
        fat_touch = 0;
        return 1;
    } else return fat_touch?1:0;
}

static void tpd_smoothing(struct touch_info *cinfo,struct touch_info *sinfo) {
    sinfo->x1 = cinfo->x1; sinfo->y1 = cinfo->y1;
    sinfo->x2 = cinfo->x2; sinfo->y2 = cinfo->y2;
}