当前位置:   article > 正文

Linux I2C子系统【2】-i2c-adapter 创建过程_linux adapter

linux adapter


前言

  1. 参考文章
    《具体芯片的I2C_Adapter驱动分析》
  2. i2c子系统分析了从启动内核如何创建i2c_adapter的过程

一、I2C控制器内部结构

I2C单独控制的话,占用CPU的时间非常高,这样不利于系统高效运转,所以一般的芯片里面都会有I2C控制器。

1.1 通用的简化结构

在这里插入图片描述
I2C控制器里面一般会有很多的寄存器。比如:

  • controller_register可以设置I2C控制器的频率
  • tx_registerrx_register控制数据的传输
  • status_register控制I2C的状态
  • int_register控制I2C的中断
    当CPU需要发送数据时,只需要写给tx_register。后面的I2C控制器会自动帮忙做好,在SDA上发送数据。
    当程序写入tx_register后,就不用管了。直到数据发送结束,会产生一个发送完成的中断

1.2 IMX6ULL的I2C控制器内部结构

在这里插入图片描述

  • I2C_IFDR(频率寄存器)
  • I2C_I2CR(控制寄存器
  • I2C_I2SR(状态寄存器)
  • I2C_I2DR(数据I/O寄存器)
  • I2C_IADR(地址寄存器

二、分析代码

2.1 设备树

  1. imx6ull:arch/arm/boot/dts/imx6ull.dtsi

    i2c1: i2c@02221a0000 {
    	#address-cells = <1>;
    	#size-cells = <0>;
    	compatible = <"fsl,imx6ul-i2c", "fsl,imx21-i2c";
    	reg = <0x021a0000 0x40000>;
    	interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
    	clocks = <&clks IMX6UL_CLK_I2C1>;
    	status = "disabled";		//在100ask_imx6ull-14x14.dts 把它改成了"okay"
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

2.2 驱动程序分析

2.2.1 Linux下I2C驱动程序的体系结构

Linux下的i2c框架,分为了3个子模块
在这里插入图片描述

  1. I2C核心
    I2C核心主要是i2c-core.c,里面涉及的adapter都是和i2c核心进行耦合的,设备和驱动不需要关心adapter部分。
  2. I2C总线驱动
    I2C总线驱动是对I2C硬件体系结构中适配器(i2c-adapter)端的实现,这部分主要是产生I2C协议的波形,操作硬件完成开始信号,数据传输,停止信号,设备应答检测等等,还是看上面那个经典的图片,adapter就是往下走的,所以就是操作到平台cpu的部分了。
  3. I2C设备驱动
    I2C设备驱动(i2c-client)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据

2.2.2 (IMX6ULL)I2C主机驱动

I2C 总线驱动重点是 I2C 适配器(也就是 SOC 的 I2C 接口控制器)驱动,这里要用到
两个重要的数据结构:i2c_adapteri2c_algorithm,Linux 内核将 SOC 的 I2C 适配器(控制器)
抽象成 i2c_adapteri2c_adapter 结构体定义在 include/linux/i2c.h 文件中。

498 struct i2c_adapter {
499 	struct module *owner;
500	 	unsigned int class; /* classes to allow probing for */
501 	const struct i2c_algorithm *algo; /* 总线访问算法 */
502 	void *algo_data;
503
504 	/* data fields that are valid for all devices */
505 	struct rt_mutex bus_lock;
506
507 	int timeout; /* in jiffies */
508 	int retries;
509 	struct device dev; /* the adapter device */
510
511 	int nr;
512 	char name[48];
513 	struct completion dev_released;
514
515 	struct mutex userspace_clients_lock;
516 	struct list_head userspace_clients;
517
518 	struct i2c_bus_recovery_info *bus_recovery_info;
519 	const struct i2c_adapter_quirks *quirks;
520 };

struct imx_i2c_struct {
	struct i2c_adapter	adapter;
	struct clk		*clk;
	void __iomem		*base;
	wait_queue_head_t	queue;
	unsigned long		i2csr;
	unsigned int		disable_delay;
	int			stopped;
	unsigned int		ifdr; /* IMX_I2C_IFDR */
	unsigned int		cur_clk;
	unsigned int		bitrate;
	const struct imx_i2c_hwdata	*hwdata;

	struct imx_i2c_dma	*dma;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
1 创建i2c_adapter

紧接着上篇文章《Linux I2C子系统【1】-I2C驱动分析-设备树创建platform_device》中的“i2c platform_driver主机驱动匹配platform_device 的过程”,.probe = i2c_imx_probe被执行,进入到开始创建i2c_adapter过程中。

static const struct of_device_id i2c_imx_dt_ids[] = {
	{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
	{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
	{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
	{ /* sentinel */ }
};
static const struct imx_i2c_hwdata imx21_i2c_hwdata  = {
	.devtype		= IMX21_I2C,
	.regshift		= IMX_I2C_REGSHIFT,
	.clk_div		= imx_i2c_clk_div,
	.ndivs			= ARRAY_SIZE(imx_i2c_clk_div),
	.i2sr_clr_opcode	= I2SR_CLR_OPCODE_W0C,
	.i2cr_ien_opcode	= I2CR_IEN_OPCODE_1,

};

i2c-imx.c(
static int i2c_imx_probe(struct platform_device *pdev)
{
	struct imx_i2c_struct *i2c_imx;
	/*告知一个设备是否匹配了(i2c_imx_dt_ids)列表中的设备*/
	/*of_id = { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },*/
	const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,
							   &pdev->dev);/*include/linux/of_device.h*/
	{
		#define of_match_device(matches, dev)	\
			__of_match_device(of_match_ptr(matches), (dev))
	}
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);/*drivers/base/platform.c*/
	base = devm_ioremap_resource(&pdev->dev, res);/*lib/devres.c*/
	if (IS_ERR(base))
		return PTR_ERR(base);

	phy_addr = (dma_addr_t)res->start;
	/*i2c_imx->adapter创建出来了*/
	i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);
	i2c_imx->hwdata = of_id->data;/*赋值硬件信息,分频等信息*/
	
		/* 填充 i2c_imx 驱动结构体 */
	strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
	i2c_imx->adapter.owner		= THIS_MODULE;
	i2c_imx->adapter.algo		= &i2c_imx_algo; /*算法通讯部分*/
	i2c_imx->adapter.dev.parent	= &pdev->dev;	/*此分配器的所属设备的父设备是他自己*/
	i2c_imx->adapter.nr		= pdev->id;
	i2c_imx->adapter.dev.of_node	= pdev->dev.of_node; /*此分配器所属设备的设备节点*/
	i2c_imx->base			= base;	/*DMA 地址首地址*/
	/* Init queue */
	init_waitqueue_head(&i2c_imx->queue);
	/* Set up adapter data */
	i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
	/* Set up clock divider *//*默认为100khz*/
	i2c_imx->bitrate = IMX_I2C_BIT_RATE;
	ret = of_property_read_u32(pdev->dev.of_node,
				   "clock-frequency", &i2c_imx->bitrate);/*clock-frequency = <100000>;*/
	/*注册到哪里?以怎么的数据结构注册链接*/
	ret = i2c_add_numbered_adapter(&i2c_imx->adapter);/*注册adapter*/
}
在include/linux/of.h里面
查看arch/arm64/KCONFIG,可以知道CONFIG_OF默认是打开的,意为使用设备树
#ifdef CONFIG_OF
...
#define of_match_ptr(_ptr)	(_ptr)
...
#else /* CONFIG_OF */
...
#define of_match_ptr(_ptr)	NULL
...
#endif /* CONFIG_OF */

/*
 * of_match_device - Tell if a struct device matches an of_device_id list
 * @ids: array of of device match structures to search in
 * @dev: the of device structure to match against
 *
 * Used by a driver to check whether an platform_device present in the
 * system is in its list of supported devices.
 */
 /*这里有一句非常重要的描述“of_match_device - Tell if a struct device matches an of_device_id list”,意思就是:告知一个设备(设备结构体)是否匹配了of_device_id列表中的设备。
如果匹配表或者设备没有对应的节点,返回NULL,匹配失败。否则,继续执行非常重要的of_match_node函数。*/

const struct of_device_id *of_match_device(const struct of_device_id *matches,
					   const struct device *dev)
{
	if ((!matches) || (!dev->of_node))
		return NULL;
	return of_match_node(matches, dev->of_node);
}

driver/of/base.c (
/*可以看出其匹配的方式有三种:name/type/compatible,这三种方式的最佳是通过score分数来判定的,匹配完成后返回score最大对应的matches*/
	static const struct of_device_id *__of_match_node(const struct of_device_id *matches,
					   				const struct device_node *node)
	{
		const struct of_device_id *best_match = NULL;
		int score, best_score = 0;
	
		if (!matches)
			return NULL;
	
		for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
			score = __of_device_is_compatible(node, matches->compatible,
							  matches->type, matches->name);
			if (score > best_score) {
				best_match = matches;
				best_score = score;
			}
		)
		return best_match;
	}

)

drvres/clk/clk-drvres.c (
	struct clk *devm_clk_get(struct device *dev, const char *id)
	{
		struct clk **ptr, *clk;
	
		ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
		if (!ptr)
			return ERR_PTR(-ENOMEM);
	
		clk = clk_get(dev, id);
		if (!IS_ERR(clk)) {
			*ptr = clk;
			devres_add(dev, ptr);
		} else {
			devres_free(ptr);
		}
	
		return clk;
	}
)

drvres/clk/clk-drvres.c(
	struct clk *clk_get(struct device *dev, const char *con_id)
	{
		const char *dev_id = dev ? dev_name(dev) : NULL;
		struct clk *clk;
	
		if (dev) {
			clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);/*通过名字获取时钟*/
			if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
				return clk;
		}
		return clk_get_sys(dev_id, con_id);
	}
)

static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
{
	dev_set_drvdata(&dev->dev, data);
	static inline void dev_set_drvdata(struct device *dev, void *data)
	{
		/*i2c_imx->adapter->(struct device*)dev->driver_data = i2c_imx*/
		/*i2c_adapter 所属设备中的设备驱动指向i2c_imx*/
		dev->driver_data = data;
	}
}
drivers/i2c/i2c-core.c(
	int i2c_add_numbered_adapter(struct i2c_adapter *adap)
	{
		if (adap->nr == -1) /* -1 means dynamically assign bus id */
			return i2c_add_adapter(adap);
	
		return __i2c_add_numbered_adapter(adap);
	}
	int i2c_add_adapter(struct i2c_adapter *adapter)
	{
		struct device *dev = &adapter->dev;
		int id;
	
		if (dev->of_node) {
			id = of_alias_get_id(dev->of_node, "i2c");
			if (id >= 0) {
				adapter->nr = id;
				return __i2c_add_numbered_adapter(adapter);
			}
		}
	}
	/*i2c_add_numbered_adapter where nr is never -1*/
	static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
	{
		return i2c_register_adapter(adap);
	}
	static int i2c_register_adapter(struct i2c_adapter *adap)
	{
		/*至此等待设备在i2c_bus_type匹配*/
		INIT_LIST_HEAD(&adap->userspace_clients);/*初始化链表头*/
		dev_set_name(&adap->dev, "i2c-%d", adap->nr);/*dev->kobj->name*/
		adap->dev.bus = &i2c_bus_type;
		adap->dev.type = &i2c_adapter_type;
		res = device_register(&adap->dev);/*注册入i2c_bus_type*/
		/* create pre-declared device nodes */
		of_i2c_register_devices(adap);
	}
)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197

/了解device_register阅读以下文章/
linux设备模型六(device细节)

2 注册i2c_adapter的时候如何发生匹配i2c_clent的

到这里我们着重分析一下,在注册i2c_adapter的时候如何发生匹配i2c_clent的?

主机驱动会根据i2c_adpter->dev->of_node来创建 i2c_client。
i2c_client 链表: i2c_bus_type->p->klist_devices
i2c_driver 链表:i2c_bus_type->p->klist_drivers
硬件i2c控制器硬件初始化完成,注册 adapter时,依据1.1.3中的dev->of_node 中信息生成i2c_client,并挂接在klist_devices链表上

在注册i2c_driver时,即:i2c_add_driver(struct i2c_driver*),会做两件事情:
(1)将 i2c_driver->drv 挂接到此链表
(2)遍历 klist_devices 链表,查找与 i2c_driver->id_table->name 相同的 i2c_client->name

2.1 注册i2c_adapter->dev
--->static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
--->static int i2c_register_adapter(struct i2c_adapter *adap)
  --->device_register(&adap->dev)
  --->static void of_i2c_register_devices(struct i2c_adapter *adap)
    -->for_each_available_child_of_node(parent, child)
    -->struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,struct device_node *node)
    -->struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
/*就是将i2c_adapter当作device注册进入i2cbus->p->klist_devices,将来供i2c_client匹配*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};
--->device_register(&adap->dev)
{
	device_add(struct device *dev)
	{
		pr_info("device: '%s',%p\n", dev_name(dev),dev);
		parent = get_device(dev->parent);
		pr_info("parent=%p",parent);

		bus_add_device(struct device *dev)
		{
			klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);/*i2c_bus_type->p->klist_devices*/
		}
		/*probe drivers for a new device*/
		bus_probe_device(struct device *dev)/*bus_probe_device(dev)*/
		{
			ret = device_attach(dev);
		}
	}
	
}
drivers/base/dd.c(
	/**
	 * device_attach - try to attach device to a driver.
	 * @dev: device.
	 *
	 * Walk the list of drivers that the bus has and call
	 * driver_probe_device() for each pair. If a compatible
	 * pair is found, break out and return.
	 *
	 * Returns 1 if the device was bound to a driver;
	 * 0 if no matching driver was found;
	 * -ENODEV if the device is not registered.
	 *
	 * When called for a USB interface, @dev->parent lock must be held.
	 */
	int device_attach(struct device *dev)
	{
		int ret = 0;
	
		device_lock(dev);
		if (dev->driver) { /* driver已经放在device了(初始化device,时,手动添加的driver) */
			if (klist_node_attached(&dev->p->knode_driver)) {
				ret = 1;
				goto out_unlock;
			}
			ret = device_bind_driver(dev);
			if (ret == 0)
				ret = 1;
			else {
				dev->driver = NULL;
				ret = 0;
			}
		} else {
			ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
			{
				struct klist_iter i;
				struct device_driver *drv;
				int error = 0;
			
				if (!bus)
					return -EINVAL;
			
				klist_iter_init_node(&bus->p->klist_drivers, &i,
						     start ? &start->p->knode_bus : NULL);
				pr_info("start match driver\n\n");
				while ((drv = next_driver(&i)) && !error)
					error = fn(drv, data);
				pr_info("end match driver\n\n");
				klist_iter_exit(&i);
				return error;
			}
			pm_request_idle(dev);
		}
	out_unlock:
		device_unlock(dev);
		return ret;
	}
	static int __device_attach(struct device_driver *drv, void *data)
	{
		struct device *dev = data;
	
		if (!driver_match_device(drv, dev))
			return 0;
	
		return driver_probe_device(drv, dev);
	}
)
drivers/base/base.h(
	static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
	{
		pr_info("drv->bus=%s",drv->bus->name);
		return drv->bus->match ? drv->bus->match(dev, drv) : 1;
	}
)
drivers/i2c/i2c-core.c(
	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){
			pr_info("%s,%p,11-faild to match\n\n",drv->name,dev);
			return 0;
		}
			
	
		/* Attempt an OF style match */
		if (of_driver_match_device(dev, drv))
			return 1;
		pr_info("faild to match\n\n");
		/* 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;
	}
	/*
	以下地址为/i2c_adapter->dev 的地址,在没有匹配到驱动时,退出。
	然后第二个bus_add_device,end match driver代表开始注册i2c_client->dev,然后开始匹配驱动,那么时怎么一个流程呢?
	bus_add_device
	device: 'i2c-0',88525038(struct device i2c_bus)(跟platform_bus一样当作所有device的父设备)
	parent=880fb010
	device: 'i2c-0',886a2400(i2c_adapter->dev)
	parent=88525038
	start match driver
		dummy,88503438,11-faild to match
		pca953x,88503438,11-faild to match
		stmpe-i2c,88503438,11-faild to match
		mc13xxx,88503438,11-faild to match
		da9052,88503438,11-faild to match
		pfuze100-regulator,88503438,11-faild to match
		at24,88503438,11-faild to match
		egalax_ts,88503438,11-faild to match
		tsc2007,88503438,11-faild to match
		vtl_ts,88503438,11-faild to match
		mma8450,88503438,11-faild to match
		ov2640,88503438,11-faild to match
		ir-kbd-i2c,88503438,11-faild to match
		sgtl5000,88503438,11-faild to match
		tlv320aic23-codec,88503438,11-faild to match
		wm8960,88503438,11-faild to match
		wm8962,88503438,11-faild to match
	bus_add_device
	end match driver (devcie_register 必经之路)
	
	of_i2c: walking child nodes
	of_i2c_register_device
	device: '0-001e',886a2c20
	parent=88525038
	start match driver
	end match driver
	
	client [ap3216c] registered with bus id 0-001e
	i2c_scan_static_board_info
	
	start match driver
	end match driver



	*/
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
2.2 注册i2c_client->dev
&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";
	
	/*2022/1/31/ tristanwang*/
	ap3216c@1e{
		compatible = "alientek,ap3216c";
		reg = <0x1e>;
	};
	
	// mag3110@0e {
	// 	compatible = "fsl,mag3110";
	// 	reg = <0x0e>;
	// 	position = <2>;
	// };
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
drivers/i2c/i2c-core.c(
	static void of_i2c_register_devices(struct i2c_adapter *adap)
	{
		struct device_node *node;
	
		/* Only register child devices if the adapter has a node pointer set */
		if (!adap->dev.of_node)
			return;
	
		dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
		for_each_available_child_of_node(adap->dev.of_node, node)
			of_i2c_register_device(adap, node);
			{
				result = i2c_new_device(adap, &info);
			}
	}
)
linuc/of.h(
	#define for_each_available_child_of_node(parent, child) \
	for (child = of_get_next_available_child(parent, NULL); child != NULL; \
	     child = of_get_next_available_child(parent, child))
	
)
drivers/of/base.c(
	/*of_get_next_available_child - Find the next available child node*/
		struct device_node *of_get_next_available_child(const struct device_node *node,
							struct device_node *prev)
	{
		struct device_node *next;
		unsigned long flags;
	
		if (!node)
			return NULL;
	
		raw_spin_lock_irqsave(&devtree_lock, flags);
		next = prev ? prev->sibling : node->child;
		for (; next; next = next->sibling) {
			if (!__of_device_is_available(next))
				continue;
			if (of_node_get(next))
				break;
		}
		of_node_put(prev);
		raw_spin_unlock_irqrestore(&devtree_lock, flags);
		return next;
	}

	 /*  __of_device_is_available - check if a device is available for use*/
	static bool __of_device_is_available(const struct device_node *device)
	{
		const char *status;
		int statlen;
	
		if (!device)
			return false;
	
		status = __of_get_property(device, "status", &statlen);
		if (status == NULL)
			return true;
	
		if (statlen > 0) {
			if (!strcmp(status, "okay") || !strcmp(status, "ok"))
				return true;
		}
	
		return false;
	}
)
drivers/i2c/i2c-core.c(
	/*
		of_i2c: register /soc/aips-bus@02100000/i2c@021a0000/ap3216c@1e
		of_i2c: register -2097126164
		of_i2c_betocpup: register 30 = ie
		client->flags=0,client->irq=0
		client->name=ap3216c
	*/

		static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
							 struct device_node *node)/*node of client*/
	{
		struct i2c_client *result;
		struct i2c_board_info info = {};

		pr_info("of_i2c: register %s\n\n", node->full_name);
		const __be32 *addr = of_get_property(node, "reg", &len);
		pr_info("of_i2c: register %d\n\n", addr);
		info.of_node = of_node_get(node);
		info.addr = be32_to_cpup(addr);
		pr_info("of_i2c_betocpup: register %d\n\n", info.addr);
	
		result = i2c_new_device(adap, &info);
		return result;
	}
	/* i2c_new_device - instantiate an i2c device,
	A driver may be bound to this device when we return from this function*/
		struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
	{
		struct i2c_client *client = kzalloc(sizeof *client, GFP_KERNEL);
		client->adapter = adap;		/*绑定adpter 与 client*/
		client->dev.platform_data = info->platform_data;/*NULL*/
		client->flags = info->flags;
		client->addr = info->addr;/*client_reg addr*/
		client->irq = info->irq;
	
		strlcpy(client->name, info->type, sizeof(client->name));
		pr_info("client->flags=%d,client->irq=%d\n\n",client->flags,client->irq);
		pr_info("client->name=%s\n\n",client->name);

		client->dev.parent = &client->adapter->dev;
		client->dev.bus = &i2c_bus_type;
		client->dev.type = &i2c_client_type;
		client->dev.of_node = info->of_node;/*node of client*/
		client->dev.fwnode = info->fwnode;
	
		i2c_dev_set_name(adap, client);
		pr_info("%s\n\n",client->dev.kobj.name);/*1-001a*/
		/*/sys/bus/i2c/devices/0-001e
		 /sys/devices/platform/soc/2100000.aips-bus/21a0000.i2c/i2c-0/0-001e*/
		status = device_register(&client->dev);
		return client;

	out_err_silent:
		kfree(client);
		return NULL;
	}
	
	static void i2c_dev_set_name(struct i2c_adapter *adap,
			     struct i2c_client *client)
	{		
		/* For 10-bit clients, add an arbitrary offset to avoid collisions */
		dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
			     client->addr | ((client->flags & I2C_CLIENT_TEN)
					     ? 0xa000 : 0));
	}
	
)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
3 i2c_del_adapter
/*i2c_del_adapter - unregister I2C adapter*/
void i2c_del_adapter(struct i2c_adapter *adap)
{
	struct i2c_adapter *found;
	struct i2c_client *client, *next;

	/* First make sure that this adapter was ever added */
	mutex_lock(&core_lock);
	found = idr_find(&i2c_adapter_idr, adap->nr);
	mutex_unlock(&core_lock);
	if (found != adap) {
		pr_debug("i2c-core: attempting to delete unregistered "
			 "adapter [%s]\n", adap->name);
		return;
	}

	acpi_i2c_remove_space_handler(adap);
	/* Tell drivers about this removal */
	mutex_lock(&core_lock);
	bus_for_each_drv(&i2c_bus_type, NULL, adap,
			       __process_removed_adapter);/*删除与adapter相匹配的client*/
	mutex_unlock(&core_lock);

	/* Remove devices instantiated from sysfs */
	mutex_lock_nested(&adap->userspace_clients_lock,
			  i2c_adapter_depth(adap));
	list_for_each_entry_safe(client, next, &adap->userspace_clients,
				 detected) {
		dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
			client->addr);
		list_del(&client->detected);
		i2c_unregister_device(client);
	}
	mutex_unlock(&adap->userspace_clients_lock);

	/* Detach any active clients. This can't fail, thus we do not
	 * check the returned value. This is a two-pass process, because
	 * we can't remove the dummy devices during the first pass: they
	 * could have been instantiated by real devices wishing to clean
	 * them up properly, so we give them a chance to do that first. */
	device_for_each_child(&adap->dev, NULL, __unregister_client);
	device_for_each_child(&adap->dev, NULL, __unregister_dummy);

