ssd2531 Capacitive Touch Panel driver

调试记录:

1.编译uImage进行调试,报告如下错误,reset host i2c,I2C不通。原因是,android是先加载uImage后再初始化I2C的,故出错,I2C不通。

2.原以为在硬件正确的情况下,触屏就会有中断。(ssd2531是低电平中断的)后来,了解后,才知,只有IC初始化正常后,中断才是可用的。

3.对linux的编译系统不了解,犯了好多错误。

编译命令笔记:

root@sunny-desktop:/home/4g/BSP/Kernel/linux-2.6.29-ssl# make ARCH=arm CROSS_COMPILE=arm-eabi- menuconfig


root@sunny-desktop:/home/4g/BSP/Kernel/linux-2.6.29-ssl# make ARCH=arm CROSS_COMPILE=arm-eabi- modules


/usr/system/setup.sh_bk


mount /usr -o remount,rw
rmmod mma7455l
echo 8 > /proc/sys/kernel/printk

insmod tp_dss2521.ko

驱动原代码如下:


//==================================================================//
// Project Name: Touch Panel (AUO TP2) for Linux System
// Engineer: David Dai
// Create Date: 2010/06/02
// Revision:
//			
//==================================================================//

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <asm/gpio.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/hardware.h>
#include <linux/timer.h>

#define   debug_ssd2521 0
//#define SINGLE_TOUCH
#if 0         
#include <linux/init.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/irqs.h>
//#nclude <asm/gpio.h>include <asm/arch/regs-gpio.h>

#include <asm/gpio.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/ioctl.h>

#endif
#define AUO_INT_LOW         1    
#define  Android_AUO_TSC_INT   GPIO_NUM(3, 17) //PD17
int tp_ssd2521_major = 60;
static long int time=0;
static struct i2c_client *save_client=NULL;
static struct work_struct works,works_timer;
struct gpio_reg{
    uint32_t ctl_reg;
    uint32_t func_reg;
    uint32_t mod_reg;
    uint32_t pull_en_reg;
    uint32_t direc_reg;
    uint32_t OSSR1_reg;
    uint32_t OSSR2_reg;
    uint32_t ISSA1_reg;
    uint32_t ISSA2_reg;
    uint32_t ISSB1_reg;
    uint32_t ISSB2_reg;
    uint32_t data_reg;
    uint32_t int_cfg1_reg;
    uint32_t int_cfg2_reg;
    uint32_t IER_reg;
    uint32_t ISR_reg;
    uint32_t pull_sel_reg;
};
struct MT_Info
{
	u8 press;
	int32_t x;
	int32_t y;	
} mt_buf[4]={{0,0,0},{0,0,0},{0,0,0},{0,0,0}},last_mt_buf[4];
typedef struct
{
	int32_t a;
	int32_t b;
	int32_t c;
	int32_t d;
	int32_t e;
	int32_t f;
	int32_t div;
} ssd2521_cal_t;
static ssd2521_cal_t calibrate ={1,0,0,0,1,0,1};
#define FINGER_ID ABS_CNT
#define FINGER_TYPE ABS_MT_TOOL_TYPE

struct gpio_reg g_irq_reg;
const char *auo_ts_name ="SSL TouchScreen";

static void tp_ssd2521_timer_handle(unsigned long data);
static void i2c_access_work(struct work_struct *work);
static int tp_ssd2521_attach_adapter(struct i2c_adapter *adapter);
static int tp_ssd2521_detach_client(struct i2c_client *client);
/* Structure for Input Type*/
struct auo_tp2_ts{
	struct input_dev * dev;
	long xp1;
	long yp1;
	char phys[32]; //for raw data or others  
};

static struct auo_tp2_ts *ts;
static int ssd2521_suspend(struct i2c_client *client, pm_message_t message);
static int ssd2521_resume(struct i2c_client *client);
static struct i2c_driver tp_driver={
	.driver ={
		.name = "tp_ssd2521",
	},
	.attach_adapter = tp_ssd2521_attach_adapter,
	.detach_client  = tp_ssd2521_detach_client,
#ifdef CONFIG_PM
	.suspend	= ssd2521_suspend,
	.resume		= ssd2521_resume,
#endif
};
void tp_ssd2521_exit(void); 
static unsigned short normal_i2c[] = { 0x5C, I2C_CLIENT_END }; //slave's 7 bit address is 0x5c or 0x48
I2C_CLIENT_INSMOD_1(tp_ssd2521);
struct timer_list *tp_ssd2521_timer;
static int tp_ssd2521_init(void)
{
	int result;		
	tp_ssd2521_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
	init_timer(tp_ssd2521_timer);
	#if debug_ssd2521
	printk( "start i2c_add_driver(&tp_driver);\n");
	#endif
	result=i2c_add_driver(&tp_driver);
	#if debug_ssd2521
	printk( "end i2c_add_driver(&tp_driver); \n");
	#endif
	if (result)
        goto fail;
	#if debug_ssd2521
	printk( KERN_ALERT "Inserting tp_ssd2521 module %d\n",result);
	#endif
	return 0;
	
fail: 
	tp_ssd2521_exit(); 
	return result;
}

