RK3588平台-ES8388音频芯片驱动解析

CPU内核版本
RK3588Linux5.10

一、ES8388芯片简介

ES8388是一款高性能、低功耗、低成本的立体声音频编解码器,它由2-chADC、2-chDAC、麦克风放大器、耳机放大器、数字音效和模拟混频和增益功能组成。

1.1 ES8388特性

ADC:
24位,8 khz至96 khz采样频率
95dB动态范围,95dB信噪比,-85dB THD+N
带麦克风放大器的立体声或单声道麦克风接口
自动电平控制和噪声门
2到1模拟输入选择
各种模拟输入混合和增益

DAC
24位,8 khz至96 khz采样频率
96 dB动态范围,96 dB信噪比,-83dB THD N
40 mw耳机放大器,无噪音,无阻塞选项
立体增强
低音和高音
各种模拟输出混合和增益

Low Power
1.8V至3.3V操作
7兆瓦回放;16兆瓦回放和记录

System*
I2C或SPI uC接口
256Fs, 384Fs, USB 12 MHz or 24 MHz
主从串行口
I2S,左对齐,DSP/PCM模式

1.2 ES8388框图

在这里插入图片描述
通过框图,可以查看音频数据的输入输出路径:
1)LIN1 LIN2 RN1 RN2作为输入端,可以与mic等输入设备的连接器相连。
音频数据输入路径:
首先经过mux多路选择(Lin1 LIN2 LIN1-R1N1 LIN2-RIN2,四选一),已左声道为例输入的左声道支持两路LIN1、LIN2 或 LIN1-RIN1、 LIN2-RIN2立体输入源。
接下来经过mic amp,及前置放大器,将采集的声音进行放大处理。
mux多路选择到ADC,将模拟音频信号转成数字信号,完成模数转换,通过Serial audio data DSDIN 走i2s转给SOC

音频输出路径
音频的输出路径较为简单,从ASDOUT —> DAC —> OUT

二、Linux 音频驱动框架

在Linux体系下,一个sound card驱动,包括3个部分的驱动 Machine、soc/platform、codec,其中soc/platform平台驱动一般由soc厂商提供,所以开发人员通常需要完成Machine和codec的driver。

2.1.Machine

Machine驱动负责platform和codec之间的耦合,处理机器特有的一些控件和音频事件。
只有platform和codec驱动时不饿能工作的,必须通过Machine把platform和codec结合在一起才能完成音频处理工作。
对应的驱动代码:sound/soc/rockchip/rockchip_multicodecs.c

static const struct of_device_id rockchip_multicodecs_of_match[] = {
	{ .compatible = "rockchip,multicodecs-card", },
	{},
};

MODULE_DEVICE_TABLE(of, rockchip_multicodecs_of_match);
static struct platform_driver rockchip_multicodecs_driver = {
	.probe = rk_multicodecs_probe,
	.driver = {
		.name = DRV_NAME,
		.pm = &snd_soc_pm_ops,
		.of_match_table = rockchip_multicodecs_of_match,
	},
};

rockchip_multicodecs_driver会通过rockchip_multicodecs_of_match查找到在dts中注册的sound资源节点并进行sound card注册。

2.2 platform

soc/platform侧驱动由soc厂商提供,驱动代码sound/soc/soc-core.c
platform驱动的主要作用是完成音频数据的管理,通过CPU的数字音频接口(DAI)把音频数据传送给codec进行处理,由codec输出驱动耳机或喇叭。

platform驱动分为两个部分:snd_soc_platfrom_driver和snd_soc_dai_driver。
snd_doc_platform_driver负责管理音频数据,把音频数据通过dma或其它方式传送到cpu dai中。
snd_soc_dai_driver主要完成cpu一侧的dai参数配置,同时也会把必要的dma等参数与snd_soc_platform_driver进行交互。

2.3 codec

codec驱动:sound/soc/codecs/es8323.c
关注snd_soc_dai_driver和snd_soc_codec_driver
es8323_dai

static struct snd_soc_dai_driver es8323_dai = {
	.name = "ES8323 HiFi",	/*dai驱动名字,需要和.codec_dai_name一致*/
	.playback = {
		     .stream_name = "Playback",
		     .channels_min = 1,
		     .channels_max = 2,
		     .rates = es8323_RATES,
		     .formats = es8323_FORMATS,
		     },
	.capture = {
		    .stream_name = "Capture",
		    .channels_min = 1,
		    .channels_max = 2,
		    .rates = es8323_RATES,
		    .formats = es8323_FORMATS,
		    },
	.ops = &es8323_ops,
	.symmetric_rates = 1,
};

es8323_ops用于实现dai的控制和参数配置

static struct snd_soc_dai_ops es8323_ops = {
	.startup = es8323_pcm_startup,
	.hw_params = es8323_pcm_hw_params,
	.set_fmt = es8323_set_dai_fmt,	/* dai的格式 */
	.set_sysclk = es8323_set_dai_sysclk, /* dai的时钟 */
	.mute_stream = es8323_mute,
	.no_capture_mute = 1,
};

soc_codec_dev_es8323的实现

static const struct snd_soc_component_driver soc_codec_dev_es8323 = {
	.probe = es8323_probe, /* codec的probe函数 */
	.remove = es8323_remove,
	.suspend = es8323_suspend,	
	.resume = es8323_resume,
	.set_bias_level = es8323_set_bias_level,	/* 偏置电压配置 */
	.dapm_widgets		= es8323_dapm_widgets,	/* dapm部件 */
	.num_dapm_widgets	= ARRAY_SIZE(es8323_dapm_widgets),
	.dapm_routes		= audio_map,	/* damp路由 */
	.num_dapm_routes	= ARRAY_SIZE(audio_map),
	.controls		= es8323_snd_controls,	/* 音频控件 */
	.num_controls		= ARRAY_SIZE(es8323_snd_controls),
	.idle_bias_on           = 1,
	.use_pmdown_time        = 1,
	.endianness             = 1,
	.non_legacy_dai_naming  = 1,
};

