RK3288_Android7.1:调试es8388(es8323)

主控:RK3288_android7.1

背景:公司需要在RK3288主板上调试ES8388音频芯片,实现喇叭外放,耳机,MIC录音功能,原理图如下。

1、ES8388 简介

ES8388是一种高性能、低功耗、低成本的音频编解码器。它由两路ADC,2通道DAC,话筒放大器、耳机放大器、数字音效、模拟混合和增益功能。
ES8388采用先进的多位Δ∑调制技术实现数字与模拟之间的数据转换。多比特Δ∑调制器使器件对时钟抖动和低带外噪声的灵敏度低。它应用于:MID,MP3, MP4, PMP,无线音频,数码相机,摄像机,GPS领域,蓝牙,便携式音频设备。
因为具有双路特性。
ADC特点为:24位,8千赫到96千赫取样频率;95分贝动态范围,95分贝信噪比,85分贝THD + N;立体声或单麦克风接口与麦克风放大器;自动电平控制和噪声门;2模拟输入选择;各种模拟输入混合和增益。
DAC特点为:24位,8千赫到96千赫取样频率;动态范围为96 dB,96 dB的信噪比,83分贝THD + N;40毫瓦耳机放大器无噪音的;耳机无模式;立体声增强;各种模拟输出混合并获得Low Power等等

2、驱动

在RK的sdk中没有ES8388的驱动,但是有ES8323的驱动,与ES8388通用。

3、修改 rockchip_defconfig

CONFIG_SND_SOC_ES8323=y

4、修改dts

    sound_card {
        status = "okay";
        compatible = "simple-audio-card";
        simple-audio-card,format = "i2s";
        simple-audio-card,name = "rockchip,es8323-codec";
        simple-audio-card,mclk-fs = <512>;
        simple-audio-card,widgets =
            "Microphone", "Microphone Jack",
            "Headphone", "Headphone Jack";
        simple-audio-card,routing =
            "MIC1", "Microphone Jack", "MIC2",
            "Microphone Jack", "Microphone Jack",
            "micbias1", "Headphone Jack", "HPOL",
            "Headphone Jack", "HPOR";
        simple-audio-card,dai-link@0 {
            format = "i2s";
            cpu {
                sound-dai = <&i2s>;
            };
            codec {
                sound-dai = <&es8323>;
            };
        };
        simple-audio-card,dai-link@1 {
            format = "i2s";
            cpu {
                sound-dai = <&i2s>;
            };
            codec {
                sound-dai = <&hdmi>;
            };
        };
    };
&i2c2 {
    status = "okay";
    es8323: es8323@10 {
        #sound-dai-cells = <0>;
        compatible = "everest,es8323";
        reg = <0x10>;
        clocks = <&cru SCLK_I2S0_OUT>;
        clock-names = "mclk";
        pinctrl-names = "default";
        pinctrl-0 = <&i2s0_mclk>;
        spk-con-gpio = <&gpio7 RK_PA5 GPIO_ACTIVE_LOW>;
        hp-det-gpio = <&gpio7 RK_PB7 GPIO_ACTIVE_LOW>;
        status = "okay";
    };
};

后续问题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函数去更改耳机状态。

百度了一下发现,Android会使用switch处理模块来检测一些开关量,例如hdmi,耳机等等。那就说明耳机插入是通过witch模块来检测的,但是还是不知道如何它是如何上报这个事件的。
后面想到了抓取耳机插入的日志,发现了事件上报的位置。

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节点,会冲突

总结:

这次调试的主要问题还是在耳机检测部分,这部分问题笔者觉得还是使用了讨巧的方法解决,希望以后能有更好的解决方式。

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Android 7.1 的源码中,您可以通过修改 fstab 文件或 init.rc 文件来添加一个可被电脑识别的分区。具体来说,您可以按照以下步骤进行操作: 1. 确定您要挂载的分区的设备节点名称,例如 `/dev/sdb1`。 2. 打开设备的 fstab 文件,例如 `/vendor/etc/fstab.rk3288`,在其中添加一行类似于以下内容的条目: `/dev/block/sdb1 /mnt/usb_storage vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0002,dmask=0002,allow_utime=0020,codepage=936,iocharset=utf8,shortname=mixed,utf8,errors=remount-ro 0 0` 这个条目的意思是将 `/dev/block/sdb1` 这个设备节点挂载到 `/mnt/usb_storage` 这个挂载点,使用 vfat 文件系统,具有一系列选项,例如读写权限、字符集等。 3. 如果您想要在设备启动时自动挂载该分区,可以修改设备的 init.rc 文件。具体来说,您可以在文件中添加以下内容: ``` mount /dev/block/sdb1 /mnt/usb_storage vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0002,dmask=0002,allow_utime=0020,codepage=936,iocharset=utf8,shortname=mixed,utf8,errors=remount-ro ``` 这个命令的意思是在设备启动时将 `/dev/block/sdb1` 挂载到 `/mnt/usb_storage`,使用 vfat 文件系统,具有一系列选项。 请注意,上述操作可能需要 root 权限才能执行,同时修改系统文件可能会导致系统不稳定或无法正常启动,请谨慎操作,并备份好您的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值