static ssize_t ssd2521_calibrate_set (struct device *dev,
		struct device_attribute *attr, char *buf);
static DEVICE_ATTR (calibrate, 0666, NULL, ssd2521_calibrate_set);
static struct attribute *ssd2521_attributes[] = {
			&dev_attr_calibrate.attr,
				NULL,
};
static struct attribute_group ssd2521_attr_group = {
		.attrs = ssd2521_attributes,
};
static uint32_t irq;
#define SSD2521_CAL_RESET	"reset"
#define SSD2521_CAL_SHOW	"show"
void ssl_calibrate_for_Android(int32_t *x, int32_t *y);
static ssize_t ssd2521_calibrate_set (struct device *dev,
		struct device_attribute *attr, char *buf)
{
	int32_t a,b,c,d,e,f,div;
	uint32_t x,y;

	if (strncmp(buf,SSD2521_CAL_RESET,sizeof(SSD2521_CAL_RESET)-1)==0)
	{
		calibrate.a=1;
		calibrate.b=0;
		calibrate.c=0;
		calibrate.d=0;
		calibrate.e=1;
		calibrate.f=0;
		calibrate.div=1;
		goto _exit;
	}
	if (strncmp(buf,SSD2521_CAL_SHOW,sizeof(SSD2521_CAL_SHOW)-1)==0)
	{
		x=100;y=200;
		ssl_calibrate_for_Android(&x, &y);
		printk("(100,200) -> (%d, %d)\n", x,y);
		x=900;y=200;
		ssl_calibrate_for_Android(&x, &y);
		printk("(900,200) -> (%d, %d)\n", x,y);
		x=100;y=800;
		ssl_calibrate_for_Android(&x, &y);
		printk("(100,800) -> (%d, %d)\n", x,y);
		x=900;y=800;
		ssl_calibrate_for_Android(&x, &y);
		printk("(900,800) -> (%d, %d)\n", x,y);
		goto _exit;
	}

	sscanf(buf,"%d %d %d %d %d %d %d",&a,&b,&c,&d,&e,&f,&div);
	if (0==div) 
	{
		printk("ssd2531 canot set the div to 0!\n");
		goto _exit;
	}

	calibrate.a=a;
	calibrate.b=b;
	calibrate.c=c;
	calibrate.d=d;
	calibrate.e=e;
	calibrate.f=f;
	calibrate.div=div;	

_exit:	
	printk("ssd2531 calibration data:\n %d %d %d %d %d %d %d\n",calibrate.a, calibrate.b,\
			calibrate.c,calibrate.d, calibrate.e,calibrate.f,calibrate.div);
	return -1;
}

void tp_ssd2521_exit(void) 
{
	sysfs_remove_group(&save_client->dev.kobj, &ssd2521_attr_group);
	disable_irq (irq);
	free_irq(irq,ts->dev) ;
	cancel_work_sync (&works);
	del_timer(tp_ssd2521_timer);
	kfree(tp_ssd2521_timer);
	i2c_del_driver(&tp_driver);
	printk( KERN_ALERT "Removing tp_ssd2521 module\n");
}
void tp_ssd2521_read_reg(u8 addr,u8 len);
u8 tp_ssd2521_write_reg(struct i2c_client *client,const char *buf ,int count);
struct tp_ssd2521_data{
	struct i2c_client client;
};
static irqreturn_t stylus_action(int irqno, void *param)
{
	//time=jiffies_to_msecs(get_jiffies_64());
	//printk("---------------%li\n",time);
	#if debug_ssd2521
		printk("in stylus_action \n");
	#endif
	disable_irq(irq);
	schedule_work(&works);
	printk("in stylus_action \n");
	//enable_irq(irqno);
	return IRQ_HANDLED;
}
static void tp_ssd2521_timer_work(struct work_struct *work);

