高级驱动——五、ts系统驱动(触摸屏)

一,了解ts的基础知识

参考:E:\peter\2010\高级驱动\6day\ts驱动专题.xls

二,电容触摸屏的驱动框架

参考:E:\peter\2010\高级驱动\6day\6day_photo\3_ts驱动框架.tif

三,电容触摸屏获取坐标的原理

参考:E:\peter\2010\高级驱动\6day\6day_photo\4_读取坐标原理.tif

四,电容触摸屏的驱动编程

1,添加从设备信息

arch/arm/mach-s5pv210/mach-smdkv210.c
		|
	static void __init smdkv210_machine_init(void)
						|
			i2c_register_board_info(2, smdkv210_i2c_devs2,ARRAY_SIZE(smdkv210_i2c_devs2));
											|
							static struct i2c_board_info smdkv210_i2c_devs2[] __initdata = {
								/* To Be Updated */
								{ I2C_BOARD_INFO("gt811_ts", 0x5d), },	//触摸屏从设备信息
							};
							
//重新编译内核,并更新:
make -j2 zImage
cp arch/arm/boot/zImage /tftpboot/

//在开发板中测试
[root@farsight /]# ls /sys/bus/i2c/devices/
0-001b  0-0050  2-005d  i2c-0   i2c-1   i2c-2
[root@farsight /]# cat /sys/bus/i2c/devices/2-005d/name
gt811_ts

2,触摸屏驱动代码实现------//框架

//参考代码:gt811_drv_v1

编译,并在开发板中测试:
[root@farsight /drv_module]# insmod gt811_i2c_drv.ko
----------^_^ gt811_i2c_drv_init---------------
----------^_^ gt811_i2c_drv_probe---------------
[root@farsight /drv_module]# ls /sys/bus/i2c/drivers
dummy          gt811_s5pv210
[root@farsight /drv_module]# ls /sys/bus/i2c/drivers/gt811_s5pv210/
2-005d  bind    module  uevent  unbind

3,触摸屏驱动代码实现------//实现probe函数中的代码

//参考代码:gt811_drv_v2

编译,并在开发板中测试:
[root@farsight /drv_module]# insmod gt811_i2c_drv.ko
----------^_^ gt811_i2c_drv_init---------------
----------^_^ gt811_i2c_drv_probe---------------
input: Unspecified device as /devices/virtual/input/input0
[root@farsight /drv_module]# ls /dev/event0 -l
crw-rw----    1 0        0          13,  64 Jan  1 00:39 /dev/event0
[root@farsight /drv_module]# ls /sys/bus/i2c/drivers/
dummy          gt811_s5pv210
[root@farsight /drv_module]# ls /sys/bus/i2c/drivers/gt811_s5pv210/
2-005d  bind    module  uevent  unbind
[root@farsight /drv_module]# cat /sys/bus/i2c/drivers/gt811_s5pv210/2-005d/name
gt811_ts

//如果同时加载了多个输入设备,则:
[root@farsight /drv_module]# insmod input_simple_key_drv.ko
--------------^_^ input_simple_key_drv_init---------------
input: Unspecified device as /devices/virtual/input/input1
[root@farsight /drv_module]# ls -l /dev/event*
crw-rw----    1 0        0          13,  64 Jan  1 00:39 /dev/event0
crw-rw----    1 0        0          13,  65 Jan  1 00:41 /dev/event1

//如何区分上面的两个设备节点对应哪个设备?
//给input_dev添加额外信息
//添加额外信息
gt811_dev->i_dev->name 	= 	"gt811_ts";
gt811_dev->i_dev->phys	=	"ts_gt811";
gt811_dev->i_dev->uniq	=	"/ts/gt811";
gt811_dev->i_dev->id.bustype =	0x4;
gt811_dev->i_dev->id.product =  0x5;
gt811_dev->i_dev->id.vendor  = 0x123;
gt811_dev->i_dev->id.version = 0x1;

