[Linux 基础] -- 内核探究:regmap 机制

前言:

regmap 机制是在 Linux 3.1 加入的新特性。主要目的是减少 I/O 驱动上的重复逻辑代码,提供一种通用的接口来操作底层硬件上的寄存器。

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

一、重要结构体

内核版本:5.11。

1.1、regmap_config

struct regmap_config {
  const char *name; //regmap名字,当一个设备有多个寄存器区域时使用

  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);
  bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
  bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);

  bool disable_locking;
  regmap_lock lock;
  regmap_unlock unlock;
  void *lock_arg;
  //读写寄存器回调函数,大部分设备不使用
  int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
  int (*reg_write)(void *context, unsigned int reg, unsigned int val);

  bool fast_io;

  unsigned int max_register; //最大寄存器地址
  const struct regmap_access_table *wr_table;
  const struct regmap_access_table *rd_table;
  const struct regmap_access_table *volatile_table;
  const struct regmap_access_table *precious_table;
  const struct regmap_access_table *wr_noinc_table;
  const struct regmap_access_table *rd_noinc_table;
  const struct reg_default *reg_defaults; //复位后默认值
  unsigned int num_reg_defaults; //有默认值的寄存器数
  enum regcache_type cache_type;
  const void *reg_defaults_raw;
  unsigned int num_reg_defaults_raw;

  unsigned long read_flag_mask;
  unsigned long write_flag_mask;
  bool zero_flag_mask;

  bool use_single_read;
  bool use_single_write;
  bool use_relaxed_mmio;
  bool can_multi_write;
  //寄存器和值的大小端
  enum regmap_endian reg_format_endian;
  enum regmap_endian val_format_endian;

  const struct regmap_range_cfg *ranges; //虚拟地址范围
  unsigned int num_ranges;

  bool use_hwlock;
  unsigned int hwlock_id;
  unsigned int hwlock_mode;

  bool can_sleep; //是否可以休眠
};

struct regmap_config 结构体代表一个设备的寄存器配置信息,初始化时需要配置。

二、API 函数

//1. 初始化接口
//i2c
#define devm_regmap_init_i2c(i2c, config)        \
  __regmap_lockdep_wrapper(__devm_regmap_init_i2c, #config,  \
        i2c, config)
//spi       
#define devm_regmap_init_spi(dev, config)        \
  __regmap_lockdep_wrapper(__devm_regmap_init_spi, #config,  \
        dev, config)
        
//2.读写接口
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);

//3. 释放
void regmap_exit(struct regmap *map);

上面只是列举了 I2C 和 SPI,regmap 还有 AC97、MMIO 和 SPMI 等其他总线的接口。

三、传统方式和 regmap

我们举个例子来看看传统方式和 regmap 的区别。以 I2C 为例:

传统方式:


static int xxx_i2c_read_reg(struct i2c_client *client, u8 reg, u8 *val)
{
    struct i2c_msg msg[] = {
        {
            .addr = client->addr,
            .flags = 0,
            .len = 1,
            .buf = &reg,
        },
        {
            .addr = client->addr,
            .flags = I2C_M_RD,
            .len = 1,
            .buf = val,
        },
    };
 
    return i2c_transfer(client->adapter, msg, 2);  
}

regmap 方式:


// 1. 定义regmap_config
static const struct regmap_config xxx_regmap_config = {
    .reg_bits = 8,
    .val_bits = 8,
};
 
// 2.初始化
regmap = devm_regmap_init_i2c(i2c_client, &xxx_regmap_config);
// 3.寄存器操作
regmap_read(regmap, XXX_REG, &value);

首先定义芯片的寄存器信息,位宽,地址位宽,寄存器总线等。初始化 regmap,不同总线调用对应的初始化函数。初始化完成之后就可以正常调用  regmap 的 API 进行读写了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值