i2c设备控制器与i2c设备的添加过程

上一篇文章我们分析了i2c驱动匹配设备的过程,i2c设备分为控制器与i2c设备,linux内核加载的时候分别加载各个i2c控制器与他们下面挂在的i2c设备,把这些设备一一注册到内核中,这就是我们整个linux系统的资源,以下是i2c设备被注册的过程

rk3x_i2c_probe ->           H:\RK3399\kernel\drivers\i2c\busses\i2c-rk3x.c  //探测到一个i2c控制器
        i2c_add_adapter ->         H:\RK3399\kernel\drivers\i2c\i2c-core.c        //添加i2c控制器设备到总线上
      __i2c_add_numbered_adapter->
              i2c_register_adapter->                                         //注册i2c控制器
                    of_i2c_register_devices->
                        of_i2c_register_device->             
                            i2c_new_device->


static void of_i2c_register_devices(struct i2c_adapter *adap)
{
    struct device_node *node;
    printk("fan of_i2c_register_devices 1436\n");

    /* 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) { //查找这个i2c控制器上所有的节点,找到把设备添加到设备链表上去
        if (of_node_test_and_set_flag(node, OF_POPULATED))
            continue;
        of_i2c_register_device(adap, node);        //
    }
}

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);

    if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {    //从compatible字段中去掉制造商前缀,取逗号后面做info.type,而这个info.type就是以后i2c节点用来与驱动匹配的设备名,看前面i2c驱动加载过程
        dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
            node->full_name)
        return ERR_PTR(-EINVAL);
    }

    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.archdata = &dev_ad;

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

    result = i2c_new_device(adap, &info);     //初始化并注册一个i2c设备,主要是填充i2c_client设备结构体并把设备挂到i2c设备总线上
    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;
}

int of_modalias_node(struct device_node *node, char *modalias, int len)
{
        const char *compatible, *p;
        int cplen;

        compatible = of_get_property(node, "compatible", &cplen);   //获取compatible属性
        if (!compatible || strlen(compatible) > cplen)
                return -ENODEV;
        p = strchr(compatible, ',');         //取逗号后面部分或者没有逗号就去整个
        strlcpy(modalias, p ? p + 1 : compatible, len);
        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术求索者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值