说完了原理
来看看regmap在安卓手机上到底用在哪些地方。下面四个案例覆盖了手机上最常见的regmap使用场景:
▲ 图5:安卓手机上的regmap实际驱动案例 — 音频、电源、触控、传感器全覆盖
案例1:音频Codec(最经典)
以高通骁龙平台上的 WCD9335/WCD9340 音频Codec为例,这类芯片有50到100多个寄存器,寄存器地址稀疏分布。驱动中大量使用 regmap_update_bits() 来调整音量、切换通道、配置时钟——每次操作只改某几个bit。如果不用regmap,每次都要手动实现"读-改-写"三步走,代码会极其繁琐且容易出竞态bug。
案例2:PMIC电源管理
瑞芯微的 RK808/RK817 PMIC驱动是一个典型的regmap高级用户。PMIC有个特殊需求:系统休眠时PMIC部分电源域会掉电,但CPU侧的驱动还需要继续配置寄存器。regmap的 cache_only 模式完美解决了这个问题——休眠前设置cache_only=true,所有写操作只进缓存;唤醒后调用 regcache_sync() 将缓存批量刷回硬件。
案例3:传感器(I2C/SPI双模)
ICM20608(InvenSense 6轴IMU)是展示regmap可移植性的最佳案例。这颗芯片同时支持I2C和SPI两种接口。在regmap框架下,驱动代码几乎不需要修改——只需把 regmap_init_i2c() 换成 regmap_init_spi(),所有 regmap_read/write 调用保持不变。这在手机主板方案切换时价值巨大。
◆ ◆ ◆
七、为什么有的驱动不用regmap?
既然regmap这么好,为什么还有驱动直接用 i2c_transfer()?原因主要有这几类:
▲ 图6:直接I2C调用 vs regmap — 如何选择一目了然
图6清晰地展示了两种方式各自的适用场景。作为经验法则:
对于I2C/SPI外设驱动,默认使用regmap;只在流式数据传输和极简设备上考虑直接调用。
有一个重要的性能考量:对于I2C/SPI这类慢速总线,regmap的额外开销(锁50-100ns + 缓存查找10-30节点 + 格式化)占整个传输时间的不到0.5%,几乎可以忽略。但对于MMIO场景(readl()只需~10ns),regmap的锁+缓存开销占比超过90%,不推荐使用。
◆ ◆ ◆
八、regmap_config:驱动工程师的"配置文件"
每个使用regmap的驱动都需要定义一个 regmap_config 结构体,它告诉regmap这个设备的寄存器长什么样。下面是一个真实案例:

其中最关键的三个字段:

九、总结:一张表记住regmap
regmap是什么?内核寄存器映射抽象层,统一I2C/SPI/MMIO等总线的寄存器访问
核心APIregmap_read / regmap_write / regmap_update_bits / regmap_bulk_read
最大收益缓存减少总线访问 + 原子RMW操作 + debugfs调试 + 总线无关可移植性
最大陷阱volatile_reg遗漏导致缓存脏读;reg_bits/val_bits配置错误导致数据错位
使用建议I2C/SPI外设:默认用regmap;MMIO外设:不用;流式数据:绕过regmap
安卓案例WCD9340音频Codec / RK808 PMIC / ICM20608 IMU / GT9xx触控
🎯 一句话记住regmap
驱动只关心"哪个寄存器的哪几个bit改成什么值",不关心"这个寄存器是挂在I2C上还是SPI上"——这就是regmap存在的全部意义。
◆ ◆ ◆
十、附录:regmap源码文件速查表
| include/linux/regmap.h | |
| drivers/base/regmap/regmap.c | |
| drivers/base/regmap/internal.h | |
| drivers/base/regmap/regmap-i2c.c | |
| drivers/base/regmap/regmap-spi.c | |
| drivers/base/regmap/regcache.c | |
| drivers/base/regmap/regcache-rbtree.c | |
| drivers/base/regmap/regcache-flat.c | |
| drivers/base/regmap/regmap-debugfs.c | |
| drivers/base/regmap/regmap-irq.c | |
| drivers/base/regmap/regmap-sdw.c | |
| drivers/base/regmap/regmap-spmi.c |
夜雨聆风