板子:rk3568
平台:android11

1.耳机功能添加

1.1 设备树配置

	rk_headset: rk-headset {
		compatible = "rockchip_headset";
		headset_gpio = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
		//hs_select = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&hp_det &hs_select_pin>;
		status = "okay";

	};

紧接着是rk809的配置:

	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",
		"IN1R", "Mic Jack",
		"Headphone Jack", "HPOL",
		"Headphone Jack", "HPOR";
		simple-audio-card,cpu {
			sound-dai = <&i2s1_8ch>;
		};
		simple-audio-card,codec {
			sound-dai = <&rk809_codec>;
		};
	};
...
/* 注意codec要放在rk809pmic节点下 */
		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>;
			spk-volume = <3>;
			spk-ctl-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
			mic-in-differential;
			status = "okay";
		};
	...
&i2s1_8ch {
	status = "okay";
	rockchip,clk-trcm = <1>;
	pinctrl-names = "default";
	pinctrl-0 = <&i2s1m0_sclktx
		     &i2s1m0_lrcktx
		     &i2s1m0_sdi0
		     &i2s1m0_sdo0>;
};

由于我的板子还接了一个功放芯片所以添加了一个功放控制引脚,spk-ctl-gpios属性在sound/soc/codecs/rk817_codec.c里面会去获取这个属性,并且会去自动控制并切换,相关源码如下:

	rk817->spk_ctl_gpio = devm_gpiod_get_optional(dev, "spk-ctl",
						  GPIOD_OUT_LOW);
	if (!IS_ERR_OR_NULL(rk817->spk_ctl_gpio)) {
		DBG("%s : spk-ctl-gpio %d\n", __func__,
		    desc_to_gpio(rk817->spk_ctl_gpio));
	}

相应的被调用函数:

static int rk817_codec_ctl_gpio(struct rk817_codec_priv *rk817,
				int gpio, int level)
{
	if ((gpio & CODEC_SET_SPK) &&
	    rk817->spk_ctl_gpio) {
		gpiod_set_value(rk817->spk_ctl_gpio, level);
		DBG("%s set spk clt %d\n", __func__, level);
		msleep(rk817->spk_mute_delay);
	}

	if ((gpio & CODEC_SET_HP) &&
	    rk817->hp_ctl_gpio) {
		gpiod_set_value(rk817->hp_ctl_gpio, level);
		DBG("%s set hp clt %d\n", __func__, level);
		msleep(rk817->hp_mute_delay);
	}

	return 0;
}

当然也可以加在head_set下面,我是采用的上面这种,下面是我的patch:

diff --git a/drivers/headset_observe/rk_headset.c b/drivers/headset_observe/rk_headset.c
index 5b16db723317..14f69afe6022 100644
--- a/drivers/headset_observe/rk_headset.c
+++ b/drivers/headset_observe/rk_headset.c
@@ -159,6 +159,22 @@ static void headsetobserve_work(struct work_struct *work)
 	printk("---headsetobserve_work---\n");
 	mutex_lock(&headset_info->mutex_lock[HEADSET]);
 	level = read_gpio(pdata->headset_gpio);
+	if(pdata->hs_select_flg == 1)	//judge support headphone speaker select
+	{
+		if(pdata->hs_select_pin)
+		{
+			if (!level) { //headset out
+				gpio_direction_output(pdata->hs_select_pin, pdata->hs_select_sta);
+				printk("%s-----------------------1\r\n",__func__);
+			}
+			else { //headset in
+				gpio_direction_output(pdata->hs_select_pin, !pdata->hs_select_sta);
+				printk("%s-----------------------2\r\n",__func__);
+			}
+			printk("%s: hs_select_pin->%d hs_select_sta->%d----------",__func__,pdata->hs_select_pin,pdata->hs_select_sta);
+		}
+	}
+
 	if (level < 0)
 		goto out;
 	msleep(100);
diff --git a/drivers/headset_observe/rk_headset.h b/drivers/headset_observe/rk_headset.h
index c10961ce66f8..9d911a082f9e 100644
--- a/drivers/headset_observe/rk_headset.h
+++ b/drivers/headset_observe/rk_headset.h
@@ -17,6 +17,12 @@ struct rk_headset_pdata {
 	unsigned int hook_gpio;
 	/* Hook key down status */
 	unsigned int hook_down_type;
+
+	unsigned int hs_select_pin;	//headphone/speaker select
+	unsigned int hs_select_sta;	//headphone/speaker select state
+	unsigned int hs_select_flg;	//headphone/speaker ping dts flag 1:suport headphone/speaker select 0:not support
+
+
 #ifdef CONFIG_MODEM_MIC_SWITCH
 	/* mic about */
 	unsigned int mic_switch_gpio;
diff --git a/drivers/headset_observe/rockchip_headset_core.c b/drivers/headset_observe/rockchip_headset_core.c
index 3c2eeb7ac213..f283a22303bf 100644
--- a/drivers/headset_observe/rockchip_headset_core.c
+++ b/drivers/headset_observe/rockchip_headset_core.c
@@ -107,6 +107,29 @@ static int rockchip_headset_probe(struct platform_device *pdev)
 		}
 	}
 