/* This function is called by i2c_probe */
static int tp_ssd2521_detect(struct i2c_adapter *adapter, int address, int kind)
{
	
	u8 tx_buff[4];
	u8 Panel_D=16;
	u8 Panel_S=10;
	u8 Skw_Rate=0;
	u8 tmp;
	struct input_dev *pInput_dev;

	//================================//
	//    Register as I2C Client      //
	//================================//
	
	struct i2c_client *new_client;
	struct tp_ssd2521_data *data;
	#if debug_ssd2521
	printk("in tp_ssd2521_detect \n");
	#endif
	int err = 0;
	
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA|I2C_FUNC_SMBUS_BYTE))
		goto exit;
	
	if (!(data = kzalloc(sizeof(struct tp_ssd2521_data), GFP_KERNEL))) {
		err = -ENOMEM;
		goto exit;
	}
	new_client = &data->client;
	save_client=new_client;
	//memset(data->data, 0xff, EEPROM_SIZE);
	printk("reach i2c_set_clientdata \n");
	i2c_set_clientdata(new_client, data);
	new_client->addr = address;
	new_client->adapter = adapter;
	new_client->driver = &tp_driver;
	new_client->flags = 0;
	#if debug_ssd2521
	if(new_client->adapter==NULL)
	printk("new_client->adapter==NULL \n");
	if(save_client->adapter==NULL)
	printk("save_client->adapter==NULL \n");
	#endif
	if (err = i2c_attach_client(new_client))
		goto exit_kfree;
	//=====================================//
	//    Touch Panel Setting & Calibrate  //
	//=====================================//	
	printk("reach Touch Panel Setting & Calibrate \n");
	tx_buff[0]=0x23; 
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//exit sleep mode
	msleep(10);
	tx_buff[0]=0x2B;
	tx_buff[1]=0x03;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//turn on clock
	tx_buff[0]=0xD4;
	tx_buff[1]=0x08;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//enable sense filter
	tx_buff[0]=0x65;
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//median filter 0 to 2
	tx_buff[0]=0x06;
	tx_buff[1]=0x0e;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//filter type for delta data default=0:1-6-1
	tx_buff[0]=0x07;
	tx_buff[1]=0x06;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//sampling delay
	tx_buff[0]=0x08;
	tx_buff[1]=0x14; //0x07
	tp_ssd2521_write_reg(new_client,tx_buff,2);//POR=04
	tx_buff[0]=0x09;
	tx_buff[1]=0x13;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//Enable self-cap
	tx_buff[0]=0x0a;
	tx_buff[1]=0x12;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//Enable self-cap
	tx_buff[0]=0x0b;
	tx_buff[1]=0x11; //Clk select
	tp_ssd2521_write_reg(new_client,tx_buff,2);//F set osc frequency default =0,range 0 to F
	tx_buff[0]=0x0c;
	tx_buff[1]=0x10;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set drive line
	tx_buff[0]=0x0d;
	tx_buff[1]=0X0F;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set sense line
	tx_buff[0]=0x0E;
	tx_buff[1]=0x0E;//9 //0A
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x0F;
	tx_buff[1]=0x0D;//0B
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x10;
	tx_buff[1]=0x0C;//0C
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x11;
	tx_buff[1]=0x0B;//0D
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x12;
	tx_buff[1]=0x00;//0E
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x13;
	tx_buff[1]=0x01;//0F
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0X14;
	tx_buff[1]=0x02;//10;
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x15;
	tx_buff[1]=0x03;//05;
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x16;
	tx_buff[1]=0x04;
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x17;
	tx_buff[1]=0x05;//03;//10
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x18;
	tx_buff[1]=0x06;//02;//19
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x19;
	tx_buff[1]=0x07;//01;//20
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x1A;
	tx_buff[1]=0x08;//00;//0
    	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x1B;
	tx_buff[1]=0x09;//13;//1
	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0xD8;
	tx_buff[1]=0x03;//14;//2
	tp_ssd2521_write_reg(new_client,tx_buff,2);
	tx_buff[0]=0x2A;
	tx_buff[1]=0x03;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set sub-frame default =3 ,range 0 to F
	tx_buff[0]=0x8D;
	tx_buff[1]=0x01;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//enable manual RAM control mode 
	tx_buff[0]=0x8E;
	tx_buff[1]=0x02;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set RAM bank to scaling RAM
	tx_buff[0]=0x94;
	tx_buff[1]=0x00;
	tx_buff[2]=0x00;
	tp_ssd2521_write_reg(new_client,tx_buff,3);//init scaling RAM
	tx_buff[0]=0x8D;
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//disable manual RAM control
	tx_buff[0]=0x25;
	tx_buff[1]=0x02; //0x04 06
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set scan mode
	msleep(100);
	tx_buff[0]=0xc1;
	tx_buff[1]=0x02;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set power down time
	tx_buff[0]=0xd5;
	tx_buff[1]=0x0F;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set No of frames escape without finger touch before enter powersave mode
	msleep(300);
	tx_buff[0]=0xd9;
	tx_buff[1]=0x01;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set charge bump * 6
	tx_buff[0]=0x59;
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set driving voltage
	
	tx_buff[0]=0x5b;
	tx_buff[1]=0x02;
    	tp_ssd2521_write_reg(new_client,tx_buff,2);//delta data range original
	tx_buff[0]=0x5a;
	tx_buff[1]=0x00; //0x02
    	tp_ssd2521_write_reg(new_client,tx_buff,2);//set min ,finger area
	tx_buff[0]=0x2c;
	tx_buff[1]=0x02;//4f,3f,45.48 50 <=======
    	tp_ssd2521_write_reg(new_client,tx_buff,2);//set min finger level
	tx_buff[0]=0x3d;
	tx_buff[1]=0x01;
    	tp_ssd2521_write_reg(new_client,tx_buff,2);//finger weight threshold
	tx_buff[0]=0x38;
	tx_buff[1]=0x00;//1e,22
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set max finger area
	tx_buff[0]=0x33;
	tx_buff[1]=0x01;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//set segmentation depth
	tx_buff[0]=0x34;
	tx_buff[1]=0x60; //0x01
	tp_ssd2521_write_reg(new_client,tx_buff,2);// 1:enable curve fitting 0:disable curve fitting
	tx_buff[0]=0x35;
	tx_buff[1]=0x00;
	tx_buff[2]=0x02;
	tp_ssd2521_write_reg(new_client,tx_buff,3);// 1:enable finger 1&2 moving average 0:disable
	tx_buff[0]=0x36;
	tx_buff[1]=0x1e;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//single click timing
	tx_buff[0]=0x37;
	tx_buff[1]=0x03;

	tp_ssd2521_write_reg(new_client,tx_buff,2);//double click timing
	tx_buff[0]=0x39;
	tx_buff[1]=0x00; //0x04
	tp_ssd2521_write_reg(new_client,tx_buff,2);//CG tolerance
	tx_buff[0]=0x56;
	tx_buff[1]=0x01; //0x2F AF
	tp_ssd2521_write_reg(new_client,tx_buff,2);//X tracking
	tx_buff[0]=0x51;
	tx_buff[1]=0x00; //1F
	tx_buff[2]=0x0f;
	tp_ssd2521_write_reg(new_client,tx_buff,3);//Y tracking
	tx_buff[0]=0x52;
	tx_buff[1]=0x02;
	tx_buff[2]=0xff;
	tp_ssd2521_write_reg(new_client,tx_buff,3);//Moving average filter
	tx_buff[0]=0x53;
	tx_buff[1]=0x08;	//0x31;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//X scaling xx.xxxxxx x1
	tx_buff[0]=0x54;
	tx_buff[1]=0x14;	//0x3F;
	tp_ssd2521_write_reg(new_client,tx_buff,2);//Y scaling xx.xxxxxx x1
	tx_buff[0]=0x55;
	tx_buff[0]=0x14;
	tp_ssd2521_write_reg(new_client,tx_buff,2);	//Event Stack Clear
	tx_buff[0]=0x7A;
	tx_buff[1]=0x80; //0xEF
	tx_buff[2]=0x00; //0x1F
	tp_ssd2521_write_reg(new_client,tx_buff,3); //Event Mask
	tx_buff[0]=0x7B;
	tx_buff[1]=0xe0; //0xE0
	tp_ssd2521_write_reg(new_client,tx_buff,2);//IRQ Mask
	tx_buff[0]=0x67;
	tx_buff[1]=0x54;
	tp_ssd2521_write_reg(new_client,tx_buff,1);	//Event Stack Clear
	
	tx_buff[0]=0x66; //
	tx_buff[1]=0x57; //
	tp_ssd2521_write_reg(new_client,tx_buff,2);//Enable moving tolerance
	tx_buff[0]=0xa2; //
	tx_buff[1]=0x00; //
	tp_ssd2521_write_reg(new_client,tx_buff,2);
		
	msleep(600);
	printk("reach msleep(600); \n");
	tp_ssd2521_read_reg(0x02,2);
	tp_ssd2521_read_reg(0x26,1);
	tp_ssd2521_read_reg(0x79,1);
	for(tmp=0;tmp<8;tmp++)
	{
		tp_ssd2521_read_reg(0x79,1);
		tp_ssd2521_read_reg(0x80,4);
	}
	
	//tp_ssd2521_read_reg(0x7C,4);
	//tp_ssd2521_read_reg(0x7D,4);
	//tp_ssd2521_read_reg(0x7E,4);
	//tp_ssd2521_read_reg(0x7F,4);
	//tp_ssd2521_read_reg(0x23,1);
	//================================//
	//    Register as Input Device    //
	//================================//
	
	ts=kzalloc(sizeof(struct auo_tp2_ts), GFP_KERNEL);
	INIT_WORK(&works_timer, tp_ssd2521_timer_work);
	INIT_WORK(&works, i2c_access_work);
	pInput_dev = input_allocate_device();
	if(!ts || !pInput_dev)
	{
		input_free_device(pInput_dev);
		kfree(ts);
		printk("input_allocate_device error in tp_ssd2521_detect\n");
		return -ENOMEM;
	}
	
	ts->dev = pInput_dev;
       //ts->dev->keybit [BIT_WORD (BTN_TOUCH)] = BIT_MASK (BTN_TOUCH);//single touch
	ts->dev->evbit[0] = BIT_MASK (EV_SYN)|BIT_MASK (EV_ABS) ;//mult touch	
