qcm6125 I2S调试

参考:
Android Qcom Audio入门学习
安卓音频学习
qcom SM6125平台 dmic调试
linux音频子系统 - ASoC-PCM之machine
[Linux Audio Driver] 高通平台MI2S总线配置
【Audio driver】mixer_paths.xml文件分析
Qualcomm Audio HAL 音频通路设置
高通8155 音频数据从HAL到DSP

平台:qcm6125
系统:android13
最近做项目需要用到I2S作输入,硬件连接如下:
在这里插入图片描述
在这里插入图片描述
IO说明
在这里插入图片描述

查看当前声卡

trinket:/sys/class/sound # ls -alh card0/
lrwxrwxrwx   1 root root    0 2024-05-23 00:28 device -> ../../../soc:qcom,msm-audio-apr:qcom,q6core-audio:sound

trinket:/sys/class/sound # ls -alh controlC0/
total 0
drwxr-xr-x   3 root root    0 1970-01-01 08:00 .
drwxr-xr-x 126 root root    0 1970-01-01 08:00 ..
-r--r--r--   1 root root 4.0K 2024-05-23 00:28 dev
lrwxrwxrwx   1 root root    0 2024-05-23 00:28 device -> ../../card0
drwxr-xr-x   2 root root    0 2024-05-23 00:28 power
lrwxrwxrwx   1 root root    0 2024-05-23 00:28 subsystem -> ../../../../../../../../../class/sound
-rw-r--r--   1 root root 4.0K 2024-05-23 00:28 uevent

查看对应的FE pcm设备是否存在: cat /proc/asound/pcm

Codec是否注册到了声卡
cat /sys/kernel/debug/asoc/codecs

ADSP core driver
./vendor/qcom/opensource/audio-kernel/dsp/q6core.c

Machine driver
./vendor/qcom/opensource/audio-kernel/asoc/sm6150.c

DAI driver
./vendor/qcom/opensource/audio-kernel/asoc/msm-dai-q6-v2.c
音频控件配置:
tinymix : 配置音频路由
tinycap: 录音
tinyplay: 播放

对应的dts配置

&sm6150_snd {
    ...
    // dmic和i2s不能共用
    //qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>;
	//qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>;
    qcom,sec-mi2s-gpios = <&cdc_sec_i2s_gpios>;
    ...
};

cdc_sec_i2s_gpios: cdc_sec_i2s_pinctrl {
		compatible = "qcom,msm-cdc-pinctrl";
		pinctrl-names = "aud_active", "aud_sleep";
		pinctrl-0 = <&sec_i2s_sck_active &sec_i2s_ws_active &sec_i2s_sd0_active &sec_i2s_sd1_active>;
		pinctrl-1 = <&sec_i2s_sck_sleep &sec_i2s_ws_sleep &sec_i2s_sd0_sleep &sec_i2s_sd1_sleep>;
 };

pinctrl DTS配置

 sec_i2s_sck_active: sec_i2s_sck_active {
                mux {
                        pins = "gpio125";
                        function = "sec_mi2s";
                };
                config {
                        pins = "gpio125";
                        drive-strength = <8>;
                        bias-disable;
                        output-high;
                };
        };

        sec_i2s_sck_sleep: sec_i2s_sck_sleep {
                mux {
                                pins = "gpio125";
                                function = "sec_mi2s";
                };   
                config {
                                pins = "gpio125";
                                drive-strength = <2>;
                                bias-pull-down;
                };   
        };   

        sec_i2s_ws_active: sec_i2s_ws_active {
                mux {
                                pins = "gpio126";
                                function = "sec_mi2s";
                };   
                config {
                                pins = "gpio126";
                                drive-strength = <8>; 
                                bias-disable;
                                output-high;
                };   
        };   

        sec_i2s_ws_sleep: sec_i2s_ws_sleep {
                mux {
                                pins = "gpio126";
                                function = "sec_mi2s";
                };      
                config {
                                pins = "gpio126";
                                drive-strength = <2>; 
                                bias-pull-down;
                };      
        };
        sec_i2s_sd0_active: sec_i2s_sd0_active {
                mux {
                                pins = "gpio127";
                                function = "sec_mi2s";
                };      
                config {
                                pins = "gpio127";
                                drive-strength = <8>;
                                bias-disable;
                                output-high;
                };      
        };              

        sec_i2s_sd0_sleep: sec_i2s_sd0_sleep {
                mux {
                                pins = "gpio127";
                                function = "sec_mi2s";
                };
                config {
                                pins = "gpio127";
                                drive-strength = <2>;
                                bias-pull-down;
                                input-enable;
                };
        };

        sec_i2s_sd1_active: sec_i2s_sd1_active {
                mux {
                                pins = "gpio128";
                                function = "sec_mi2s";
                };      
                config {
                                pins = "gpio128";
                                drive-strength = <8>;
                                bias-disable;
                                input-enable;
                };
        };

        sec_i2s_sd1_sleep: sec_i2s_sd1_sleep {
                mux {
                                pins = "gpio128";
                                function = "sec_mi2s";
                };
                config {
                                pins = "gpio128";
                                drive-strength = <2>;
                                bias-pull-down;
                                input-enable;
                };
        };