//在开发板中测试:
[root@farsight /drv_module]# cat /sys/class/input/event0/device/name
gt811_ts
[root@farsight /drv_module]# cat /sys/class/input/event0/device/uniq
/ts/gt811
[root@farsight /drv_module]# cat /sys/class/input/event0/device/phys
ts_gt811
[root@farsight /drv_module]# cat /sys/class/input/event0/device/id/bustype
0004
[root@farsight /drv_module]# cat /sys/class/input/event0/device/id/product
0005
[root@farsight /drv_module]# cat /sys/class/input/event0/device/id/vendor
0123
[root@farsight /drv_module]# cat /sys/class/input/event0/device/id/version
0001

4,触摸屏驱动代码实现------//触控IC初始化

INT	---- gph1_6
RESET --- gpd0_3

//硬件初始化步骤
1》设置INT为输入态,RESET为内部拉高
2》RESET输出低,延时1ms,转为输入态
3》延时至少20ms ,i2c寻址gt811--监测gt811是否存在,且没有损坏
4》如果有响应,则分一次或者多次初始化配置寄存器:[0x6A2]-[0x70B]共 106 个寄存器

//参考代码:gt811_drv_v3

5,触摸屏驱动代码实现------//中断处理函数:中断下半部

//参考代码:gt811_drv_v4

//使用工作队列实现中断下半部
struct work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;			//下半部执行函数指针:typedef void (*work_func_t)(struct work_struct *work);

};

//初始化工作队列 --------在probe中调用
INIT_WORK(struct work_struct *work,work_func_t _func)

//启动中断下半部 ------- 在中断处理函数中调用
int schedule_work(struct work_struct *work)

//在开发板中测试:
[root@farsight /drv_module]# insmod gt811_i2c_drv.ko
----------^_^ gt811_i2c_drv_init---------------
----------^_^ gt811_i2c_drv_probe---------------
input: gt811_ts as /devices/virtual/input/input5
gt811 device found OK!
----------^_^ gt811_ts_init---------------
config_info[62] = 0x3
config_info[61] = 0x20
config_info[64] = 0x1
config_info[63] = 0xe0
[root@farsight /drv_module]# input_x = 314,input_y = 189,input_p = 6,input_id = 0
input_x = 314,input_y = 189,input_p = 6,input_id = 0
input_x = 314,input_y = 189,input_p = 6,input_id = 0
input_x = 314,input_y = 189,input_p = 6,input_id = 0		//按下一个点

input_x = 408,input_y = 191,input_p = 6,input_id = 0		//按下两个点
input_x = 357,input_y = 319,input_p = 10,input_id = 1
input_x = 408,input_y = 191,input_p = 6,input_id = 0

input_x = 308,input_y = 180,input_p = 5,input_id = 0		//按下三个点
input_x = 423,input_y = 240,input_p = 8,input_id = 1
input_x = 349,input_y = 407,input_p = 5,input_id = 2
input_x = 308,input_y = 181,input_p = 5,input_id = 0
input_x = 423,input_y = 239,input_p = 8,input_id = 1
input_x = 349,input_y = 407,input_p = 5,input_id = 2
input_x = 308,input_y = 181,input_p = 5,input_id = 0

input_x = 132,input_y = 154,input_p = 8,input_id = 0		//按下四个点
input_x = 407,input_y = 208,input_p = 3,input_id = 1
input_x = 521,input_y = 268,input_p = 6,input_id = 2
input_x = 406,input_y = 407,input_p = 5,input_id = 3
input_x = 131,input_y = 155,input_p = 10,input_id = 0
input_x = 407,input_y = 208,input_p = 5,input_id = 1
input_x = 521,input_y = 268,input_p = 6,input_id = 2
input_x = 406,input_y = 407,input_p = 5,input_id = 3
input_x = 131,input_y = 155,input_p = 10,input_id = 0
input_x = 407,input_y = 208,input_p = 5,input_id = 1
input_x = 521,input_y = 268,input_p = 6,input_id = 2
input_x = 406,input_y = 407,input_p = 5,input_id = 3

input_x = 283,input_y = 101,input_p = 6,input_id = 0		//按下五个点
input_x = 518,input_y = 133,input_p = 3,input_id = 1
input_x = 615,input_y = 188,input_p = 6,input_id = 2
input_x = 615,input_y = 298,input_p = 5,input_id = 3
input_x = 88,input_y = 452,input_p = 8,input_id = 4
input_x = 280,input_y = 101,input_p = 6,input_id = 0
input_x = 517,input_y = 133,input_p = 3,input_id = 1
input_x = 615,input_y = 188,input_p = 6,input_id = 2
input_x = 615,input_y = 298,input_p = 5,input_id = 3
input_x = 88,input_y = 452,input_p = 6,input_id = 4