#ifdef SINGLE_TOUCH   //single touch
	ts->dev->evbit[0] = BIT_MASK (EV_SYN) | BIT_MASK (EV_KEY) | BIT_MASK (EV_ABS);//single touch
	ts->dev->keybit [BIT_WORD (BTN_TOUCH)] = BIT_MASK (BTN_TOUCH);
	input_set_abs_params(ts->dev, ABS_Y, 0, 480, 0, 0);
	input_set_abs_params(ts->dev, ABS_X, 0, 800, 0, 0);
	input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0);
#else
   	//multi touch
	input_set_abs_params(ts->dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);
	input_set_abs_params(ts->dev, ABS_MT_TOUCH_MAJOR,0, 1, 0, 0);
	input_set_abs_params(ts->dev, ABS_MT_POSITION_Y, 0, 480, 0, 0);
	input_set_abs_params(ts->dev, ABS_MT_POSITION_X, 0, 800, 0, 0);
#endif
	sprintf(ts->phys, "ts0");
	#if debug_ssd2521
	printk("ts->dev->name = auo_ts_name; \n");
	#endif
	ts->dev->name = auo_ts_name;
	ts->dev->phys = ts->phys;
	ts->dev->id.bustype = BUS_I2C;
	ts->dev->id.vendor = 0xABCD;
	ts->dev->id.product = 0xBEEE;
	#define AUO_TS_VERSION	0x0001
	ts->dev->id.version = AUO_TS_VERSION;    
    	//register the GPIO inerrupt
    	gpio_direction_input(Android_AUO_TSC_INT);
    	irq = gpio_to_irq(Android_AUO_TSC_INT);
    	//if (AUO_INT_LOW){
        //	set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
    	//}
    	//else {
       //		set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
	//}
	set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
    	#if debug_ssd2521
	printk("start request_irq\n");
	#endif	
    	if (request_irq(irq, stylus_action, IRQF_SHARED, "andriod-ts-i2c", (void *) ts->dev)) {
		input_free_device(ts->dev);
		kfree(ts);
		return -EIO;
	}
	printk("end request_irq\n");
	input_register_device(ts->dev);
	#if debug_ssd2521
	printk("exit tp_ssd2521_detect \n");
	#endif	
	tp_ssd2521_timer->function = &tp_ssd2521_timer_handle;
	tp_ssd2521_timer->expires = jiffies + 100;
	tp_ssd2521_timer->data = 0;
	add_timer(tp_ssd2521_timer);

	err=sysfs_create_group (&save_client->dev.kobj, &ssd2521_attr_group);
	if (err)
	{
		printk("Can't create sysfs attributes!\n ");
		return err;
	}
	return 0;
	/*
	exit_detach:
	i2c_detach_client(new_client);
	*/
	exit_kfree:
		kfree(data);
	exit:
		return err;
	
}
u8   tp_ssd2521_read_single_byte(u8 addr);
void   in_sleep_ssd2521()
{
	u8 tx_buff[2];	
	printk("SSD2521 in sleep\n");
	tx_buff[0]=0x25;
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(save_client,tx_buff,2);
	while(tp_ssd2521_read_single_byte(0x26)!=0);
	tx_buff[0]=0x24;
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(save_client,tx_buff,2);
}
void   out_sleep_ssd2521()
{
	u8 tx_buff[2];
	tx_buff[0]=0x23;
	tx_buff[1]=0x00;
	tp_ssd2521_write_reg(save_client,tx_buff,2);
	tx_buff[0]=0x25;
	tx_buff[1]=0x06;
	tp_ssd2521_write_reg(save_client,tx_buff,2);
	printk("SSD2521 out sleep\n");
}
static int ssd2521_suspend(struct i2c_client *client, pm_message_t message)
{
	in_sleep_ssd2521();
	return 0;
}
static int ssd2521_resume(struct i2c_client *client)
{
	out_sleep_ssd2521();
	return 0;
}
static void *g_pGPIOReg_I2C_INT_V;
static int tp_ssd2521_attach_adapter(struct i2c_adapter *adapter)
{
	printk("in tp_ssd2521_attach_adapter \n");
	return i2c_probe(adapter, &addr_data, tp_ssd2521_detect);
}
static int tp_ssd2521_detach_client(struct i2c_client *client)
{
	int err;
	err = i2c_detach_client(client);
	if(err)
		return err;
	kfree(i2c_get_clientdata(client));
	disable_irq(&g_irq_reg.IER_reg);
	input_free_device(ts->dev);
	kfree(ts);
	iounmap(g_pGPIOReg_I2C_INT_V);
	printk("in tp_ssd2521_attach_adapter \n");
	return 0;
}
u8 tp_ssd2521_write_reg(struct i2c_client *client,const char *buf ,int count)
{
	int ret;
	struct i2c_adapter *adap=client->adapter;
	struct i2c_msg msg;

	msg.addr = save_client->addr;
	msg.flags = 0;
	msg.len = count;
	msg.buf = (char *)buf;

	ret = i2c_transfer(adap, &msg, 1);
	if (i2c_transfer(save_client->adapter, &msg, 1) < 0)
	{
		printk("write the address (0x%x) of the ssd2521 fail.",buf[0]);
		return false;
	}
}
u8 tp_ssd2521_read_event_state(u8 addr,u8* buf_to_i2c)
{
	u8 msgbuf[1] = { addr };// get Device ID
	struct i2c_msg msgs[] = {
		{
			.addr   = save_client->addr,
			.flags  = 0, //Write
			.len    = 1,
			.buf    = msgbuf,
		},
		{
			.addr   = save_client->addr,
			.flags  = I2C_M_RD,
			.len    = 1,
			.buf    = buf_to_i2c,
		},
	};
	i2c_transfer(save_client->adapter, msgs, 2);
}

