Linux i2c子系统驱动probe

I2C 子系统

I2C 子系统使用的概率非常大,我之前有做过手机的经验, 手机跑的安卓系统,内核是Linux,手机的很多器件都是用I2C通信的,我经历过从板级设备到dts设备树的阶段,知道I2C在整个系统的举足轻重,正常的TP,Camera,sonser等等都是使用I2C进行控制的。

吹牛逼这么多,就是让大家知道理解I2C子系统的重要性,不过这篇文章就写一个小细节,I2C驱动的probe是如何被触发的,如果你不知道其中的原理,可能在写驱动的时候不能成功执行probe也是有可能的。

static const struct i2c_device_id goodix_ts_id[] = {	{ GTP_I2C_NAME, 0 },	{ }	
};	static struct of_device_id goodix_ts_dt_ids[] = {	{ .compatible = "goodix,gt9xx" },	{ }	
};	static struct i2c_driver goodix_ts_driver = {	.probe      = goodix_ts_probe,	.remove     = goodix_ts_remove,	.id_table   = goodix_ts_id,	.driver = {	.name     = GTP_I2C_NAME,	.owner    = THIS_MODULE,	.of_match_table = of_match_ptr(goodix_ts_dt_ids),	},	
};	/*******************************************************    	
Function:	Driver Install function.	
Input:	None.	
Output:	Executive Outcomes. 0---succeed.	
********************************************************/	
static int goodix_ts_init(void)	
{	s32 ret;	/*	......	*/	ret = i2c_add_driver(&goodix_ts_driver);	return ret; 	
}

i2c_add_driver 驱动和设备匹配

i2c_add_driver()

i2c_register_driver 

driver_register 

driver_find 

bus_add_driver 

driver_attach 

bus_for_each_dev 

next_device

__driver_attach

driver_match_device

i2c_device_match 

acpi_driver_match_device

i2c_match_id 

of_driver_match_device 

of_match_device of_match_node

__of_match_node

__of_device_is_compatible

这个要说明的一个点是,我提出来一下,可能大家看代码的时候就不会那么困惑了,Linux 下的指针那么多,你每次如果调用都要追根溯源,那可能需要花费非常多的时间。

总线上的device和driver进行匹配的时候会调用 bus 对应的 match函数,对于i2c bus而言就是i2c_match,如果是platform_bus 那么就会回调到platform_match里面去执行。

static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,	const struct i2c_client *client)	
{	while (id->name[0]) {	if (strcmp(client->name, id->name) == 0)	return id;	id++;	}	return NULL;	
}	static int i2c_device_match(struct device *dev, struct device_driver *drv)	
{	struct i2c_client    *client = i2c_verify_client(dev);	struct i2c_driver    *driver;	if (!client)	return 0;	/* Attempt an OF style match */	if (of_driver_match_device(dev, drv))	return 1;	/* Then ACPI style match */	if (acpi_driver_match_device(dev, drv))	return 1;	driver = to_i2c_driver(drv);	/* match on an id table if there is one */	if (driver->id_table)	return i2c_match_id(driver->id_table, client) != NULL;	return 0;	
}

里面有三种 match 的函数,最后才会调用 i2c_match_id 这个函数,这个也是低版本内核还没有使用dts的时候使用的方式,也就是匹配dev和driver的name。

看下面新的 compatible 匹配方式

/**	* __of_device_is_compatible() - Check if the node matches given constraints	* @device: pointer to node	* @compat: required compatible string, NULL or "" for any match	* @type: required device_type value, NULL or "" for any match	* @name: required node name, NULL or "" for any match	*	* Checks if the given @compat, @type and @name strings match the	* properties of the given @device. A constraints can be skipped by	* passing NULL or an empty string as the constraint.	*	* Returns 0 for no match, and a positive integer on match. The return	* value is a relative score with larger values indicating better	* matches. The score is weighted for the most specific compatible value	* to get the highest score. Matching type is next, followed by matching	* name. Practically speaking, this results in the following priority	* order for matches:	*	* 1. specific compatible && type && name	* 2. specific compatible && type	* 3. specific compatible && name	* 4. specific compatible	* 5. general compatible && type && name	* 6. general compatible && type	* 7. general compatible && name	* 8. general compatible	* 9. type && name	* 10. type	* 11. name	*/	
static int __of_device_is_compatible(const struct device_node *device,	const char *compat, const char *type, const char *name)	
{	struct property *prop;	const char *cp;	int index = 0, score = 0;	/* Compatible match has highest priority */	if (compat && compat[0]) {	/*获取dts里面该节点的值*/	prop = __of_find_property(device, "compatible", NULL);	for (cp = of_prop_next_string(prop, NULL); cp;	cp = of_prop_next_string(prop, cp), index++) {	/*字符串比较*/	if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {	score = INT_MAX/2 - (index << 2);	break;	}	}	/*返回成功*/	if (!score)	return 0;	}	/* Matching type is better than matching name */	if (type && type[0]) {	if (!device->type || of_node_cmp(type, device->type))	return 0;	score += 2;	}	/* Matching name is a bit better than not */	if (name && name[0]) {	if (!device->name || of_node_cmp(name, device->name))	return 0;	score++;	}	return score;	
}

