【Linux驱动编程】regmap框架模型应用详解

2023-10-29 19:50

本文主要是介绍【Linux驱动编程】regmap框架模型应用详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1 前言
  • 2 什么是regmap
    • 2.1 为什么要用regmap
    • 2.2 regmap 框架模型
  • 3 怎样使用regmap
    • 3.1 配置信息
    • 3.2 注册接口
    • 3.3 抽象访问接口
    • 3.4 释放接口
  • 4 实例


1 前言

  Linux驱动开发中,对于一些外设型器件驱动,如ADC、DAC、EEPROM、Sensor,这里器件通常是以uart、i2c、spi、mipi为控制接口,通过配置器件寄存器来设置芯片工作模式、运行参数、校准值等等,并通过获取寄存器值来获得有效数据。


  普通的做法,我们是根据不同的控制总线接口来实现寄存器访问,这样的方式是需要根据总线类型来调整访问接口、数据结构,这样显得繁琐。比如,目前有个ADC器件,支持spi和i2c接口;在此之前采用的是spi接口;后面因cpu spi接口不够用,线需要改为i2c控制。这样,该ADC驱动程序得修改,从spi改为i2c驱动,虽然工作量不大,但是也得花费一定时间。那么大体工作量有:

  • spi_write/spi_rea接口修改为 i2c_transfer
  • spi片选(cs)修改为i2c从地址寻址
  • 数据结构修改, struct spi_message修改为struct rt_i2c_msg

  基于代码代码复用的原则之一,Linux在3.1内核后引入了regmap模型,将寄存器访问的共同逻辑抽象出来,只需初始化时指定总线类型、寄存器位宽等关键参数,即可通过regmap模型接口来操作器件寄存器。当然,regmap同样适用于操作cpu自身的寄存器。


2 什么是regmap

  regmap是在 linux 内核为减少慢速 I/O 驱动上的重复逻辑,提供一种通用的接口来操作底层硬件寄存器的模型框架。此外,regmap在驱动和硬件寄存器之间增加了cache,减少底层低速 I/O 的操作次数,提高访问效率;当然实时性会有所降低。


2.1 为什么要用regmap

  regmap的特性和优点决定了我们为什么要用regmap。

  • 统一寄存器操作接口
  • 提高代码重用性和驱动一致性
  • 减少底层I/O操作次数,提高访问效率
  • 简化驱动开发过程

2.2 regmap 框架模型

  regmap整体上分为三层,从下到上分别为物理总线、regmap核心、regmap api。

在这里插入图片描述

regmap框架模型


  • 底层,对接的是具体物理总线,目前regmap框架支持i2c、spi、mmio、spmi、ac97总线
  • 核心层,regmap 核心实现
  • api,抽象通用接口

  对于使用regmap框架来说,可以不用关心regmap核心的实现过程,只需根据物理总线类型,配置好相关参数信息,即可调用regmap api访问芯片寄存器。


3 怎样使用regmap

  使用regmap比较简单,使用前,只需根据外设属性配置总线类型、寄存器位宽、缓存类型、读写属性等参数;接着注册一个regmap实例;然后调用抽象访问接口访问寄存器。

  • 第一步,配置regmap信息
  • 第二步,注册regmap实例
  • 第三步,访问寄存器
  • 第四步,释放regmap实例

3.1 配置信息

  配置信息,首先需了解配置信息数据结构,linux内核以 struct regmap_config描述该数据结构,位于kernel/include/linux/regmap.h中声明。我们将关键而且驱动工程师常配置的参数用中文注释出来。

struct regmap_config {const char *name;int reg_bits;	/* 寄存器地址位宽,常见有8位、16位,必须设置 */int reg_stride; /* 寄存器地址对齐位宽 */int pad_bits;	/* 寄存器填充位宽 */int val_bits;	/* 寄存器值位宽,常见有8位、16位,必须设置 */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;	/* cache数据类型,支持三种:flat、rbtree、Izo */const void *reg_defaults_raw;unsigned int num_reg_defaults_raw;u8 read_flag_mask;	/* 读寄存器掩码 */u8 write_flag_mask; /* 写寄存器掩码 */bool use_single_rw;bool can_multi_write;enum regmap_endian reg_format_endian;	/* 寄存器地址大小端,大于8位时需设置 */enum regmap_endian val_format_endian;	/* 寄存器值大小端,大于8位时需设置 */const struct regmap_range_cfg *ranges;unsigned int num_ranges;
};

  目前linux内核支持三种cache数据类型,三种类型位于kernel/include/linux/regmap.h中定义:

  • flat,普通数据类型

  • rbtree,红黑树类型

  • lzo,压缩类型

/* An enum of all the supported cache types */
enum regcache_type {REGCACHE_NONE,REGCACHE_RBTREE,REGCACHE_COMPRESSED,REGCACHE_FLAT,
};

3.2 注册接口

  regmap为每一种物理接口提供了一个注册函数。

