Beispiel #1
0
//重新唤醒
static int goodix_ts_resume(struct i2c_client *client)
{
	int ret;
	struct goodix_ts_data *ts = i2c_get_clientdata(client);
	struct goodix_i2c_rmi_platform_data *pdata = client->dev.platform_data;
	
	if (ts->power) {
		ret = ts->power(1);
		if (ret < 0)
			printk(KERN_ERR "goodix_ts_resume power on failed\n");
	}else if(pdata->gpio_shutdown){
		gpio_direction_output(pdata->gpio_shutdown, 0);
		mdelay(10);
		goodix_init_panel(ts);
		gpio_direction_input(pdata ->gpio_irq);
		gpio_enable_edge_int(gpio_to_idx(pdata ->gpio_irq),
		          pdata->irq_edge, client->irq - INT_GPIO_0);
	}

	if (ts->use_irq)
		enable_irq(client->irq);
	if (!ts->use_irq)
		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
	return 0;
}
Beispiel #2
0
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret = 0;
	int retry=0;
	struct gt818_ts_data *ts;

	struct gt818_platform_data *pdata;
	dev_info(&client->dev,"Install touch driver.\n");
	printk("gt818: Install touch driver.\n");
	//Check I2C function
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
	{
		dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n");
		ret = -ENODEV;
		goto err_check_functionality_failed;
	}

	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
	if (ts == NULL) {
		ret = -ENOMEM;
		goto err_alloc_data_failed;
	}

	i2c_connect_client = client;	//used by Guitar_Update
	pdata = client->dev.platform_data;
	ts->client = client;
	i2c_set_clientdata(client, ts);

	//init int and reset ports
	ret = gpio_request(pdata->gpio_pendown, "TS_INT");	//Request IO
	if (ret){
		dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)pdata->gpio_pendown, ret);
		goto err_gpio_request_failed;
	}
	rk29_mux_api_set(pdata->pendown_iomux_name, pdata->pendown_iomux_mode);
	gpio_direction_input(pdata->gpio_pendown);
	gpio_pull_updown(pdata->gpio_pendown, 0);

	ret = gpio_request(pdata->gpio_reset, "gt818_resetPin");
	if(ret){
		dev_err(&client->dev, "failed to request resetPin GPIO%d\n", pdata->gpio_reset);
		goto err_gpio_request_failed;
	}
	rk29_mux_api_set(pdata->resetpin_iomux_name, pdata->resetpin_iomux_mode);

#if 1
	for(retry = 0; retry < 4; retry++)
	{
		gpio_pull_updown(pdata->gpio_reset, 1);
		gpio_direction_output(pdata->gpio_reset, 0);
		msleep(1);     //delay at least 1ms
		gpio_direction_input(pdata->gpio_reset);
		gpio_pull_updown(pdata->gpio_reset, 0);
		msleep(25);   //delay at least 20ms
		ret = i2c_pre_cmd(ts);
		if (ret > 0)
			break;
		msleep(50);
	}

	if(ret <= 0)
	{
		dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n");
		goto err_i2c_failed;
	}	

#endif

	for(retry = 0; retry < 3; retry++)
	{
		ret = goodix_init_panel(ts);

		dev_info(&client->dev,"the config ret is :%d\n", ret);
		msleep(20);
		if(ret < 0)	//Initiall failed
			continue;
		else
			break;
	}

	if(ret < 0) {
		ts->bad_data = 1;
		goto err_init_godix_ts;
	}

	goodix_read_version(ts);


	INIT_WORK(&ts->work, goodix_ts_work_func);		//init work_struct
	ts->input_dev = input_allocate_device();
	if (ts->input_dev == NULL) {
		ret = -ENOMEM;
		dev_dbg(&client->dev,"goodix_ts_probe: Failed to allocate input device\n");
		goto err_input_dev_alloc_failed;
	}

	//ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
	//ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
	//ts->input_dev->absbit[0] = BIT_MASK(ABS_MT_POSITION_X) | BIT_MASK(ABS_MT_POSITION_Y) |
	//		BIT_MASK(ABS_MT_TOUCH_MAJOR) | BIT_MASK(ABS_MT_WIDTH_MAJOR);  // for android


#ifdef HAVE_TOUCH_KEY
	for(retry = 0; retry < MAX_KEY_NUM; retry++)
	{
		input_set_capability(ts->input_dev, EV_KEY, gt818_key_array[retry]);
	}
#endif

	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev));
	snprintf(ts->name, sizeof(ts->name), "gt818-touchscreen");

	ts->input_dev->name = "gt818_ts";//ts->name;
	ts->input_dev->phys = ts->phys;
	ts->input_dev->dev.parent = &client->dev;
	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;	//screen firmware version

	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
	__set_bit(EV_ABS, ts->input_dev->evbit);
#ifdef GOODIX_MULTI_TOUCH
	input_mt_init_slots(ts->input_dev, MAX_FINGER_NUM);
	//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_POSITION_X, 0, SCREEN_MAX_WIDTH, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_HEIGHT, 0, 0);
	//input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, MAX_FINGER_NUM, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
