欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

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

程序员文章站 2022-06-16 18:02:55
dtb文件中的i2c节点&i2c2 {clock-frequency = <100000>; //时钟频率pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c2>; //i2c使用的引脚status = "okay"; //默认状态为使能状态codec: wm8904@1a {compatible = "wlf,wm8904"; //...

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