linux设备驱动模型 - regmap

1. regmap介绍

regmap主要是为了方便操作寄存器而设计的,它将所有模块的寄存器(包括soc上模块的寄存器和外围设备的寄存器等)
抽象出来,用一套统一接口来操作寄存器

比如,如果要操作i2c设备的寄存器,那么就要调用i2c_transfer接口,要操作spi设备的寄存器,就要调用spi_write/spi_read等接口,
如果把它们都抽象为regmap结构,那么只要调用regmap_read/regmap_write就可以了

regmap的代码在目录:drivers/base/regmap

目前regmap抽象的设备主要分两种类型,一种是cache类型的,这种设备就是把寄存器值写入到内存中,
另一种是实际的硬件设备,寄存器的值要写入实际的模块中

在内核版本4.14上,cache的类型有3中:
- flat:普通数组类型
- rb-tree:红黑树类型
- lzo:压缩类型

 enum regcache_type {
    REGCACHE_NONE,
    REGCACHE_RBTREE,
    REGCACHE_COMPRESSED,
    REGCACHE_FLAT,
 };

实际的硬件设备实现regmap的有:I2C/SPI/spmi/mmio等,后面会举例介绍一下mmio

2. regmap设计框架

regmap的整个框架如下:

这里写图片描述

2.1 regmap结构体

简单介绍下regmap结构体

struct regmap {
    。。。。。。
    struct device *dev; /* Device we do I/O on */
    void *work_buf;     /* Scratch buffer used to format I/O */
    struct regmap_format format;  /* Buffer format */
    const struct regmap_bus *bus;-------------regmap设备总线
    void *bus_context;------------------------总线私有数据
    const char *name;

    unsigned int max_register;
    /×判断是否可读写的函数×/
    bool (*writeable_reg)(struct device *dev, unsigned int reg);
    bool (*readable_reg)(struct device *dev, unsigned int reg);
    bool (*volatile_reg)(struct device *dev, unsigned int reg);
    bool (*precious_reg)(struct device *dev, unsigned int reg);
    /×读写寄存器函数×/
    int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
    int (*reg_write)(void *context, unsigned int reg, unsigned int val);
    int (*reg_update_bits)(void *context, unsigned int reg,
                   unsigned int mask, unsigned int val);
    /×读写掩码×/
    unsigned long read_flag_mask;
    unsigned long write_flag_mask;

    /* number of bits to (left) shift the reg value when formatting*/
    int reg_shift;------------寄存器偏移
    int reg_stride;-----------寄存器对齐位
    int reg_stride_order;

    /×regcache相关的函数×/
    /* regcache specific members */
    const struct regcache_ops *cache_ops;
    enum regcache_type cache_type;

    /* number of bytes in reg_defaults_raw */
    unsigned int cache_size_raw;
    /* number of bytes per word in reg_defaults_raw */
    unsigned int cache_word_size;
    /* number of entries in reg_defaults */
    unsigned int num_reg_defaults;
    /* number of entries in reg_defaults_raw */
    unsigned int num_reg_defaults_raw;

    /* if set, only the cache is modified not the HW */
    bool cache_only;
    /* if set, only the HW is modified not the cache */
    bool cache_bypass;
    /* if set, remember to free reg_defaults_raw */
    bool cache_free;

    /×多寄存器读写相关字段×/
    /* if set, converts bulk read to single read */
    bool use_single_read;
    /* if set, converts bulk read to single read */
    bool use_single_write;
    /* if set, the device supports multi write mode */
    bool can_multi_write;

    /* if set, raw reads/writes are limited to this size */
    size_t max_raw_read;---------能读的寄存器范围
    size_t max_raw_write;--------能写的寄存器范围
。。。。。。
};

2.2 regmap_config结构体

我们要创建自己的regmap的时候,一般会先初始化regmap_config结构体,然后进行regmap的创建

struct regmap_config {
    int reg_bits;-------------------寄存器地址位数
    int reg_stride;-----------------寄存器地址对齐
    int pad_bits;-------------------填充位数
    int val_bits;-------------------寄存器值位数

