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


    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    注册函数完成的功能就是向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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    (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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

  • 相关阅读:
    【10套模拟】【6】
    Linux 内存之vmstat
    【C++】类与对象 第二篇(构造函数,析构函数,拷贝构造,赋值重载)
    【QML】vscode安装QML格式化插件方法
    基于android 平台的校园二手物品交易系统设计与实现
    Code::Blocks下载和安装教程
    2022强网杯web(部分)
    CentOS上安装JDK的详细教程
    HMS Core基于地理位置请求广告,流量变现快人一步
    电机控制器HIL测试系统:实现高效、安全的硬件在环验证
  • 原文地址:https://blog.csdn.net/weixin_42031299/article/details/125610967