调试记录:
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");