#else
	input_set_abs_params(ts->input_dev, ABS_X, 0, SCREEN_MAX_HEIGHT, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_Y, 0, SCREEN_MAX_WIDTH, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
#endif	
	
	ret = input_register_device(ts->input_dev);
	if (ret) {
		dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
		goto err_input_register_device_failed;
	}
	ts->bad_data = 0;
//	16finger_list.length = 0;

	client->irq = gpio_to_irq(pdata->gpio_pendown);		//If not defined in client
	if (client->irq)
	{

	#if INT_TRIGGER==0
		#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_RISING
	#elif INT_TRIGGER==1
		#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_FALLING
	#elif INT_TRIGGER==2
		#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_LOW
	#elif INT_TRIGGER==3
		#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_HIGH
	#endif

		ret = request_irq(client->irq, goodix_ts_irq_handler, GT801_PLUS_IRQ_TYPE,
			client->name, ts);
		if (ret != 0) {
			dev_err(&client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret);
			gpio_direction_input(pdata->gpio_pendown);
			gpio_free(pdata->gpio_pendown);
			goto err_gpio_request_failed;
		}
		else 
		{	
			disable_irq(client->irq);
			ts->use_irq = 1;
			dev_dbg(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n", client->irq, pdata->gpio_pendown);
		}	
	}

err_gpio_request_failed:
	ts->power = goodix_ts_power;
#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
	dev_info(&client->dev,"Start %s in %s mode\n",
		ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");

	if (ts->use_irq)
	{
		enable_irq(client->irq);
	}
	else
	{
		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		ts->timer.function = goodix_ts_timer_func;
		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
	}

	i2c_end_cmd(ts);
	return 0;

err_init_godix_ts:
	i2c_end_cmd(ts);
	if(ts->use_irq)
	{
		ts->use_irq = 0;
		free_irq(client->irq,ts);
		gpio_direction_input(pdata->gpio_pendown);
		gpio_free(pdata->gpio_pendown);
	}
	else 
		hrtimer_cancel(&ts->timer);

err_input_register_device_failed:
	input_free_device(ts->input_dev);

err_input_dev_alloc_failed:
	i2c_set_clientdata(client, NULL);
err_i2c_failed:	
	kfree(ts);
err_alloc_data_failed:
err_check_functionality_failed:
	return ret;
}
Beispiel #3
0
/*******************************************************	
功能:
	触摸屏探测函数
	在注册驱动时调用(要求存在对应的client);
	用于IO,中断等资源申请;设备注册;触摸屏初始化等工作
参数:
	client:待驱动的设备结构体
	id:设备ID
return:
	执行结果码,0表示正常执行
********************************************************/
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct goodix_ts_data *ts;
	int ret = 0;
	int retry=0;
	int count=0;

	struct goodix_i2c_rmi_platform_data *pdata = client->dev.platform_data;
	int INT_PORT  = pdata ->gpio_irq;
	int SHUTDOWN_PORT  = pdata->gpio_shutdown;
	if (!SHUTDOWN_PORT  || !INT_PORT) {
	    ret = -1;
	    printk(KERN_ALERT  "goodix platform data error\n");
	    goto err_check_functionality_failed ;
	}
	dev_dbg(&client->dev,"Install touchscreen driver for guitar.\n");
	//Check I2C function
	ret = gpio_request(SHUTDOWN_PORT, "TS_SHUTDOWN");	//Request IO
	if (ret < 0) 
	{
		printk(KERN_ALERT "Failed to request GPIO:%d, ERRNO:%d\n",(int)SHUTDOWN_PORT,ret);
		goto err_check_functionality_failed;
	}	
	gpio_direction_output(SHUTDOWN_PORT, 0);	//Touchscreen is waiting to wakeup
	ret = gpio_get_value(SHUTDOWN_PORT);
	if (ret)
	{
		printk(KERN_ALERT  "Cannot set touchscreen to work.\n");
		goto err_check_functionality_failed;
	}								//waite guitar start
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
	{
		dev_err(&client->dev, "System need I2C function.\n");
		ret = -ENODEV;
		goto err_check_functionality_failed;
	}

	i2c_connect_client = client;	//used by Guitar Updating.
	msleep(16);
	for(retry=0; retry < 5; retry++)
	{
		ret =i2c_write_bytes(client, NULL, 0);	//Test i2c.
		if (ret > 0)
			break;
	}
	if(ret < 0)
	{
		dev_err(&client->dev, "Warnning: I2C connection might be something wrong!\n");
		ret = -ENOSYS;
		goto err_i2c_failed;
	}

//	gpio_set_value(SHUTDOWN_PORT, 1);		//suspend
	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
	if (ts == NULL) {
		ret = -ENOMEM;
		goto err_alloc_data_failed;
	}
	
	INIT_WORK(&ts->work, goodix_ts_work_func);
	ts->client = client;
	i2c_set_clientdata(client, ts);
	
	ts->input_dev = input_allocate_device();
	if (ts->input_dev == NULL) {
		ret = -ENOMEM;
		dev_dbg(&client->dev," In File:%s Function:%s Failed to allocate input device\n", __FILE__, __func__);
		goto err_input_dev_alloc_failed;
	}

	ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
	ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
	ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); // for android

	//#ifdef GOODIX_MULTI_TOUCH	//used by android 1.x for multi-touch, not realized
	//ts->input_dev->absbit[0]=BIT(ABS_HAT0X) |BIT(ABS_HAT0Y);	
	//ts->input_dev->keybit[BIT_WORD(BTN_2)] = BIT_MASK(BTN_2);
	//#endif

	input_set_abs_params(ts->input_dev, ABS_X, 0, pdata->xmax, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_Y, 0, pdata->ymax, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
	
#ifdef GOODIX_MULTI_TOUCH
	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 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_POSITION_X, 0, pdata->xmax, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, pdata->ymax, 0, 0);	
#endif	
	sprintf(ts->phys, "input/ts)");

	ts->input_dev->name = s3c_ts_name;
	ts->input_dev->phys = ts->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;	

	finger_list.length = 0;
	ret = input_register_device(ts->input_dev);
	if (ret) {
		dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
		goto err_input_register_device_failed;
	}

	gpio_set_value(SHUTDOWN_PORT, 1);
	msleep(100);
	gpio_set_value(SHUTDOWN_PORT, 0);
	msleep(100);
	goodix_init_panel(ts);
	goodix_read_version(ts);
	msleep(500);
	struct device *dev = &client->dev;
  sysfs_create_group(&dev->kobj, &goodix_attr_group);
	dev_set_drvdata(dev, ts);

	ts->init_finished = 0;
	ts->use_irq = 0;
	ts->retry=0;
	ts->bad_data = 0;
	if (client->irq)
	{
		ret = gpio_request(INT_PORT, "TS_INT");	//Request IO
		if (ret < 0) 
		{
			dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)INT_PORT,ret);
			goto err_gpio_request_failed;
		}
		/* set input mode */
		gpio_direction_input(INT_PORT);
		gpio_enable_edge_int(gpio_to_idx(INT_PORT),
		          pdata->irq_edge, client->irq - INT_GPIO_0);
		ret  = request_irq(client->irq, goodix_ts_irq_handler,
			pdata->irq_edge ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING,
			client->name, ts);
		if (ret != 0) {
			dev_err(&client->dev,"Can't allocate touchscreen's interrupt!ERRNO:%d\n", ret);
			gpio_free( INT_PORT);
			goto err_gpio_request_failed;
		}
		else 
		{	
//			disable_irq(client->irq);
			ts->use_irq = 1;
			dev_info(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n",client->irq,INT_PORT);
		}
	}
	
