【RK3568调试记】给RK809添加音量调节功能

文章讲述了在RK3568项目中遇到的音量调节问题,通过设备树配置实现了初步的音量调整,然后深入到RK809codec的驱动源码,添加了音量控制的控件,解决了alsamixer无法调节音量的问题。在过程中,参照了WM8960codec的驱动实现,并修复了调节音量时的反向问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在搞一个RK3568的项目,用到了codec的录音放音功能。使用aplay来播放wav,差点把我耳朵震聋。于是我打算使用alsamixer来调小音量,结果给我整了这么一出:
在这里插入图片描述
没有音量条也就无法调节音量,使用amixer命令看一下:
在这里插入图片描述
仅有两个控件,而这两个控件也不是调音量的,难道说RK3568的codec不支持音量调节吗?
RK3568使用的codec芯片是rk809,同时也是PMIC(就很神奇)。带着问题百度了下,发现可以通过修改设备树来调节音量:

rk809_codec: codec {
			#sound-dai-cells = <0>;
			compatible = "rockchip,rk809-codec", "rockchip,rk817-codec";
			clocks = <&cru I2S1_MCLKOUT>;
			clock-names = "mclk";
			assigned-clocks = <&cru I2S1_MCLKOUT>, <&cru I2S1_MCLK_TX_IOE>;
			assigned-clock-rates = <12288000>;
			assigned-clock-parents = <&cru I2S1_MCLKOUT_TX>, <&cru I2S1_MCLKOUT_TX>;
			pinctrl-names = "default";
			pinctrl-0 = <&i2s1m0_mclk>;
			hp-volume = <20>;  //此处修改耳机音量,3~255即1.125db~-95db,0.375db/step
			spk-volume = <3>;  //此处修改喇叭音量,3~255即1.125db~-95db,0.375db/step
			mic-in-differential;
			status = "okay";
		};

修改后再播放果然生效,证明rk809是具备调节音量的功能的。

但问题还是没有解决,总不能听个音乐想调下音量,于是修改设备树,重新编译,烧写到产品中…正确的做法是把音量调节控件添加到codec驱动中使其支持音量调节功能。

根据设备树rk809的compatible属性找到它的驱动源码sound/soc/codecs/rk817_codec.c。找到它的控件注册位置:

static int rk817_probe(struct snd_soc_component *component)
{
	/* 省略 */
	snd_soc_add_component_controls(component, rk817_snd_path_controls,
				       ARRAY_SIZE(rk817_snd_path_controls));
	return 0;
}

rk817_snd_path_controls就是控件对象了,它的定义也在本文件中:

static struct snd_kcontrol_new rk817_snd_path_controls[] = {
	SOC_ENUM_EXT("Playback Path", rk817_playback_path_type,
		     rk817_playback_path_get, rk817_playback_path_put),

	SOC_ENUM_EXT("Capture MIC Path", rk817_capture_path_type,
		     rk817_capture_path_get, rk817_capture_path_put),
};

这两个控件与amixer命令查找出了两个控件相吻合。需要添加第三个控件用于音量调节。

这里我的做法是参考一个比较熟悉的codec的驱动wm8960(sound/soc/codecs/wm8960.c),它是这样添加音量调节控件的:
在这里插入图片描述
这个宏的原型:

include/sound/soc.h
SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array)
参数:
xname: 控件件名称,
reg_left: 左声道寄存器地址
reg_right: 右声道寄存器地址
xshift: 控件功能在寄存器中需要修改第几个bit
xmax: 寄存器可写入的最大值
xinvert: 写入寄存器的值是否需要反转(0:0就是0; 1:0为xmax-0)
tlv_array: 控制元数据(就是一个容器),alsa以此来定义dB范围/比例

宏展开SOC_DOUBLE_R_TLV(“Playback Volume”, WM8960_LDAC, WM8960_RDAC,
0, 255, 0, dac_tlv),

SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC, 0, 255, 0, dac_tlv),
{
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = ("Playback Volume"),
	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,
	.tlv.p = (dac_tlv),  //控制元数据
	.info = snd_soc_info_volsw,
	.get = snd_soc_get_volsw,  //amixer的sget或cget的回调
	.put = snd_soc_put_volsw,  //amixer的sset或cset的回调
	.private_value = SOC_DOUBLE_R_VALUE( WM8960_LDAC,   WM8960_RDAC,             0,        255,                0)
  //.private_value = SOC_DOUBLE_R_VALUE(左声道音量reg,  右声道音量reg, 寄存器位offset, 寄存器最大值, 设置的值是否反转)
},

再看它的元数据dac_tlv的定义:

static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
dac_tlv: 元数据变量
-12750: 最小增益(单位0.01dB),即最小音量为-127.5dB,需要参考codec datasheet
50: 调节音量的步长(单位0.01dB),0.5dB 0~255-127.5dB~0dB,127.5/256约为0.5
1: 音量最小是是否需要静音(0:; 1: 是)

rk809的道理基本一样,只是需要确定音量调节的寄存器地址,查看rk809的datasheet:
在这里插入图片描述
二者在sound/soc/codecs/rk817_codec.h中有定义:

#define RK817_CODEC_DDAC_VOLL		(RK817_CODEC_BASE + 0x31)
#define RK817_CODEC_DDAC_VOLR		(RK817_CODEC_BASE + 0x32)

最后照猫画虎,添加音量调节控件:

