Linux系统音频子系统知识梳理需求 硬件将耳机接口通过功放输出而耳机有插拔检测需要去掉插拔检测功能,即系统开机便要默认耳机已插入。问题 无。分析原理图分析注以下原理图截取自野火开发板鲁班猫2由于耳机输出功率较小接大喇叭需要使用功率放大芯片放大信号再输出到喇叭。由于喇叭不需要耳机的插拔检测因此需要屏蔽掉耳机驱动的插拔检测部分。RK809有SPK和HP两个输出但是我们的产品既要SPK也要大喇叭因此需要使用HP作为大喇叭RK809 是瑞芯微Rockchip推出的一款集成音频编解码器Codec的电源管理芯片PMIC其中的HPHeadphone和SPKSpeaker是两个音频输出通道它们在功能和用途上有明显区别1 HP耳机输出用途用于驱动耳机通常是双声道立体声输出。输出功率相对较低适合耳机阻抗一般为 16Ω~32Ω。音质表现支持高采样率最高192kHz适合高保真音频播放。配置参数在设备树DTS中可以设置hp-volume例如20表示耳机音量等级。2SPK扬声器输出用途用于驱动单声道喇叭适合外放场景。输出功率更高支持 1.3W 单声道输出适合驱动小型扬声器。音质表现虽然功率大但通常音质不如耳机输出细腻。配置参数在 DTS 中设置spk-volume例如3表示扬声器音量等级。3技术接口差异两者都通过 RK809 内部的 Codec 模块输出音频信号使用 I2S 接口进行数据传输但在硬件连接和电路设计上HP 通常连接到 3.5mm 耳机插孔SPK 通常连接到板载扬声器或外部功放模块。源代码分析设备树信息描述耳机检测io喇叭不需要改Io直接删掉。rk809_sound { hp-det-gpio gpio0 RK_PD6 GPIO_ACTIVE_LOW; };rk809声卡设备信息旧版本4.9的内核瑞芯微使用的是simple-audio-card驱动新版本的5.2内核使用的是rockchip,multicodecs-card驱动。kernel-5.2: rk809_sound: rk809-sound { status okay; compatible rockchip,multicodecs-card; rockchip,card-name rockchip-rk809; hp-det-gpio gpio0 RK_PD6 GPIO_ACTIVE_LOW; rockchip,format i2s; rockchip,mclk-fs 256; rockchip,cpu i2s1_8ch; rockchip,codec rk809_codec; pinctrl-names default; pinctrl-0 hp_det; };kernel-4.9: rk809_sound: rk809-sound { status okay; compatible simple-audio-card; simple-audio-card,format i2s; simple-audio-card,name rockchip,rk809-codec; simple-audio-card,mclk-fs 256; simple-audio-card,widgets Microphone, Mic Jack, Headphone, Headphone Jack; simple-audio-card,routing Mic Jack, MICBIAS1, IN1P, Mic Jack, Headphone Jack, HPOL, Headphone Jack, HPOR; simple-audio-card,cpu { sound-dai i2s1_8ch; }; simple-audio-card,codec { sound-dai rk809_codec; }; }; };rockchip,multicodecs-card配置项目./Documentation/devicetree/bindings/sound/rockchip,multicodecs.txt ROCKCHIP multicodecs audio Required properties: - compatible: rockchip,multicodecs-card - rockchip,cpu: The phandle of the Rockchip I2S/PDM controller thats connected to the CODEC - rockchip,codec: The phandle of audio codecs Optional properties: - rockchip,card-name: User specified audio sound card name, one string property. - rockchip,codec-hp-det : Detect the headphone via internal codec. - rockchip,wait-card-locked : This is a variable length array, user specified these sound cards need to be prepared and locked, otherwise the local slave card can be probed. - rockchip,audio-routing : sound card dapm routing. - hp-det-gpio : headphone detect gpio. - io-channels : headset mic/key detect adc channel. - io-channel-names : headset mic/key adc channel name. - spk-con-gpio : speaker enable/disabled gpio. - hp-con-gpio : headphone enable/disabled gpio. - keyup-threshold-microvolt: keyup-threshold-microvolt uV. - poll-interval : headset adc key poller internal ms. - play-pause-key : PLAYPAUSE key, can define the other key like vol/vol- and so on. Optional dai-link subnode properties: - rockchip,format : CPU/CODEC common audio format. i2s, right_j, left_j , dsp_a dsp_b, ac97, pdm, msb, lsb. - rockchip,frame-master : Indicates dai-link frame master. phandle to a cpu or codec subnode. - rockchip,bitclock-master : Indicates dai-link bit clock master. phandle to a cpu or codec subnode. - rockchip,bitclock-inversion : bool property. Add this if the dai-link uses bit clock inversion. - rockchip,frame-inversion : bool property. Add this if the dai-link uses frame clock inversion. - rockchip,mclk-fs : Multiplication factor between stream rate and codec mclk, applied only for the dai-link. Example: sound { compatible rockchip,multicodecs-card; rockchip,mclk-fs 256; rockchip,cpu i2s0_8ch; rockchip,codec codec, vad; }; Example 2 : es8388_sound: es8388-sound { status okay; compatible rockchip,multicodecs-card; rockchip,card-name rockchip-es8388; hp-det-gpio gpio1 RK_PD5 GPIO_ACTIVE_LOW; io-channels saradc 3; io-channel-names adc-detect; spk-con-gpio gpio1 RK_PD3 GPIO_ACTIVE_HIGH; hp-con-gpio gpio1 RK_PD2 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; keyup-threshold-microvolt 1800000; poll-interval 100; play-pause-key{ label playpause; linux,code KEY_PLAYPAUSE; press-threshold-microvolt 2000; }; };耳机驱动通过compatible属性可以定位到源代码的位置adc_jack_handler是耳机检测函数内容如下static void adc_jack_handler(struct work_struct *work) { struct multicodecs_data *mc_data container_of(to_delayed_work(work), struct multicodecs_data, handler); struct snd_soc_jack *jack_headset mc_data-jack_headset; int adc, ret 0; if (!gpiod_get_value(mc_data-hp_det_gpio)) { snd_soc_jack_report(jack_headset, 0, SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, false); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); if (mc_data-poller) mc_keys_poller_stop(mc_data-poller); return; } if (!mc_data-adc) { /* no ADC, so is headphone */ snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); return; } ret iio_read_channel_processed(mc_data-adc, adc); if (ret 0) { /* failed to read ADC, so assume headphone */ snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); } else { snd_soc_jack_report(jack_headset, snd_soc_jack_get_type(jack_headset, adc), SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); if (snd_soc_jack_get_type(jack_headset, adc) SND_JACK_HEADSET) { extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, true); if (mc_data-poller) mc_keys_poller_start(mc_data-poller); } } };上面是耳机检测的流程图耳麦的状态是通过snd_soc_jack_report上报给内核的因此可以在耳机驱动初始化时虚拟上报插入状态即可代码更改如下static int rk_dailink_init(struct snd_soc_pcm_runtime *rtd) { ... #define HP_NO_DET 1 #if HP_NO_DET snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET);//virtual report extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); #endif return 0; }这样系统启动后默认耳机就是已经插入可以正常播放音频。
【Linux】RK3568 Linux系统音频子系统知识梳理
Linux系统音频子系统知识梳理需求 硬件将耳机接口通过功放输出而耳机有插拔检测需要去掉插拔检测功能,即系统开机便要默认耳机已插入。问题 无。分析原理图分析注以下原理图截取自野火开发板鲁班猫2由于耳机输出功率较小接大喇叭需要使用功率放大芯片放大信号再输出到喇叭。由于喇叭不需要耳机的插拔检测因此需要屏蔽掉耳机驱动的插拔检测部分。RK809有SPK和HP两个输出但是我们的产品既要SPK也要大喇叭因此需要使用HP作为大喇叭RK809 是瑞芯微Rockchip推出的一款集成音频编解码器Codec的电源管理芯片PMIC其中的HPHeadphone和SPKSpeaker是两个音频输出通道它们在功能和用途上有明显区别1 HP耳机输出用途用于驱动耳机通常是双声道立体声输出。输出功率相对较低适合耳机阻抗一般为 16Ω~32Ω。音质表现支持高采样率最高192kHz适合高保真音频播放。配置参数在设备树DTS中可以设置hp-volume例如20表示耳机音量等级。2SPK扬声器输出用途用于驱动单声道喇叭适合外放场景。输出功率更高支持 1.3W 单声道输出适合驱动小型扬声器。音质表现虽然功率大但通常音质不如耳机输出细腻。配置参数在 DTS 中设置spk-volume例如3表示扬声器音量等级。3技术接口差异两者都通过 RK809 内部的 Codec 模块输出音频信号使用 I2S 接口进行数据传输但在硬件连接和电路设计上HP 通常连接到 3.5mm 耳机插孔SPK 通常连接到板载扬声器或外部功放模块。源代码分析设备树信息描述耳机检测io喇叭不需要改Io直接删掉。rk809_sound { hp-det-gpio gpio0 RK_PD6 GPIO_ACTIVE_LOW; };rk809声卡设备信息旧版本4.9的内核瑞芯微使用的是simple-audio-card驱动新版本的5.2内核使用的是rockchip,multicodecs-card驱动。kernel-5.2: rk809_sound: rk809-sound { status okay; compatible rockchip,multicodecs-card; rockchip,card-name rockchip-rk809; hp-det-gpio gpio0 RK_PD6 GPIO_ACTIVE_LOW; rockchip,format i2s; rockchip,mclk-fs 256; rockchip,cpu i2s1_8ch; rockchip,codec rk809_codec; pinctrl-names default; pinctrl-0 hp_det; };kernel-4.9: rk809_sound: rk809-sound { status okay; compatible simple-audio-card; simple-audio-card,format i2s; simple-audio-card,name rockchip,rk809-codec; simple-audio-card,mclk-fs 256; simple-audio-card,widgets Microphone, Mic Jack, Headphone, Headphone Jack; simple-audio-card,routing Mic Jack, MICBIAS1, IN1P, Mic Jack, Headphone Jack, HPOL, Headphone Jack, HPOR; simple-audio-card,cpu { sound-dai i2s1_8ch; }; simple-audio-card,codec { sound-dai rk809_codec; }; }; };rockchip,multicodecs-card配置项目./Documentation/devicetree/bindings/sound/rockchip,multicodecs.txt ROCKCHIP multicodecs audio Required properties: - compatible: rockchip,multicodecs-card - rockchip,cpu: The phandle of the Rockchip I2S/PDM controller thats connected to the CODEC - rockchip,codec: The phandle of audio codecs Optional properties: - rockchip,card-name: User specified audio sound card name, one string property. - rockchip,codec-hp-det : Detect the headphone via internal codec. - rockchip,wait-card-locked : This is a variable length array, user specified these sound cards need to be prepared and locked, otherwise the local slave card can be probed. - rockchip,audio-routing : sound card dapm routing. - hp-det-gpio : headphone detect gpio. - io-channels : headset mic/key detect adc channel. - io-channel-names : headset mic/key adc channel name. - spk-con-gpio : speaker enable/disabled gpio. - hp-con-gpio : headphone enable/disabled gpio. - keyup-threshold-microvolt: keyup-threshold-microvolt uV. - poll-interval : headset adc key poller internal ms. - play-pause-key : PLAYPAUSE key, can define the other key like vol/vol- and so on. Optional dai-link subnode properties: - rockchip,format : CPU/CODEC common audio format. i2s, right_j, left_j , dsp_a dsp_b, ac97, pdm, msb, lsb. - rockchip,frame-master : Indicates dai-link frame master. phandle to a cpu or codec subnode. - rockchip,bitclock-master : Indicates dai-link bit clock master. phandle to a cpu or codec subnode. - rockchip,bitclock-inversion : bool property. Add this if the dai-link uses bit clock inversion. - rockchip,frame-inversion : bool property. Add this if the dai-link uses frame clock inversion. - rockchip,mclk-fs : Multiplication factor between stream rate and codec mclk, applied only for the dai-link. Example: sound { compatible rockchip,multicodecs-card; rockchip,mclk-fs 256; rockchip,cpu i2s0_8ch; rockchip,codec codec, vad; }; Example 2 : es8388_sound: es8388-sound { status okay; compatible rockchip,multicodecs-card; rockchip,card-name rockchip-es8388; hp-det-gpio gpio1 RK_PD5 GPIO_ACTIVE_LOW; io-channels saradc 3; io-channel-names adc-detect; spk-con-gpio gpio1 RK_PD3 GPIO_ACTIVE_HIGH; hp-con-gpio gpio1 RK_PD2 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; keyup-threshold-microvolt 1800000; poll-interval 100; play-pause-key{ label playpause; linux,code KEY_PLAYPAUSE; press-threshold-microvolt 2000; }; };耳机驱动通过compatible属性可以定位到源代码的位置adc_jack_handler是耳机检测函数内容如下static void adc_jack_handler(struct work_struct *work) { struct multicodecs_data *mc_data container_of(to_delayed_work(work), struct multicodecs_data, handler); struct snd_soc_jack *jack_headset mc_data-jack_headset; int adc, ret 0; if (!gpiod_get_value(mc_data-hp_det_gpio)) { snd_soc_jack_report(jack_headset, 0, SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, false); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); if (mc_data-poller) mc_keys_poller_stop(mc_data-poller); return; } if (!mc_data-adc) { /* no ADC, so is headphone */ snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); return; } ret iio_read_channel_processed(mc_data-adc, adc); if (ret 0) { /* failed to read ADC, so assume headphone */ snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); } else { snd_soc_jack_report(jack_headset, snd_soc_jack_get_type(jack_headset, adc), SND_JACK_HEADSET); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); if (snd_soc_jack_get_type(jack_headset, adc) SND_JACK_HEADSET) { extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, true); if (mc_data-poller) mc_keys_poller_start(mc_data-poller); } } };上面是耳机检测的流程图耳麦的状态是通过snd_soc_jack_report上报给内核的因此可以在耳机驱动初始化时虚拟上报插入状态即可代码更改如下static int rk_dailink_init(struct snd_soc_pcm_runtime *rtd) { ... #define HP_NO_DET 1 #if HP_NO_DET snd_soc_jack_report(jack_headset, SND_JACK_HEADPHONE, SND_JACK_HEADSET);//virtual report extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_HEADPHONE, true); extcon_set_state_sync(mc_data-extcon, EXTCON_JACK_MICROPHONE, false); #endif return 0; }这样系统启动后默认耳机就是已经插入可以正常播放音频。