代码里面我们看到是同时比较 name ,type,compatible 这三个属性的,但是我们使用dts进行设置的时候,name和type的属性很多时候都是空的。

&i2c1 {	status = "okay";	/*	......	*/	gt9xx: gt9xx@14 {	compatible = "goodix,gt9xx";	reg = <0x14>;	touch-gpio = <&gpio1 0 IRQ_TYPE_EDGE_RISING>;	reset-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;	max-x = <800>;	max-y = <1280>;	tp-size = <89>;	configfile-num = <1>;	status = "okay";	tp-supply =  <&vcc3v0_tp>;	};	
};	

i2c probe被探测 执行的流程

i2c_add_driver()

i2c_register_driver 

driver_register driver_find 

kset_find_obj 

kobject_put 

to_driver

bus_add_driver

driver_attach 

bus_for_each_dev 

next_device

__driver_attach

driver_match_device 

driver_probe_device 

really_probe

i2c_device_probe

i2c_match_id

你以为上面设置就好了吗?我们看到

static struct i2c_driver goodix_ts_driver = {	.probe      = goodix_ts_probe,	.remove     = goodix_ts_remove,	.id_table   = goodix_ts_id,	.driver = {	.name     = GTP_I2C_NAME,	.owner    = THIS_MODULE,	.of_match_table = of_match_ptr(goodix_ts_dt_ids),	},	
};

里面有一个 id_tabel和一个 of_match_table 两个东西,既然probe探测只需要 of_match_tabel就可以了,是不是可以去掉id_tabel了呢?

这感觉是一个遗留问题,在i2c_probe函数里面有一个判断,不知道历史原因还是为何,不能做到完全兼容,看代码如下

static int i2c_device_probe(struct device *dev)	
{	/* ...... */	driver = to_i2c_driver(dev->driver);	/* 判断id_table为空就退出 */	if (!driver->probe || !driver->id_table)	return -ENODEV;	/* ...... */	
}

640?wx_fmt=jpeg

扫码或长按关注

回复「 加群 」进入技术群聊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java生成flash_web-flash发布了代码生成插件

