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