err_gpio_request_failed:	
	if (!ts->use_irq) 
	{
		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		ts->timer.function = goodix_ts_timer_func;
		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
	}
	
#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
	dev_info(&client->dev,"Start  %s in %s mode\n", 
		ts->input_dev->name, ts->use_irq ? "Interrupt" : "Polling\n");
	return 0;

err_init_godix_ts:
	if(ts->use_irq)
		free_irq(client->irq,ts);
	gpio_request(INT_PORT,"TS_INT");	
	gpio_free(INT_PORT);

err_input_register_device_failed:
	input_free_device(ts->input_dev);

err_input_dev_alloc_failed:
	i2c_set_clientdata(client, NULL);
	kfree(ts);
err_i2c_failed:
	gpio_direction_input(SHUTDOWN_PORT);
	gpio_free(SHUTDOWN_PORT);
err_alloc_data_failed:
err_check_functionality_failed:
	return ret;
}
Beispiel #4
0
/*******************************************************	
功能:
	触摸屏工作函数
	由中断触发,接受1组坐标数据,校验后再分析输出
参数:
	ts:	client私有数据结构体
return:
	执行结果码,0表示正常执行
********************************************************/
static void goodix_ts_work_func(struct work_struct *work)
{	
	uint8_t  point_data[35]={ 0 };
	static uint8_t  finger_bit=0;
	uint8_t finger=0;
	int ret=-1;
	unsigned int pressure[MAX_FINGER_NUM];	
	int pos[MAX_FINGER_NUM][2];
	int position =0;
	int count = 0, read_position = 0;
	int check_sum = 0;
	
	struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);
	struct goodix_i2c_rmi_platform_data *pdata = ts->client->dev.platform_data;
	int SHUTDOWN_PORT  = pdata->gpio_shutdown;

	if (gpio_get_value(SHUTDOWN_PORT))
	{
		printk(KERN_ALERT  "Guitar stop working.The data is invalid. \n");
		goto NO_ACTION;
	}	

start_read_i2c:
	//if i2c transfer is failed, let it restart less than 10 times
	if( ts->retry > 9) {
		if(!ts->use_irq)
			//ts->timer.state = HRTIMER_STATE_INACTIVE;
			hrtimer_cancel(&ts->timer);
		dev_info(&(ts->client->dev), "Because of transfer error, Guitar's driver stop working.\n");
		return ;
	}
	if(ts->bad_data) 
		msleep(16);
	ret=i2c_read_bytes(ts->client, point_data, 35);
	if(ret <= 0)	
	{
		dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
		ts->bad_data = 1;
		ts->retry++;
		goodix_init_panel(ts);
		goto start_read_i2c;
	}	
	ts->bad_data = 0; 
	
	//The bit indicate which fingers pressed down
	switch(point_data[1]& 0x1f)
	{
		case 0:
		case 1:
			for(count=1; count<8; count++)
				check_sum += (int)point_data[count];
			if((check_sum%256) != point_data[8])
				goto XFER_ERROR;
			break;
		case 2:
		case 3:
			for(count=1; count<13;count++)
				check_sum += (int)point_data[count];
			if((check_sum%256) != point_data[13])
				goto XFER_ERROR;
			break;	
		default:		//(point_data[1]& 0x1f) > 3
			for(count=1; count<34;count++)
				check_sum += (int)point_data[count];
			if((check_sum%256) != point_data[34])
				goto XFER_ERROR;
	}
	
	point_data[1]&=0x1f;
	finger = finger_bit^point_data[1];
	if(finger == 0 && point_data[1] == 0)			
		goto NO_ACTION;						//no fingers and no action
	else if(finger == 0)							//the same as last time
		goto BIT_NO_CHANGE;					
	//check which point(s) DOWN or UP
	for(position = 0; (finger !=0)&& (position < MAX_FINGER_NUM);  position++)
	{
		if((finger&0x01) == 1)		//current bit is 1?
		{							//NO.postion finger is change
			if(((finger_bit>>position)&0x01)==1)	//NO.postion finger is UP
				set_up_point(&finger_list, position);
			else 
				add_point(&finger_list, position);
		}
		finger>>=1;
	}
