linux内核学习-驱动-I2C

先来看看linux内核的I2C驱动的文件在/drivers/i2c目录下。
在这里插入图片描述

一、先看看Makefile文件

#
# Makefile for the i2c core.
#

obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
obj-$(CONFIG_I2C)		+= i2c-core.o
obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
obj-y				+= algos/ busses/

ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
endif

还是比较简单的。

二、再来看看I2C子系统的启动顺序

根据上面的分析我们可以知道在linux系统中iic子系统的初始化顺序为:

  1. /driver/i2c/i2c-core.c postcore_initcall(i2c_init);
  2. /arch/arm/mach-s3c2440 MACHINE_START(S3C2440, “SMDK2440”)
  3. /drivers/i2c/busses/i2c-s3c2410.c subsys_initcall(i2c_adap_s3c_init);
  4. /driver/i2c/i2c-dev.c module_init(i2c_dev_init);

三、补充知识:Linux驱动模型

1.最开始写硬件驱动,直接写,然后创建一个节点给应用调用就行。
2.后来发现太混乱,引入了“驱动-总线-设备”的模型。这样就对相似的设备做了分类。将底层代码和设备代码分离。思路清晰了。
3.在2.6版本内核以后,发现在内核代码中有很多关于“board”、“platform”的冗余代码(比方说不同的开发板会有很多相似的硬件,那么代码就是一样的。)。为了解决这种辣鸡代码太多的问题,引进了“设备树”的概念。将某IC的驱动都放入drivers目录下,不同的

四、I2C bus总线

在I2C Bus用来挂载后面将会使用到的I2C 适配器(adapter)和I2C设备(client)。I2C bus是一个虚拟的设备。
注意这里的i2c bus与platform bus不是属于同一个类型的总线,platform bus用来管理platform driver 和platform device。.在整个linux 系统中只有一条platform bus,它在内核启动时初始化:

start_kernel(/init/main.c) ->
rest_init (/init/main.c)->
kernel_thread(创建系统进程/arch/arm/kernel/process.c) ->
kernel_init(/init/main.c) -> do_basic_setup(/init/main.c) ->
driver_init(/drivers/base/init.c) -> platform_bus_init(/drivers/base/platform.c) ->
device_register(&platform_bus)
以上内容包括了函数所在位置(括号里的就是位置。)

五、platform_bus注册过程

源码如下

struct device platform_bus = {
	.init_name	= "platform",
};

int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);
	if (error)
		return error;
	error =  bus_register(&platform_bus_type);
	if (error)
		device_unregister(&platform_bus);
	return error;
}

关键函数是device_register

error = device_register(&platform_bus);
error = bus_register(&platform_bus_type);
这两句,就实现了bus的注册。

六、i2c_bus注册过程

上面准备好了platform_bus的总线,下一步就是i2c_bus的注册。
首先初始化的是i2c_init() 函数,IIC Bus 就是在该函数中初始化的。
/dricer/i2c/i2c-core.c
在这里插入图片描述

(1.0)通过bus_register()函数注册IIC总线。我们看参数i2c_bus_type,它被定义为:

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,1.1.probe		= i2c_device_probe,1.2.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.suspend	= i2c_device_suspend,
	.resume		= i2c_device_resume,
};

(1.1)总线提供的match方法:match方法用来进行 device 和driver 的匹配,在向总线注册设备或是驱动的的时候会调用此方法。其函数定义为:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
	struct i2c_client	*client = i2c_verify_client(dev);1.1.0struct i2c_driver	*driver;
 
	if (!client)
		return 0;                                                    
 
	driver = to_i2c_driver(drv);1.1.1/* match on an id table if there is one */
	if (driver->id_table)
		return i2c_match_id(driver->id_table, client) != NULL;1.1.2return 0;
}

(1.1.0)用struct i2c_client 来描述一个具体的IIC设备,这里指的是client device 。
(1.1.1)获取driver
(1.1.2)如果IIC驱动的id_table 存在的话,使用i2c_match_id 进行函数进行匹配。匹配的方法是拿id_table 中的每一项与client 的name 进行匹配,如果名字相同则匹配成功。从这里我们可以看出IIC总线的匹配方式与platform 总线的匹配方式是不同的:

  • IIC总线根据设备名字和驱动中的id_table进行匹配
  • platform总线根据设备名字和设备驱动名字进行匹配

driver是一张表(id_table),device有一个名字。

(1.2)总线提供的probe方法:probe方法在完成设备和驱动的配对之后调用执行。在里面可以做一些更进一步的初始化工作

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;
 
	if (!client)
		return 0;
 
	driver = to_i2c_driver(dev->driver);
	if (!driver->probe || !driver->id_table)
		return -ENODEV;
	client->driver = driver;
	if (!device_can_wakeup(&client->dev))1.2.0device_init_wakeup(&client->dev,
					client->flags & I2C_CLIENT_WAKE);
	dev_dbg(dev, "probe\n");
 
	status = driver->probe(client, i2c_match_id(driver->id_table, client));1.2.1if (status)
		client->driver = NULL;
	return status;
}

(1.2.0)IIC的电源管理
(1.2.1)调用IIC设备驱动中的Probe 函数

七、I2C platform device 初始化

上面的继续梳理下:

  1. I2c bus的启动过程,
  2. i2c bus如何注册总线
  3. i2c bus如何match 驱动和设备
  4. i2c bus调用设备的probe方法。

OK,有了 总线,那么就需要device和driver。不过内核为了更进一步的抽象,把device和driver抽象成platform device和platform_driver。

I2C的platform device 初始化在mach-smdk2440.c文件中进行

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值