输入命令

tinymix 'MultiMedia1 Mixer SEC_MI2S_TX' 1
tinycap /data/test.wav
Unable to open PCM device 
(cannot set hw params: Invalid argument)Captured 0 frames

在这里插入图片描述
刚开始毫无头绪,开始查找文档 寻找疑点。发现qcom,msm-mi2s-master默认配置的是master模式,作为输入 应该配置成slave。

/* kernel/msm-4.14/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt */
/*- qcom,msm-mi2s-master: This property is used to inform machine driver
  if MSM is the clock master of mi2s. 1 means master and 0 means slave. The
  first entry is primary mi2s; the second entry is secondary mi2s, and so on.
*/

	/* vendor/qcom/opensource/audio-kernel/asoc/sm6150.c
	    enum {
	        PRIM_MI2S = 0,
	        SEC_MI2S,
	        TERT_MI2S,
	        QUAT_MI2S,
	        QUIN_MI2S,
	        MI2S_MAX,
        };
	*/
	qcom,msm-mi2s-master = <1>, <0>, <1>, <1>, <1>;
	qcom,auxpcm-audio-intf = <0>;  //怕会影响也一起关了

编译烧录测试发现还是不行,头大!
后面在Machine 中添加打印继续追踪


static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
    ...
	case 1:
		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_SD0)
			goto error_invalid_data;
   ...
}

static int msm_dai_q6_mi2s_platform_data_validation(
	struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
{
	struct msm_dai_q6_mi2s_dai_data *dai_data = dev_get_drvdata(&pdev->dev);
	struct msm_mi2s_pdata *mi2s_pdata =
			(struct msm_mi2s_pdata *) pdev->dev.platform_data;
	unsigned int ch_cnt;
	int rc = 0;
	u16 sd_line;

	if (mi2s_pdata == NULL) {
		pr_err("%s: mi2s_pdata NULL", __func__);
		return -EINVAL;
	}

	rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->rx_sd_lines,
					    &sd_line, &ch_cnt);
	if (rc < 0) {
		dev_err(&pdev->dev, "invalid MI2S RX sd line config\n");
		goto rtn;
	}

	if (ch_cnt) {
		dai_data->rx_dai.mi2s_dai_data.port_config.i2s.channel_mode =
		sd_line;
		dai_data->rx_dai.pdata_mi2s_lines = sd_line;
		dai_driver->playback.channels_min = 1;
		dai_driver->playback.channels_max = ch_cnt << 1;
	} else {
		dai_driver->playback.channels_min = 0;
		dai_driver->playback.channels_max = 0;
	}
	rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->tx_sd_lines,
					    &sd_line, &ch_cnt);
	if (rc < 0) {
		dev_err(&pdev->dev, "invalid MI2S TX sd line config\n");
		goto rtn;
	}

	if (ch_cnt) {
		dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode =
		sd_line;
		dai_data->tx_dai.pdata_mi2s_lines = sd_line;
		dai_driver->capture.channels_min = 1;
		dai_driver->capture.channels_max = ch_cnt << 1;
	} else {
		dai_driver->capture.channels_min = 0;
		dai_driver->capture.channels_max = 0;
	}

	dev_err(&pdev->dev, "%s: playback sdline 0x%x capture sdline 0x%x\n",
		__func__, dai_data->rx_dai.pdata_mi2s_lines,
		dai_data->tx_dai.pdata_mi2s_lines);
	dev_err(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
		__func__, dai_driver->playback.channels_max,
		dai_driver->capture.channels_max);