static int guitar_update_proc(void *v_ts)
{
    s32 ret;
    u32 retry = 100;
    u32 i = 0;
    struct goodix_ts_data* ts = NULL;
    u8* data = NULL;
    u8* ic_nvram = NULL;
    st_fw_head fw_head;
    u8 buf[32];

    ts = (struct goodix_ts_data*)v_ts;
    data = kzalloc(UPDATE_DATA_LENGTH, GFP_KERNEL);
    if (NULL == data)
    {
        DEBUG_UPDATE("data failed apply for memory.\n");
        return fail;
    }
    
    ic_nvram = kzalloc(UPDATE_DATA_LENGTH, GFP_KERNEL);
    if (NULL == ic_nvram)
    {
        DEBUG_UPDATE("ic_nvram failed apply for memory.\n");
        goto app_mem_failed;
    }
    DEBUG_UPDATE("Apply for memory successfully.memory size: %d.\n", UPDATE_DATA_LENGTH);

    msleep(1000);
    DEBUG_UPDATE("Updating...\n");

    if (fail == load_update_file(ts, &fw_head, &data[2], NULL))
    {
        DEBUG_UPDATE("Load file data failed!\n");
        goto load_failed;
    }
    DEBUG_UPDATE("Load file data successfully!\n");

    if (ts->use_irq)
    {
        if(!ts->irq_is_disable)
        {
            disable_irq(ts->client->irq);
        }
        ts->irq_is_disable = 2;
    }

    for (i = 0; i < 5; i++)
    {
        if (fail == guitar_update_mode(ts))
        {
            DEBUG_UPDATE("Next try![Enter update mode]\n");
            continue;
        }
        else
        {
            DEBUG_UPDATE("Set update mode successfully.\n");
            break;
        }
    }
    if (i >= 5)
    {
        DEBUG_UPDATE("Set update mode failed.\n");
        return fail;
    }
    
    retry = 0;
    while(retry++ < 5)
    {
        if (fail == guitar_update_firmware(ts, &fw_head, &data[2]))
        {
            DEBUG_UPDATE("Update firmware failed.\n");
            continue;
        }
        DEBUG_UPDATE("Update firmware successfully.\n");

        //while(1)  // simulation store operation failed
        if (fail == guitar_nvram_store(ts))
        {
            DEBUG_UPDATE("Store nvram failed.\n");
            continue;
        }

        msleep(100);

        if (fail == get_ic_msg(ts, 0x1201, buf, 1))
        {
            DEBUG_UPDATE("Read NVRCS failed.(Store)\n");
            continue;
        }
        if (buf[ADDR_LENGTH] & 0x01)
        {
            DEBUG_UPDATE("Check NVRCS(0x%02x) failed.(Store)\n", buf[ADDR_LENGTH]);
            continue;
        }

        DEBUG_UPDATE("Store nvram successfully.\n");

        if (fail == guitar_nvram_recall(ts))
        {
            DEBUG_UPDATE("Recall nvram failed.\n");
            continue;
        }
        msleep(5);
        
        if (fail == get_ic_msg(ts, 0x1201, buf, 1))
        {
            DEBUG_UPDATE("Read NVRCS failed.(Recall)\n");
            continue;
        }
        if (buf[ADDR_LENGTH] & 0x02)
        {
            DEBUG_UPDATE("Check NVRCS(0x%02x) failed.(Recall)\n", buf[ADDR_LENGTH]);
            continue;
        }
        DEBUG_UPDATE("Recall nvram successfully.\n");

        ic_nvram[0] = fw_head.st_addr[0];
        ic_nvram[1] = fw_head.st_addr[1];

        for ( i = 0; i < 10; i++)
        {
            ret = i2c_read_bytes(ts->client, ic_nvram, ADDR_LENGTH + fw_head.lenth);
            if (ret <= 0)
            {
                continue;
            }
            break;
        }

        if (i >= 10)
        {
            DEBUG_UPDATE("Read nvram failed!\n");
            continue;
        }
        DEBUG_UPDATE("Read nvram successfully!\n");

        if (false == is_equal(&data[2], &ic_nvram[2], fw_head.lenth))
        {
            DEBUG_UPDATE("Nvram not equal!\n");
            continue;
        }
        DEBUG_UPDATE("Check nvram by byte successfully!\n");
        
        if (update_msg.gt_loc > 0)
        {
            DEBUG_UPDATE("Location:%d, Ret:%d.\n", (s32)update_msg.gt_loc, (s32)ret);
            memset(buf, 0, sizeof(buf));
            ret = update_msg.file->f_op->write(update_msg.file, buf, 6, &update_msg.gt_loc);
            if (ret < 0)
            {
                DEBUG_UPDATE("Didn't clear the focre update flag in file.\n");
            }
            else
            {
                DEBUG_UPDATE("Clear the focre update flag in file.Location:%d, Ret:%d.\n", (s32)update_msg.gt_loc, (s32)ret);
            }
        }
        DEBUG_UPDATE("Update successfully!\n");
        break;
    }
    
    set_fs(update_msg.old_fs);
    filp_close(update_msg.file, NULL);
    guitar_leave_update_mode();
    DEBUG_UPDATE("Leave update mode!\n");
    
    //Reset guitar
    DEBUG_UPDATE("Reset IC and send config!\n");
    guitar_reset(10);
    for (i = 0; i < 3; i++)
    {
        if (fail == goodix_init_panel(ts, 1))
        {
            msleep(10);
            continue;
        }
        break;
    }
    if (i >= 3)
    {
        DEBUG_UPDATE("Send config data failed.\n");
    }
    
    msleep(10);
    if (ts->use_irq)
    {
        ts->irq_is_disable = 0;
        enable_irq(ts->client->irq);
    }

load_failed:
    kfree(ic_nvram);
app_mem_failed:
    kfree(data);

    if (retry < 5)
    {
        return success;
    }

    DEBUG_UPDATE("Update failed!\n");
    return fail;    
}
Beispiel #6
0
static int gt811_probe(struct i2c_client *client, const struct i2c_device_id *id)
{	
	int ret;
	int retry;
	const char irq_table[2] = {IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING};
	
	fs210_ts_dev =kmalloc(sizeof(struct ts_device), GFP_KERNEL);
	if(!fs210_ts_dev->ts_client){
		printk(KERN_ERR "malloc failed!\n");
		return -ENOMEM;
	}

	fs210_ts_dev->ts_client =client;

	INIT_WORK(&fs210_ts_dev->work, goodix_ts_work_func);

	/*1.硬件相关的操作
	*/
	/*1.1 管脚申请*/
	ret=gpio_request(SHUTDOWN_PORT,"reset");
	if (ret < 0)
    {
		dev_err(&client->dev, "Failed to request RESET GPIO:%d, ERRNO:%d\n",(int)SHUTDOWN_PORT,ret);
		goto err0;
	}
	//一定要上拉
	s3c_gpio_setpull(SHUTDOWN_PORT, S3C_GPIO_PULL_UP);
	//gpio_direction_input(SHUTDOWN_PORT);

	/*1.2 复位触摸屏 
	*/
	for(retry=0;retry <= 10; retry++)
	{
		gpio_direction_output(SHUTDOWN_PORT,0);
		msleep(1);
		gpio_direction_input(SHUTDOWN_PORT);

		msleep(100);
		printk(KERN_INFO "num_adatper =%d\n",client->adapter->nr);
		ret =i2c_write_byte(&test_data, 1);	//Test I2C connection.
		if (ret > 0)
			break;
		dev_info(&client->dev, "GT811 I2C TEST FAILED!Please check the HARDWARE connect\n");
	}

	if(ret <= 0)
	{
		dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n");
		goto err1;
	}	

	/*1.2 初始化触摸屏*/
	for(retry=0; retry<3; retry++)
	{
		/*初始化触摸屏面板*/
		ret=goodix_init_panel(fs210_ts_dev);
		msleep(2);
		if(ret != 0)	//Initiall failed
			continue;
		else
			break;
	}
	
	if(ret!= 0) 
	{
		//ts->bad_data=1;				//标志位
		goto err1;
	}

	/*1.3 触摸屏中断要进行注册*/
	/*1.3.1 申请GPIO管脚*/
	ret = gpio_request(INT_PORT, "TS_INT");	//Request IO
	if (ret < 0) 
	{
		dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)INT_PORT,ret);
		goto err1;
	}
	
	/*1.3.2 获取中断号*/
	client->irq =gpio_to_irq(INT_PORT);
	

	/*1.3.3 申请中断, */	
	ret  = request_irq(client->irq, goodix_ts_irq_handler,irq_table[fs210_ts_dev->int_trigger_type],
			client->name, fs210_ts_dev);
	if (ret != 0)
	{
		dev_err(&client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret);
		gpio_direction_input(INT_PORT);
		gpio_free(INT_PORT);
		goto err1;
	}

	/*2.分配input_dev结构体*/
	fs210_ts_dev->ts_input =input_allocate_device();
	if(!fs210_ts_dev->ts_input){
		printk(KERN_ERR "malloc failed!\n");
		ret =-ENOMEM;
		goto err0;
	}

	/*3.设置input_dev结构体*/
	/*3.1 设置能产生哪类事件*/
	//set_bit(EV_SYN,fs210_ts_dev->ts_input->evbit);
	set_bit(EV_KEY,fs210_ts_dev->ts_input->evbit);
	set_bit(EV_ABS,fs210_ts_dev->ts_input->evbit);

	/*3.2 设置能产生哪些事件*/
	set_bit(BTN_TOUCH,fs210_ts_dev->ts_input->keybit);
	input_set_capability(fs210_ts_dev->ts_input,EV_KEY,KEY_BACK);


	input_set_capability(fs210_ts_dev->ts_input,EV_ABS,ABS_X);
	//set_bit(ABS_X, fs210_ts_dev->ts_input->absbit);
	set_bit(ABS_Y, fs210_ts_dev->ts_input->absbit);
	set_bit(ABS_PRESSURE, fs210_ts_dev->ts_input->absbit);

	/*3.3 设置绝对位移的各种参数*/
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_X, 0,  fs210_ts_dev->abs_x_max, 0, 0);
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_Y, 0, fs210_ts_dev->abs_y_max, 0, 0);
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_PRESSURE, 0, 255, 0, 0);

	

	#ifdef GOODIX_MULTI_TOUCH
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_POSITION_X, 0,  fs210_ts_dev->abs_x_max, 0, 0);
	input_set_abs_params(fs210_ts_dev->ts_input, ABS_MT_POSITION_Y, 0, fs210_ts_dev->abs_y_max, 0, 0);	
	#endif	

	/*4.注册input_dev*/
	ret=input_register_device(fs210_ts_dev->ts_input);
	if(ret){
		printk(KERN_ERR "register input_dev failed!\n");
		ret =-EINVAL;
		goto err2;
	}

	
	return 0;
	
