• Linux内核4.14版本——I2C子系统(5)_I2C死锁相关


           在前面的一篇文章中,讲述了I2C死锁的相关概念,下面我们分析一下Linux内核怎么引入改机制的。

    源码:

    drivers\i2c\busses\i2c-st.c
    drivers\i2c\i2c-core-base.c

    目录

    1. i2c_init_recovery(死锁复位机制初始化)

    2. i2c_recover_bus(死锁复位机制的调用)

    3. 如何在自己的I2C控制器中加入该机制?

    4. I2C Adapter最终的使用 


    1. i2c_init_recovery(死锁复位机制初始化)

    1. i2c_add_adapter->i2c_register_adapter->i2c_init_recovery
    2. static int i2c_register_adapter(struct i2c_adapter *adap)
    3. {
    4. int res = -EINVAL;
    5. ................
    6. i2c_init_recovery(adap);
    7. ...........
    8. }
    1. static void i2c_init_recovery(struct i2c_adapter *adap)
    2. {
    3. struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
    4. char *err_str, *err_level = KERN_ERR;
    5. if (!bri)
    6. return;
    7. if (!bri->recover_bus) { //(1)
    8. err_str = "no suitable method provided";
    9. err_level = KERN_DEBUG;
    10. goto err;
    11. }
    12. /* Generic GPIO recovery */
    13. if (bri->recover_bus == i2c_generic_gpio_recovery) { //(2)
    14. if (!gpio_is_valid(bri->scl_gpio)) {
    15. err_str = "invalid SCL gpio";
    16. goto err;
    17. }
    18. if (gpio_is_valid(bri->sda_gpio))
    19. bri->get_sda = get_sda_gpio_value;
    20. else
    21. bri->get_sda = NULL;
    22. bri->get_scl = get_scl_gpio_value;
    23. bri->set_scl = set_scl_gpio_value;
    24. } else if (bri->recover_bus == i2c_generic_scl_recovery) { //(3)
    25. /* Generic SCL recovery */
    26. if (!bri->set_scl || !bri->get_scl) {
    27. err_str = "no {get|set}_scl() found";
    28. goto err;
    29. }
    30. }
    31. return;
    32. err:
    33. dev_printk(err_level, &adap->dev, "Not using recovery: %s\n", err_str);
    34. adap->bus_recovery_info = NULL;
    35. }

    从I2C适配器中得到struct i2c_bus_recovery_info结构体变量bri。

    (1)检查是否支持死锁复位。
    (2)死锁复位方式是GPIO的话,进行必要的函数检查。
    (3)死锁复位方式是SCL的话,进行必要的函数检查。

    1. /**
    2. * struct i2c_bus_recovery_info - I2C bus recovery information
    3. * @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or
    4. * i2c_generic_scl_recovery() or i2c_generic_gpio_recovery().
    5. * @get_scl: This gets current value of SCL line. Mandatory for generic SCL
    6. * recovery. Used internally for generic GPIO recovery.
    7. * @set_scl: This sets/clears SCL line. Mandatory for generic SCL recovery. Used
    8. * internally for generic GPIO recovery.
    9. * @get_sda: This gets current value of SDA line. Optional for generic SCL
    10. * recovery. Used internally, if sda_gpio is a valid GPIO, for generic GPIO
    11. * recovery.
    12. * @prepare_recovery: This will be called before starting recovery. Platform may
    13. * configure padmux here for SDA/SCL line or something else they want.
    14. * @unprepare_recovery: This will be called after completing recovery. Platform
    15. * may configure padmux here for SDA/SCL line or something else they want.
    16. * @scl_gpio: gpio number of the SCL line. Only required for GPIO recovery.
    17. * @sda_gpio: gpio number of the SDA line. Only required for GPIO recovery.
    18. */
    19. struct i2c_bus_recovery_info {
    20. int (*recover_bus)(struct i2c_adapter *);
    21. int (*get_scl)(struct i2c_adapter *);
    22. void (*set_scl)(struct i2c_adapter *, int val);
    23. int (*get_sda)(struct i2c_adapter *);
    24. void (*prepare_recovery)(struct i2c_adapter *);
    25. void (*unprepare_recovery)(struct i2c_adapter *);
    26. /* gpio recovery */
    27. int scl_gpio;
    28. int sda_gpio;
    29. };

    2. i2c_recover_bus(死锁复位机制的调用)

           从第1节中可以知道recover_bus是最终要调用的函数,搜索本文,找到函数i2c_recover_bus。

    1. int i2c_recover_bus(struct i2c_adapter *adap)
    2. {
    3. if (!adap->bus_recovery_info)
    4. return -EOPNOTSUPP;
    5. dev_dbg(&adap->dev, "Trying i2c bus recovery\n");
    6. return adap->bus_recovery_info->recover_bus(adap);
    7. }

    3. 如何在自己的I2C控制器中加入该机制?

           我们以以下的i2c控制器为例,代码在drivers\i2c\busses\i2c-st.c。

    1. static int st_i2c_probe(struct platform_device *pdev)
    2. {
    3. ........
    4. adap->bus_recovery_info = &st_i2c_recovery_info;
    5. ........
    6. ret = i2c_add_adapter(adap);
    7. .......
    8. return 0;
    9. }
    10. static struct i2c_bus_recovery_info st_i2c_recovery_info = {
    11. .recover_bus = st_i2c_recover_bus,
    12. };

          简单来说就是在i2c probe函数中,填充struct i2c_bus_recovery_info结构体,并赋值给adapter。

          这个函数可以是自己实现的,可以是使用内核提供的。如果使用内核提供的,那么需要补充一些内核函数需要的一些参数或者函数。

         自己写的可以参考:drivers\i2c\busses\i2c-st.c

         使用内核的可以参考:drivers\i2c\busses\i2c-davinci.c

    4. I2C Adapter最终的使用 

    1. static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
    2. {
    3. u32 sta;
    4. int i, ret;
    5. for (i = 0; i < 10; i++) {
    6. sta = readl_relaxed(i2c_dev->base + SSC_STA);
    7. if (!(sta & SSC_STA_BUSY))
    8. return 0;
    9. usleep_range(2000, 4000);
    10. }
    11. dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta);
    12. ret = i2c_recover_bus(&i2c_dev->adap);
    13. if (ret) {
    14. dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
    15. return ret;
    16. }
    17. return -EBUSY;
    18. }

           一般会在i2c的master_xfer中使用。

    1. static const struct i2c_algorithm st_i2c_algo = {
    2. .master_xfer = st_i2c_xfer,
    3. .functionality = st_i2c_func,
    4. };

  • 相关阅读:
    小程序request请求封装
    静态代理、动态代理概念及使用
    信息/数据
    【Linux】Linux文本处理-grep、awk、sed
    Java -- JDK中SPI机制
    死锁产生的条件及其预防
    GEE——自GLDAS-2.0 每日流域模型批量导出逐月Terrestrial water storage水存量影像下载
    Redis缓存(缓存预热,缓存穿透,缓存雪崩,缓存击穿)
    43.228.64.X游戏盾在业务高峰时间段,出现用户大量掉线问题,可能是什么原因导致
    Python数据结构——数组
  • 原文地址:https://blog.csdn.net/yangguoyu8023/article/details/122462285