深度解析ES8389/ES8390/音频芯片Linux驱动(Linux6.1内核)

电子说

1.4w人已加入

描述

 

 

 

在嵌入式音频开发中,顺芯(EverestES8389/ES8390是一款高集成度的音频Codec芯片,广泛应用于智能音箱、车载终端、便携设备等场景。本文基于Linux6.1内核,从驱动架构、寄存器配置、核心函数、数据流走向四个维度,完整拆解ES8389Linux驱动实现,帮你吃透这款芯片的驱动逻辑。

 

 

注意:在讲解rk3576系列课程的视频中有提到es8388已经停产了,目前这个8390pinpin替代的,估计也是升级版。

 

 

一、驱动整体架构:基于ASoC+I2C框架

 

 

ES8389驱动完全遵循Linux音频子系统的ASoCALSA System on Chip 框架设计,同时依托I2C完成芯片寄存器的读写交互,整体架构分为三层:

 

 

I2C驱动层:实现芯片与内核的I2C通信,是驱动的基础载体;

 

 

ASoC Component:封装Codec的硬件操作(probe/remove/suspend/resume)、音频控制(音量/静音/混音);

 

 

ASoC DAI:定义音频接口(I2S/TDM)、采样率/格式等参数,是CPUCodec的音频数据交互入口。

 

 

核心代码中,es8389_i2c_driver I2C驱动主体,soc_codec_dev_es8389 ASoC Component驱动,es8389_dai DAIDigital Audio Interface)驱动,三者共同构成完整的驱动体系。

 

 

二、核心数据结构:驱动的骨架

 

 