err3:
	input_unregister_device(fs210_ts_dev->ts_input);
	
err2:
	gpio_free(INT_PORT);
	input_free_device(fs210_ts_dev->ts_input);
	
err1:
	gpio_free(SHUTDOWN_PORT);
err0:
	kfree(fs210_ts_dev);
	return ret;
}
Beispiel #7
0
/*******************************************************	
功能:
	触摸屏探测函数
	在注册驱动时调用(要求存在对应的client);
	用于IO,中断等资源申请;设备注册;触摸屏初始化等工作
参数:
	client:待驱动的设备结构体
	id:设备ID
return:
	执行结果码,0表示正常执行
********************************************************/
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct goodix_ts_data *ts;
	int ret = 0;
	int retry=0;
	int count=0;
FNC_ENTERY;
	struct goodix_i2c_platform_data *pdata;
	dev_dbg(&client->dev,"Install touchscreen driver for guitar.\n");

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
	{
		dev_err(&client->dev, "System need I2C function.\n");
		ret = -ENODEV;
		goto err_check_functionality_failed;
	}
        
	if (!(((board_version == 1)&&(hw_version == 0))||(board_version == 0)))
        {
		printk("%s: system hardware version:%d, GOODIX touchscreen is unsupported!!!\n", __func__, hw_version);
		ret = -1;
		goto err_check_functionality_failed;
	}
	
	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
	if (ts == NULL) {
		ret = -ENOMEM;
		goto err_alloc_data_failed;
	}

	/* 获取预定义资源 */
	pdata = client->dev.platform_data;
	if(pdata != NULL) {
		//ts->gpio_shutdown = pdata->gpio_shutdown;
		//ts->gpio_irq = pdata->gpio_irq;
		
		//use as s3c_gpio_cfgpin(ts->gpio_shutdown, pdata->shutdown_cfg);		/* output */
	}
	
