Regmap子系统:(寄存器映射)
文章目录
- Regmap简述
- Remap配置流程:
- Remap示例(I2C操作OLED):
Regmap简述
- Regmap野心很大,希望加入所有总线接口,目前已支持I2C、SPI、MMIO、SPMI等。
- 当然Regmap框架不仅提供了一种统一接口,而且支持缓存(减少内存的开销)。
Remap配置流程:
- 1配置regmap_config结构体
- 2 Regmap初始化
- 3调用Remap API函数进行读写操作
- 4释放Regmap
经过上面的步骤,我们就可以使用Regmap。
**1配置结构体:(一般在驱动程序中声明)
static struct regmap *xxx_regmap;
struct regmap_config{
const char *name;
int reg_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);//回调函数,涉及缓存中读写寄存器会触发
unsigned int max_register;//最大寄存器地址,防止越界
const struct regmap_access_table* wr_table;//no support
};
**2结构体初始化:(一般在probe函数中)
由于Regmap仅仅只是一个统一的接口,其底层调用最终还是走的各个子系统协议。
例如要使用I2C子系统,那么我们需要将Regmap映射到I2C接口上(regmap_init_i2c函数),
这样操作regmap的时候实际上就是在操作i2c接口
struct regmap * regmap_init_i2c(struct i2c_client *i2c, //I2C客户端结构体
const struct *regmap_config)//regmap配置结构体
struct regmap * regmap_init_spi(struct spi_device *spi,//spi设备结构体
const struct *regmap_config);//regmap配置结构体
**3 Regmap读写操作(在桥梁函数里,即实际的设备操作)
最终目的是操作各个设备进行通信,linux内核提供了响应的接口函数供驱动开发者使用。
//单个寄存器写一个值
static inline int regmap_write(struct regmap *map, unsigned int reg,unsigned int val)
//向单个寄存器写入多个数据
static inline int regmap_raw_write( struct regmap *map,unsigned int reg,//寄存器地址 const void *val, size_t val_len)//写入数据的地址//写入数据的长度
//向多个连续的寄存器中写入多个值
static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_count)
//同样还有读操作,以及其它操作
regmap_read、regmap_raw_read、regmap_bulk_read
**4 释放Regmap结构体
void regmap_exit(struct regmap *map)
Remap示例(I2C操作OLED):
- 0 添加设备树节点:(其中使用OLED内部显示控制器为SSD1306驱动)
- 1 驱动绑定与解绑(sysfs、regmap、platform)
static struct regmap *oled_regmap;
static uint8_t diaplay_buffer[128][8];
static int oled_write_cmd(uint8_t cmd){
ret = regmap_write(oled_regmap,0x00,cmd); //DC=0 command
}
static int oled_write_data(uint8_t data){
ret = regmap_write(oled_regmap,0x40,data); //DC=1 command
}
static void oled_on(void) {
oled_write_cmd(0x8D); oled_write_cmd(0x14); oled_write_cmd(0xAF);
}
static void oled_off(void) {
oled_write_cmd(0x8D); oled_write_cmd(0x10); oled_write_cmd(0xAE);
}
//xxxxxxxxxx省略代码xxxxxxxxxregmap提供读写寄存器函数xxxxxxxxxx
static const struct regmap_config oled_config = {//regmap配置结构体
.reg_bits = 8, //寄存器 8 位
.val_bits = 8, //数据 8 位
.max_register = 255, //最大寄存器 255 个
.cache_type = REGCACHE_NONE, //不使用 cache
.volatile_reg = false,
};
static ssize_t oled_show(struct device *dev,struct device_attribute *attr,char *buf) {
oled_off();return 1;
}
static ssize_t oled_store(struct device *dev,struct device_attribute *attr,const char*buf, size_t count){
oled_fill_screen(*buf);return count;
}
static DEVICE_ATTR(oled, 0660, oled_show, oled_store); //定义文件属性
static int oled_probe(struct i2c_client *client, const struct i2c_device_id *id) {
ret = device_create_file(&client->dev,&dev_attr_oled);//创建属性文件
oled_regmap = regmap_init_i2c(client,&oled_config);
}
static int oled_remove(struct i2c_client *client){
device_remove_file(&client->dev,&dev_attr_oled);//删除属性文件
regmap_exit(oled_regmap);
}
static const struct i2c_device_id oled_id[] = {
{ "test,oled", 0 },
}
static const struct of_device_id oled_of_match[] = {
{ .compatible = "test,oled"},
};
MODULE_DEVICE_TABLE(of, oled_of_match);
static struct i2c_driver oled_driver = {
.driver = {
.name = "test,oled",
.owner = THIS_MODULE,
.of_match_table = oled_of_match,
},
.probe = oled_probe,
.remove = oled_remove,
.id_table = oled_id,
};
module_i2c_driver(oled_driver);
bb那么多的模型框架以及接口目的就是简化我们驱动开发,提高代码规范,到底还是内核抗下了所有