板子:rk3568
平台:android12
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>;
};
由于我的板子还接了一个SPEAKER所以添加了一个SPEAKER控制引脚,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
下面是瑞芯微给出的思路:
播放无声