u8 tp_ssd2521_read_event_stack(u8 addr,u8* buf_to_i2c)
{
	u8 msgbuf[1] = { addr };// get Device ID
	struct i2c_msg msgs[] = {
		{
			.addr	= save_client->addr,
			.flags	= 0, //Write
			.len	= 1,
			.buf	= msgbuf,
		},
		{
			.addr	= save_client->addr,
			.flags	= I2C_M_RD,
			.len	= 4,
			.buf	= buf_to_i2c,
		},
	};
	i2c_transfer(save_client->adapter, msgs, 2);		
}
u8   tp_ssd2521_read_single_byte(u8 addr)
{
	u8 msgbuf[1] = { addr };// get Device ID
	u8 ret=0;
	struct i2c_msg msgs[] = {
		{
			.addr   = save_client->addr,
			.flags  = 0, //Write
			.len    = 1,
			.buf    = msgbuf,
		},
		{
			.addr   = save_client->addr,
			.flags  = I2C_M_RD,
			.len    = 1,
			.buf    = &ret,
		},
	};
	i2c_transfer(save_client->adapter, msgs, 2);
	return ret;
}
void tp_ssd2521_read_reg(u8 addr,u8 len)
{
	u8 buf_to_i2c[4]={0,0,0,0},tmp;
	u8 msgbuf[1] = { addr };// get Device ID
	struct i2c_msg msgs[] = {
		{
			.addr	= save_client->addr,
			.flags	= 0, //Write
			.len	= 1,
			.buf	= msgbuf,
		},
		{
			.addr	= save_client->addr,
			.flags	= I2C_M_RD,
			.len	= len,
			.buf	= buf_to_i2c,
		},
	};
	if(len>4)
	{
		printk("Erro:the read length is %d ,greater than the maximum length 4\n",len);
		return;
	}
	//printk("in tp_ssd2521_read_reg \n");
	#if debug_ssd2521
	if(save_client==NULL)
	{
		printk("in tp_ssd2521_read_reg save_client=NULL \n");
		return ;
	}
	if(save_client->adapter==NULL)
	{
		printk("in tp_ssd2521_read_reg save_client->adapter=NULL \n");
		return ;
	}
	if(msgs==NULL)
	{
		printk("in tp_ssd2521_read_reg msgs=NULL \n");
		return ;
	}
	#endif
	if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
	{
		printk("read the address (0x%x) of the ssd2521 fail.",addr);
		return;
	}
	else
	{
		;
		 //printk("len =%d \n",len);
		 //printk("read the address (0x%x) of the ssd2521 is 0x",addr);	
		 //for(tmp=0;tmp<len;tmp++)
		 //{
		 //	printk("%x:",buf_to_i2c[tmp]);	
		 //}
		 //printk("\n");
		 //printk("read the address (0x%x) of the ssd2521 is 0x%x%x\n",addr,buf_to_i2c[0],buf_to_i2c[1]);	
	}
	return;
	//printk("exit  tp_ssd2521_read_reg \n");
}
#define SRSC_EVENT 	1	//single finger single click event
#define SFDC_EVENT 	2 	//single finger double click event
#define TFSC_EVENT 	3	//two fingers singer click event
#define TFDC_EVENT 	4	//two fingers double click event
#define FE_EVENT     	5	//finger-enter event per finger base
#define FL_EVENT 	6	//finger-leave event per finger base
#define FM_EVENT 	7	//finger-move event per finger base

