针对Linux,RK3568平台下,I2C驱动的一点小小的领悟

总结:

I2C驱动子系统的实现是如下说明:以下说明仅针对硬件I2C;若所需为软件I2C的设备、驱动都需要我们自己编写

I2C驱动由:

i2c_client(i2c设备)、i2c_driver(i2c驱动)

i2c core:i2c核心层

i2c_adapter(i2c控制器/i2c适配器)、i2c_algorithm(i2c算法/i2c通信协议/i2c通信时序构成)

其中:i2c_client(i2c设备)、i2c_driver(i2c驱动),由我们驱动工程师做

i2c core:为硬件无关代码,主要作用是将i2c_client(i2c设备)、i2c_driver(i2c驱动)等的操作转换为i2c_adapter所需要的:简单理解为中间件/翻译等

i2c_adapter(i2c控制器/i2c适配器)、i2c_algorithm(i2c算法/i2c通信协议/i2c通信时序构成):由原厂工程师编写,也就是SOC的工程师:瑞芯微、海思等

其中I2C是具有自己的总线的,i2c_client、i2c_driver注册在I2C总线上

总线结构体如下:

c 复制代码
struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};

但反直觉的是,i2c_adapter并不是直接通过i2c总线去匹配注册的,而是转了一道,通过platform里面的probe去进行的注册

c 复制代码
static struct platform_driver rk3x_i2c_driver = {
	.probe   = rk3x_i2c_probe,
	.remove  = rk3x_i2c_remove,
	.driver  = {
		.name  = "rk3x-i2c",
		.of_match_table = rk3x_i2c_match,
		.pm = &rk3x_i2c_pm_ops,
	},
};

#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
static int __init rk3x_i2c_driver_init(void)
{
	return platform_driver_register(&rk3x_i2c_driver);
}
subsys_initcall_sync(rk3x_i2c_driver_init);

static void __exit rk3x_i2c_driver_exit(void)
{
	platform_driver_unregister(&rk3x_i2c_driver);
}
module_exit(rk3x_i2c_driver_exit);
#else
module_platform_driver(rk3x_i2c_driver);
#endif

不过也不难以理解,设备树中指定了硬件i2c的设备,然后编写驱动,通过platform_driver去匹配注册,然后再在对应的Probe内进行i2c_adapter、i2c_client的注册

i2c_adapter的注册在i2c_add_adapter申请空间,剩下的位置填充,最后赋给旗下的i2c_client

i2c_client的注册:i2c_add_adapter->i2c_register_adapter->of_i2c_register_devices->...->i2c_new_device

也就是说i2c_client的注册是随着i2c_adapter的注册一同完成的,不过也不难以理解,i2c_adapter是用来控制i2c设备的

误区:误以为i2c-core-base.c文件中的dummy:

c 复制代码
static struct i2c_driver dummy_driver = {
	.driver.name	= "dummy",
	.probe		= dummy_probe,
	.remove		= dummy_remove,
	.id_table	= dummy_id,
};

是注册的i2c驱动,实际上并不是,这个只是针对同一设备具有多地址时的一个优化,具体作用还没理解清楚。

误区2:i2c-dev.c文件中的const struct file_operations i2cdev_fops以为是注册了实际的设备

实际并不是,稍微追一下就可以发现是直接调用了i2c_adapter,可以很简单的理解为,通过这个玩意可以跳过编写i2c的驱动,在启动了对于管脚的i2c_adapter后,就可以在应用层编写应用,进行一定的处理,不需要在内核里面增加新的i2c_client、i2c_driver。

总结,对于非soc驱动工程师来说,针对硬件I2C,只需要关注i2c_client、i2c_driver的编写即可,甚至i2c_client直接使用设备树,而去编写i2c_driver就行。

核心思想依然是:总线、驱动、设备模型;
i2c_bus_type(总线)、i2c_driver(驱动)、i2c_client(设备)
platform_bus_type(总线)、platform_driver rk3x_i2c_driver(驱动)、rk3x_i2c_match/设备树中指定的i2c节点(设备)

相关推荐
小成202303202654 小时前
Linux高级02
linux·开发语言
mounter6254 小时前
【硬核前沿】CXL 深度解析:重塑数据中心架构的“高速公路”,Linux 内核如何应对挑战?-- CXL 协议详解与 LSF/MM 最新动态
linux·服务器·网络·架构·kernel
++==4 小时前
Linux 进程间通信与线程同步技术详解:IPC 机制、线程 API、同步工具与经典同步问题
linux
特长腿特长5 小时前
centos、ubantu系列机的用户和用户组的结构是什么?具体怎么配置?用户组权限怎么使用?这篇文章持续更新,帮助你复习linux的基础知识
linux·运维·centos
zzzyyy5385 小时前
Linux环境变量
linux·运维·服务器
pluvium275 小时前
记对 xonsh shell 的使用, 脚本编写, 迁移及调优
linux·python·shell·xonsh
无级程序员5 小时前
centos7 安装 llvm-toolset-7-clang出错的问题解决
linux·centos
CHHC18806 小时前
NetCore树莓派桌面应用程序
linux·运维·服务器
云栖梦泽7 小时前
Linux内核与驱动:9.Linux 驱动 API 封装
linux·c++
si莉亚8 小时前
ROS2安装EVO工具包
linux·开发语言·c++·开源