I2C总线(一)核心

发布时间:2023年12月18日

基于linux-3.14.16

一、简介

硬件上,i2c总线由,i2c控制器、i2c总线、i2c设备组成。
在这里插入图片描述
驱动代码将通过设置i2c寄存器,从而在总线上产生数据信息,来和i2c设备通信(读/写)。

i2c核心,主要的功能包括:
1、注册i2c总线类型(Linux设备驱动模型(二)总线,总线驱动和总线设备,有讲到),及定义其附属接口,比如注册i2c设备,注册i2c总线,等等。。。

2、定义i2c总线软件上的规范,

二、注册i2c总线

i2c核心在内核启动,将会执行 i2c_init,做的事情,主要是
注册 i2c总线
注册一个i2c驱动 dummy_driver
在这里插入图片描述

看下i2c总线的定义,注意有,match,probe
设备驱动模型,我们了解到,当有新的驱动或者设备添加,将会调用match,和probe。
在这里插入图片描述

记录一下,同时注册的i2c驱动,目前还不了解,具体用处
仅仅记录一下
在这里插入图片描述

至此,就能在内核中添加i2c驱动和i2c设备了。。。

三、重要接口

1、注册i2c控制器设备

调用 i2c_add_numbered_adapter 注册 i2c 控制器/适配器,
在这里插入图片描述

nr在之前就被复制为pdev->id,所以会走__i2c_add_numbered_adapter,但不管走哪个,最终都会调用i2c_register_adapter,,直接看 i2c_register_adapter 干了啥。
在这里插入图片描述

static int i2c_register_adapter(struct i2c_adapter *adap)
{
	int res = 0;

	// 这里做了一些判断,,我们不必关心
	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p))) {
		res = -EAGAIN;
		goto out_list;
	}

	/* Sanity checks */
	if (unlikely(adap->name[0] == '\0')) {
		pr_err("i2c-core: Attempt to register an adapter with "
		       "no name!\n");
		return -EINVAL;
	}
	if (unlikely(!adap->algo)) {
		pr_err("i2c-core: Attempt to register adapter '%s' with "
		       "no algo!\n", adap->name);
		return -EINVAL;
	}

	rt_mutex_init(&adap->bus_lock);
	mutex_init(&adap->userspace_clients_lock);
	INIT_LIST_HEAD(&adap->userspace_clients);

	/* Set default timeout to 1 second if not already set */
	if (adap->timeout == 0)
		adap->timeout = HZ;

	// 下面是注册 i2c 控制器过程
	// 1、根据i2c 控制器的标号,对 i2c_adapter 的设备命名,,
	//    这里可以看出来,这里注册的适配器,其实在i2c总线中是以,设备存在
	dev_set_name(&adap->dev, "i2c-%d", adap->nr);
	// 2、设置设备所属的总线,这里是i2c,前面开机注册的
	adap->dev.bus = &i2c_bus_type;
	// 3、对设备设置文件属性,将会在sysfs中的i2c-1中看到
	adap->dev.type = &i2c_adapter_type;
	// 4、向总线注册设备
	res = device_register(&adap->dev);
	if (res)
		goto out_list;


	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

#ifdef CONFIG_I2C_COMPAT
	res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
				       adap->dev.parent);
	if (res)
		dev_warn(&adap->dev,
			 "Failed to create compatibility class link\n");
#endif

	/* bus recovery specific initialization */
	if (adap->bus_recovery_info) {
		struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;

		if (!bri->recover_bus) {
			dev_err(&adap->dev, "No recover_bus() found, not using recovery\n");
			adap->bus_recovery_info = NULL;
			goto exit_recovery;
		}

		/* Generic GPIO recovery */
		if (bri->recover_bus == i2c_generic_gpio_recovery) {
			if (!gpio_is_valid(bri->scl_gpio)) {
				dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n");
				adap->bus_recovery_info = NULL;
				goto exit_recovery;
			}

			if (gpio_is_valid(bri->sda_gpio))
				bri->get_sda = get_sda_gpio_value;
			else
				bri->get_sda = NULL;

			bri->get_scl = get_scl_gpio_value;
			bri->set_scl = set_scl_gpio_value;
		} else if (!bri->set_scl || !bri->get_scl) {
			/* Generic SCL recovery */
			dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");
			adap->bus_recovery_info = NULL;
		}
	}

exit_recovery:
	/* create pre-declared device nodes */
	of_i2c_register_devices(adap);
	acpi_i2c_register_devices(adap);

	// 按条件扫描 board_info,这个board_info 我们知道,写驱动的时候就是注册的 i2c_board_info
	// 关于注册 i2c_board_info 的接口,后面分析,印证。。。。
	if (adap->nr < __i2c_first_dynamic_bus_num)
		i2c_scan_static_board_info(adap);

	// 遍历 i2c 总线上的驱动,以驱动和适配器为参数,执行 __process_new_adapter,
	// __process_new_adapter 做了什么,稍后分析...
	/* Notify drivers */
	mutex_lock(&core_lock);
	bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
	mutex_unlock(&core_lock);

	return 0;

out_list:
	mutex_lock(&core_lock);
	idr_remove(&i2c_adapter_idr, adap->nr);
	mutex_unlock(&core_lock);
	return res;
}

注册适配后,会遍历全局链表,__i2c_board_list ,对属于该适配器的设备,创建一个新的 i2c 设备
在这里插入图片描述

关于 __process_new_adapter 做的事情,,
1、
2、如果
在这里插入图片描述

i2c_adapter

文章来源:https://blog.csdn.net/GeiGe123/article/details/135052610
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。