+	//headphone/speaker select gpio
+	ret = of_get_named_gpio_flags(node, "hs_select", 0, &pdata->hs_select_sta);
+	if(ret < 0)
+	{
+		pdata->hs_select_flg = 0;
+		printk("%s:can not get hs_select gpio property---------- %d",__func__,pdata->hs_select_flg);
+		
+	}
+	else
+	{
+		pdata->hs_select_pin = ret;
+		ret = devm_gpio_request(&pdev->dev, pdata->hs_select_pin,
+			"hs_select");
+		if(ret < 0)
+		{
+			printk("%s:can not request hs_select gpio ----------",__func__);
+			goto err;
+		}
+		printk("%s: hs_select_pin->%d hs_select_sta->%d----------",__func__,pdata->hs_select_pin,pdata->hs_select_sta);
+
+		pdata->hs_select_flg = 1;
+	}
+
 #ifdef CONFIG_MODEM_MIC_SWITCH
 	/* mic */
 	ret = of_get_named_gpio_flags(node, "mic_switch_gpio", 0, &flags);

但是我按照上面的添加了发现耳机是有声音的,不插耳机SPEAKER无声音输出,并且我尝试在插入耳机的同时也将SPEAKER控制脚打开SPEAKER就能有声音,所以确定上层应该是没有问题的,所以将问题锁定在驱动上,参考瑞星微文档解析:


Documentation/devicetree/bindings/sound/rockchip,rk817-codec.txt 
- compatible: "rockchip,rk817-codec" 
- - clocks: a list of phandle + clock-specifer pairs, one for each entry inclock-names. 
- - clock-names: should be "mclk". 
- - spk-ctl-gpios: spk mute enable/disable 用于外置功放使能脚,如果产品上有使用外置功放,请配置对应的使能脚 
- - hp-ctl-gpios: hp mute enable/disable 
- - spk-mute-delay-ms: spk mute delay time 
- - hp-mute-delay-ms: hp mute delay time 
- - spk-volume: DAC L/R volume digital setting for Speaker 配置喇叭输出音量,0 最大,255 最小 
- - hp-volume: DAC L/R volume digital setting for Headphone 配置耳机输出音量,0 最大,255 最小 
*
* DDAC L/R volume setting 
*  0db~-95db,0.375db/step,for example: 
* 0: 0dB 
*  10: -3.75dB * 125: -46dB 
*  255: -95dB 
* 
- capture-volume: ADC L/R volume digital setting for Microphone 配置录音输入音量,0 最大,255 最小 
*
* DADC L/R volume setting 
*  0db~-95db,0.375db/step,for example: 
*  0: 0dB * 10: -3.75dB 
*  125: -46dB * 255: -95dB 
* 
- mic-in-differential: 
 Boolean. Indicate MIC input is differential, rather than single-ended.
  指定使用差分 MIC,否则为单端 MIC,所以使用差分 MIC 时加上此 property- pdmdata-out-enable: 
 Boolean. Indicate pdmdata output is enabled or disabled. 
 录音数据使用 PDM 数字接口。 
 - use-ext-amplifier: 
 Boolean. Indicate use external amplifier or not. 
 指定是否使用外部功放。 - 
 adc-for-loopback: 
 Boolean. Indicate adc use for loopback or not. 指定 ADC 用于回采,一般音箱类产品使用。

从这里我们看出要使用外放功能设备树里面就要添加 use-ext-amplifier: 这个属性
所以更改设备树:

		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>;
			spk-volume = <3>;
			use-ext-amplifier;
			spk-ctl-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
			mic-in-differential;
			status = "okay";
		};

use-ext-amplifier;这个属性指定是否使用外部功放,改过之后就可以正常放音了,下面是adb shellz中使用tinymix看到的,输出Playback Path是speaker:

sbc_rk3568:/ # tinymix                                                                                                                                                                                 
Mixer name: 'rockchip,rk809-codec'
Number of controls: 2
ctl	type	num	name                                     value

0	ENUM	1	Playback Path                            SPK
1	ENUM	1	Capture MIC Path                         MIC OFF

插上耳机后显示的Playback Path是HP_NO_MIC:

sbc_rk3568:/ # tinymix                                                                                                                                                                                     
Mixer name: 'rockchip,rk809-codec'
Number of controls: 2
ctl	type	num	name                                     value

0	ENUM	1	Playback Path                            HP_NO_MIC
1	ENUM	1	Capture MIC Path                         MIC OFF

下面是瑞芯微给出的思路:
播放无声

  • 确认音频源为 非静音文件
  • 使用 aplay 或者 tinyplay 播放,定位问题是发生在用户态还是内核态
  • 播放等待10秒以上确认是否为 I/O error 问题
  • 使用 amixer 或者 tinymix 检查 CODEC 内部 DAC 通路是否打开,音量是否静音
  • 查看 寄存器 配置,配合芯片手册或者 CODEC 手册确认配置是否正确:IOMUX,DAI,CODEC。
  • 使用 万用表 和 示波器 测量电压,时钟,数据。确认电压,时钟正常,数据线上有波形;测量
  • CODEC 近端 模拟输出信号是否正常,测量 PA 使能 gpio 电平,逐级定位问题点

查看 codec 寄存器

rk3326_evb:/ # cd /d/regmap/0-0020-rk817-codec/ 
rk3326_evb:/d/regmap/0-0020-rk817-codec # cat registers
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