yoda24/DOC_MECHA_PRJ_NIC1_20260617_CASE_REGMAP_I2C
GitHub: yoda24/DOC_MECHA_PRJ_NIC1_20260617_CASE_REGMAP_I2C
该项目记录并修复了 MediaTek 平台上 TFA9890 音频放大器驱动因 I2C regmap 结构体类型转换导致的垃圾数据通信错误。
Stars: 0 | Forks: 0
## TFA98XX 驱动 - Mediatek I2C 扩展兼容性适配
### TFA9890 音频放大器 - 关键规格
### 概述
NXP TFA9890 是一款高性能 D 类音频放大器,集成了 DSP 和 DC-DC 升压转换器,专为移动微型扬声器设计。
### 与驱动开发相关的主要特性
| 特性 | 详情 |
|---|---|
| 控制接口 | I2C(400 kHz 快速模式) |
| DSP | NXP CoolFlux,嵌入式固件 |
| 输出功率 | 3.6W RMS(8Ω,9.5V 升压) |
| 供电电压 | 2.7V - 5.5V |
| 采样率 | 8 kHz - 48 kHz |
| I2S 输入 | 2(支持双音频源) |
| 扬声器保护 | 自适应偏移控制,实时温度监控 |
| 固件 | 基于容器(.cnt),包含音乐/语音配置文件 |
### 驱动需求
| 需求 | 实现方式 |
|---|---|
| I2C 通信 | 400 kHz 快速模式,16 位寄存器 |
| 固件加载 | 通过 regmap 或直接 I2C 加载容器(.cnt) |
| DSP 控制 | 启动/停止,配置文件切换(音乐/语音) |
| 音频路由 | ALSA SoC codec 集成 |
| 中断处理 | 扬声器错误,温度过高警告,削波检测 |
| 电源管理 | 挂起/恢复,LDO 控制,GPIO 复位 |
#### 主要错误([错误日志](./dev_log_main_err.txt))
### 配置
```
CONFIG_MTK_I2C_EXTENSION=y
```
```
static struct i2c_algorithm mt_i2c_algorithm = {
#ifdef CONFIG_MTK_I2C_EXTENSION
.master_xfer = (pmaster_xfer)mtk_i2c_transfer,
#else
.master_xfer = standard_i2c_transfer,
#endif
.functionality = mt_i2c_functionality,
};
```
KERNEL LINUX (GENERIC)
┌─────────────────────┐
│ i2c_transfer() │
│ regmap, SMBus, dll │
└──────────┬──────────┘
│ struct i2c_msg (standar)
│ no timing
│ no ext_flag
▼
┌────────────────────────────────┐
│ CONFIG_MTK_I2C_EXTENSION? │
└────────┬───────────────┬───────┘
│ │
=y =n
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ mt_i2c_msg │ │ i2c_msg │
│ (custom MTK) │ │ (standard) │
│ * timing │ │ │
│ * ext_flag │ │ │
└──────────────┘ └──────────────┘
### 垃圾数据流错误
struct i2c_msg (12 BYTE)
#include <linux/i2c.h> ┌────────────────────────────────┐
─────────────────────────► │ addr │ flags │ len │ *buf │
└──────┴───────┴──────┴──────────┘
no member timing
no member ext_flag
│
│ CAST
▼
#include <linux/mt_i2c.h> ┌────────────────────────────────────────────────────┐
─────────────────────────► │ addr │ flags │ len │ *buf │ timing │ ext_flag │
└──────┴───────┴──────┴──────────┴────────┴──────────┘
has member timing (4 byte) → value 400 KHz
has member ext_flag (4 byte) → value 0
═══════════════════════════════════════════════════════════════════════════════════════
COMPARING:
<linux/i2c.h> <linux/mt_i2c.h>
┌────┬────┬────┬────┐ ┌────┬────┬────┬────┬────────┬──────────┐
│addr│flg │len │*buf│ │addr│flg │len │*buf│ timing │ ext_flag │
└────┴────┴────┴────┘ └────┴────┴────┴────┴──┬─────┴────┬─────┘
│ │
CAST ▼ │ │
┌────┬────┬────┬────┬────────┬──────────┐ │ │
│addr│flg │len │*buf│ ?????? │ ???????? │ ▼ ▼
└────┴────┴────┴────┴──┬─────┴────┬─────┘ 400 KHz 0 (safe)
│ │
GARBAGE! GARBAGE!
0x4DE6D418 0xFFFFFFC0
(54 MHz!) (RND!)
│ │
▼ ▼
┌─────────────────────┐
│ ERROR! │
│ speed too fast │
│ probe FAILS │
└─────────────────────┘
结果([日志 1](./LOG1.txt)):
```
dev_err("Failed to read Revision register: -22")
return -EIO;
```
### 修复结果([日志 2](./LOG2.txt))。
╔══════════════════════════════════════════════════════════════════════════════════════════╗
║ COMPARE 3 METHODE I2C READ - TFA98XX ║
╠══════════════════════════════╦══════════════════════════════╦════════════════════════════╣
║ SMBus Byte ║ SMBus Word ║ Regmap Custom ║
╠══════════════════════════════╬══════════════════════════════╬════════════════════════════╣
║ ║ ║ ║
║ Func Name: ║ Func Name: ║ Func Name: ║
║ i2c_smbus_read_byte_data() ║ i2c_smbus_read_word_data() ║ tfa98xx_regmap_read() ║
║ ║ ║ ║
╠══════════════════════════════╬══════════════════════════════╬════════════════════════════╣
║ PARAMS ║ PARAMS ║ PARAMS ║
║ ─────────────────────── ║ ─────────────────────── ║ ───────────────────── ║
║ timing = 0x0 ║ timing = 0x0 ║ timing = 0x0 ║
║ ext_flag = 0x0 ║ ext_flag = 0x0 ║ ext_flag = 0x0 ║
║ mode = ST_MODE ║ mode = ST_MODE ║ mode = ST_MODE ║
║ speed = 100 KHz ║ speed = 100 KHz ║ speed = 100 KHz ║
║ dma_en = false ║ dma_en = false ║ dma_en = false ║
║ ║ ║ ║
╠══════════════════════════════╬══════════════════════════════╬════════════════════════════╣
║ TRANSFER ║ TRANSFER ║ TRANSFER ║
║ ─────────────────────── ║ ─────────────────────── ║ ───────────────────── ║
║ Message : 1 (WRITE) ║ Message : 1 (WRITE+READ) ║ Message : 2 (WR + RD) ║
║ Data : 1 byte ║ Data : 2 byte ║ Data : 2 byte ║
║ Protocol: SMBus ║ Protocol: SMBus ║ Protocol: I2C bare ║
║ ║ ║ ║
║ I2C Wire: ║ I2C Wire: ║ I2C Wire: ║
║ ┌──────────────────────┐ ║ ┌──────────────────────┐ ║ ┌──────────────────────┐ ║
║ │ S │ ADDR+W │ CMD │ │ ║ │ S │ ADDR+W │ CMD │ │ ║ │ S │ ADDR+W │ CMD │ │ ║
║ │ │ │0x03 │ │ ║ │ │ │0x03 │ │ ║ │ │ │0x03 │ │ ║
║ │ │ DATA_L │ STOP│ │ ║ │ Sr│ ADDR+R │ │ │ ║ │ Sr│ ADDR+R │ │ │ ║
║ │ │ 0x00 │ │ │ ║ │ │ DATA_L │DTA_H│ │ ║ │ │ DATA_H │DTA_L│ │ ║
║ └──────────────────────┘ ║ │ │ 0x00 │0x80 │ │ ║ │ │ 0x00 │0x80 │ │ ║
║ ║ │ │ STOP │ │ │ ║ │ │ STOP │ │ │ ║
║ ║ └──────────────────────┘ ║ └──────────────────────┘ ║
║ ║ ║ ║
╠══════════════════════════════╬══════════════════════════════╬════════════════════════════╣
║ Result ║ Result ║ Result ║
║ ─────────────────────── ║ ─────────────────────── ║ ───────────────────── ║
║ Raw Data: 0x00 ║ Raw Data: 0x8000 ║ Raw Data: 0x00 0x80 ║
║ Value : 0x00 ║ Value : 0x8000 ║ Value : 0x0080 ║
║ ║ ║ ║
║ Only LOW byte ║ Byte Order Swap ║ HIGH=0x00, LOW=0x80 ║
║ 8-bit ║ ║ Revision = 0x80 ║
║ ║ ║ TFA9890 detected ║
║ ║ ║ ║
║ ║ ║ ║
╠══════════════════════════════╩══════════════════════════════╩════════════════════════════╣
║ ║
║ Result: ║
║ ────────────────────────────────────────────────────────────────────────────────────── ║
║ SMBus Byte = 8-bit, not enough for register 16-bit ║
║ SMBus Word = 16-bit byte order swap (little-endian vs big-endian) ║
║ Regmap Custom = 16-bit, byte order valid, flexible (support DMA, change speed) ║
║ ║
╚══════════════════════════════════════════════════════════════════════════════════════════╝
╔════════════════════════════════════════════════════════╗
║ COMPARE 3 METHODE READ 0x03 ║
╠══════════════════════╦═══════════════════════════════════╣
║ SMBus byte ║ 0x00 Only 1 byte ║
║ SMBus word ║ 0x8000 Byte order swap ║
║ Regmap Custom ║ 0x0080 Valid ║
╚══════════════════════╩═══════════════════════════════════╝
### 最终结果([最终日志](./console-ramoops_DEV_Final_Log))。
通过以下方式成功解决了 TFA98XX 驱动集成问题:
1. **修复不兼容的 I2C 结构体** - 通过正确初始化 `timing` 和 `ext_flag` 字段,将标准 Linux `struct i2c_msg`(12 字节)适配为 Mediatek 的 `struct mt_i2c_msg`(24 字节),消除了导致“速度过快”错误的垃圾数据。
2. **探测芯片** - 在总线 0 上的 I2C 地址 0x35 处检测到 TFA9890 版本 0x80。
3. **固件安装** - 成功加载容器固件 `tfa98xx.cnt`(4761 字节),注册了 DSP 实例(句柄 0),并创建了 3 个音频配置文件:
- MUSIC_44100 (44.1 kHz)
- MUSIC_48000 (48 kHz)
- VOICE_16000 (16 kHz)
尚未进行音频播放测试。后续更新待定。
标签:ALSA, DSP固件, I2C通信, Linux驱动, MediaTek, 安全渗透, 音频放大器