#ifdef CONFIG_I2C_COMPAT
	class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
				 adap->dev.parent);
#endif

	/* device name is gone after device_unregister */
	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);

	/* wait until all references to the device are gone
	 *
	 * FIXME: This is old code and should ideally be replaced by an
	 * alternative which results in decoupling the lifetime of the struct
	 * device from the i2c_adapter, like spi or netdev do. Any solution
	 * should be throughly tested with DEBUG_KOBJECT_RELEASE enabled!
	 */
	init_completion(&adap->dev_released);
	device_unregister(&adap->dev);
	wait_for_completion(&adap->dev_released);

	/* free bus id */
	mutex_lock(&core_lock);
	idr_remove(&i2c_adapter_idr, adap->nr);
	mutex_unlock(&core_lock);

	/* Clear the device structure in case this adapter is ever going to be
	   added again */
	memset(&adap->dev, 0, sizeof(adap->dev));
}
drivers/base/bus.c 
(
	int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
		     void *data, int (*fn)(struct device_driver *, void *))
	{
		struct klist_iter i;
		struct device_driver *drv;
		int error = 0;
	
		if (!bus)
			return -EINVAL;
	
		klist_iter_init_node(&bus->p->klist_drivers, &i,
				     start ? &start->p->knode_bus : NULL);
		while ((drv = next_driver(&i)) && !error)
			error = fn(drv, data);
		klist_iter_exit(&i);
		return error;
	}
)
static int __process_removed_adapter(struct device_driver *d, void *data)
{
	i2c_do_del_adapter(to_i2c_driver(d), data);
	return 0;
}
static void i2c_do_del_adapter(struct i2c_driver *driver,
			      struct i2c_adapter *adapter)
{
	struct i2c_client *client, *_n;

