查看: 3703|回复: 0

[评测分享] 【ALINX AXU2CGB试用】atmel at24 驱动源码框架分析

[复制链接]
  • TA的每日心情
    开心
    3 天前
  • 签到天数: 597 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2021-7-9 22:58:31 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 robe.zhang 于 2021-7-9 22:58 编辑

    【ALINX AXU2CGB试用】atmel at24 驱动源码框架分析


    Atmel at24 eeprom 驱动程序最终是注册了mvmem实现的所有功能
    1.png

    struct at24_data 数据结构中包括 nvmem 成员变量,还包括一个struct at24_client 类型的client[] 数组。两个疑问:
    为什么不是 struct i2c_client 类型,而是 structat24_client
    为什么不是 client,而是 client 数组
    2.png
    为什么不是 struct i2c_client 类型,而是 structat24_client,这个疑问打开 struct at24_client数据结构就有了答案,struct at24_client  数据结构封装了struct i2c_client 数据结构,同时还封装了一个 structregmap 数据结构
    新的疑问:regmap 干什么用?
    3.png
    为什么不是 client,而是 client 数组:初始化的时候确实只有一个 client,如下截图:
    4.png
    但是有的芯片是多地址芯片:每个地址对应一个 struct i2c_client, 就会有多个client 了
    5.png
    其余的多个 client 全部在 at24_make_dummy_client函数中初始化,并在第 528 行赋值给 client 数据,同时赋值了一个 regmap 结构体变量
    6.png
    Atmel at24 注册nvmem,当作 nvmem 来看待;它同时继承了 struct i2c_client 数据结构和 regmap 数据结构,同时具有 i2c 功能和 regmap 功能。

    这是 nvmem 注册驱动的过程:从源码中仅仅提炼了核心代码:
    7.png
    最终创建了设备文件,可以通过设备文件来访问。
    访问设备文件时候,调用了 nvmem->reg_read/write 接口,此接口来自at24_read / at24_write 可以追踪:
    8.png
    追踪 at24_read / at24_write 函数可知,不用 regmap 时候,at24 的读写直接调用 map->bus->read /write 完成;使用 regmap 时候,分两步,一次是cache 读写,一次是 map->bus->read /write.
    9.png
    map->bus->read /write 函数是 bus 中的两个方法,bus 是在 regmap_get_i2c_bus函数中获取到的regmap_i2c,此方法退化为 i2c 核心层实现的传输函数i2c_master_send、i2c_transfer 等,就接上 i2c 驱动源码核心框架部分了
    10.png
    regmap 是个啥东西,自己可以去网上搜,笔者换个角度去看regmap,从源码角度去看 regmap 是个啥东西。
    1.                         _regmap_read(map, reg + regmap_get_offset(map, i), &ival);                        # 2
    2.                                 regcache_read(map, reg, val);
    3.                                 map->reg_read(context, reg, val);

    4.                         _regmap_write(map, reg + regmap_get_offset(map, i), ival);                        # 1
    5.                                 regcache_write(map, reg, val);
    6.                                 map->reg_write(context, reg, val);
    复制代码

    这是 regmap 读写的函数的实现,先 regcache 读写,然后在调用 map->reg_read /reg_write,本质是在 i2c 总线到 eeprom 器件之间加了一层 cache,类似与 cpu 和 内存之间的加了cache 一样。
    Regcache_read / Regcache_write 是如何实现的:先看他的初始化过程,初始化在__regmap_init 中regcache_init 函数中:
    11.png
    Cache 初始化时候直接赋值:
    map->cache_ops = cache_types;

    cache 初始化时候,有三种类型可选,一种是 rbtree,索引效率高,一种是 lzo 压缩格式,一种是 flat 平坦型。
    1.                                                                 static const struct regcache_ops *cache_types[] = {
    2.                                                                         ®cache_rbtree_ops,
    3.                                                                 #if IS_ENABLED(CONFIG_REGCACHE_COMPRESSED)
    4.                                                                         ®cache_lzo_ops,
    5.                                                                 #endif
    6.                                                                         ®cache_flat_ops,
    7.                                                                 };
    复制代码
    详细看 regcache_flat_ops,,读写函数直接就是赋值,读cache把 cache 中的数据赋值给变量,写 cache 把数据赋值给 cache,相当简单快捷
    1. struct regcache_ops regcache_flat_ops = {
    2.         .type = REGCACHE_FLAT,
    3.         .name = "flat",
    4.         .init = regcache_flat_init,
    5.         .exit = regcache_flat_exit,
    6.         .read = regcache_flat_read,                                                                # *value = cache[index];
    7.         .write = regcache_flat_write,                                                        # cache[index] = value;
    8. };
    复制代码
    赋值后调用 init 初始化cahce,init 函数如下,创建 regmap 的 cache,然后先填充初值
    12.png
    Regcache_read / Regcache_write 读写函数调用了map->cache_ops->write / read 函数,最终就是两个赋值完成的 *value = cache[index]; 和 cache[index] =value;
    Regcache_read / Regcache_write 读写之后照样调用map->reg_read / write 读写,map->reg_read/ write 来自 devm_regmap_init_i2c 中的 __devm_regmap_init_i2c 中的 __devm_regmap_init中的 __regmap_init 函数中赋值的,其实就是 at24_read/ at24_write,又接住上面了。
    13.png
    Regcache_read / Regcache_write 都是被 at24_read / at24_write 调用的.


    总结:At24 eeprom 驱动,注册 nvmem 驱动,通过sysfs 文件系统访问 eeprom实现读写,读写最终还是通过 i2c 子系统实现的读写,读写过程中引入了 regmap 层类似 cache 功能。

    看完 atmel at24 驱动,有个相似的 atmel at25 驱动,扫一眼看懂
    14.png
    15.png
    从源码获取到两个信息 1,同样是注册nvmem,2,spi 总线。
    就看这么多,能猜出来,atmel at25 和 atmel at24 驱动所有的几乎都一摸一样,仅仅的区别是一个 i2c 总线,一个 spi 总线,仅此而已。笔者没看代码,猜的哈,应该没大错,如果有告诉我







    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-11-23 09:23 , Processed in 0.116272 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.