#ifdef SHUTDOWN_PORT	
	ts->gpio_shutdown = SHUTDOWN_PORT;
	if(ts->gpio_shutdown)
	{
		//ret = gpio_request(ts->gpio_shutdown, "TS_SHUTDOWN");	//Request IO
		if (ret < 0) 
		{
			printk(KERN_ALERT "Failed to request GPIO:%d, ERRNO:%d\n", ts->gpio_shutdown, ret);
			goto err_gpio_request;
		}	
		gpio_direction_output(ts->gpio_shutdown, 0);	//Touchscreen is waiting to wake up
		ret = gpio_get_value(ts->gpio_shutdown);
		if (ret)
		{
			printk(KERN_ALERT  "Cannot set touchscreen to work.\n");
			goto err_i2c_failed;
		}
		ts->use_shutdown = 1;
		msleep(25);		//waiting for initialization of Guitar.
	}
#endif		
	RESETPIN_CFG;
	RESETPIN_SET1;
	mdelay(200);
	RESETPIN_SET0;
	mdelay(200);

	i2c_connect_client = client;				//used by Guitar Updating.
	//TODO: used to set speed of i2c transfer. Must change as your paltform.
//	s3c24xx_set_i2c_clockrate(client->adapter, 250, &count);	//set i2c <=250kHz
	dev_dbg(&client->dev, "i2c set frequency:%dkHz.\n", count);
#if 0
	for(retry=0; retry < 5; retry++)
	{
		
	ret=i2c_read_bytes(ts->client,version_data, GT80X_VERSION_LENGTH);
		ret =i2c_write_bytes(client, NULL, 0);	//Test i2c.
		if (ret > 0)
			break;
	}
	if(ret < 0)
	{
		dev_err(&client->dev, "Warnning: I2C connection might be something wrong!\n");
		goto err_i2c_failed;
	}
