• Linux内核4.14版本——I2C子系统(4)_I2C示例(i2c-designware-platdrv.c和at24.c)


    目录

    1. DTS

    2. I2C control实例化分析

    3. adapter如何注册slave device

    3.1 i2c_register_adapter

    3.2 of_i2c_register_device

    3.2.1 of_modalias_node

    3.2.2 i2c_new_device

    4. i2c consumer driver注册


    源码:

    drivers\i2c\busses\i2c-designware-platdrv.c
    drivers\i2c\busses\i2c-designware-master.c
    drivers\i2c\busses\i2c-designware-slave.c

    drivers\misc\eeprom\at24.c

    1. DTS

    1. i2c2: i2c@f0d80000 {
    2. compatible = "snps,designware-i2c";
    3. status = "disabled";
    4. interrupt-parent = <&gic>;
    5. interrupts = 30 IRQ_TYPE_LEVEL_HIGH>;
    6. reg = <0x0 0xf0d80000 0x0 0x1000>;
    7. clock-frequency = <400000>;
    8. #address-cells = <1>;
    9. #size-cells = <0>;
    10. };
    11. &i2c2 {
    12. status = "okay";
    13. eeprom: eeprom@50 {
    14. compatible = "atmel,24c32";
    15. reg = <0x50>;
    16. pagesize = <32>;
    17. };
    18. };

         可以看出,i2c下面挂了一个eeprom设备。

    2. I2C control实例化分析

    1. static const struct of_device_id dw_i2c_of_match[] = {
    2.     { .compatible = "snps,designware-i2c", },
    3.     {},
    4. };

    最终dw_i2c_plat_probe(drivers\i2c\busses\i2c-designware-platdrv.c)函数会调用。

    1. static int dw_i2c_plat_probe(struct platform_device *pdev)
    2. {
    3. ......
    4. ret = i2c_dw_probe_lock_support(dev);
    5. if (ret)
    6. goto exit_reset;
    7. if (i2c_detect_slave_mode(&pdev->dev))
    8. i2c_dw_configure_slave(dev);
    9. else
    10. i2c_dw_configure_master(dev);
    11. ......
    12. if (dev->mode == DW_IC_SLAVE)
    13. ret = i2c_dw_probe_slave(dev);
    14. else
    15. ret = i2c_dw_probe(dev);
    16. ......
    17. }

        根据该i2c控制器是主机还是从机,进行控制器配置并且调用响应的probe函数,这里我们分析主机模式,调用i2c_dw_probe函数。

    1. static const struct i2c_algorithm i2c_dw_algo = {
    2. .master_xfer = i2c_dw_xfer,
    3. .functionality = i2c_dw_func,
    4. };
    5. int i2c_dw_probe(struct dw_i2c_dev *dev)
    6. {
    7. struct i2c_adapter *adap = &dev->adapter;
    8. unsigned long irq_flags;
    9. int ret;
    10. .......
    11. ret = dev->init(dev);
    12. if (ret)
    13. return ret;
    14. snprintf(adap->name, sizeof(adap->name),
    15. "Synopsys DesignWare I2C adapter");
    16. adap->retries = 3;
    17. adap->algo = &i2c_dw_algo;
    18. adap->dev.parent = dev->dev;
    19. i2c_set_adapdata(adap, dev);
    20. if (dev->pm_disabled) {
    21. dev_pm_syscore_device(dev->dev, true);
    22. irq_flags = IRQF_NO_SUSPEND;
    23. } else {
    24. irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
    25. }
    26. .....
    27. i2c_dw_disable_int(dev);
    28. ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
    29. dev_name(dev->dev), dev);
    30. ......
    31. ret = i2c_add_numbered_adapter(adap);
    32. }

       这个很简单,设置struct i2c_adapter结构体,主要是adap->algo = &i2c_dw_algo,注册中断,最终调用i2c_add_numbered_adapter注册adapter,这个前文已经写过。

    3. adapter如何注册slave device

    3.1 i2c_register_adapter

          i2c_add_numbered_adapter->__i2c_add_numbered_adapter->i2c_register_adapter,我们查看i2c_register_adapter函数。

    1. static int i2c_register_adapter(struct i2c_adapter *adap)
    2. {
    3. .......
    4. dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    5. adap->dev.bus = &i2c_bus_type;
    6. adap->dev.type = &i2c_adapter_type;
    7. res = device_register(&adap->dev);
    8. .......
    9. i2c_init_recovery(adap);
    10. /* create pre-declared device nodes */
    11. of_i2c_register_devices(adap);
    12. i2c_acpi_install_space_handler(adap);
    13. i2c_acpi_register_devices(adap);
    14. ......
    15. }

          i2c_register_adapter->of_i2c_register_devices->of_i2c_register_device,我们看of_i2c_register_device函数。

    3.2 of_i2c_register_device

    1. static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
    2. struct device_node *node)
    3. {
    4. ........
    5. if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
    6. dev_err(&adap->dev, "of_i2c: modalias failure on %pOF\n",
    7. node);
    8. return ERR_PTR(-EINVAL);
    9. }
    10. .......
    11. result = i2c_new_device(adap, &info);
    12. ......
    13. }

         我们先看of_modalias_node函数。

    3.2.1 of_modalias_node

    1. int of_modalias_node(struct device_node *node, char *modalias, int len)
    2. {
    3. const char *compatible, *p;
    4. int cplen;
    5. compatible = of_get_property(node, "compatible", &cplen);
    6. if (!compatible || strlen(compatible) > cplen)
    7. return -ENODEV;
    8. p = strchr(compatible, ',');
    9. strlcpy(modalias, p ? p + 1 : compatible, len);
    10. return 0;
    11. }

        注意,找到i2c控制器的子节点的compatible字段,取后面的字段,根据前面的DTS介绍,最终把“at24”返回,赋值在info.type变量中。

    3.2.2 i2c_new_device

    1. /**
    2. * i2c_new_device - instantiate an i2c device
    3. * @adap: the adapter managing the device
    4. * @info: describes one I2C device; bus_num is ignored
    5. * Context: can sleep
    6. */
    7. struct i2c_client *
    8. i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
    9. {
    10. ......
    11. strlcpy(client->name, info->type, sizeof(client->name));
    12. .......
    13. i2c_dev_set_name(adap, client);
    14. if (info->properties) {
    15. status = device_add_properties(&client->dev, info->properties);
    16. if (status) {
    17. dev_err(&adap->dev,
    18. "Failed to add properties to client %s: %d\n",
    19. client->name, status);
    20. goto out_err;
    21. }
    22. }
    23. status = device_register(&client->dev);
    24. ......
    25. }

    4. i2c consumer driver注册

    drivers\misc\eeprom\at24.c

    1. static struct i2c_driver at24_driver = {
    2. .driver = {
    3. .name = "at24",
    4. .acpi_match_table = ACPI_PTR(at24_acpi_ids),
    5. },
    6. .probe = at24_probe,
    7. .remove = at24_remove,
    8. .id_table = at24_ids,
    9. };

    前面已经写过,at24 device已经注册了,这里是at24 driver,最终调用at24_probe。

  • 相关阅读:
    Weblogic10中常用Linux指令
    倍福--两台TwinCAT3之间做Ethernet IP通信
    从0到1搭建redis6.0.7
    react中获取input输入框内容的两种方法
    Keep-Alive中通过component多次加载同样的动态组件无法保持状态的解决办法
    Java基于SpringBoot的旅游网站的设计与实现论文
    Spring中的响应式编程实践:从Spring MVC到WebFlux的转变
    WPF-控件的常用属性-单例-隧道事件
    Windows连接Linux上安装的Redis
    Query Kmeans
  • 原文地址:https://blog.csdn.net/yangguoyu8023/article/details/122362946