2020-12-16 14:35:44 +08:00
|
|
|
|
# RegMap 机制
|
|
|
|
|
|
|
|
|
|
## 1.概要
|
|
|
|
|
|
|
|
|
|
regmap 机制是在 Linux 3.1 加入进来的特性。主要目的是减少慢速 I/O 驱动上的重复逻辑,提供一种通用的接口来操作底层硬件上的寄存器。其实这就是内核做的一次重构。regmap 除了能做到统一的 I/O 接口,还可以在驱动和硬件 IC 之间做一层缓存,从而能减少底层 I/O 的操作次数。
|
|
|
|
|
|
|
|
|
|
为了让慢速 I/O 能够专注于自身的逻辑,内核把 SPI, I2C 等总线操作方式全部封装在 regmap 里,这样驱动若要做 I/O 操作,直接调用 regmap 的函数就可以了。
|
|
|
|
|
|
|
|
|
|
使用 regmap 机制进行总线访问的基本流程如下:
|
|
|
|
|
|
|
|
|
|
1. 配置 regmap_config 结构体;
|
|
|
|
|
2. 调用 regmap_init 类方法进行初始化;
|
2020-12-16 14:53:07 +08:00
|
|
|
|
3. 调用 regmap_write/regmap_read/regmap_update_bits 方法进行读写;
|
2020-12-16 14:35:44 +08:00
|
|
|
|
4. 退出时调用 regmap_exit 释放资源。
|
|
|
|
|
|
|
|
|
|
regmap 机制的主要 API 声明在 <linux/regmap.h> 文件中。
|
|
|
|
|
|
|
|
|
|
## 2.struct regmap_config
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
struct regmap_config {
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
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 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 use_single_rw;
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 2.I2C
|
|
|
|
|
|
|
|
|
|
主要调用 devm_regmap_init_i2c() 方法来对 remap 进行初始化。
|
|
|
|
|
|
|
|
|
|
**函数原型:**
|
|
|
|
|
|
|
|
|
|
函数原型如下:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
#include <linux/regmap.h>
|
|
|
|
|
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, const struct regmap_config *config);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**返回值:**
|
|
|
|
|
|
|
|
|
|
成功返回有效的 struct regmap 指针,失败返回 NULL。可以用 IS_ERR() 来判断结果。
|
|
|
|
|
|
|
|
|
|
## 3.SPI
|
|
|
|
|
|
2020-12-16 14:53:07 +08:00
|
|
|
|
SPI 设备驱动使用 regmap 方式进行设备读写时,SPI 的工作模式仍是通过设置 spi_device 来实现,例如:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
static const struct regmap_config demo_regmap = {
|
|
|
|
|
.reg_bits = 8,
|
|
|
|
|
.val_bits = 8,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int demo_spi_probe(struct spi_device *spi)
|
|
|
|
|
{
|
|
|
|
|
spi->bits_per_word = 8;
|
|
|
|
|
spi->mode = SPI_MODE_0;
|
|
|
|
|
spi->max_speed_hz = 1000000;
|
|
|
|
|
devm_regmap_init_spi(spi, &demo_regmap);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 14:35:44 +08:00
|
|
|
|
主要调用 devm_regmap_init_spi() 方法来对 remap 进行初始化。
|
|
|
|
|
|
|
|
|
|
**函数原型:**
|
|
|
|
|
|
|
|
|
|
函数原型如下:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
#include <linux/regmap.h>
|
|
|
|
|
struct regmap *devm_regmap_init_spi(struct spi_device *spi, const struct regmap_config *config);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**返回值:**
|
|
|
|
|
|
|
|
|
|
成功返回有效的 struct regmap 指针,失败返回 NULL。可以用 IS_ERR() 来判断结果。
|