Linux regmap子系统分析从数据结构分析系统实现

178人浏览   2024-05-14 22:46:49


一、数据结构间的关联及说明

针对regmap子系统,我们首先要知道regmap子系统要解决的痛点是什么?我们知道大多的传感器芯片(io扩展芯片、温度传感器、电源管理芯片、input设备、hwmon类型设备等等),基本上都是spi设备或者iic设备,而在这些设备的业务处理接口中充斥着大量的iic设备读写、spi设备读写的调用。另外有的设备厂家针对一款设备可能存在iic接口与spi接口两种可选的接口方式,针对这一类设备进行设备驱动开发时,该驱动也会抽象出统一的读写接口(如AD913x型号、AD538x型号的设备,就包含两种接口类型的型号);基于以上考虑,linux内核子系统提供了regmap子系统,该子系统对外提供统一的读写接口,而针对AD913x型号、AD538x型号的设备驱动而言,则只需要提供两种类型的probe、remove(xxx_i2c_dev_probe、xxx_spi_dev_probe接口)接口,并在probe接口中完成regmap的创建,接着在具体的业务处理接口中直接调用regmap子系统提供的读写接口即可。

而regmap子系统主要的好处有两个:1.提供统一的读写接口 2.提供缓存机制。为了实现统一的读写接口,regmap子系统提供了regamp数据结构、regmap_bus数据结构、regcache_ops数据结构等,下面我们来简要说明下。

针对regmap子系统而言,其提供的主要数据结构抽象可理解如下(数据结构间的关联图如下所示):

  1. regmap_bus数据结构,该数据结构即对具体总线控制器map的抽象(i2c、spi模块均完成了regmap_bus的定义,其中定义了对i2c设备、spi设备的统一读写接口);
  2. regmap数据结构即为对具体设备的map(如一个i2c设备、spi设备均需要一个regmap),而regmap里则包含regcache相关的支持、该regmap关联的regmap、寄存器是否可读写等接口;
  3. 为了在进行regmap初始化时,对regmap进行初始化,regmap也提供了数据结构regmap_config,实现对regmap的初始化操作。

regmap子系统的数据结构间的定义相对来说并不复杂,并且regmap子系统的设计相对来说也不算复杂(比如并没有提供remap_bus的注册接口,也不需要关注系统中已经定义了多少个regmap_bus以及系统中已经创建了多少个regmap等等),相比于设备驱动模型、pinctrl子系统、input子系统而言,算是较简单的子系统设计。针对regmap子系统,只要我们理解了regmap、regmap_bus的定义,基本上也可以大概了解regmap子系统的实现了。下面我们详细说明下。


regmap_bus数据结构定义

如下即为regmap_bus的定义,其主要提供如下几个方面的内容:

  1. Regmap bus的同步写接口;
  2. Regmap bus的异步写接口;
  3. Regmap bus的读接口;
  4. Regmap bus的读写flag;
  5. Regmap bus的寄存器、寄存器值的格式(大端、小端);
  6. Regmap bus异步写相关的缓存申请接口等

regmap_bus的定义也是比较简单,只需提供regmap_bus对应总线控制器的访问方法即可。

regmap数据结构定义

如下即为regmp的定义,针对regmap的定义包含如下几个方面:

  1. 该regmap对应的设备(即struct device *dev);
  2. 该regmap对应的缓存;
  3. 该regmap所绑定的regmap_bus(若该regmap不依附于regmap_bus,则需要单独提供读写接口);
  4. 该regmap相关的异步写链表以及异步写相关的等待队列;
  5. 该regmap相关的cache操作接口、是否支持cache操作等;
  6. 该regmap相关的寄存器读写权限(提供寄存器是否可写接口、是否可读接口、是否为volatile等),并提供可写寄存器table、可读寄存器table、volatile_table等等,regmap子系统实现了寄存器的访问权限控制,这个设计还是很好的。
  7. 该regmap是否支持按页访问操作(针对某类设备而言,如phy寄存器,协议上规则只支持32个寄存器,但有些phy设备提供的功能比较复杂,对外提供的寄存器个数超过了32个,那它就提供按页访问操作,比如定义向寄存器27写入值进行页的选择,这样的话支持的寄存器就好超过32个(如marvell的88exxxx系统的芯片,基本上都是支持按页访问的)),若该设备支持按页访问,则需要设定page 访问的范围、page 选择寄存器号及其偏移等等,并会将对应的信息存放在红黑树range_tree中。
  8. 针对有些设备而言,其寄存器的位数、寄存器值的位数可能有所不同(有的设备寄存器为8位、寄存器值也是8位;有的设备寄存器为16位、寄存器值也是16位等等),而且存在字节序的问题,因此提供struct regmap_format类型的变量,实现寄存器、寄存器值位数设定、寄存器及其值的格式化操作接口等。

regmap基本上就以上这些功能,围绕这regmap又定义了regmap_format、regmap_access_table等数据结构。

regmap_format数据结构

该数据结构主要实现寄存器及其值的位数、格式化操作等接口。针对寄存器值不是8bit整数倍的情形,则需要实现format_write接口(如reg占用4个bit、value占用12bit情况);而针对寄存器值是8bit整数倍的情况,则只需要实现format_reg、format_val、parse_val、parse_inplace接口接口。

regmap_access_table数据结构

该数据结构主要用于描述regmap的寄存器读写权限控制的,该数据结构内部包含struct regmap_ranage类型的变量。

  1. 支持访问的寄存器的范围;
  2. 不支持访问的寄存器的范围等。


regmap_config数据结构定义

该数据结构主要在创建一个regmap时,实现对regmap的初始化,主要信息如下:

  1. 寄存器的位数、寄存器值的位数;
  2. 寄存器读写权限判断的回调函数、读写范围的定义;
  3. 加锁、解锁函数;
  4. 读写flag;
  5. 字节序相关的配置;
  6. 是否支持page读写方式,若需要定义regmap_range_cfg类型的变量,说明page select reg、page reg范围等内容

以上即为regmap相关数据结构的定义。只要我们熟悉了regmap的定义以及regmap、regmap_bus的关联,基本上也就熟悉了regmap的实现流程了。regmap子系统的设计相对来说也不算复杂(比如并没有提供remap_bus的注册接口,也不需要关注系统中已经定义了多少个regmap_bus以及系统中已经创建了多少个regmap等等),相比于设备驱动模型、pinctrl子系统、input子系统而言,算是较简单的子系统设计,但是却解决了很大的问题。这个和设备驱动模型中的设备资源管理类似,设备资源管理的设计也不复杂,但是却解决了设备资源释放问题,其借助于设备驱动模型中提供的引用计数,可自动实现设备相关缓存资源的释放,不需要设备驱动程序在remove接口中手动实现资源的释放。我们现在分析的regmap子系统也提供了基于设备资源管理的接口(devm_regmap_init_i2c、devm_regmap_init_spi、devm_regmap_init等)。

相关推荐