最近在搞一个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,正好相反!因此需要修改控件参数:文章来源:https://www.toymoban.com/news/detail-619677.html
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!文章来源地址https://www.toymoban.com/news/detail-619677.html
到了这里,关于【RK3568调试记】给RK809添加音量调节功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!