regmap_init_i2c(struct i2c_client *i2c, struct regmap_config *config);   
regmap_init_spi(struct spi_device *spi, strcut regmap_config *config);
regmap_init_mmio(struct device *dev, struct regmap_config *config);   
regmap_init_spmi_base(struct spmi_device *dev, strcut regmap_config *config);
regmap_init_spmi_ext(struct spmi_device *dev, strcut regmap_config *config);
regmap_init_ac97(struct snd_ac97 *ac97, strcut regmap_config *config);

注:
注册函数声明位于kernel/include/linux/regmap.h中,原型中linux内核通过宏定义实现,展开后即是上面函数声明。


3.3 抽象访问接口

  配置和注册regmap实例后,我们就可以使用抽象接口来访问寄存器,摈弃之前那套繁琐的数据结构和函数api。接口比较通俗,根据函数名称和入口参数即可知道函数功能。接口分为两大类,设置类(与初始化配置信息不同)和访问类,访问类根据访问过程又分为两种:

  • 经过regmap cache,提高访问效率,对于写操作,待cache存在一定数据量或者超出时间后写入物理寄存器;但降低实时性

  • 不经过regmap cache,对于写操作,立即写入物理寄存器,实时性好;对于读操作,则经过cache,减少拷贝时间


常用访问类api:

int regmap_write(struct regmap *map, int reg, int val); /* 写单个寄存器 */ 
int regmap_raw_write(struct regmap *map, int reg, void *val, size_t val_len); /* 单个寄存器写指定长度数据 */
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,size_t val_count); /* 写多个寄存器 */
int regmap_multi_reg_write_bypassed(struct regmap *map, const struct reg_sequence *regs,int num_regs);/* 直接写入寄存器,不经过regmap cache */
int regmap_raw_write_async(struct regmap *map, unsigned int reg,const void *val, size_t val_len);/* 写多个寄存器,并立即刷新cache写入 */
int regmap_read(struct regmap *map, int reg, int *val); /* 读单个寄存器 */
int regmap_raw_read(struct regmap *map, int reg, void *val, size_t val_len); /* 单个寄存器读指定长度数据 */  
int regmap_bulk_read(struct regmap *map, int reg, void *val, size_t val_count); /* 读多个寄存器 */
int regmap_update_bits(struct regmap *map, int reg, int mask, int val); 	/* 更新寄存器值指定bit */
int regmap_write_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val);/* 写入寄存器值指定bit */

  更多的操作api参考regmap.h中的声明。


3.4 释放接口

  在驱动注销函数里应调用regmap_exit释放已注册的regmap实例。

void regmap_exit(struct regmap *map);

4 实例

  以i2c为例,以伪代码访问寄存器比较传统方式和通过regmap访问方式。


  • 传统方式
static int read_regs(struct i2c_client *client, uint8_t reg, uint8_t *pdata, int size)
{int ret = 0;struct i2c_msg msg[2];if(size == 0){return 0;}msg[0].addr  = client->addr;  	 msg[0].buf   = ®               msg[0].len   = 1;                     msg[0].flags = 0; msg[1].addr  = client->addr;  	 msg[1].buf   = pdata;               msg[1].len   = size;                     msg[1].flags = I2C_M_RD; if(i2c_transfer(client->adapter, msg, 2) != 2){ret =-1;}return ret;
}

  • regmap方式
/* 第一步配置信息 */
static const struct regmap_config regmap_config = 
{     .reg_bits = 8,     .val_bits = 8,       .max_register = 255,     .cache_type = REGCACHE_RBTREE,     .volatile_reg = false,
};   /* 第二步,注册regmap实例 */
regmap = regmap_init_i2c(i2c_client, &regmap_config);  /* 第三步,访问操作 */
static int read_regs(uint8_t reg, uint8_t *pdata, int size)
{return regmap_raw_read(regmap, reg, pdata, size);
}

  通过比较两者,很显然,regmap方式将i2c的数据结构、传输api隐藏,使用者无需关心i2c内部实现,简化驱动开发过程,提高代码的复用性。如果将该器件物理接口更换为spi,只需修改配置信息即可,寄存器访问过程无需更改。

这篇关于【Linux驱动编程】regmap框架模型应用详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/302968

相关文章

一文详解如何在Python中从字符串中提取部分内容

《一文详解如何在Python中从字符串中提取部分内容》:本文主要介绍如何在Python中从字符串中提取部分内容的相关资料,包括使用正则表达式、Pyparsing库、AST(抽象语法树)、字符串操作... 目录前言解决方案方法一:使用正则表达式方法二:使用 Pyparsing方法三:使用 AST方法四:使用字

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

SQL表间关联查询实例详解

《SQL表间关联查询实例详解》本文主要讲解SQL语句中常用的表间关联查询方式,包括:左连接(leftjoin)、右连接(rightjoin)、全连接(fulljoin)、内连接(innerjoin)、... 目录简介样例准备左外连接右外连接全外连接内连接交叉连接自然连接简介本文主要讲解SQL语句中常用的表

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

SpringShell命令行之交互式Shell应用开发方式

《SpringShell命令行之交互式Shell应用开发方式》本文将深入探讨SpringShell的核心特性、实现方式及应用场景,帮助开发者掌握这一强大工具,具有很好的参考价值,希望对大家有所帮助,如... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F