当前位置: 移动技术网 > 网络运营>服务器>Linux > 设备树中的i2c设备以及内核对i2c节点的处理过程

设备树中的i2c设备以及内核对i2c节点的处理过程

2020年07月13日  | 移动技术网网络运营  | 我要评论

dtb文件中的i2c节点

&i2c2 {
	clock-frequency = <100000>;  //时钟频率
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>; //i2c使用的引脚
	status = "okay";             //默认状态为使能状态
	
	codec: wm8904@1a {
		compatible = "wlf,wm8904";            
		reg = <0x1a>;                         //设备地址
		clocks = <&clk IMX8MQ_CLK_SAI2_SRC>;  //使用的时钟
		clock-names = "mclk";
	};
 ....
 }

dtsi文件中的i2c节点

i2c2: i2c@30a30000 {
        #address-cells = <1>; //表示用一个32位的数来描述地址
        #size-cells = <0>; //表示用0个32位的数来描述该地址的大小
        compatible = "fsl,imx21-i2c"; //匹配的platform_driver

        //起始地址0x30a30000 长度0x10000
        reg = <0x0 0x30a30000 0x0 0x10000>;

        //使用的中断 以及触发方式
        interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&clk IMX8MQ_CLK_I2C2_ROOT>;
        status = "disabled";
	};

/i2c节点一般表示i2c控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;一般为厂商所配套的platform_driver文件(freescale的处理文件为i2c-imx.c)。platform_driver的probe函数中会调用i2c_add_numbered_adapter():

/* 将设备树转换成platform_device后i2c_imx_probe函数被调用 */
i2c_imx_probe
    i2c_add_numbered_adapter /* 添加I2C控制器 */
        __i2c_add_numbered_adapter
            i2c_register_adapter /* 注册I2C控制器 */
                device_register /* I2C控制器设备注册 */
                of_i2c_register_devices /* 查找设备树控制器下面的从设备 */
                    of_i2c_register_device /*解析设备树属性*/
                        i2c_new_device
                            client->dev.bus = &i2c_bus_type;
                            device_register /* 添加设备I2C从设备 */
                i2c_scan_static_board_info /* 查找静态表,有些I2C设备是在代码中写死的,不是通过设备树的形式 */
                    i2c_new_device
                        client->dev.bus = &i2c_bus_type;
                        device_register /* 添加设备I2C从设备 */

下面我们来看一下of_i2c_register_device函数,该函数主要用于解析i2c节点设备树内容

static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
						 struct device_node *node)
{
	struct i2c_client *result;
	struct i2c_board_info info = {};
	struct dev_archdata dev_ad = {};
	const __be32 *addr_be;
	u32 addr;
	int len;

	dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);

    //获取i2c节点中的compatible属性 拷贝到info.type中
	if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) 
	{
		dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
			node->full_name);
		return ERR_PTR(-EINVAL);
	}
    
	//获取i2c节点中的reg属性(设备地址) 
	addr_be = of_get_property(node, "reg", &len);
	if (!addr_be || (len < sizeof(*addr_be))) {
		dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
			node->full_name);
		return ERR_PTR(-EINVAL);
	}

    //解析设备地址
	addr = be32_to_cpup(addr_be);
	if (addr & I2C_TEN_BIT_ADDRESS) {
		addr &= ~I2C_TEN_BIT_ADDRESS;
		info.flags |= I2C_CLIENT_TEN;
	}

	if (addr & I2C_OWN_SLAVE_ADDRESS) {
		addr &= ~I2C_OWN_SLAVE_ADDRESS;
		info.flags |= I2C_CLIENT_SLAVE;
	}

    //检查设备地址
	if (i2c_check_addr_validity(addr, info.flags)) {
		dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
			addr, node->full_name);
		return ERR_PTR(-EINVAL);
	}

	info.addr = addr;
	info.of_node = of_node_get(node); //将设备树节点存入info.of_node
	info.archdata = &dev_ad;

	if (of_get_property(node, "wakeup-source", NULL))
		info.flags |= I2C_CLIENT_WAKE;

    //注册i2c 设备
	result = i2c_new_device(adap, &info);
	if (result == NULL) {
		dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
			node->full_name);
		of_node_put(node);
		return ERR_PTR(-EINVAL);
	}
	return result;
}

在完成i2c设备注册后,将通过i2c_bus_type.i2c_device_match匹配驱动程序。

本文地址:https://blog.csdn.net/qq_17270067/article/details/107233760

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网