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
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;--------能写的寄存器范围
。。。。。。
};
我们要创建自己的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;-----寄存器值大小端
};
调用devm接口方便驱动卸载的时候释放资源
init的过程如下:
使用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)
regmap-mmio是用来映射soc上的模块寄存器,方便驱动操作模块而设计的
可以调用函数:
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