#include <sound/tlv.h>  //+ 头文件。否则编译找不到宏DECLARE_TLV_DB_SCALE
/* 省略 */
static const DECLARE_TLV_DB_SCALE(dac_tlv, -9500, 37, 1);  //+ 音量调节控件元数据,根据rk809datasheet -1.125db~-95db,0.375db/step

static struct snd_kcontrol_new rk817_snd_path_controls[] = {
	SOC_ENUM_EXT("Playback Path", rk817_playback_path_type,
		     rk817_playback_path_get, rk817_playback_path_put),

	SOC_ENUM_EXT("Capture MIC Path", rk817_capture_path_type,
		     rk817_capture_path_get, rk817_capture_path_put),
	
	SOC_DOUBLE_R_TLV("Playback Volume", RK817_CODEC_DDAC_VOLL,  RK817_CODEC_DDAC_VOLR,
		 0, 255, 0, dac_tlv),  //+ 音量调节控件
};

编译烧写内核,alsamixer成功出现音量条:
在这里插入图片描述
amixer查看,出现音量控件’Playback’:
在这里插入图片描述
使用amixer contents查看详情:
在这里插入图片描述
分别用amixer sset Playback 0,0以及amixer sset Playback 255,255测试最大和最小音量:
在这里插入图片描述
然后使用aplay放歌出现了一个小bug,使用amixer sset Playback 0,0原本表示静音却放出了最大音量,而amixer sset Playback 255,255是最小音量,这与标定值相反。控件的配置是照搬wm8960的,对比wm8960和rk809的datasheet得到答案:
rk809:
在这里插入图片描述
wm8960:
在这里插入图片描述
wm8960音量与寄存器值对应关系为255对应最大值0dB,而rk809 255对应最小值-95dB,正好相反!因此需要修改控件参数:

static struct snd_kcontrol_new rk817_snd_path_controls[] = {
	SOC_ENUM_EXT("Playback Path", rk817_playback_path_type,
		     rk817_playback_path_get, rk817_playback_path_put),

	SOC_ENUM_EXT("Capture MIC Path", rk817_capture_path_type,
		     rk817_capture_path_get, rk817_capture_path_put),
	
	SOC_DOUBLE_R_TLV("Playback Volume", RK817_CODEC_DDAC_VOLL,  RK817_CODEC_DDAC_VOLR,
		 0, 255, 1/*这里把0修改为1,表示寄存器写入x,实际值为255-x*/, dac_tlv),
};

成功修复bug!

### RK3326 平台 Android 9.0 音量调节 ADC 配置教程 在 RK3326 平台上实现 Android 9.0 的音量调节功能涉及多个层面的配置,包括硬件抽象层 (HAL) 和驱动程序的支持。以下是关于如何完成此任务的具体说明。 #### HAL 库支持 为了使音频设备能够正常工作,需要确保 HAL 层已经正确编译并部署到目标设备上。对于 RK3326 而言,其 HAL 文件路径可能类似于 `./out/target/product/rk3326/vendor/lib/hw/audio.primary.rk30board.so`[^1]。如果该文件不存在,则需重新构建项目以生成所需的 HAL 库。 将新生成的 HAL 库替换至设备中的对应位置: ```bash adb push audio.primary.rk30board.so /vendor/lib/hw/ ``` #### 设备树配置 音量调节通常依赖于特定的寄存器设置来控制模拟数字转换器 (ADC),这些设置可以通过修改设备树 (Device Tree, DTB) 来完成。具体操作如下: 1. 找到当前使用的设备树源码文件(通常是 `.dts` 文件)。例如,在 RK3326 上可能是 `rk3326-evb.dts`。 2. 添加或调整与 ES7210 或其他声卡芯片相关的节点定义。以下是一个示例片段: ```dts sound { compatible = "simple-audio-card"; simple-audio-card,name = "ES7210 Audio"; /* 定义输入输出端口 */ simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; /* 连接 CPU DAI 到 Codec */ simple-audio-card,cpu { sound-dai = <&i2s>; }; simple-audio-card,codec { sound-dai = <&es7210_codec>; // 声卡对应的 codec 名称 }; }; ``` 3. 编译更新后的设备树文件,并将其刷入设备中。 #### 驱动调试与错误排查 当遇到音量调节失败或其他问题时,可以按照以下方法进行排查: - **日志分析** 使用 ADB 工具捕获系统日志,重点关注音频子系统的消息输出: ```bash adb logcat | grep -i audio ``` 如果发现异常提示,比如找不到指定的 HAL 模块或者无法初始化某些资源,则表明可能存在未满足的依赖项。 - **权限验证** 确认应用程序具有访问麦克风和扬声器所需的所有必要权限。可以在应用清单文件 (`AndroidManifest.xml`) 中声明如下权限: ```xml <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> ``` - **参数校准** 对于基于 ADC 实现的功能来说,精确设定增益范围至关重要。通过实验确定最佳数值组合后写入固件代码里保存下来供后续调用即可。 --- ### 示例代码:动态改变媒体音量水平 下面给出一段用于演示如何编程方式更改全局音乐播放响度等级的例子: ```java import android.media.AudioManager; public class VolumeController { private AudioManager mAudioMgr; public void adjustVolume(int direction){ mAudioMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); if(direction > 0){ mAudioMgr.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI); } else{ mAudioMgr.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI); } } } ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值