rtn:
	return rc;
}

static int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
{
    ....
	rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-rx-lines",
				  &rx_line);
	if (rc) {
		dev_err(&pdev->dev, "%s: Rx line from DT file %s\n", __func__,
			"qcom,msm-mi2s-rx-lines");
		goto free_pdata;
	}

	rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-tx-lines",
				  &tx_line);
	if (rc) {
		dev_err(&pdev->dev, "%s: Tx line from DT file %s\n", __func__,
			"qcom,msm-mi2s-tx-lines");
		goto free_pdata;
	}
	dev_err(&pdev->dev, "dev name %s Rx line 0x%x , Tx ine 0x%x\n",
		dev_name(&pdev->dev), rx_line, tx_line);
	mi2s_pdata->rx_sd_lines = rx_line;
	mi2s_pdata->tx_sd_lines = tx_line;
	mi2s_pdata->intf_id = mi2s_intf; 
    ....
}

最后发现 msm-mi2s-tx-lines 默认是0 导致这个问题

...
		dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
			compatible = "qcom,msm-dai-q6-mi2s";
			qcom,msm-dai-q6-mi2s-dev-id = <1>;
			qcom,msm-mi2s-rx-lines = <1>;
			qcom,msm-mi2s-tx-lines = <0>;
		};
...

改成1就能正常录音了,后续再补充

&dai_mi2s1{
    compatible = "qcom,msm-dai-q6-mi2s";
	qcom,msm-dai-q6-mi2s-dev-id = <1>;
	qcom,msm-mi2s-rx-lines = <0>;
	qcom,msm-mi2s-tx-lines = <1>;
};
### 将Android系统移植到QCM6125平台 #### 准备工作 为了顺利进行移植操作,需先准备好开发环境。这包括但不限于安装特定版本的JDK(如1.8),以及安装包含gradle、sdk manager和avd manager在内的Android Studio (例如3.3.1)[^3]。 #### 获取源码及相关资源 对于高通平台上的Android 11(R)系统的编译过程涉及多个方面的工作流概述[^1]。针对具体芯片组如QCM6125,则需要访问官方文档和支持渠道来获取适用于该硬件的具体指导说明与必要的补丁集合。通常情况下,可以从Qualcomm开发者网站下载对应的BSP(Baseband Software Package)包和其他支持材料。 #### 修改内核配置 基于rk3566/rk3568的例子,在处理类似的任务时可能涉及到调整kernel设置以适应新的SoC特性。比如增加USB驱动的支持或是其他外设接口的相关改动[^4]。对于QCM6125而言,重点在于确保其特有的通信模块(如调制解调器)能够被正确识别并正常运作。 #### 编写Makefile及构建脚本 当目标是创建自定义的Linux Kernel Module(KM),则要熟悉`obj-m`变量的应用场景——它用于指定哪些文件会被编译成`.ko`形式加载入内存中作为独立于核心部分运行的服务程序[^5]。同样地,在为QCM6125定制化操作系统镜像的过程中也需要编写相应的规则集以便自动化完成整个组装流程。 #### 测试与调试阶段 最后但同样重要的是,利用Espresso框架下的测试库来进行功能验证是非常有帮助的做法之一[^2]。通过这种方式可以有效地捕捉潜在缺陷从而提高最终产品的质量水平。 ```bash # 示例命令行指令用于启动模拟设备上执行单元测试案例 adb shell am instrument -w -r \ -e debug false \ -e class com.example.MyTestClass \ androidx.test.runner.AndroidJUnitRunner ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值