static void report_ssd2521_inf(u8 finger,u8 event_no,int32_t x,int32_t y)
{
	//add your code to report the number of finger

	
	switch(event_no)
	{
		case SFDC_EVENT://break;
		case SRSC_EVENT:
			input_report_abs(ts->dev, ABS_X, y);
			input_report_abs(ts->dev, ABS_Y, x);
			input_report_abs(ts->dev, ABS_PRESSURE, 1);
			input_sync(ts->dev);
			input_report_abs(ts->dev, ABS_X, y);
			input_report_abs(ts->dev, ABS_Y, x);
			input_report_abs(ts->dev, ABS_PRESSURE, 0);
			input_sync(ts->dev);
			break;		
		case TFSC_EVENT:break;
		case TFDC_EVENT:break;
		case FE_EVENT://input_report_key (ts->dev, BTN_TOUCH, 1);//break;
		case FM_EVENT:			
			input_report_abs(ts->dev, ABS_MT_POSITION_X, y);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, x);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, finger);
			//input_report_abs(ts->dev, ABS_PRESSURE, 1);
			input_mt_sync(ts->dev);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, y);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, x);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, finger);
			//input_report_abs(ts->dev, ABS_PRESSURE, 1);
			input_mt_sync(ts->dev);
			input_sync(ts->dev);
			break;
		case FL_EVENT:
			//input_report_abs(ts->dev, ABS_X, x);
			//input_report_abs(ts->dev, ABS_Y, y);
			//input_report_abs(ts->dev, ABS_PRESSURE, 0);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 0);
			//input_report_key (ts->dev, BTN_TOUCH, 0);
			input_mt_sync(ts->dev);
			input_sync(ts->dev);
			break;
		
	}
}
void ssl_calibrate_for_Android(int32_t *x, int32_t *y)
{
	int32_t tx,ty;
	tx=*x;
	ty=*y;
	*x=(calibrate.a*tx + calibrate.b *ty +calibrate.c) / calibrate.div;
	*y=(calibrate.d*tx + calibrate.e *ty +calibrate.f) / calibrate.div;
	//printk("(%d, %d) -> (%d, %d)\n", tx,ty,*x,*y);

}
u8 last_event_status=0;
static void tp_ssd2521_timer_handle(unsigned long data)
{
	schedule_work(&works_timer);
	//printk("key is pressed too long to run tp_ssd2521_timer_handle\n");
}
static void tp_ssd2521_timer_work(struct work_struct *work)
{
	u8 tx_buff[2]={0xA2,0x00};
	u8 event_status=0,i; 
	tp_ssd2521_read_event_state(0x79,&event_status);	
	//printk("******event_status=%d\n",event_status);
	if((event_status&0x0F)==0x00)
	{
		for(i=0;i<=3;i++)
		{
			input_report_abs(ts->dev, ABS_MT_POSITION_X, mt_buf[i].y);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, mt_buf[i].x);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 0);
			input_mt_sync(ts->dev);
		}
		input_sync(ts->dev);
		last_event_status=0;
    		tp_ssd2521_write_reg(save_client,tx_buff,2);//rest init reference procedure
	}
	else
	{
		//printk("-----\n");
		mod_timer(tp_ssd2521_timer,jiffies + 100 );
	}

} 
#define FIFO_NOT_EMPTY 0x10
static void i2c_access_work(struct work_struct *work)
{
	u8 buf[4]={0,0,0,0},i;
	u8 event_status=0;
	static long int time1=0;
	int32_t x=0, y=0;
	printk("+++++++++in  work  +++++++++\n");
	//time=jiffies_to_msecs(get_jiffies_64());
	//printk("++++++++++++++++++%li\n",time);
	//time1=jiffies_to_msecs(get_jiffies_64());
	//printk("*****************%li\n",time1-time);
	//time=time1;
	//printk("***********************in i2c_access_work****************************\n");
	while(1)
	{
		//time1=jiffies_to_msecs(get_jiffies_64());
		//printk("^^^^^^^^^^^^^^^^^^^^^^^%li\n",time1-time);
		//time=time1;
		if(gpio_get_value(Android_AUO_TSC_INT)!=0)
		{
			enable_irq(irq);
			mod_timer(tp_ssd2521_timer,jiffies + 100);
			break;
		}
		tp_ssd2521_read_event_state(0x79,&event_status);	
		//if(event_status!=last_event_status)
		//	printk("event_status = %x\n",event_status);
		
		if(event_status&0x10)
			tp_ssd2521_read_reg(0x80,4);
		if((event_status&0x0F)==0&&((last_event_status&0x0F)==0))
		{
			enable_irq(irq);
			mod_timer(tp_ssd2521_timer,jiffies + 100);
			break;
		}
#ifdef SINGLE_TOUCH
		if(event_status&0x01)
		{
			tp_ssd2521_read_event_stack(0x7C,buf);
			mt_buf[0].x=buf[0]|((buf[2]&0xF0)<<4);
			mt_buf[0].y=buf[1]|((buf[2]&0x0F)<<8);
			if(mt_buf[0].x==0xFFF)
			{
				enable_irq(irq);
				break;
			}
			x=mt_buf[0].y;
			y=mt_buf[0].x;
			input_report_abs(ts->dev, ABS_X, x);
			input_report_abs(ts->dev, ABS_Y, y);
			input_report_abs(ts->dev,ABS_PRESSURE, 1);
			input_report_key (ts->dev, BTN_TOUCH, 1);
		}
		else
		{
			x=mt_buf[0].y;
			y=mt_buf[0].x;
			input_report_abs(ts->dev, ABS_X, x);
			input_report_abs(ts->dev, ABS_Y, y);
			input_report_abs(ts->dev,ABS_PRESSURE, 0);
			input_report_key (ts->dev, BTN_TOUCH, 0);
		}
		input_sync(ts->dev);
		last_event_status=event_status;
		//msleep(10);
		continue;
#endif
		/*for( i=0;i<4;i++)
		{
			if((event_status>>i)&1)
			{
				tp_ssd2521_read_event_stack(0x7C+i,buf);
				mt_buf[0].x=buf[0]|((buf[2]&0xF0)<<4);
				mt_buf[0].y=buf[1]|((buf[2]&0x0F)<<8);
				x=mt_buf[0].y;
				y=mt_buf[0].x;
				input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
				input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
				input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 1);
				input_mt_sync(ts->dev);
			}
		}
		last_event_status=event_status;
		input_sync(ts->dev);
		continue;*********************************/
		if(event_status&0x01)
		{
			tp_ssd2521_read_event_stack(0x7C,buf);
			mt_buf[0].x=buf[0]|((buf[2]&0xF0)<<4);
			mt_buf[0].y=buf[1]|((buf[2]&0x0F)<<8);
			//printk("x=%d,y=%d\n",mt_buf[0].x,mt_buf[0].y);
			if(mt_buf[0].x==0xFFF)
			{
				enable_irq(irq);
				break;
			}
			x=mt_buf[0].y;
			y=mt_buf[0].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 1);
			input_report_abs(ts->dev,ABS_MT_WIDTH_MAJOR,(buf[3]&0xF0)>>4);
			input_mt_sync(ts->dev);
		}
		else
		{
			x=mt_buf[0].y;
			y=mt_buf[0].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);

			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 0);
			input_mt_sync(ts->dev);
		}
	//		last_event_status=event_status;
	//		input_sync(ts->dev);
	//	continue;
		if(((event_status&0x0E)==0)&&((last_event_status&0x0E)==0))
		{
			msleep(10);
			last_event_status=event_status;
			input_sync(ts->dev);
			continue;
		}
		if(event_status&0x02)
		{
			tp_ssd2521_read_event_stack(0x7D,buf);
			mt_buf[1].x=buf[0]|((buf[2]&0xF0)<<4);
			mt_buf[1].y=buf[1]|((buf[2]&0x0F)<<8);
			if(mt_buf[1].x==0xFFF)
			{
				input_sync(ts->dev);
				enable_irq(irq);
				break;
			}
			x=mt_buf[1].y;
			y=mt_buf[1].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 1);
			 input_report_abs(ts->dev,ABS_MT_WIDTH_MAJOR,(buf[3]&0xF0)>>4);
			input_mt_sync(ts->dev);
		}
		else
		{
			x=mt_buf[1].y;
			y=mt_buf[1].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 0);
			input_mt_sync(ts->dev);
		}
		//imsleep(10);
		if(((event_status&0x0C)==0)&&((last_event_status&0x0C)==0))
		{
			last_event_status=event_status;
			input_sync(ts->dev);
			//msleep(10);
			continue;
		}
		if(event_status&0x04)
		{
			tp_ssd2521_read_event_stack(0x7E,buf);
			mt_buf[2].x=buf[0]|((buf[2]&0xF0)<<4);
			mt_buf[2].y=buf[1]|((buf[2]&0x0F)<<8);
			if(mt_buf[2].x==0xFFF)
			{
				input_sync(ts->dev);
				enable_irq(irq);
				break;
			}
			x=mt_buf[2].y;
			y=mt_buf[2].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 1);
			input_report_abs(ts->dev,ABS_MT_WIDTH_MAJOR,(buf[3]&0xF0)>>4);
			input_mt_sync(ts->dev);
		}
		else
		{
			x=mt_buf[2].y;
			y=mt_buf[2].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 0);
			input_mt_sync(ts->dev);
		}
		//msleep(10);
		if(((event_status&0x08)==0)&&((last_event_status&0x08)==0))
		{
			last_event_status=event_status;
			input_sync(ts->dev);
			//msleep(10);
			continue;
		}
		if(event_status&0x08)
		{
			tp_ssd2521_read_event_stack(0x7F,buf);
			mt_buf[3].x=buf[0]|((buf[2]&0xF0)<<4);
			mt_buf[3].y=buf[1]|((buf[2]&0x0F)<<8);
			if(mt_buf[3].x==0xFFF)
			{
				input_sync(ts->dev);
				enable_irq(irq);
				break;
			}
			x=mt_buf[3].y;
			y=mt_buf[3].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 1);
			input_report_abs(ts->dev,ABS_MT_WIDTH_MAJOR,(buf[3]&0xF0)>>4);
			input_mt_sync(ts->dev);
		}
		else
		{
			x=mt_buf[3].y;
			y=mt_buf[3].x;
			ssl_calibrate_for_Android(&x,&y);
			input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, 0);
			input_mt_sync(ts->dev);
		}
		last_event_status=event_status;
		input_sync(ts->dev);
		//msleep(10);
		/*for(i=0;(i<4);i++)
		{
			tp_ssd2521_read_event_stack(0x7C+i,buf);
			x=buf[0]|((buf[2]&0xF0)<<4);
			y=buf[1]|((buf[2]&0x0F)<<8);
			if( ((y+x)>688)&&(event_status>>i&0x01))
			{
				;
			}
			else
			{

				if(event_status>>i&0x01)
				{
					mt_buf[i].y=buf[1]|((buf[2]&0x0F)<<8);
					mt_buf[i].x=buf[0]|((buf[2]&0xF0)<<4);
				}
			}
			input_report_abs(ts->dev, ABS_MT_POSITION_X, mt_buf[i].y);
			input_report_abs(ts->dev, ABS_MT_POSITION_Y, mt_buf[i].x);
			input_report_abs(ts->dev,ABS_MT_TOUCH_MAJOR, mt_buf[i].press=event_status>>i&0x01);
			//input_report_abs(ts->dev,ABS_MT_WIDTH_MAJOR,(buf[3]&0xF0)>>4);
			input_mt_sync(ts->dev);
			printk("finger=%d   pressed=%d  x=%d  y=%d\n",i, event_status>>i&0x01,mt_buf[i].x,mt_buf[i].y);
			if((event_status&0x0F)>>(i+1)==0&&mt_buf[i+1].press==0)break;
			msleep(10);
		}	*/		
		//if((event_status&FIFO_NOT_EMPTY)==0)
			//break;
	}
	/*if((event_no==FL_EVENT)&&(finger==0))
	{
		disable_irq (irq);
		msleep(60);		
		enable_irq(irq);
		tx_buff[0]=0x81;
		tp_ssd2521_write_reg(save_client,tx_buff,1);	//Event Stack Clear		
	}*********************************/	
}
/* Declaration of the init and exit functions */
module_init(tp_ssd2521_init);
module_exit(tp_ssd2521_exit);

MODULE_AUTHOR("TP ssd2521 Test");
MODULE_DESCRIPTION("TP ssd2521 Test");
MODULE_LICENSE("Dual BSD/GPL");



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值