This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

I2C Based touchscreen on omap3

Other Parts Discussed in Thread: DM3730

Hi

We are working on DM3730 based custom board . We are using a I2c based touchscreen panel (SSD2531) on our board . We have brought the touch panel up by inserting the touch panel driver into the kernel. We have also observed that on a single touch event multiple interrupts are getting generated.

The issue we are facing is that the calibration(ts_calibrate) is failing before launching the matrix GUI.
Please look at the following error we have got while booting

Calibrating touchscreen (first time only)xres = 1024, yres = 600
tslib: Selected device is not a touchscreen (must support ABS_X and ABS_Y events)
Took 3 samples...
Top left : X =    0 Y = 123192
Took 3 samples...
Top right : X =    0 Y = 123192
Took 3 samples...
Bot right : X =    0 Y = 123192
Took 3 samples...
Bot left : X =    0 Y = 123192
Took 3 samples...
Center : X =    0 Y = 123192
ts_calibrate: determinant is too small -- 0.000000
Calibration failed.


Please can anybody confirm on the following points

1. We are getting multiple interrupts on a single finger touch on the panel - is the behavior correct?

2. Why Touch panel calibration is failing?

Thanks & Regards
Harsh

  • Hello,

    It'seems that your driver doesn't support ABS_X and ABS_Y events,

    The SSD2531 is a multitouch contoller and use dedicated events like ABS_MT_POSITION_X.

    Could you point me where you find the driver sources of the SSD2531 ?

    Thanks

    Patrick

  • Concerning the multiples interrupts,

    I have checked the datasheet of the SSD2531 and there is many events per finger:

    Finger-enter, Finger-leave, Finger-Move, Single Click, ...

    Patrick

  • Hi Patrick 

    Thanks for your reply.

    We have got the driver from the vendor itself. 

    We have commented Multitouch option in the driver and now we are getting different error while calibration .

    Calibrating touchscreen (first time only)xres = 1024, yres = 600
    tslib: Selected device is not a touchscreen (must support ABS and KEY event types)
    Took 3 samples...
    Top left : X =    0 Y = 127288
    Took 3 samples...
    Top right : X =    0 Y = 127288
    Took 3 samples...
    Bot right : X =    0 Y = 127288
    Took 3 samples...
    Bot left : X =    0 Y = 127288
    Took 3 samples...
    Center : X =    0 Y = 127288
    ts_calibrate: determinant is too small -- 0.000000
    Calibration failed.

    We are able to see two events are getting formed (event 1 and event2) in /dev/input/  on inserting the Touch panel driver and event 2 is showing above mentioned error.

    On inserting default driver we were not able see any interrupt getting generated , so we have changed the driver regarding interrupt handling . Following are the changes we have made in kernel and driver. After the changes in the driver , we could see the interrupts getting generated.

    Changes inside board-omap3evm.c

    static struct i2c_board_info __initdata omap3evm_i2c_boardinfo1[] = {

            {                                                       // dataway added code
                    I2C_BOARD_INFO("ssd2531", 0x5c),

            },

    };

    static int __init omap3_evm_i2c_init(void)
    {
            /*
             * REVISIT: These entries can be set in omap3evm_twl_data
             * after a merge with MFD tree
             */
            omap3evm_twldata.vmmc1 = &vmmc1_data;
            omap3evm_twldata.vsim = &vsim_data;
            omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
                            ARRAY_SIZE(omap3evm_i2c_boardinfo));
            omap_register_i2c_bus(2, 400, NULL, 0);
            omap_register_i2c_bus(3, 400, omap3evm_i2c_boardinfo1, ARRAY_SIZE(omap3evm_i2c_boardinfo1));
            return 0;
    }

    Changes in Driver

    ____________________________________________________________________________________________________________________________

    Inside static int __devinit ssd2531_probe

    // Dataway changes

    -   gpio_direction_output(SSD2531_INT_GPIO, 1);
    +  gpio_direction_input(SSD2531_INT_GPIO);

    +    if (request_irq(ssd2531_irq, ssd2531_interrupt, 
    +                                                     IRQF_TRIGGER_LOW, "ssd2531", NULL))
    +    {
    +                printk("\n trying pin change workaround on irq %d\n", ssd2531_irq);
    +                err = request_irq(ssd2531_irq, ssd2531_interrupt,
    +                                  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
    +                                  "ssd2531", NULL);
        if (err != 0) {
            printk("%s: cannot register irq\n", __func__);
            goto exit;
        }    
    +    }

    I am attaching original driver for your reference.

    Please suggest us the solution for this.

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/sched.h>
    #include <linux/time.h>
    #include <linux/init.h>
    #include <linux/interrupt.h>
    #include <linux/workqueue.h>
    #include <linux/input.h>
    #include <linux/delay.h>
    #include <linux/i2c.h>
    #include <linux/platform_device.h>
    #include <asm/irq.h>
    #include <mach/hardware.h>
    #include <mach/io.h>
    #include <mach/system.h>
    #include <mach/gpio.h>
    //#include <linux/earlysuspend.h>
    #include <linux/string.h>
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
    
    /*----------------------- i2c start -------------------*/
    
    #define SSD2531_SCL_GPIO        93
    #define SSD2531_SDA_GPIO       91
    #define SSD2531_INT_GPIO       20
    #define SSD2531_RESET_GPIO	  30
    
    #define SSD_ADDR 0x5c
    
    #if 0
    #define G_I2C_SDA_BIT 8
    #define G_I2C_SCL_BIT 7
    #define BIT_SET  0X01
    #endif
    
    #define SSD2531_I2C_NAME	"ssd2531"
    
    static struct i2c_client *ssd2531_i2c_client;
    static const struct i2c_device_id ssd2531_id[] = {
    	{ SSD2531_I2C_NAME, 0 },
    	{ }
    };
    
    static int __devinit ssd2531_probe(struct i2c_client *client, const struct i2c_device_id *id);
    static int __devexit ssd2531_remove(struct i2c_client *client);
    
    static struct i2c_driver ssd2531_driver = {
    	.probe 		= ssd2531_probe,
    	.remove 	= ssd2531_remove,
    	.id_table	= ssd2531_id,
    	.driver 	= {
    		.owner	= THIS_MODULE,
    		.name	= SSD2531_I2C_NAME,
    	},
    };
    
    #if 0
    #define G_I2C_SCL(value)	(gpio_set_value(SSD2531_SCL_GPIO, value))
    #define G_I2C_SDA(value)	(gpio_set_value(SSD2531_SDA_GPIO, value))
    #define G_I2C_SDA_READ()	(gpio_get_value(SSD2531_SDA_GPIO))
    #define G_I2C_SCL_PULL(n)	(gpio_set_value(SSD2531_SCL_GPIO, n))
    #define G_I2C_SDA_PULL(n)	(gpio_set_value(SSD2531_SDA_GPIO, n))
    
    
    #define _delay1us()				udelay(1)
    #define delay5us()				udelay(5)
    #define WaitTime(n)				mdelay(n)
    #endif
    
    static u8 touchscreen_is_giantplus = 1;
    static u8 pre_state = 0;
    static int pre_key_value = 0;
    static unsigned char error_times = 0;
    spinlock_t touch_lock;
    
    //#define SSD2531_DEBUG
    #ifdef  SSD2531_DEBUG
    #define	dbg(fmt, arg...) printk(KERN_INFO fmt, ##arg)
    #else
    #define	dbg(fmt, arg...)
    #endif
    
    #if 0
    void G_I2C_SCL_DIR(int value)
    {
    	if (value == 1)
    	{
    		//gpio_configure(SSD2531_SCL_GPIO, GPIOF_INPUT);
    		gpio_direction_input(SSD2531_SCL_GPIO);
    	}
    	else
    	{
    		//gpio_configure(SSD2531_SCL_GPIO, GPIOF_DRIVE_OUTPUT);
    		gpio_direction_output(SSD2531_SCL_GPIO, 1);
    	}
    }
    
    void G_I2C_SDA_DIR(int value)
    {
    	if (value == 1)
    	{
    		//gpio_configure(SSD2531_SDA_GPIO, GPIOF_INPUT);
    		gpio_direction_input(SSD2531_SDA_GPIO);
    	}
    	else
    	{
    		//gpio_configure(SSD2531_SDA_GPIO, GPIOF_DRIVE_OUTPUT);
    		gpio_direction_output(SSD2531_SDA_GPIO, 1);
    	}
    }
    
    //init IIC
    void g_i2c_init(void)  
    {	
    	G_I2C_SCL_PULL(1);
      G_I2C_SDA_PULL(1);
      
    	G_I2C_SCL_DIR(0);
    	G_I2C_SDA_DIR(0);
    	
    	delay5us();
    }
    
    void g_i2c_start(void)
    {
    	G_I2C_SDA(1);
    	delay5us();
    	G_I2C_SCL(1);
    	delay5us();
    	G_I2C_SDA(0);
    	delay5us();
    	G_I2C_SCL(0);
    	delay5us();
    	
    }
    
    int g_i2c_stop(void)
    {
    	G_I2C_SDA_DIR(0);
    	G_I2C_SCL(0);
    	delay5us();
    	G_I2C_SDA(0);
    	delay5us();
    	G_I2C_SCL(1);
    	delay5us();
    	G_I2C_SDA(1);
    	delay5us();
    	return 0;
    }	
    
    int test_ack(void)   
    {
    
    	G_I2C_SDA_DIR(1);
    
    	delay5us();
    	G_I2C_SCL(1);
    	
    	delay5us();
    	
    	if((G_I2C_SDA_READ()&(BIT_SET<<G_I2C_SDA_BIT)))
    		return 1;
    		
    	delay5us();
    	G_I2C_SCL(0);
    
    	delay5us();
    	return 0;
    }
    
    void ack(void)
    {
    	G_I2C_SDA_DIR(0);
    	G_I2C_SDA(0);
    	delay5us();
    	G_I2C_SCL(1);
    	delay5us();
    	G_I2C_SCL(0);
    	delay5us();
    	G_I2C_SDA(1);
    }	
    
    int no_ack(void)
    {
    	G_I2C_SDA_DIR(0);
    	G_I2C_SDA(1);
    	
    	delay5us();
    	G_I2C_SCL(1);
    	
    	delay5us();
    	G_I2C_SCL(0);
    	
    	delay5us();
    	return 0;
    
    }
    
    int write_g_i2c(unsigned char data)
    {
    	unsigned char i,temp,j;
    	G_I2C_SDA_DIR(0);
    	
    	for(i=0;i<8;i++)
    	{
    		temp=data&0x80;
    		if(temp==0x80)
    			G_I2C_SDA(1);
    			
    		else
    			G_I2C_SDA(0);
    			;
    		for(j=0;j<10;j++);
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		
    		
    		G_I2C_SCL(1);
    		for(j=0;j<10;j++);
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		G_I2C_SCL(0);
    		for(j=0;j<10;j++);
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		_delay1us();
    		
    		data=data<<1;
    	}
    	return 0;
    }
    
    unsigned char read_g_i2c(void)
    {
     	unsigned int i,j;
     	unsigned char byte=0;
    	u_long	flags;
    	
     	spin_lock_irqsave(&touch_lock, flags);
    	
     	G_I2C_SDA_DIR(1);
     
     	for(i=0;i<4000;i++);  //NEED TO ADD
     	
     	for(i=0;i<8;i++)
     		{
      		G_I2C_SCL(1);
      		for(j=0;j<10;j++);
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      
      		byte=byte<<1;
      		
      		if(G_I2C_SDA_READ()&(BIT_SET/*<<G_I2C_SDA_BIT*/))
       			byte=(byte|0x01);
      		//for(j=0;j<10;j++);
      		_delay1us();
      
      		G_I2C_SCL(0);
      
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      		_delay1us();
      
     		}
     		
      G_I2C_SDA_DIR(0);
      spin_unlock_irqrestore(&touch_lock, flags);
      
      return (byte);
       
    } 
    #endif
    
    int g_i2c_read_bytes(unsigned char chip,unsigned char addr,unsigned char *pData,unsigned char len)
    {
    #if 0
    		unsigned short i,j;
    		
    		g_i2c_init();
    		g_i2c_start();
    		write_g_i2c(chip<<1|0);
    		
    		if(test_ack()!=0)
    		{
    			return 0;
    		}
    		
    		write_g_i2c(addr); 
    		
    		if(test_ack()!=0)
    		{
    			return 0;
    		}
    	
    		G_I2C_SDA_DIR(0);
    	
    		g_i2c_start();
    		write_g_i2c(chip<<1|1);
    		
    		if(test_ack()!=0)
    		{
    			return 0;
    		}
    	
    		for(i=0;i<len;i++)
    		{
    			if(i==len-1)
    			{
    				*pData=read_g_i2c();
    				
    				for(j=0;j<4000;j++);	
    				
    				no_ack();
    			}
    			else
    			{
    				*pData=read_g_i2c(); 
    				ack();
    				pData++; 
    			}
    		}
    	
    		g_i2c_stop();
    		G_I2C_SDA_DIR(0);
    #endif
    	i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, addr, len, pData);
    	return 1;
    }
    
    int g_i2c_write_bytes(unsigned char chip,unsigned char addr,unsigned char *pData,unsigned char len)
    {
    #if 0
    		unsigned int i;
    		
    		g_i2c_init();
    		g_i2c_start();
    		write_g_i2c(chip<<1|0);
    		 
    		if(test_ack()!=0)
    		{
    			g_i2c_stop(); 	
    			return 0;
    		}
    		write_g_i2c(addr); 
    		if(test_ack()!=0)
    		{
    			g_i2c_stop(); 	
    			return 0;
    		}
    		
    		for(i=0;i<2000;i++); //must be used
    		
    		for(i=0;i<len;i++)
    		{
    			write_g_i2c(*pData); 
    			if(test_ack()!=0)
    			{
    				g_i2c_stop(); 	
    				return 0;
    			}
    			pData++; 
    		}
    		g_i2c_stop();
    #endif
    	i2c_smbus_write_i2c_block_data(ssd2531_i2c_client, addr, len, pData);
    	return 1;
    }
    
    void TP_Reset(void)
    {
    	//gpio_configure(SSD2531_RESET_GPIO, GPIOF_DRIVE_OUTPUT);
    	gpio_direction_output(SSD2531_RESET_GPIO, 1);
    	gpio_set_value(SSD2531_RESET_GPIO, 1);	
    	udelay(10);
    	gpio_set_value(SSD2531_RESET_GPIO, 0);
    	udelay(10);
    	gpio_set_value(SSD2531_RESET_GPIO, 1);
    	udelay(1);
    }
    
    //all init code in this file
    //#include "ssd2531_init.h"
    
    void TP_init(void)
    {
    	unsigned char reg = 0;
    	unsigned char value[4] = {0};
    
    	dbg("TP_init\n");
    	
    	TP_Reset();
    	
    	//exit sleep mode
    	reg = 0x23;
    	value[0] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	mdelay(10);
    	
    	//enable DSP clock
    	reg = 0x2b;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//Clk speed
    	reg = 0xd4;
    	value[0] = 0x08;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//ADC range
    	reg = 0xd7;
    	value[0] = 0x03;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//Drive No: 21
    	reg = 0x06;
    	value[0] = 0x0f;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Sense No: 12
    	reg = 0x07;
    	value[0] = 0x06;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 1 drive line reg
    	reg = 0x08;
    	value[0] = 0x09;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 2 drive line reg
    	reg = 0x09;
    	value[0] = 0x08;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 3 drive line reg
    	reg = 0x0a;
    	value[0] = 0x07;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 4 drive line reg
    	reg = 0x0b;
    	value[0] = 0x06;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 5 drive line reg
    	reg = 0x0c;
    	value[0] = 0x05;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 6 drive line reg
    	reg = 0x0d;
    	value[0] = 0x04;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 7 drive line reg
    	reg = 0x0e;
    	value[0] = 0x3;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 8 drive line reg
    	reg = 0x0f;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 9 drive line reg
    	reg = 0x10;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 10 drive line reg
    	reg = 0x11;
    	value[0] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 11 drive line reg
    	reg = 0x12;
    	value[0] = 0x14;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 12 drive line reg
    	reg = 0x13;
    	value[0] = 0x13;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 13 drive line reg
    	reg = 0x14;
    	value[0] = 0x12;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 14 drive line reg
    	reg = 0x15;
    	value[0] = 0x11;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 15 drive line reg
    	reg = 0x16;
    	value[0] = 0x10;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//Set 16 drive line reg
    	reg = 0x17;
    	value[0] = 0x0f;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	reg = 0x18;
    	value[0] = 0x0e;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 17 drive line reg
    	reg = 0x19;
    	value[0] = 0x0d;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Set 18 drive line reg
    	reg = 0x1a;
    	value[0] = 0x0c;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//Set 19 drive line reg
    	reg = 0x1b;
    	value[0] = 0x0b;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//Set 20 drive line reg
    	reg = 0x1c;
    	value[0] = 0x0a;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//sub-frame
    	reg = 0x2a;
    	value[0] = 0x03;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//enable RAM control mode
    	reg = 0x8d;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//RAM bank to scaling RAM
    	reg = 0x8e;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//initial scaling RAM
    	reg = 0x94;
    	value[0] = 0x00;
    	value[1] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//disable maunal RAM control  mode
    	reg = 0x8d;
    	value[0] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//set scan mode
      reg = 0x25;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    	mdelay(100);
    
    	//set charge bump x 6
    	reg = 0xc1;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
      //set driving voltage
    	reg = 0xd5;
    	value[0] = 0x0f;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    	mdelay(300);		
    	
    	//enable sense filter
    	reg = 0xd9;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//enable move tolerance
    	reg = 0x59;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//set max. miss frame
    	reg = 0x5b;
    	value[0] = 0x0a;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//set move tolerance
    	reg = 0x5a;
    	value[0] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//set median filter
    	reg = 0x2c;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//2D filter
    	reg = 0x3d;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	//Delta Data Ragne//is 0
    	reg = 0x38;
    	value[0] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//min. finger area
    	reg = 0x33;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//min finger level
      reg = 0x34;
    	value[0] = 0x40;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//finger weight threshold
    	reg = 0x35;
    	value[0] = 0x00;
    	value[1] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//max. finger area
    	reg = 0x36;
    	value[0] = 0x1e;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//enable curve fitting
    	reg = 0x39;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//segmentation depth
    	reg = 0x37;
    	value[0] = 0x03;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//enable finger 1&2//moving average
    	reg = 0x56;
    	value[0] = 0x01;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//single click timing
    	reg = 0x51;
    	value[0] = 0x00;
    	value[1] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//double click timing
    	reg = 0x52;
    	value[0] = 0x00;
    	value[1] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//CG tolerance
    	reg = 0x53;
    	value[0] = 0x10;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//X tracking
    	reg = 0x54;
    	value[0] = 0x30;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//Y tracking
    	reg = 0x55;
    	value[0] = 0x30;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    
    	//remap orientation
    	reg = 0x65;
    	value[0] = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    
    	reg = 0x66;
    	value[0] = 0x57;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	reg = 0x67;
    	value[0] = 0x50;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);
    	
    	//reset init reference
    	reg = 0xa2;
    	value[0] = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    	
    	//event mask
    	reg = 0x7a;
    	value[0] = 0xff;
    	value[1] = 0xbf;
    	i2c_smbus_write_i2c_block_data(ssd2531_i2c_client, reg, 2, value);
    
    	//irq mask
    	reg = 0x7b;
    	value[0] = 0xe0;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value[0]);	
    	mdelay(300);	
    }
    
    /*----------------------- i2c end -------------------*/
    
    #define PEN_DOWN 		5
    #define PEN_MOVE 		7
    #define PEN_UP 	 		6
    
    #define REG_EVENT_STATUS	0X79
    #define REG_EVENT_STACK	0X80
    #define REG_FINGER1			0X7c
    #define REG_FINGER2			0X7d
    #define REG_FINGER3			0X7e
    #define REG_FINGER4			0X7f
    
    #define FIFO_NOT_EMPTY 			0x10
    #define LCD_W 					320
    #define SSD2531_KEY_HOME 		230
    #define SSD2531_KEY_SEARCH 	84
    
    #define MULTI_TOUCH
    #define INVALID_VALUE		4095
    
    static struct work_struct ssd2531_wq;
    static int ssd2531_irq = 0;
    static struct input_dev *ssd2531_input = NULL;
    static struct input_dev *simulate_key_input = NULL;
    static struct early_suspend early_suspend;
    
    #ifndef MULTI_TOUCH
    	static unsigned short tmp_y = 480;
    #endif
    
    typedef struct
    {
    	unsigned short x1;
    	unsigned short y1;
    	unsigned short x2;
    	unsigned short y2;
    	unsigned short x3;
    	unsigned short y3;
    	unsigned short x4;
    	unsigned short y4;
    }FOUR_FINGER;
    
    static int ssd2531_read_four_finger(FOUR_FINGER *four_finger)
    {
    	unsigned char finger1_info[4] = {0};
    	unsigned char finger2_info[4] = {0};
    	unsigned char finger3_info[4] = {0};
    	unsigned char finger4_info[4] = {0};
    
    	if (four_finger == NULL)
    	{
    		return -1;
    	}
    	
    	i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_FINGER1, 4, finger1_info);
    	i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_FINGER2, 4, finger2_info);
    	i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_FINGER3, 4, finger3_info);
    	i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_FINGER4, 4, finger4_info);
    	
    	four_finger->x1 = ((finger1_info[2] & 0xf0) << 4) | finger1_info[0];
    	four_finger->y1 = ((finger1_info[2] & 0x0f) << 8) | finger1_info[1];
    	four_finger->x2 = ((finger2_info[2] & 0xf0) << 4) | finger2_info[0];
    	four_finger->y2 = ((finger2_info[2] & 0x0f) << 8) | finger2_info[1];
    	four_finger->x3 = ((finger3_info[2] & 0xf0) << 4) | finger3_info[0];
    	four_finger->y3 = ((finger3_info[2] & 0x0f) << 8) | finger3_info[1];
    	four_finger->x4 = ((finger4_info[2] & 0xf0) << 4) | finger4_info[0];
    	four_finger->y4 = ((finger4_info[2] & 0x0f) << 8) | finger4_info[1];
    
    	//dbg("F x1 = %d, y1 = %d\n", four_finger->x1, four_finger->y1);
    	//dbg("F x2 = %d, y2 = %d\n", four_finger->x2, four_finger->y2);
    	//dbg("F x3 = %d, y3 = %d\n", four_finger->x3, four_finger->y3);  
    	//dbg("F x4 = %d, y4 = %d\n", four_finger->x4, four_finger->y4);
    
    	return 0;
    		
    }
    
    static int ssd2531_report_four_finger(FOUR_FINGER *four_finger, unsigned short cord_y)
    {
    
    	if (four_finger == NULL)
    	{
    		return -1;
    	}
    	if (cord_y != 0) {
    		if ((four_finger->x1 != INVALID_VALUE) && (four_finger->y1 <= cord_y)) 
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x1);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y1);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);	
    			dbg("F x1 = %d, y1 = %d\n", four_finger->x1, four_finger->y1);
    		}
    
    		if ((four_finger->x2 != INVALID_VALUE)&& (four_finger->y2 <= cord_y))
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x2);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y2);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);	
    			dbg("F x2 = %d, y2 = %d\n", four_finger->x2, four_finger->y2);
    		}
    
    		if ((four_finger->x3 != INVALID_VALUE)&& (four_finger->y3 <= cord_y))
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x3);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y3);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);
    			dbg("F x3 = %d, y3 = %d\n", four_finger->x3, four_finger->y3);  
    		}
    
    		if ((four_finger->x4 != INVALID_VALUE)&& (four_finger->y4 <= cord_y))
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x4);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y4);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);
    			dbg("F x4 = %d, y4 = %d\n", four_finger->x4, four_finger->y4);
    		}
    	}
    	else {
    		if (four_finger->x1 != INVALID_VALUE) 
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x1);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y1);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);	
    			dbg("F x1 = %d, y1 = %d\n", four_finger->x1, four_finger->y1);
    		}
    
    		if (four_finger->x2 != INVALID_VALUE)
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x2);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y2);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);	
    			dbg("F x2 = %d, y2 = %d\n", four_finger->x2, four_finger->y2);
    		}
    
    		if (four_finger->x3 != INVALID_VALUE)
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x3);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y3);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);
    			dbg("F x3 = %d, y3 = %d\n", four_finger->x3, four_finger->y3);  
    		}
    
    		if (four_finger->x4 != INVALID_VALUE)
    		{
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_X, four_finger->x4);
    			input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, four_finger->y4);
    			input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    			input_mt_sync(ssd2531_input);
    			dbg("F x4 = %d, y4 = %d\n", four_finger->x4, four_finger->y4);
    		}				
    	}
    
    	return 0;
    	
    }
    
    
    static int ssd2531_get_event_info(void)
    {
    	unsigned char event_type = 0;
    	unsigned char finger_num = 0;
    	unsigned char event_status = 0;
    	unsigned char event_stack[4] = {0};
    	unsigned short x0 = 0;
    	unsigned short y0 = 0;
    	unsigned char reg = 0;
    	unsigned char value = 0;
    	
    #ifdef CONFIG_TRULY
    	unsigned char finger1_info_[4] = {0};
    	unsigned char finger2_info_[4] = {0};
    	unsigned short x1 = 0;
    	unsigned short y1 = 0;
    	unsigned short x2 = 0;
    	unsigned short y2 = 0;
    #endif
    	FOUR_FINGER four_finger = {0};
    
    #if defined(CONFIG_CELLON_PRJ_C8093)
    	unsigned short area_value;
    	unsigned short cord_y = 0;
    	
    	if (touchscreen_is_giantplus == 1) {
    		cord_y = 480;
    	} 
    	else {
    		cord_y = 470;
    	}
    #endif
    
    	#ifdef CONFIG_TRULY
    		i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_FINGER1, 4, finger1_info_);
    		i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_FINGER2, 4, finger2_info_);
    	#endif
    		event_status=i2c_smbus_read_byte_data(ssd2531_i2c_client, REG_EVENT_STATUS);
    		i2c_smbus_read_i2c_block_data(ssd2531_i2c_client, REG_EVENT_STACK, 4, event_stack);
    		finger_num =  event_stack[0] & 0xf0;		
    		event_type =  event_stack[0] & 0x0f;
    		//printk("===========event_type=%d============\n", event_type);
    		if (event_type != 0)
    		{
    			if(event_type == 15) {
    				error_times++;
    				if (error_times == 10) {
    					error_times = 0;
    					/*sleep ssd2531*/
    					reg = 0x24;
    					value = 0x00;
    					if (i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value) < 0)
    						{
    							pr_info("---tp_init_truly_c8096    write err---\n");
    						}
    					mdelay(10);
    					reg = 0x25;
    					value = 0x00;
    					i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    					mdelay(20);
    
    					/*exit sleep ssd2531*/
    					reg = 0x23;
    					value = 0x00;
    					i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    					mdelay(10);
    					reg = 0x25;
    					value = 0x02;
    					i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    					mdelay(10);
    				}
    			}
    			else {
    				error_times = 0;
    			}
    			
    
    #ifdef CONFIG_TRULY
    			if (event_status == 0x13) {
    				x1 = ((finger1_info_[2] & 0xf0) << 4) | finger1_info_[0];
    				y1 = ((finger1_info_[2] & 0x0f) << 8) | finger1_info_[1];
    				x2 = ((finger2_info_[2] & 0xf0) << 4) | finger2_info_[0];
    				y2 = ((finger2_info_[2] & 0x0f) << 8) | finger2_info_[1];
    
    				if ((abs(x1 - x2) < 80) && (abs(y1 - y2) < 80) 
    					&& (x1 != INVALID_VALUE) && (x2 != INVALID_VALUE)) {
    
    					input_report_abs(ssd2531_input, ABS_MT_POSITION_X, x1);
    					input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, y1);
    					input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    					input_mt_sync(ssd2531_input);	
    					input_sync(ssd2531_input);	
    					return 0;
    				}
    			}
    #endif
    			x0 = ((event_stack[3] & 0xf0) << 4) | event_stack[1];			
    			y0 = ((event_stack[3] & 0x0f) << 8) | event_stack[2];
    
    			#ifdef MULTI_TOUCH
    			ssd2531_read_four_finger(&four_finger);
    			#endif
    #if defined(CONFIG_CELLON_PRJ_C8093)	
    			area_value = in_key_area(x0, y0, cord_y);
    			
    		#ifndef AFTER_TS
    			if ((area_value != abs(pre_key_value)) &&  (pre_key_value < 0)) {  
    				pre_key_value = abs(pre_key_value);
    				input_report_key(simulate_key_input, pre_key_value, 0);
    				input_sync(simulate_key_input);
    				dbg("Key--%d--UP_MT..~!\n", pre_key_value);
    			}
    		#else
    			if ((area_value != 0)&&(area_value != abs(pre_key_value)) &&  (pre_key_value < 0)) {  
    				pre_key_value = abs(pre_key_value);
    				input_report_key(simulate_key_input, pre_key_value, 0);
    				input_sync(simulate_key_input);
    			} 
    		#endif
    
    
    			if (area_value != 0) {
    				
    				if (pre_state ==  1) {
    					pre_state = 0;			
    					input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 0);
    					input_mt_sync(ssd2531_input);
    					input_sync(ssd2531_input);
    				}			
    				
    				if (event_type == PEN_DOWN) {
    					input_report_key(simulate_key_input, area_value, 1);
    					pre_key_value = -area_value;
    					//input_sync(simulate_key_input);
    					dbg("Key_%d _DOWN!\n", area_value);
    				}
    				else if(event_type == PEN_UP) {
    					pre_key_value = area_value;
    					input_report_key(simulate_key_input, area_value, 0);
    					input_sync(simulate_key_input);
    					dbg("Key_%d _UP!\n", area_value);
    				}
    				#ifndef MULTI_TOUCH
    				tmp_y = y0;
    				#endif
    				return 0;
    			}
    
    
    			if (event_type == PEN_DOWN)
    			{
    				#ifndef MULTI_TOUCH
    				
    				if( y0 <= cord_y){
    					pre_state = 1;	
    					input_report_abs(ssd2531_input, ABS_X, x0);
    					input_report_abs(ssd2531_input, ABS_Y, y0);
    					input_report_abs(ssd2531_input, ABS_PRESSURE, 1);
    					input_report_key(ssd2531_input, BTN_TOUCH, 1);
    					dbg("PEN_DOWN_x0 = %d, y0 = %d\n", x0 , y0);
    				} 
    			
    				#else
    				pre_state = 1;	
    				ssd2531_report_four_finger(&four_finger, cord_y);
    				
    				if (((finger_num == 16 && four_finger.x1 == INVALID_VALUE)
    					|| (finger_num == 32 && four_finger.x2 == INVALID_VALUE)
    					|| (finger_num == 64 && four_finger.x3 == INVALID_VALUE)
    					|| (finger_num == 128 && four_finger.x4 == INVALID_VALUE)
    					)&& y0 <= cord_y)
    				{
    					input_report_abs(ssd2531_input, ABS_MT_POSITION_X, x0);
    					input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, y0);
    					input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    					input_mt_sync(ssd2531_input);
    					dbg("F x0 = %d, y0 = %d\n", x0, y0);
    				}
    				
    				#endif
    			}
    			else if (event_type == PEN_MOVE)
    			{
    				#ifndef MULTI_TOUCH
    				
    				if( y0 <= cord_y) {
    					pre_state = 1;	
    					if(tmp_y > cord_y) {
    						input_report_abs(ssd2531_input, ABS_X, x0);
    						input_report_abs(ssd2531_input, ABS_Y, y0);
    						input_report_abs(ssd2531_input, ABS_PRESSURE, 1);
    						input_report_key(ssd2531_input, BTN_TOUCH, 1);
    						dbg("PEN__MOVE_AS_DOWN_x0 = %d, y0 = %d\n", x0 , y0);		
    					}
    					else {
    						input_report_abs(ssd2531_input, ABS_X, x0);
    						input_report_abs(ssd2531_input, ABS_Y, y0);
    						input_report_abs(ssd2531_input, ABS_PRESSURE, 255);
    						dbg("PEN_MOVE_x0 = %d, y0 = %d\n", x0 , y0);
    					}
    				}
    				
    				#else
    				pre_state = 1;
    				ssd2531_report_four_finger(&four_finger, cord_y);	
    				#endif
    			}
    			else if (event_type == PEN_UP)
    			{
    				#ifndef MULTI_TOUCH
    				
    				if( y0 <= cord_y) {
    					pre_state = 0;
    					input_report_abs(ssd2531_input, ABS_PRESSURE, 0);
    					input_report_key(ssd2531_input, BTN_TOUCH, 0);
    					dbg("PEN_UP_x0 = %d, y0 = %d\n", x0 , y0);
    				}
    				
    				#else
    				pre_state = 0;
    
    				dbg("F_UP__--Start......\n");
    				ssd2531_report_four_finger(&four_finger, cord_y);				
    				input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 0);
    				input_mt_sync(ssd2531_input);
    				dbg("F_UP__--END  .....\n");
    				#endif
    			}	
    						
    			#ifdef AFTER_TS
    			if((area_value == 0)&& (pre_key_value < 0)){
    				pre_key_value = abs(pre_key_value);
    				input_report_key(simulate_key_input, pre_key_value, 0);
    				input_sync(simulate_key_input);
    			}
    			#endif
    
    			#ifndef MULTI_TOUCH
    			tmp_y = y0;		
    			#endif
    
    #else
    		if (event_type == PEN_DOWN)
    		{
    			#ifndef MULTI_TOUCH
    			input_report_abs(ssd2531_input, ABS_X, x0);
    			input_report_abs(ssd2531_input, ABS_Y, y0);
    			input_report_abs(ssd2531_input, ABS_PRESSURE, 1);
    			input_report_key(ssd2531_input, BTN_TOUCH, 1);
    
    			#else
    			pre_state = 1;	
    			ssd2531_report_four_finger(&four_finger, 0);
    				
    			if ((finger_num == 16 && four_finger.x1 == INVALID_VALUE)
    				|| (finger_num == 32 && four_finger.x2 == INVALID_VALUE)
    				|| (finger_num == 64 && four_finger.x3 == INVALID_VALUE)
    				|| (finger_num == 128 && four_finger.x4 == INVALID_VALUE)
    				)
    			{
    				input_report_abs(ssd2531_input, ABS_MT_POSITION_X, x0);
    				input_report_abs(ssd2531_input, ABS_MT_POSITION_Y, y0);
    				input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 1);
    				input_mt_sync(ssd2531_input);
    			}
    				
    			#endif
    			}
    			else if (event_type == PEN_MOVE)
    			{
    				#ifndef MULTI_TOUCH
    				input_report_abs(ssd2531_input, ABS_X, x0);
    				input_report_abs(ssd2531_input, ABS_Y, y0);
    				input_report_abs(ssd2531_input, ABS_PRESSURE, 255);
    				#else
    				pre_state = 1;
    				ssd2531_report_four_finger(&four_finger, 0);				
    				#endif
    			}
    			else if (event_type == PEN_UP)
    			{
    				#ifndef MULTI_TOUCH
    				input_report_abs(ssd2531_input, ABS_PRESSURE, 0);
    				input_report_key(ssd2531_input, BTN_TOUCH, 0);
    				#else
    				pre_state = 0;
    				
    				ssd2531_report_four_finger(&four_finger, 0);				
    
    				input_report_abs(ssd2531_input, ABS_MT_TOUCH_MAJOR, 0);
    				input_mt_sync(ssd2531_input);
    				#endif
    			}
    #endif
    	}	
    	input_sync(ssd2531_input);
    
    	return 0;				
    }
    
    
    static irqreturn_t ssd2531_interrupt(int irq, void *dev_id)
    {	
    	disable_irq_nosync(ssd2531_irq);
    	//printk("==========irq=============\n");
    	schedule_work(&ssd2531_wq);
    	
    	return IRQ_HANDLED;
    }
    
    static void ssd2531_do_work(struct work_struct *work)
    {
    	ssd2531_get_event_info();
    	enable_irq(ssd2531_irq);
    }
    
    
    static int ssd2531_init_input(void)
    {
    	int result = 0;
    	
    	ssd2531_input = input_allocate_device();
    	if (ssd2531_input == NULL) {
    		dbg("%s: not enough memory for input device\n", __func__);
    		result = -ENOMEM;
    		goto fail_alloc_input;
    	}
    	ssd2531_input->name = "ssd2531_input";
    	
    	//setting the supported event type and code
    	__set_bit(EV_KEY, ssd2531_input->evbit);
    	__set_bit(EV_ABS, ssd2531_input->evbit);
    	#ifndef MULTI_TOUCH
    	__set_bit(BTN_TOUCH, ssd2531_input->keybit);
    	__set_bit(ABS_X, ssd2531_input->absbit);
    	__set_bit(ABS_Y, ssd2531_input->absbit);
    	__set_bit(ABS_PRESSURE, ssd2531_input->absbit);	
    	#else
    	__set_bit(ABS_MT_TOUCH_MAJOR, ssd2531_input->absbit);
    	__set_bit(ABS_MT_POSITION_X, ssd2531_input->absbit);
    	__set_bit(ABS_MT_POSITION_Y, ssd2531_input->absbit);
    	#endif
    	
    	result = input_register_device(ssd2531_input);
    	if (result != 0) {
    		dbg("%s: failed to register input device\n", __func__);
    		goto fail_input_dev_reg;
    	}
    
    	//create simulate key input
    	simulate_key_input = input_allocate_device();
    	if (simulate_key_input == NULL) {
    		dbg("%s: not enough memory for input device\n", __func__);
    		result = -ENOMEM;
    		goto fail_alloc_simulate_key_input;
    	}
    	simulate_key_input->name = "7k_ffa_keypad";
    	__set_bit(EV_KEY, simulate_key_input->evbit);
    	__set_bit(KEY_BACK, simulate_key_input->keybit);
    	__set_bit(KEY_MENU, simulate_key_input->keybit);
    	__set_bit(SSD2531_KEY_HOME, simulate_key_input->keybit);
    	__set_bit(SSD2531_KEY_SEARCH, simulate_key_input->keybit);
    	result = input_register_device(simulate_key_input);
    	if (result != 0) {
    		dbg("%s: failed to register input device\n", __func__);
    		goto fail_simulate_key_input_dev_reg;
    	}
    	
    	return 0;
    
    fail_simulate_key_input_dev_reg:
    	input_free_device(simulate_key_input);
    	
    fail_alloc_simulate_key_input:
    	input_unregister_device(ssd2531_input);
    	
    fail_input_dev_reg:	
    	input_free_device(ssd2531_input);
    	
    fail_alloc_input:	
    	return result;
    		
    }
    
    static void ssd2531_early_suspend(struct early_suspend *h)
    {
    	unsigned char reg = 0;
    	unsigned char value = 0;
    
    	printk("enter ssd2531_early_suspend\n");
    
    	reg = 0x24;
    	value = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    	mdelay(10);
    
    	reg = 0x25;
    	value = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    	mdelay(10);
    	
    }
    
    static void ssd2531_late_resume(struct early_suspend *h)
    {
    	unsigned char reg = 0;
    	unsigned char value = 0;
    
    	printk("enter ssd2531_late_resume\n");
    
    	
    //exit sleep mode
    	reg = 0x23;
    	value = 0x00;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    	mdelay(10);
    
    	reg = 0x25;
    	value = 0x02;
    	i2c_smbus_write_byte_data(ssd2531_i2c_client, reg, value);
    	mdelay(10);
    
    }
    
    static int __devinit ssd2531_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
    	int  err = 0;
    
    	#ifdef CONFIG_GIANTPLUS
    	touchscreen_is_giantplus = 1;
    	#else
    	touchscreen_is_giantplus = 0;
    	#endif
    
    	ssd2531_i2c_client = client;
    	
    
    	gpio_request(SSD2531_INT_GPIO, "interrupt");
    	gpio_request(SSD2531_RESET_GPIO, "reset");
    	gpio_direction_output(SSD2531_INT_GPIO, 1);
    
    	TP_init();
    	INIT_WORK(&ssd2531_wq, ssd2531_do_work);
    	ssd2531_init_input();
    	ssd2531_irq = gpio_to_irq(SSD2531_INT_GPIO);	
    	err = request_irq(ssd2531_irq, ssd2531_interrupt, 
    							IRQF_TRIGGER_LOW, "ssd2531", NULL);
    	if (err != 0) {
    		printk("%s: cannot register irq\n", __func__);
    		goto exit;
    	}	
    
    	#ifdef CONFIG_HAS_EARLYSUSPEND
    	early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
    	early_suspend.suspend = ssd2531_early_suspend;
    	early_suspend.resume = ssd2531_late_resume;
    	register_early_suspend(&early_suspend);
    	#endif
    
    	return 0;
    	
    exit:
    	return err;
    }
    
    static int __devexit ssd2531_remove(struct i2c_client *client)
    {
    	//free_irq(ssd2531_irq, NULL);
    	//input_unregister_device(ssd2531_input);
    	//input_unregister_device(simulate_key_input);
    	
    	return 0;
    }
    
    static int __init ssd2531_init(void)
    {
    
    	//#ifdef CONFIG_TRULY
    	#ifdef CONFIG_GIANTPLUS
    	touchscreen_is_giantplus = 1;
    	#else
    	touchscreen_is_giantplus = 0;
    	#endif
    	printk("=====ssd2531_driver=====\n");
    	return i2c_add_driver(&ssd2531_driver);
    }
    
    static void __exit ssd2531_exit(void)
    {
    	dbg("ssd2531_exit\n");
    
    //	unregister_early_suspend(&early_suspend);
    	
    	free_irq(ssd2531_irq, NULL);
    	input_unregister_device(ssd2531_input);
    	input_unregister_device(simulate_key_input);
    
    	i2c_del_driver(&ssd2531_driver);
    }
    
    module_init(ssd2531_Init);
    
    module_exit(ssd2531_exit);
    
    

    Thanks

    Harsh