示例代码

1、pdrv


#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/delay.h>


#include <plat/gpio-cfg.h>

#define TOUCH_MAX_WIDTH  800
#define TOUCH_MAX_HEIGHT 480
//设计全局设备对象
struct s5pv210_gt811{
	int irqno;
	struct input_dev *i_dev;
	struct i2c_client *client;
	struct work_struct ts_work;
};
struct s5pv210_gt811 *gt811_dev;

int gt811_read_combine(struct i2c_client * client,char *buf,int count)
{
	int ret;
	struct i2c_msg msg[2];

	msg[0].addr = client->addr;
	msg[0].flags = 0;
	msg[0].len = 2;
	msg[0].buf = &buf[0];

	msg[1].addr = client->addr;
	msg[1].flags = 1;
	msg[1].len = count - 2;
	msg[1].buf = &buf[2];
	

	ret = i2c_transfer(client->adapter, msg, 2);
	
	return (ret == 2) ? count-2 : ret;
}

//单点上报
void gt811_touch_report(uint8_t id, uint16_t x, uint16_t y, uint8_t p)
{
	input_report_abs(gt811_dev->i_dev, ABS_MT_POSITION_X, x);
	input_report_abs(gt811_dev->i_dev, ABS_MT_POSITION_X, y);
	input_report_abs(gt811_dev->i_dev, ABS_MT_PRESSURE, p);
	input_report_abs(gt811_dev->i_dev, ABS_MT_TRACKING_ID, id);
	input_sync(gt811_dev->i_dev);

	printk("input_x = %d,input_y = %d,input_p = %d,input_id = %d\n",x,y,p,id);
}



//实现中断下半部
void gt811_irq_fun(struct work_struct *work)
{
	int ret,count,i;
	uint8_t point_data[36] = {0x7,0x21,0};
	uint8_t position;   //记录校验和的位置
	uint8_t check_sum = 0;
	uint8_t tmp;
	uint8_t track_id[5];     //被按下的点的编号
	uint8_t point_count = 0;  //被按下的点的个数
	uint8_t point_position;

	uint16_t ts_x,ts_y;
	uint8_t ts_p;
	
	// 1, 获取所有坐标数据
	ret = gt811_read_combine(gt811_dev->client,point_data,ARRAY_SIZE(point_data));
	if(ret < 0){
		printk(" gt811_read_combine error\n");
	}
	// 2, 分许被按下的点的数据
	// 2.1 比对校验和是否正确
	switch(point_data[2] & 0x1f){
		case 0:  // 没有点被按下
				position = 4;
				for(count = 2; count < position; count++)
					check_sum += point_data[count];
			break;
		case 1:
				position = 9;
				for(count = 2; count < position; count++)
					check_sum += point_data[count];
				break;
		case 2:
		case 3:
				position = 14;
				for(count = 2; count < position; count++)
					check_sum += point_data[count];
				break;
		default:
				position = 35;
				for(count = 2; count < position; count++)
					check_sum += point_data[count];
				
	}		
	if(check_sum != point_data[position])
		printk("check_sum error!\n");

	// 2.2 判断有几个点被按下,分别是哪些点
	tmp = point_data[2] & 0x1f;
	for(i = 0; i < 5; i++){
		if(tmp & 0x1){
			track_id[point_count++] = i;
		}
		tmp >>= 1;
	}

	

	// 2.3 保存被按下的点的信息
	for(i = 0; i< point_count; i++){ //每循环一次保存一个点的坐标
		if(track_id[i] != 3){  // 编号为 0, 1, 2, 4 的点
			if(track_id[i] < 3){ // 0, 1, 2
				point_position = 4+ 5 * track_id[i];
			}else{  // 4
				point_position = 30;
			}
			ts_x = point_data[point_position]<< 8 |  point_data[point_position+1];
			ts_y = point_data[point_position+2]<< 8 |  point_data[point_position+3];
			ts_p = point_data[point_position+4];
		}else{  // 编号为 3的点
				point_position = 19;

			ts_x = point_data[point_position]<< 8 |  point_data[point_position+7];
			ts_y = point_data[point_position+8]<< 8 |  point_data[point_position+9];
			ts_p = point_data[point_position+10];
		}

		// 3,上报数据 ----一个点坐标
		gt811_touch_report(track_id[i],ts_x,ts_y,ts_p);
		
	}

	input_sync(gt811_dev->i_dev);
}