codec的注册

static const struct of_device_id es8323_of_match[] = {
	{ .compatible = "everest,es8323", },
	{ }
};
MODULE_DEVICE_TABLE(of, es8323_of_match);

static struct i2c_driver es8323_i2c_driver = {
	.driver = {
		.name = "ES8323",	/* 注意driver的名称要和 rockchip_dailinks里的一致 */
		.of_match_table = of_match_ptr(es8323_of_match),
		},
	.shutdown = es8323_i2c_shutdown,
	.probe = es8323_i2c_probe,
	.remove = es8323_i2c_remove,
	.id_table = es8323_i2c_id,
};
module_i2c_driver(es8323_i2c_driver);
);

整个codec 驱动的入口函数

static int es8323_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct es8323_priv *es8323;
	int ret = -1;
	struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent);
	char reg;

	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
		dev_warn(&adapter->dev,
			 "I2C-Adapter doesn't support I2C_FUNC_I2C\n");
		return -EIO;
	}

	es8323 = devm_kzalloc(&i2c->dev, sizeof(struct es8323_priv), GFP_KERNEL);
	if (!es8323)
		return -ENOMEM;
	es8323_param = es8323;
	es8323->regmap = devm_regmap_init_i2c(i2c, &es8323_regmap_config);
	if (IS_ERR(es8323->regmap))
		return PTR_ERR(es8323->regmap);

	i2c_set_clientdata(i2c, es8323);

	reg = ES8323_DACCONTROL18;
	ret = i2c_master_recv(i2c, &reg, 1);
	if (ret < 0) {
		dev_err(&i2c->dev, "i2c recv Failed\n");
		return ret;
	}

	ret = devm_snd_soc_register_component(&i2c->dev,
					      &soc_codec_dev_es8323,
					      &es8323_dai, 1);
	return ret;
}

es8323_i2c_probe后检查i2c接口的功能,在确认i2c读写寄存器正常后,会调用devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_es8323,
&es8323_dai, 1);
进行codec dai的注册。

三、驱动适配

3.1 电路原理分析在这里插入图片描述

通过原理图可以看到其使用的配置接口为I2C3,结合es8388的datasheet中关于芯片地址的定义,确定其I2C SLAVE ADDR为0x11
在这里插入图片描述
另外,还要确定音频数据传输使用的i2s接口,及几个关键的GPIO管脚:spk-con-gpio、hp-con-gpio、hp-det-gpio以及saradc。

3.2 设备树修改

在i2c3下定义codec即es8388的节点

&i2c3 {
	status = "disabled";
	es8388: es8388@11 {
		status = "disabled";
		#sound-dai-cells = <0>;
		compatible = "everest,es8388", "everest,es8323";
		reg = <0x11>;
		clocks = <&cru I2S0_8CH_MCLKOUT>;
		clock-names = "mclk";
		assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
		assigned-clock-rates = <12288000>;
		pinctrl-names = "default";
		pinctrl-0 = <&i2s0_mclk>;
	};
};

定义es86388-sound节点

	es8388_sound: es8388-sound {
		status = "disabled";
		compatible = "rockchip,multicodecs-card";
		rockchip,card-name = "rockchip-es8388";
		hp-det-gpio = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>;
		io-channels = <&saradc 3>;
		io-channel-names = "adc-detect";
		spk-con-gpio = <&gpio3 RK_PB2 GPIO_ACTIVE_HIGH>;
		hp-con-gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>;
		rockchip,format = "i2s";
		rockchip,mclk-fs = <256>;
		rockchip,cpu = <&i2s0_8ch>;
		rockchip,codec = <&es8388>;
		rockchip,audio-routing =
			"Headphone", "LOUT1",
			"Headphone", "ROUT1",
			"Speaker", "LOUT2",
			"Speaker", "ROUT2",
			"Headphone", "Headphone Power",
			"Headphone", "Headphone Power",
			"Speaker", "Speaker Power",
			"Speaker", "Speaker Power",
			"LINPUT1", "Main Mic",
			"LINPUT2", "Main Mic",
			"RINPUT1", "Headset Mic",
			"RINPUT2", "Headset Mic";
		pinctrl-names = "default";
		pinctrl-0 = <&hp_det>;
	};

3.3 涉及的驱动代码

根据dts中的compatible字段也可以识别到,es8388所需要的驱动一部分在sound/soc/codecs/es8323.c中,一部分在sound/soc/rockchip/rockchip_multicodecs.c中。

3.4 Debug

查询dts中定义的es8388声卡设备是否生成:
cd ​/sys/device/platform/es8388-sound,ls查看目录下内容
在这里插入图片描述
查看dev下的声卡设备
cd /dev/snd/by-path
在这里插入图片描述
查看声卡相关信息
cd /proc/asound/cards
在这里插入图片描述
cat cards
在这里插入图片描述
放音测试:
sudo aplay -Dplughw:1,0 xxx.wav
参数-Dplughw:x,其中x表示系统中的第几个声卡,在上图可以看到和es8388对应的声卡序号为1。


补充:
es8388 datasheet 下载链接

  • 21
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值