    bool (*writeable_reg)(struct device *dev, unsigned int reg);---判断寄存器是否可写
    bool (*readable_reg)(struct device *dev, unsigned int reg);----判断寄存器是否可读
    bool (*volatile_reg)(struct device *dev, unsigned int reg);
    bool (*precious_reg)(struct device *dev, unsigned int reg);

    int (*reg_read)(void *context, unsigned int reg, unsigned int *val);---寄存器读函数
    int (*reg_write)(void *context, unsigned int reg, unsigned int val);---寄存器写函数

    unsigned int max_register;------------最大寄存器地址

    enum regcache_type cache_type;--------regmap类型

    unsigned long read_flag_mask;---------读掩码
    unsigned long write_flag_mask;--------写掩码

    enum regmap_endian reg_format_endian;-----寄存器地址大小端
    enum regmap_endian val_format_endian;-----寄存器值大小端
};

2.3 regmap创建

2.3.1 __devm_regmap_init

调用devm接口方便驱动卸载的时候释放资源

2.3.2 __regmap_init

init的过程如下:

  1. config的lock配置给regmap
  2. config的reg-bit/val-bit等配置给regmap
  3. 把regmap_bus给regmap
  4. 把config的读写判断函数(writeable_reg/readable_reg)等相关配置给regmap
  5. 如果regmap_bus不为空,那么把regmap_bus的读写函数给regmap,否则把config的配置给regmap
  6. 给regmap提供数据格式化format的相关函数

2.4 常用寄存器操作接口

使用regmap读写寄存器的接口有:

static inline int regmap_write(struct regmap *map, unsigned int reg,
               unsigned int val)
static inline int regmap_read(struct regmap *map, unsigned int reg,
              unsigned int *val)
static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
               void *val, size_t val_count)
static inline int regmap_update_bits_base(struct regmap *map, unsigned int reg,
                  unsigned int mask, unsigned int val,
                  bool *change, bool async, bool force)

3. regmap用例(regmap-mmio)

regmap-mmio是用来映射soc上的模块寄存器,方便驱动操作模块而设计的

3.1 regmap-mmio的创建

可以调用函数:

struct regmap *__regmap_init_mmio_clk(...)

struct regmap *__devm_regmap_init_mmio_clk(...)

创建过程:
1. 先初始化regmap-mmio的私有结构体:regmap_mmio_context
主要是分配读写函数和clock
2. 然后进行regmap的初始化,使用regmap_bus总线为regmap_mmio

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux设备驱动程序的调试技术是指在开发和调试Linux设备驱动程序时使用的技术和工具。调试技术对于解决设备驱动程序中的错误和问题非常重要,可以有效地提高驱动程序的稳定性和性能。 首先,调试驱动程序时通常使用的技术是打印调试信息。通过在驱动程序中插入打印语句,可以在运行时输出相关的调试信息,如变量的值、函数的调用等。这可以帮助开发者追踪程序的执行流程,查找和定位错误。 另外,使用断点调试也是一种常用的技术。开发者可以通过使用调试器来设置断点,使程序在指定位置停下来,以便进一步调试。这个过程可以在实际硬件上进行,也可以在模拟器或虚拟机中进行。 为了更方便地调试驱动程序,还可以使用一些特定的调试工具。例如,通过使用内核调试器kgdb,开发者可以在驱动程序崩溃时连接到目标系统,并查看相关的内核信息,从而帮助定位问题。另外还有一些跟踪工具,如strace和sysprof,可以用于跟踪系统调用和函数调用,以及分析程序的运行性能。 此外,对于一些特殊的嵌入式系统,可能还需要使用硬件调试工具来进行调试。例如,使用JTAG接口连接到目标板上,可以通过调试器软件实时监视和控制系统状态,读取和修改寄存器的值,以进一步分析和定位问题。 总之,Linux设备驱动程序的调试技术非常重要,可以通过打印调试信息、断点调试、调试工具和硬件调试工具等方式来帮助开发者定位和解决问题,提高驱动程序的质量和性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值