#endif
	if(ts->use_shutdown)
		gpio_set_value(ts->gpio_shutdown, 1);		//suspend
	
	INIT_WORK(&ts->work, goodix_ts_work_func);
	ts->client = client;
	i2c_set_clientdata(client, ts);
	pdata = client->dev.platform_data;
	
	ts->input_dev = input_allocate_device();
	if (ts->input_dev == NULL) {
		ret = -ENOMEM;
		dev_dbg(&client->dev,"Failed to allocate input device\n");
		goto err_input_dev_alloc_failed;
	}

	ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
#ifndef GOODIX_MULTI_TOUCH	
	ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
	ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);

	input_set_abs_params(ts->input_dev, ABS_X, 0, SCREEN_MAX_HEIGHT, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_Y, 0, SCREEN_MAX_WIDTH, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);	
#else
	//ts->input_dev->absbit[0] = BIT_MASK(ABS_MT_TRACKING_ID) |
	ts->input_dev->absbit[0] = 
		BIT_MASK(ABS_MT_TOUCH_MAJOR)| BIT_MASK(ABS_MT_WIDTH_MAJOR) |
  		BIT_MASK(ABS_MT_POSITION_X) | BIT_MASK(ABS_MT_POSITION_Y); 	// for android
	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_POSITION_X, 0, SCREEN_MAX_HEIGHT, 0, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_WIDTH, 0, 0);	
	//input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, MAX_FINGER_NUM-1, 0, 0);	
#endif	

	sprintf(ts->phys, "input/ts)");
	ts->input_dev->name = s3c_ts_name;
	ts->input_dev->phys = ts->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 = 0x1103;	

	finger_list.length = 0;
	ret = input_register_device(ts->input_dev);
	if (ret) {
		dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
		goto err_input_register_device_failed;
	}

	ts->use_irq = 1;
	//ts->use_irq = 0;
	ts->retry = 0;
	ts->bad_data = 0;

#if defined(INT_PORT)	
	ts->gpio_irq = INT_PORT;
	client->irq=TS_INT; //If not define in client
	if (client->irq)
	{
	
#ifdef CONFIG_MACH_EMEV
				writel(readl(CHG_PULL1)|0xC000, CHG_PULL1);
				gpio_direction_input(irq_to_gpio(client->irq));
#endif
		//ret = gpio_request(ts->gpio_irq, "TS_INT");	//Request IO
		if (ret < 0) 
		{
			dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n", ts->gpio_irq, ret);
			goto err_int_request_failed;
		}
//		ret = s3c_gpio_cfgpin(ts->gpio_irq, INT_CFG);	//Set IO port function
		ret  = request_irq(client->irq, goodix_ts_irq_handler ,  IRQ_TYPE_EDGE_RISING,
			"GoodixIRQ", ts);
		if (ret != 0) {
			dev_err(&client->dev,"Can't allocate touchscreen's interrupt%d!ERRNO:%d\n",client->irq, ret);
			gpio_direction_input(ts->gpio_irq);
			gpio_free(ts->gpio_irq);
			goto err_int_request_failed;
		}
		else 
		{	
			disable_irq(client->irq);
			ts->use_irq = 1;
			dev_dbg(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n",client->irq, ts->gpio_irq);
		}
	}
#endif

err_int_request_failed:	
	if (!ts->use_irq) 
	{
		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		ts->timer.function = goodix_ts_timer_func;
		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
	}

	flush_workqueue(goodix_wq);
	if(ts->use_shutdown)
	{		
		gpio_set_value(ts->gpio_shutdown, 0);	
	#ifdef SHUTDOWN_PORT	
		ts->power = goodix_ts_power;
	#endif
		msleep(30);
	}	
	
	ret = goodix_init_panel(ts);
	if(ret != 0) 
		goto err_init_godix_ts;
	if(ts->use_irq)
		enable_irq(client->irq);
	
	goodix_read_version(ts);
	//msleep(500);
	
#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
	dev_dbg(&client->dev,"Start  %s in %s mode\n", 
		ts->input_dev->name, ts->use_irq ? "Interrupt" : "Polling");
	return 0;

err_init_godix_ts:
	if(ts->use_irq)
	{
		free_irq(client->irq,ts);	
		gpio_free(ts->gpio_irq);
	}

err_input_register_device_failed:
	input_free_device(ts->input_dev);

err_input_dev_alloc_failed:
	i2c_set_clientdata(client, NULL);
err_i2c_failed:
	if(ts->use_shutdown)
	{
		gpio_direction_input(ts->gpio_shutdown);
		gpio_free(ts->gpio_shutdown);
	}
err_gpio_request:
	kfree(ts);
err_alloc_data_failed:
err_check_functionality_failed:
	return ret;
}
Beispiel #8
0
/*******************************************************	
功能:
	触摸屏工作函数
	由中断触发,接受1组坐标数据,校验后再分析输出
参数:
	ts:	client私有数据结构体
return:
	执行结果码,0表示正常执行
********************************************************/
static void goodix_ts_work_func(struct work_struct *work)
{	
	static uint8_t finger_bit=0;	//last time fingers' state
	struct point_data * p = NULL;
	uint8_t read_position = 0;
	uint8_t point_data[READ_BYTES_NUM]={ 0 };
	uint8_t finger=0;				//record which finger is changed
	uint8_t check_sum = 0;
	int ret = -1; 
	int count = 0;

	struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);

	if (ts->use_shutdown && gpio_get_value(ts->gpio_shutdown))
		goto NO_ACTION;					//The data is invalid.

	//if i2c-transfer is failed, let it restart less than 10 times. FOR DEBUG.
	/*
	if( ts->retry > 9) {
		if(!ts->use_irq && (ts->timer.state != HRTIMER_STATE_INACTIVE))		
			hrtimer_cancel(&ts->timer);
		dev_info(&(ts->client->dev), "Because of transfer error, %s stop working.\n",s3c_ts_name);
		ts->bad_data = 1;
		return ;
	}
	*/
	ret=i2c_read_bytes(ts->client, point_data, sizeof(point_data));
	if(ret <= 0)	
	{
		dev_dbg(&(ts->client->dev),"I2C transfer error. ERROR Number:%d\n ", ret);
		ts->retry++;
		if(ts->power)
		{
			ts->power(ts, 0);
			ts->power(ts, 1);
		}
		else
		{
			goodix_init_panel(ts);
			msleep(260);
		}
		goto XFER_ERROR;
	}	
	
	//如果能够保证在INT中断后及时的读取坐标数据,可以不进行校验
	if(!ts->use_irq)	
	{
		switch(point_data[1]& 0x1f)
		{
		case 0:
			break;
		case 1:
			for(count=1; count<8; count++)
				check_sum += (int)point_data[count];
			read_position = 8;
			break;
		case 2:
		case 3:
			for(count=1; count<13;count++)
				check_sum += (int)point_data[count];
			read_position = 13;
			break;	
		default:		//(point_data[1]& 0x1f) > 3
			for(count=1; count<34;count++)
				check_sum += (int)point_data[count];
			read_position = 34;
		}
		if(check_sum != point_data[read_position])
			goto XFER_ERROR;
	}
	//The bits indicate which fingers pressed down
	point_data[1]&=0x1f;
	finger = finger_bit^point_data[1];
	if(finger == 0 && point_data[1] == 0)			
		goto NO_ACTION;						//no fingers and no action
	else if(finger == 0)						//the same as last time
		goto BIT_NO_CHANGE;
	
	//check which point(s) DOWN or UP
	analyse_points(&finger_list, finger_bit, finger);

	if(finger_list.head == NULL)
		goto NO_ACTION;
	else
		dev_dbg(&ts->client->dev, "fingers count:%d\n", finger_list.length);

