乐于分享
好东西不私藏

安卓手机上的regmap实际案例

安卓手机上的regmap实际案例

说完了原理

Linux内核regmap子系统

来看看regmap在安卓手机上到底用在哪些地方。下面四个案例覆盖了手机上最常见的regmap使用场景:

安卓手机上使用 regmap 的实际驱动案例🎵 音频 Codec(最常见)芯片:WCD9335/9340, WM8960, ES8316接口:I2C / SoundWire / Slimbus驱动路径:sound/soc/codecs/56+个寄存器 · RBTREE缓存 · 大量update_bits高通骁龙⚡ 电源管理 PMIC芯片:RK808/RK817, WM8994, 88PM800接口:I2C驱动路径:drivers/mfd/cache_only模式 · 休眠唤醒regcache_sync瑞芯微方案👆 触控芯片芯片:Goodix GT9xx, Focaltech FT5x06接口:I2C驱动路径:drivers/input/touchscreen/中断处理中regmap_read · volatile寄存器多汇顶/敦泰🧭 传感器芯片:ICM20608(IMU), BMP280(气压)接口:I2C / SPI 双模驱动路径:drivers/iio/I2C+SPI共用一套regmap驱动代码InvenSense📊 一句话总结手机上几乎所有 I2C/SPI 外设驱动都在使用 regmapregmap 不是"可选项",而是现代 Linux 外设驱动的标配/* 安卓手机音频Codec驱动 — 典型regmap用法 (sound/soc/codecs/es8316.c) */es8316->regmap =devm_regmap_init_i2c(i2c_client, &es8316_regmap);// 读芯片IDregmap_read(es8316->regmap, ES8316_RESET_ID, &val);// 修改指定位(读-改-写,原子操作)regmap_update_bits(es8316->regmap, ES8316_CLK_CTL, 0x07, 0x03);

▲ 图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()?原因主要有这几类:

直接 I2C 调用 vs regmap — 适用场景对比直接调用 i2c_transfer()✅ 适合场景• 流式数据传输(音频PCM、ADC批量采样)• 启动阶段寄存器批量初始化• 特殊I2C时序(非标准消息序列)• 纯数据传输(无寄存器概念)• 极简设备(1-2个寄存器)❌ 不适合• 寄存器密集型设备(重复代码多)• 需要读-改-写原子操作• 需要调试寄存器dump• 需要缓存减少总线访问使用 regmap✅ 适合场景• 寄存器密集型外设(Codec/PMIC/Sensor)• 需要寄存器缓存加速访问• 需要regmap_update_bits原子操作• 同一芯片支持I2C+SPI双接口• 需要debugfs寄存器dump调试💡 额外收益• 统一API → 驱动可移植性 ↑• 内置锁 → 多线程安全• devm自动管理 → 无内存泄漏• regmap_multi_reg_write → 批量写

▲ 图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
公共API声明、regmap_config定义、初始化宏
drivers/base/regmap/regmap.c
核心实现:read/write/init/exit
drivers/base/regmap/internal.h
内部数据结构:struct regmap、struct regmap_bus
drivers/base/regmap/regmap-i2c.c
I2C总线适配
drivers/base/regmap/regmap-spi.c
SPI总线适配
drivers/base/regmap/regcache.c
缓存核心实现
drivers/base/regmap/regcache-rbtree.c
红黑树缓存
drivers/base/regmap/regcache-flat.c
扁平数组缓存
drivers/base/regmap/regmap-debugfs.c
debugfs调试支持
drivers/base/regmap/regmap-irq.c
中断控制器支持
drivers/base/regmap/regmap-sdw.c
SoundWire总线适配
drivers/base/regmap/regmap-spmi.c
SPMI总线适配

相关学习资料