web-flash 是一个基于 Spring BootVue.js 的后台管理系统。现在发布了其基于 Intellij IDEA 的代码生成插件!你可以再 idea 插件仓库中搜索 webflash-generator (目前插件在发布审核中&#xff0c;可能会搜索不到)&#xff0c;或者直接从本地安装插件&#xff1a;flash-generat…

JAVA多线程程序ProgressBar

JAVA多线程程序ProgressBar 题目简介&#xff1a; 思维导图&#xff1a; 实验代码&#xff1a;建议先看CalThread类&#xff0c;计算线程的实现&#xff0c;再作基本CalFrame类的界面&#xff0c; 然后作ReadThread类&#xff0c;结合CalFrame的组件&#xff0c;最后完善CalFra…

为什么Linux内核里大量使用goto,而很多书籍却不提倡使用?

关于C语言的goto语句存在很多争议&#xff0c;很多书籍都建议“谨慎使用&#xff0c;或者根本不用”。Linux之父Linus在Linux中大量使用goto&#xff0c;也是在启示着我们可以合理使用goto语句。存在即合理&#xff0c;既然是C语言中的一个知识点&#xff0c;我们还是有必要学会…

python特征匹配 查找_特征匹配+单纯形查找对象

我尝试使用opencv获取一个查询图像并在一个基本图像中进行匹配。我看了一下在线教程&#xff0c;你看&#xff0c;他们有示例代码来做这件事。所以我复制并粘贴了代码&#xff0c;并尝试用一些试用图像来运行它。下面是代码和一组图像示例。在import numpy as npimport cv2from…

python数据类型有哪些、分别有什么用途_python中的数据类型有哪些

python中的数据类型有9种&#xff0c;分别是1、字符串2、布尔类型3、整数4、浮点数5、数字6、列表7、元组8、字典9、日期。1、字符串 1.1、如何在Python中使用字符串 a、使用单引号() 用单引号括起来表示字符串&#xff0c;例如&#xff1a;strthis is string; print str; b、使…

java access jdbc_Java连接Access数据库

JDBC(Java DataBase Connectivity)是Java数据库连接API。JDBC能完成与一个数据库建立连接&#xff0c;然后向数据库发送SQL语句&#xff0c;再处理数据库返回的结果。JDBC在设计上和ODBC相似。JDBC和数据库建立连接的一种方式是首先建立起一个JDBC-ODBC桥接器。首先安装office2…

五分钟搞懂什么是红黑树(全程图解)

红黑树&#xff0c;对很多童鞋来说&#xff0c;是既熟悉又陌生。熟悉是因为在校学习期间&#xff0c;准备面试时&#xff0c;这是重点。然后经过多年的荒废&#xff0c;如今已经忘记的差不多了。如果正在看文章的你&#xff0c;马上快要毕业&#xff0c;面临着找工作的压力&…

SequenceFile文件

SequenceFile文件是Hadoop用来存储二进制形式的key-value对而设计的一种平面文件(Flat File)。目前&#xff0c;也有不少人在该文件的基础之上提出了一些HDFS中小文件存储的解决方案&#xff0c;他们的基本思路就是将小文件进行合并成一个大文件&#xff0c;同时对这些小文件的…

win10右键闪退到桌面_WIN10设置闪退,桌面右键个性化显示设置等均无效

开始菜单点击设置&#xff0c;会报错&#xff0c;详细信息记不清了&#xff0c;提示路径C:\Windows\ImmersiveControlPanel\SystemSettings.exe&#xff0c;使用fix it修复工具无效尝试更新系统&#xff0c;更新至最新版本后仍然存在问题事件管理器中找到了这个错误应用程序名称…

Linux 内核红黑树分析

Android binder 内核实现是用红黑树的&#xff0c;理解红黑树我觉得是每一个Linux er的重中之重&#xff0c;感谢格子森同学的投稿&#xff0c;周末愉快。内核版本为 linux4.2.1 本文主要从红黑树的代码实现入手&#xff0c;来讨论linux内核中是如何实现红黑树的(主要是插入和删…

postgresql数据库安装及简单操作

自从MySQL被Oracle收购以后&#xff0c;PostgreSQL逐渐成为开源关系型数据库的首选。 本文介绍PostgreSQL的安装和基本用法&#xff0c;供初次使用者上手。以下内容基于Debian操作系统&#xff0c;其他操作系统实在没有精力兼顾&#xff0c;但是大部分内容应该普遍适用。 一、安…

周末随想,野路子

焦虑不知道是不是因为科技太发达的原因&#xff0c;晚上睡觉之前总是要看看手机&#xff0c;现在写公众号之后&#xff0c;也经常有读者问问题&#xff0c;总是担心错过哪条消息&#xff0c;所以时刻想看手机&#xff0c;而且因为太过于焦虑的原因&#xff0c;我把微信设置为静…

sizeof你真的弄明白了吗?

sizeof基础在C语言中&#xff0c;sizeof是一个操作符&#xff08;operator&#xff09;&#xff0c;而不是函数&#xff01;其用于判断数据类型或者表达式长度&#xff08;所占的内存字节数&#xff09;。其有两种表达形式&#xff1a;&#xff08;1&#xff09;sizeof(类型说明…

一道90%都会做错的指针题

今天&#xff0c;在我们的一个小群里&#xff0c;一个同学发了一道题目给我看&#xff0c;这道题目应该是C语言面试的一股清流了&#xff0c;各种招聘笔试上都可以看到&#xff0c;我试着发到我的大群里去&#xff0c;发现有人对这个理解不是很深刻&#xff0c;所以再发出来&am…

python调用arcgis_arcgis python 调用工具两种两种方法

原博文 2019-09-20 11:26 − arcpy.Select_analysis("p","kk") arcpy.analysis.Select("p","kk1") ... 相关推荐 2019-12-18 20:28 − import time import wmi, zlib def get_cpu_info(): tmpdict {} tmpdict["CpuCores"] …

ibatis mysql 同时删多个表报错_MySQL中Multiple primary key defined报错的解决办法

MySQL中Multiple primary key defined报错的解决办法创建主键可以有两种方式&#xff1a;create table 表名(字段名 类型&#xff0c;字段名 类型&#xff0c;……primary key(name));或者是create table 表名(字段名 类型 primary key&#xff0c;字段名 类型&#xff0c;………

Android ANR视角InputDispatcher

作者&#xff1a;王小二前言有好多人向我咨询过Input ANR问题&#xff0c;说实话&#xff0c;我也是一直无法彻底的解释清楚&#xff0c;我下决心要彻底搞懂这块知识点。话不多说先上图一个event的正常流程InputReader线程1.InputReader线程一旦发现有新的event&#xff0c;判断…

频繁跳槽,这谁顶得住~

最近应该是校招的时候&#xff0c;相信很多人都面临择业的问题&#xff0c;正念同学的文章&#xff0c;记录了自己一个嵌入式工程师这几年找工作换工作的经历。加我好友的都知道&#xff0c;我这几天发了一个朋友圈&#xff0c;说不要乱跳槽&#xff0c;我想表达的是&#xff0…

java script object_javascript Object与Array用法

引用类型&#xff1a;引用类型是一种数据结构&#xff0c;用于将数据和功能组织在一起。引用类型的值是引用类型的一个实例。一、ObjectECMAScript中的对象其实就是一组数据和功能的结合。Object类型其实是所有它的实例的基础&#xff0c;换句话说&#xff0c;Object类型所有具…

Linux内核编程广泛使用的前向声明(Forward Declaration)

前向声明编程定律先强调一点&#xff1a;在一切可能的场景&#xff0c;尽可能地使用前向声明(Forward Declaration)。这符合信息隐蔽的原则。一个例子regmap那么前向声明究竟是个什么鬼&#xff1f;在内核写代码和看代码的童鞋&#xff0c;经常发现Linux内核里面充斥着这样的代…