	/* Remove the devices we created ourselves as the result of hardware
	 * probing (using a driver's detect method) */
	list_for_each_entry_safe(client, _n, &driver->clients, detected) {
		if (client->adapter == adapter) {
			dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
				client->name, client->addr);
			list_del(&client->detected);
			i2c_unregister_device(client);
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
4 device_unregister
void device_unregister(struct device *dev)
{
	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
	device_del(dev);
	{
		bus_remove_device(dev);
	}
	put_device(dev);
}
void bus_remove_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;

	if (!bus)
		return;

	mutex_lock(&bus->p->mutex);
	list_for_each_entry(sif, &bus->p->interfaces, node)
		if (sif->remove_dev)
			sif->remove_dev(dev, sif);
	mutex_unlock(&bus->p->mutex);

	sysfs_remove_link(&dev->kobj, "subsystem");
	sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
			  dev_name(dev));
	device_remove_attrs(dev->bus, dev);
	device_remove_groups(dev, dev->bus->dev_groups);
	if (klist_node_attached(&dev->p->knode_bus))
		klist_del(&dev->p->knode_bus);

	pr_debug("bus: '%s': remove device %s\n",
		 dev->bus->name, dev_name(dev));
	device_release_driver(dev);
	bus_put(dev->bus);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

总结

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/826863
推荐阅读
相关标签
  

闽ICP备14008679号