主控:RK3288_android7.1
背景:公司需要在RK3288主板上调试ES8388音频芯片,实现喇叭外放,耳机,MIC录音功能,原理图如下。
1、ES8388 简介
2、驱动
3、修改 rockchip_defconfig
4、修改dts
后续问题1:
添加完上述部分es8388的MIC和耳机都能正常使用了,喇叭只有在耳机插入时才有声音,说明耳机插入检测反了,需要修改驱动。
kernel\sound\soc\codecs\es8323.c
static irqreturn_t hp_det_irq_handler(int irq, void *dev_id)
{
struct es8323_priv *es8323 = es8323_private;
- if (gpio_get_value(es8323->hp_det_gpio)){
+ if (!gpio_get_value(es8323->hp_det_gpio)){
es8323->hp_inserted = 0;
}
else{
es8323->hp_inserted = 1;
}
if (es8323->muted == 0) {
if (es8323->hp_det_level != es8323->hp_inserted){
es8323_set_gpio(ES8323_CODEC_SET_SPK, !es8323->spk_gpio_level);
}
else{
es8323_set_gpio(ES8323_CODEC_SET_SPK, es8323->spk_gpio_level);
}
}
return IRQ_HANDLED;
}
后续问题2:
修改之后耳机检测正常,插入耳机时喇叭静音,但后续又发现耳机插入时无耳机图标,之前在做rk3568搭配rk809codec时是有耳机图标的,检查dts发现之前3568是使用了rk_headset.c驱动来检测耳机插入,将耳机插入事件上报到上层,才显示耳机图标。
现在es8323驱动有耳机检测脚但不会上报插入事件,如果换成将耳机检测也换成rockchip_headset来检测,耳机插入时会有图标显示,但是喇叭不会静音,二者不可兼得。
于是我查看了rk_headset.c驱动发现了耳机插入事件上报的地方,理论上只要将这部分处理也添加到es8323里即可
rk_headset.c中在headsetobserve_work的中断处理函数来检测耳机是否插入,在检测完后有一个switch_set_state函数去更改耳机状态。
frameworks\base\services\core\java\com\android\server\WiredAccessoryManager.java
它是通过检测/sys/devices/virtual/switch/h2w/state(/sys/class/switch/h2w/state)节点的值,来判断耳机插入。
具体流程参考该文章 :Android 耳机事件传递流程_msg_new_device_state-CSDN博客
现在知道是通过检测/sys/devices/virtual/switch/h2w/节点来判断耳机是否插入,那我们就只需要效仿rk_headset.c在es8323驱动中添加这一部分代码。
--- a/kernel/sound/soc/codecs/es8323.c
+++ b/kernel/sound/soc/codecs/es8323.c
@@ -33,6 +33,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/switch.h> //add by xuan 2024.03.14
#include "es8323.h"
#define INVALID_GPIO -1
@@ -42,6 +43,13 @@
#define es8323_DEF_VOL 0x1b
+struct switch_dev headset_switch; //add by xuan 2024.03.14
+
+static ssize_t Headset_print_name(struct switch_dev *sdev, char *buf)
+{
+ return sprintf(buf, "Headset\n");
+}
+
static int es8323_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level);
@@ -103,16 +111,26 @@ static irqreturn_t hp_det_irq_handler(int irq, void *dev_id)
{
struct es8323_priv *es8323 = es8323_private;
- if (gpio_get_value(es8323->hp_det_gpio))
+ if (!gpio_get_value(es8323->hp_det_gpio)){
es8323->hp_inserted = 0;
- else
+ switch_set_state(&headset_switch, 0); //add by xuan 2024.03.14 (耳机插入状态更改)
+ }
+ else{
es8323->hp_inserted = 1;
+ switch_set_state(&headset_switch, 1); //add by xuan 2024.03.14 (耳机插入状态更改)
+ }
+
+ printk("es8323->hp_inserted = %d\n", es8323->hp_inserted);
if (es8323->muted == 0) {
- if (es8323->hp_det_level != es8323->hp_inserted)
+ if (es8323->hp_det_level != es8323->hp_inserted){
es8323_set_gpio(ES8323_CODEC_SET_SPK, !es8323->spk_gpio_level);
- else
+ printk("es8323_set_gpio = %d\n", !es8323->spk_gpio_level);
+ }
+ else{
es8323_set_gpio(ES8323_CODEC_SET_SPK, es8323->spk_gpio_level);
+ printk("es8323_set_gpio = %d\n", es8323->spk_gpio_level);
+ }
}
return IRQ_HANDLED;
}
@@ -799,6 +817,14 @@ static int es8323_probe(struct snd_soc_codec *codec)
struct es8323_priv *es8323 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
+ /* add by xuan 2024.03.14 [耳机插入检测switch事件上报 (参考:rk_headset.c的switch上报处理)] */
+ headset_switch.name = "h2w";
+ headset_switch.print_name = Headset_print_name;
+ ret = switch_dev_register(&headset_switch);
+ if(ret < 0){
+ printk("es8323: register headset_switch failed!!!\n");
+ }
+ /* end, add by xuan 2024.03.14 */
if (codec == NULL) {
dev_err(codec->dev, "Codec device not registered\n");
return -ENODEV;
修改完后,dts中rockchip_headset和es8323不能同时打开,否则都会生成h2w节点,会冲突。
总结:
这次调试的主要问题还是在耳机检测部分,这部分问题笔者觉得还是使用了讨巧的方法解决,希望以后能有更好的解决方式。