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的整个框架如下:

linux设备驱动模型 - regmap_第1张图片

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

你可能感兴趣的:(Linux驱动)