//中断处理函数
irqreturn_t gt811_svc_handler(int irqno, void * dev)
{
	
	//启动中断下半部执行
	schedule_work(&gt811_dev->ts_work);
	return IRQ_HANDLED;
}

//初始化触控IC中的106个寄存器
static int i2c_write_bytes(struct i2c_client *client,uint8_t *data,int len)
{	
	struct i2c_msg msg;	
	int ret=-1;	//发送设备地址	
	msg.flags= 0;
	//写消息	
	msg.addr=client->addr;	
	msg.len=len;	
	msg.buf=data;		
		
	ret=i2c_transfer(client->adapter,&msg, 1);	
	return ret;
}


int gt811_ts_init(void)
{
	short ret=-1;
	
	uint8_t config_info[] = {	
		0x06,0xA2,  //第一个寄存器的地址
		0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x05,0x55,0x15,0x55,0x25,0x55,	
		0x35,0x55,0x45,0x55,0x55,0x55,0x65,0x55,0x75,0x55,0x85,0x55,0x95,0x55,0xA5,0x55,	
		0xB5,0x55,0xC5,0x55,0xD5,0x55,0xE5,0x55,0xF5,0x55,0x1B,0x03,0x00,0x00,0x00,0x13,	
		0x13,0x13,0x0F,0x0F,0x0A,0x50,0x30,0x0D,0x03,0x00,0x05,0x58,0x02,0x00,0x04,0x00,	
		0x00,0x32,0x2C,0x34,0x2E,0x00,0x00,0x04,0x14,0x22,0x04,0x00,0x00,0x00,0x00,0x00,	
		0x20,0x14,0xEC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,	
		0x25,0x28,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x01
	};
	printk("----------^_^ %s---------------\n",__FUNCTION__);
	config_info[62] = TOUCH_MAX_WIDTH >> 8;    	
	config_info[61] = TOUCH_MAX_WIDTH & 0xff;    	
	config_info[64] = TOUCH_MAX_HEIGHT >> 8;    	
	config_info[63] = TOUCH_MAX_HEIGHT & 0xff;	

	printk("config_info[62] = 0x%x\n",config_info[62]);
	printk("config_info[61] = 0x%x\n",config_info[61]);
	printk("config_info[64] = 0x%x\n",config_info[64]);
	printk("config_info[63] = 0x%x\n",config_info[63]);
	
	ret = i2c_write_bytes(gt811_dev->client, config_info, ARRAY_SIZE(config_info));	
	if(ret < 0)	{		
		dev_info(&gt811_dev->client->dev, "GT811 Send config failed!\n");		
		return ret;	
	}

	return 0;
}


