当前位置:网站首页>gslx680触摸屏驱动源码码分析(gslX680.c)

gslx680触摸屏驱动源码码分析(gslX680.c)

2022-07-07 03:58:00 正在起飞的蜗牛

1、触摸屏代码整体分析

(1)gslx680触摸屏是I2C接口设备,所以驱动代码是利用I2C子系统提供的接口来编写,用I2C核心层提供的I2C驱动注册接口将构建好的I2C驱动结构体向I2C子系统注册;】
(2)注册的触摸屏I2C驱动会在I2C总线上和对应的I2C设备匹配上,从而调用I2C驱动的probe方法;
(3)I2C子系统在整个触摸屏驱动代码中,只是负责I2C设备和主控Soc的通信,整个触摸屏代码还涉及了input子系统用于向上层应用上报触摸时间,涉及中断子系统用于处理触摸屏的中断;

2、触摸屏驱动注册函数

static struct i2c_driver gsl_ts_driver = {
    
	.driver = {
    
		.name = GSLX680_I2C_NAME,
		.owner = THIS_MODULE,
	},
#ifndef CONFIG_HAS_EARLYSUSPEND
	.suspend	= gsl_ts_suspend,
	.resume	= gsl_ts_resume,
#endif
	.probe		= gsl_ts_probe,
	.remove		= __devexit_p(gsl_ts_remove),
	.id_table	= gsl_ts_id,
};

static int __init gsl_ts_init(void)
{
    
    int ret;
	print_info("==gsl_ts_init==\n");
	
	ret = i2c_add_driver(&gsl_ts_driver);
	
	print_info("ret=%d\n",ret);
	return ret;
}

注册函数完成的功能就是向I2C子系统注册了名字是gsl_ts_driver的I2C驱动;

3、触摸屏驱动的probe函数

//在gslx680触摸屏驱动中用来描述I2C驱动的结构体
struct gsl_ts {
    
	struct i2c_client *client;
	struct input_dev *input;
	struct work_struct work;
	struct workqueue_struct *wq;
	struct gsl_ts_data *dd;
	u8 *touch_data;
	u8 device_id;
	int irq;
#if defined(CONFIG_HAS_EARLYSUSPEND)
	struct early_suspend early_suspend;
#endif
};

static int __devinit gsl_ts_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
    
	struct gsl_ts *ts;
	int rc;

	······

	//检查适配器是否支持标准I2C通信协议
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    
		dev_err(&client->dev, "I2C functionality not supported\n");
		return -ENODEV;
	}
 
	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;
	print_info("==kzalloc success=\n");

	//将client保存到ts结构体中
	ts->client = client;
	
	//把ts保存到client->dev的私有数据
	i2c_set_clientdata(client, ts);
	ts->device_id = id->driver_data;

	//注册input子系统,初始化工作队列,绑定触摸屏中断的下半部
	rc = gslX680_ts_init(client, ts);
	if (rc < 0) {
    
		dev_err(&client->dev, "GSLX680 init failed\n");
		goto error_mutex_destroy;
	}	

	gsl_client = client;

	//设置触摸屏相关GPIO引脚
	gslX680_init();

	//通过读写触摸屏芯片相关的寄存器完成初始化
	init_chip(ts->client);
	
	check_mem_data(ts->client);

	//申请中断号并绑定中断处理程序
	rc=  request_irq(client->irq, gsl_ts_irq, IRQF_TRIGGER_RISING, client->name, ts);
	if (rc < 0) {
    
		print_info( "gsl_probe: request irq failed\n");
		goto error_req_irq_fail;
	}

	······
}

(1)向I2C核心层注册的I2C触摸屏驱动最终会在I2C总线上匹配上I2C设备,也就是struct i2c_client结构体;
(2)I2C总线会调用I2C驱动的probe方法,把匹配上的struct i2c_client结构体传进去;
(3)probe函数中会完成初始化工作,其中包括input子系统的注册,中断程序的注册;

4、中断处理函数

static irqreturn_t gsl_ts_irq(int irq, void *dev_id)
{
    	
	struct gsl_ts *ts = dev_id;

	print_info("========gslX680 Interrupt=========\n");				 

	//禁止中断
	disable_irq_nosync(ts->irq);

	//检测中断下半部所属的工作队列是否挂起,如果挂起则将中断的下半部添加到队列中进行调度
	//调用中断下半部函数,也就是gslX680_ts_worker()
	if (!work_pending(&ts->work)) 
	{
    
		queue_work(ts->wq, &ts->work);
	}
	
	return IRQ_HANDLED;

}

(1)gsl_ts_irq()函数只是中断处理函数的上半部,实际功能就是禁止中断,然后调用中断下半部;
(2)gslX680_ts_worker()是中断的下半部,在gslX680_ts_init()函数中指定;
补充:参考博客:《中断的顶半部和底半部介绍以及实现方式(tasklet 和 工作队列)》

5、整个触摸屏驱动代码工作的逻辑

gsl_ts_irq()	//中断上半部
	gslX680_ts_worker()	//中断下半部
		gsl_ts_write()	//触摸屏驱动的写数据
			i2c_master_send()	//实际调用I2C核心层的发数据接口
		gsl_ts_read()	//触摸屏驱动的读数据
			i2c_master_recv()	//实际调用I2C核心层的收数据接口
		report_data()	//上报数据
			input_report_abs()	//实际调用input子系统的上报接口

(1)当触摸屏发生触摸事件时,触发绑定的中断处理程序gsl_ts_irq();
(2)gsl_ts_irq()是中断上半部,禁止中断然后调用中断下半部gslX680_ts_worker();
(3)gslX680_ts_worker()函数会通过I2C子系统提供的I2C总线的收发数据接口函数,读写触摸屏芯片的相关寄存器;
(4)gslX680_ts_worker()函数将从触摸屏芯片读取到的数据进行计算和转换,然后填充成输入事件结构体,根据之前注册的input子系统,按input子系统的输入事件往应用层上报;

原网站

版权声明
本文为[正在起飞的蜗牛]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_42031299/article/details/125610967