BIT_NO_CHANGE:
	for(p = finger_list.head; p != NULL; p = p->next)
	{	
		if(p->state == FLAG_UP)
		{
			p->x = p->y = 0;
			p->pressure = 0;
			continue;
		}
		
		if(p->id < 3)
			read_position = p->id*5+3;
		else
			read_position = 29;

		
		if(p->id != 3)
		{
			p->x = (unsigned int) (point_data[read_position]<<8) + (unsigned int)( point_data[read_position+1]);
			p->y = (unsigned int)(point_data[read_position+2]<<8) + (unsigned int) (point_data[read_position+3]);
			p->pressure = point_data[read_position+4];
		}
		
		#if MAX_FINGER_NUM > 3
		else 
		{
			p->x = (unsigned int) (point_data[18]<<8) + (unsigned int)( point_data[25]);
			p->y = (unsigned int)(point_data[26]<<8) + (unsigned int) (point_data[27]);
			p->pressure = point_data[28];
		}
		#endif

		// 将触摸屏的坐标映射到LCD坐标上. 触摸屏短边为X轴,LCD坐标一般长边为X轴,可能需要调整原点位置
		p->x = (TOUCH_MAX_WIDTH - p->x)*SCREEN_MAX_WIDTH/TOUCH_MAX_WIDTH;//y
		if (board_version == 0){
			p->y =  p->y*SCREEN_MAX_HEIGHT/TOUCH_MAX_HEIGHT;//x

		} else if (board_version == 1) {
			p->y = (TOUCH_MAX_HEIGHT - p->y)*SCREEN_MAX_HEIGHT/TOUCH_MAX_HEIGHT;//x
		}
		swap(p->x, p->y); 
	}

#ifndef GOODIX_MULTI_TOUCH	
		if(finger_list.head->state == FLAG_DOWN)
		{
			input_report_abs(ts->input_dev, ABS_X, finger_list.head->x);
			input_report_abs(ts->input_dev, ABS_Y, finger_list.head.y);	
		} 
		input_report_abs(ts->input_dev, ABS_PRESSURE, finger_list.head->pressure);
		input_report_key(ts->input_dev, BTN_TOUCH, finger_list.head->state);   
#else

	/* ABS_MT_TOUCH_MAJOR is used as ABS_MT_PRESSURE in android. */
	for(p = finger_list.head; p != NULL; p = p->next)
	{
		if(p->state == FLAG_DOWN)
		{
			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, p->x);
			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, p->y);
		} 
		//input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, p->id);
		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, p->pressure);
		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, p->pressure);
		//printk("ID:%d.\n", p->id);
		input_mt_sync(ts->input_dev);	
	}

#endif
	input_sync(ts->input_dev);

	delete_points(&finger_list);
	finger_bit = point_data[1]&0x1f;	//restore last presse state.

XFER_ERROR:	
NO_ACTION:
	if(ts->use_irq)
		enable_irq(ts->client->irq);

}