1. 私有数据结构体(es8389_private

 

 

驱动通过该结构体管理芯片的运行时状态,是贯穿整个驱动的核心:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
struct es8389_private {    struct snd_soc_component *component;  // 关联ASoC组件    struct regmap *regmap;                // 寄存器映射(简化I2C读写)    struct clk *mclk;                     // 主时钟句柄    unsigned int sysclk;                  // 系统时钟频率    int mastermode;                       // 主/从模式标识
    u8 adc_slot;       // ADC TDM时隙    u8 dac_slot;       // DAC TDM时隙    int dmic;          // DMIC使能标识    u8 mclk_src;       // 主时钟源    enum snd_soc_bias_level bias_level;   // 功耗偏置等级};

2. 时钟系数结构体(_coeff_div

 

 

ES8389的时钟配置高度依赖采样率和主时钟(MCLK)的匹配,驱动预定义了不同MCLK/采样率组合下的寄存器配置表:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
struct _coeff_div {    u16 fs;          // 采样率(如8000/16000/48000)    u32 mclk;        // 主时钟频率    u32 rate;        // 音频速率    u8 Reg0x04;      // 时钟分频寄存器0x04配置值    // ... 省略其他寄存器配置项    u8 Reg0x19;      // 系统寄存器0x19配置值};

代码中coeff_div数组包含了8kHz/16kHz/44.1kHz/48kHz等主流采样率的时钟参数,get_coeff()函数负责根据实际MCLK和采样率匹配对应的寄存器配置。

 

 

三、关键寄存器解析:硬件的指令集

 

 

ES8389驱动的核心是寄存器操作,按功能可分为5大类,以下结合代码中的关键操作解析:

 

 

1. 时钟配置寄存器(0x04-0x0A0x0F0x11

 

 

作用:配置时钟分频、倍频、源选择,是音频采样率匹配的核心;

 

 

关键操作es8389_pcm_hw_params()函数中,根据采样率匹配coeff_div表后,批量写入时钟寄存器:

 

 

  •  
  •  
  •  
regmap_write(es8389->regmap, ES8389_CLK_DIV1_REG04, coeff_div[coeff].Reg0x04);regmap_write(es8389->regmap, ES8389_CLK_MUL_REG05, coeff_div[coeff].Reg0x05);// ... 其他时钟寄存器写入

2. ADC/DAC核心寄存器(0x200x40

 

 

作用:配置音频格式(S16_LE/S24_LE/S32_LE)、I2S/TDM模式、静音等;

 

 

关键操作

 

 

格式配置:hw_params()中根据PCM参数设置数据长度:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
switch (params_format(params)){    case SNDRV_PCM_FORMAT_S16_LE:        state |= ES8389_S16_LE;  // 16位小端格式        break;    // ... 其他格式配置}regmap_update_bits(es8389->regmap, ES8389_ADC_REG20, ES8389_DATA_LEN_MASK, state);

静音控制:es8389_mute()中通过0x20/0x40寄存器的低2位控制ADC/DAC静音:

 

 

  •  
regmap_update_bits(es8389->regmap, ES8389_DAC_REG40, 0x03, 0x03); // 静音DAC

3. 模拟偏置寄存器(0x60-0x63

 

 

作用:配置模拟电路的偏置电压、电源模式,是芯片正常工作的基础;

 

 

关键操作es8389_init()中初始化模拟电路:

 

 

  •  
  •  
regmap_write(es8389->regmap, ES8389_VMID_REG60, 0x2A);  // 偏置电压配置regmap_write(es8389->regmap, ES8389_ANA_CTL1_REG61, 0xC9); // 模拟控制1

4. 混音/路由寄存器(0x2B0x440x31

 

 

作用:配置ADC/DAC的混音源、通道路由(如左右声道交换、ADC MUX选择);

 

 

关键操作:通过DAPMDynamic Audio Power Management)控件配置路由,例如:

 

 

  •  
  •  
  •  
// 配置ADC MUX选择AMIC/DMICstatic const struct soc_enum es8389_dmic_mux_enum =    SOC_VALUE_ENUM_SINGLE(ES8389_DMIC_EN_REG6D, 63, es8389_dmic_mux_txt, es8389_dmic_mux_values);

5. 功耗控制寄存器(0x000x100x69

 

 

作用:控制芯片的复位、功耗等级(ON/STANDBY/OFF);

 

 

关键操作es8389_set_bias_level()中切换功耗状态:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
case SND_SOC_BIAS_ON:    regmap_write(es8389->regmap, ES8389_RESET_REG00, 0x01); // 退出复位    regmap_update_bits(es8389->regmap, ES8389_HPSW_REG69, 0x200x20); // 开启耳机电源    break;case SND_SOC_BIAS_STANDBY:    regmap_write(es8389->regmap, ES8389_RESET_REG00, 0x3E); // 进入待机    break;

四、核心函数分析:驱动的灵魂

 

 

1. probe函数:驱动初始化入口

 

 

es8389_probe()是驱动加载时的核心函数,完成以下关键操作:

 

 

1.从设备树读取配置(mclk-srcadc-slotdmic-enabled等);

 

 

2.获取并使能主时钟(MCLK);

 

 

3.调用es8389_init()完成芯片默认寄存器配置;

 

 

4.关联ASoC组件和私有数据。

 

 

2. hw_params函数:音频参数适配

 

 

es8389_pcm_hw_params()在音频流启动前被调用,核心逻辑:

 

 

1.解析PCM参数(采样率、格式、通道数);

 

 

2.配置ADC/DAC的数据格式(如S16_LE);

 

 

3.匹配时钟系数表,写入时钟寄存器;

 

 

4.完成硬件参数与芯片寄存器的映射。

 

 

3. set_bias_level函数:功耗管理

 

 

ES8389支持4种功耗等级(OFF/STANDBY/PREPARE/ON),该函数负责切换不同等级:

 

 

ON:芯片全功能运行,开启模拟电路、时钟;

 

 

STANDBY:低功耗待机,关闭部分时钟和模拟电路;

 

 

OFF:深度休眠,仅保留必要的电源。

 

 

4. mute函数:静音控制

 

 

es8389_mute()实现ADC/DAC的静音/取消静音:

 

 

静音:设置ADC/DAC寄存器的静音位;

 

 

取消静音:清除静音位,同时恢复ADC使能和时钟配置。

 

 

五、音频数据流走向:从CPU到耳机/麦克风

 

 

ES8389的数据流分为播放(Playback 采集(Capture 两条路径,驱动通过DAPM路由定义了完整的数据流链路,以下结合流程图详解:

 

 

1. 播放(Playback)数据流

 

 

 

 

 

音频芯片

关键节点

 

 

I2S INCPU通过I2S接口发送音频数据到Codec

 

 

DACL/DACR:数字音频解码为模拟信号;

 

 

OUT MUX:支持左右声道交换(如DAC2→DAC1);

 

 

HPOL/HPOR:最终输出到耳机左/右声道。

 

 

2. 采集(Capture)数据流

 

 

 

 

 

音频芯片

关键节点

 

 

PGAL/PGAR:模拟信号前置放大(增益可通过寄存器0x72/0x73配置);

 

 

ADC Mixer:支持DAC信号回灌到ADC(如音频回环测试);

 

 

ADC MUX:切换模拟麦克风(AMIC/数字麦克风(DMIC);

 

 

I2S OUT:数字音频数据通过I2S发送到CPU

 

 

六、总结与拓展

 

 

核心要点

 

 

1.框架依赖:驱动基于ASoC+I2C框架,遵循Linux音频子系统的标准设计,适配性强;

 

 

2.时钟核心:采样率匹配的关键是coeff_div时钟表,需确保MCLK与采样率的匹配;

 

 

3.功耗管理:通过bias_level实现不同功耗等级的切换,平衡性能与功耗;

 

 

4.路由灵活DAPM路由支持混音、声道交换、麦克风类型切换,满足复杂音频场景。

 

 

适配注意事项

 

 

1.设备树需配置everest,mclk-src(时钟源)、everest,dmic-enabledDMIC使能)等属性;

 

 

2.不同硬件平台的MCLK频率不同,需确认coeff_div表中是否有匹配的时钟参数;

 

 

3.Linux6.1内核下,ASoC框架的接口无重大变化,适配其他版本(如5.15/6.6)仅需微调寄存器配置。

 

 

如需获取相关驱动,请评论区留言,需要适配其他Linux内核版本(如4.19/5.10),或定制音频路由、功耗策略,可私信交流具体的修改方案。

音频芯片

本文从驱动架构到数据流,完整拆解了ES8389音频CodecLinux驱动实现,希望能帮助嵌入式开发者快速掌握这款芯片的驱动逻辑,解决实际开发中的音频适配问题。

审核编辑 黄宇
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
其徐如林 04-08
0 回复 举报
驱动能分享一下吗 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分