int gt811_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
{
	int ret;
	char value;
	printk("----------^_^ %s---------------\n",__FUNCTION__);

	// 1,实例化全局设备对象
	gt811_dev = kzalloc(sizeof(struct s5pv210_gt811), GFP_KERNEL);

	// 2, 记录client对象
	gt811_dev->client = client;

	// 3, 分配input_dev对象空间
	gt811_dev->i_dev = input_allocate_device();

	// 4,初始化input_dev对象 

	//添加额外信息
	gt811_dev->i_dev->name 	= 	"gt811_ts";
	gt811_dev->i_dev->phys	=	"ts_gt811";
	gt811_dev->i_dev->uniq	=	"/ts/gt811";
	gt811_dev->i_dev->id.bustype =	0x4;
	gt811_dev->i_dev->id.product =  0x5;
	gt811_dev->i_dev->id.vendor  = 0x123;
	gt811_dev->i_dev->id.version = 0x1;
	
	__set_bit(EV_ABS, gt811_dev->i_dev->evbit);
	__set_bit(ABS_X, gt811_dev->i_dev->absbit);
	__set_bit(ABS_Y, gt811_dev->i_dev->absbit);
	__set_bit(ABS_PRESSURE, gt811_dev->i_dev->absbit);

	//参数1 ------input_dev对象
	//参数2 ------ 坐标,如,ABS_X,ABS_Y
	//参数3 ------ 最小值
	//参数4 ------ 最大值
	//参数5 ------ 误差范围,一般为0
	//参数6 ------ 中心位置,一般为0
	input_set_abs_params(gt811_dev->i_dev, ABS_X, 0, 800, 0, 0);
	input_set_abs_params(gt811_dev->i_dev, ABS_Y, 0, 480, 0, 0);
	input_set_abs_params(gt811_dev->i_dev, ABS_PRESSURE, 0, 255, 0, 0);

	// 5,注册input_dev对象
	ret = input_register_device(gt811_dev->i_dev);

	// 6,硬件初始化 --- 初始化触控IC+中断申请

	// 6.1 初始化触控IC

	// 1》 设置INT为输入态,RESET为内部拉高
	gpio_request(S5PV210_GPH1(6), "TS_INT");
	gpio_direction_input(S5PV210_GPH1(6));
	gpio_free(S5PV210_GPH1(6));

	gpio_request(S5PV210_GPD0(3), "TS_RESET");
	s3c_gpio_setpull(S5PV210_GPD0(3), S3C_GPIO_PULL_UP);//内部拉高
	gpio_free(S5PV210_GPD0(3));

	// 2》 RESET输出低,延时1ms,转为输入态
	msleep(5);
	gpio_request(S5PV210_GPD0(3), "TS_RESET");
	gpio_direction_output(S5PV210_GPD0(3), 0);
	msleep(1);
	gpio_direction_input(S5PV210_GPD0(3));
	gpio_free(S5PV210_GPD0(3));
	
	// 3》 延时至少20ms ,i2c寻址gt811--监测gt811是否存在,且没有损坏
	msleep(80);

	//i2c寻址---监测gt811 
	value = 1;
	ret = i2c_master_send(gt811_dev->client, &value, 1);
	if(ret > 0){
		printk("gt811 device found OK!\n");
	}else{
		printk("gt811 device no found !\n");
		input_unregister_device(gt811_dev->i_dev);
		input_free_device(gt811_dev->i_dev);
		kfree(gt811_dev);
		return -ENODEV;
	}
	
	// 4》 如果有响应,则分一次或者多次初始化配置寄存器:[0x6A2]-[0x70B]共 106 个寄存器
	gt811_ts_init();

	// 6.2 中断申请
	gt811_dev->irqno = IRQ_EINT(14);
	ret = request_irq(gt811_dev->irqno, gt811_svc_handler, IRQF_TRIGGER_FALLING, "eint14_ts", NULL);

	// 初始化工作队列
	INIT_WORK(&gt811_dev->ts_work, gt811_irq_fun);
	
	return 0;
}
int gt811_i2c_drv_remove(struct i2c_client *client)
{
	printk("----------^_^ %s---------------\n",__FUNCTION__);
	free_irq(gt811_dev->irqno, NULL);
	input_unregister_device(gt811_dev->i_dev);
	input_free_device(gt811_dev->i_dev);
	kfree(gt811_dev);
	
	return 0;
}

struct i2c_device_id  gt811_id_table[] = {
		{"gt811_ts",0x1234},
		{"gt911_ts",0x5678},
};


// 1, 实例化i2c_driver对象
struct i2c_driver gt811_drv = {
	.probe		=		gt811_i2c_drv_probe,
	.remove		=		gt811_i2c_drv_remove,
	.driver		=	{
		.name 	=	"gt811_s5pv210",
	},
	.id_table	=	gt811_id_table,
};

static int __init gt811_i2c_drv_init(void)
{
	printk("----------^_^ %s---------------\n",__FUNCTION__);
	// 2,注册i2c_driver对象
	return i2c_add_driver(&gt811_drv);
}


static void __exit gt811_i2c_drv_exit(void)
{
	printk("----------^_^ %s---------------\n",__FUNCTION__);
	i2c_del_driver(&gt811_drv);
}

module_init(gt811_i2c_drv_init);
module_exit(gt811_i2c_drv_exit);
MODULE_LICENSE("GPL");


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值