针对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节点(设备)

相关推荐
秋919 小时前
MySQL 8.0.46 全平台安装与配置详解(Windows/Linux/macOS)
linux·windows·mysql
小康小小涵19 小时前
基于ESP32S3实现无人机RID模块底层源码编译
linux·开发语言·python
CQU_JIAKE19 小时前
4.28~4.30【Q】
linux·运维·服务器
左手厨刀右手茼蒿19 小时前
Linux 内核中的设备驱动开发:从字符设备到网络设备
linux·嵌入式·系统内核
先知后行。19 小时前
Linux 设备模型和platform平台
linux·运维·服务器
lzh2004091920 小时前
深入理解进程:从PCB内核结构到写时拷贝的底层实战
linux·c++
日取其半万世不竭20 小时前
Minecraft Java版社区服务器搭建教程(Linux,适合新手)
java·linux·服务器
时空自由民.20 小时前
蓝牙协议之GAP协议
linux·服务器·网络
leaves falling21 小时前
Linux 基础指令完全指南 —— 从入门到熟练
linux·运维·服务器
charlie1145141911 天前
嵌入式Linux驱动开发——新字符设备驱动 API 概览
linux·运维·驱动开发