SM8150 Audio驱动分析

1. TDM硬件接口介绍:

I2S只能传2个声道的数据,PCM可以传多达16路数据,采用时分复用的方式,就是TDM。

TDM不像I2S有统一的标准,不同的IC厂商在应用TDM时可能略有差异,这些差异表现在时钟的极性、声道配置的触发条件和对闲置声道的处理等。

特点

  • 比I2S节省管脚数量
  • 支持多路传输
  • 最多支持16路=16通道

TDM系统框图:

https://www.crifan.com/files/pic/uploads/2019/04/6eaf631a6d6ca321b7505485961182c1.png

 2. Kernel Dtsi 配置

参考:Documentation/devicetree/bindings/sound/qcom-audio-dev.txt

sa8155-audio.dtsi :

/*TDM Pri组RX端口组配置*/
tdm_pri_rx: qcom,msm-dai-tdm-pri-rx {
     /*匹配节点,驱动和设备的compatible属性相同时,才会调用probe函数。*/
    compatible = "qcom,msm-dai-tdm";
    /*TDM 群组ID:
    支持列表如下:
        Primary RX: 	37120
        Primary TX: 	37121
        Secondary RX: 	37136
        Secondary TX: 	37137
        Tertiary RX: 	37152
        Tertiary TX: 	37153
        Quaternary RX: 	37168
        Quaternary TX: 	37169
    */
    qcom,msm-cpudai-tdm-group-id = <37120>;
    /*端口数,最大支持端口数量为8*/
    qcom,msm-cpudai-tdm-group-num-ports = <4>;
    /*TDM端口ID数组,数组的大小由msm-cpudai-tdm-group-num-ports 中的值决定。每组最多支持 8 个端口:
        Primary RX: 	36864, 36866, 36868, 36870,
                        36872, 36874, 36876, 36878
        Primary TX: 	36865, 36867, 36869, 36871,
                        36873, 36875, 36877, 36879
        Secondary RX: 	36880, 36882, 36884, 36886,
                        36888, 36890, 36892, 36894
        Secondary TX:	36881, 36883, 36885, 36887,
                        36889, 36891, 36893, 36895
        Tertiary RX: 	36896, 36898, 36900, 36902,
                        36904, 36906, 36908, 36910
        Tertiary TX: 	36897, 36899, 36901, 36903,
                        36905, 36907, 36909, 36911
        Quaternary RX:	36912, 36914, 36916, 36918,
                        36920, 36922, 36924, 36926
        Quaternary TX:	36913, 36915, 36917, 36919,
                        36921, 36923, 36925, 36927
    */
    qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>;
    /*TDM时钟速率,设置为0说明使用外部时钟*/
    qcom,msm-cpudai-tdm-clk-rate = <12288000>;
    /*时钟源。
        0 -  EBIT 时钟
        1 -  IBIT 时钟
    */
    qcom,msm-cpudai-tdm-clk-internal = <1>;
    /*同步设置。
        0 - 短同步位模式
        1 - 长同步模式
        2 - 短同步槽模式
    */
    qcom,msm-cpudai-tdm-sync-mode = <0>;
    /*同步源。
        0 - 外部源
        1 - 内部来源 
    */
    qcom,msm-cpudai-tdm-sync-src = <1>;
    /*其他主机驱动的数据输出。
        0 - 禁用
        1 - 启用
    */
    qcom,msm-cpudai-tdm-data-out = <0>;
    /*反转同步。
        0 - 正常
        1 - 反转
    */
    qcom,msm-cpudai-tdm-invert-sync = <0>;
    /*相对于同步边沿延迟数据的位时钟数。
        0 - 0 位时钟周期
        1 - 1 位时钟周期
        2 - 2 位时钟周期
    */
    qcom,msm-cpudai-tdm-data-delay = <1>;
    /*TDM CLK 属性配置*/
    qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
    /*TDM RX端口配置,几路端口由msm-cpudai-tdm-group-num-ports 中的值决定
    msm-cpudai-tdm-dev-id 由 msm-cpudai-tdm-group-port-id 端口ID数组决定
    */
    dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36864>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };

    dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36866>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };

    dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36868>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };

    dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36870>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };
};

/*TDM Pri组TX端口组配置*/
tdm_pri_tx: qcom,msm-dai-tdm-pri-tx {
    /*匹配节点,驱动和设备的compatible属性相同时,才会调用probe函数。*/
    compatible = "qcom,msm-dai-tdm";
    qcom,msm-cpudai-tdm-group-id = <37121>;
    qcom,msm-cpudai-tdm-group-num-ports = <4>;
    qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>;
    qcom,msm-cpudai-tdm-clk-rate = <12288000>;
    qcom,msm-cpudai-tdm-clk-internal = <1>;
    qcom,msm-cpudai-tdm-sync-mode = <0>;
    qcom,msm-cpudai-tdm-sync-src = <1>;
    qcom,msm-cpudai-tdm-data-out = <0>;
    qcom,msm-cpudai-tdm-invert-sync = <0>;
    qcom,msm-cpudai-tdm-data-delay = <1>;
    qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
    dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36865>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };

    dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36867>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };

    dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36869>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };

    dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36871>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };
};

3. Kernel Driver:

 3.1 tdm驱动(audio front-end (AFE) port 端):kernel/techpack/audio/asoc/msm-dai-q6-v2.c

/*
DTM设备驱动,匹配dtsi中 dtm组端口的
tdm_pri_rx: qcom,msm-dai-tdm-pri-rx {
    compatible = "qcom,msm-dai-tdm";
    ...
    dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
        compatible = "qcom,msm-dai-q6-tdm";
        qcom,msm-cpudai-tdm-dev-id = <36864>;
        qcom,msm-cpudai-tdm-data-align = <0>;
    };
    ...
};
*/
static const struct of_device_id msm_dai_q6_tdm_dev_dt_match[] = {
	{ .compatible = "qcom,msm-dai-q6-tdm", },
	{}
};

MODULE_DEVICE_TABLE(of, msm_dai_q6_tdm_dev_dt_match);

static struct platform_driver msm_dai_q6_tdm_driver = {
	.probe  = msm_dai_q6_tdm_dev_probe,
	.remove  = msm_dai_q6_tdm_dev_remove,
	.driver = {
		.name = "msm-dai-q6-tdm",
		.owner = THIS_MODULE,
		.of_match_table = msm_dai_q6_tdm_dev_dt_match,
	},
};

/*DTM驱动*/
static const struct of_device_id msm_dai_tdm_dt_match[] = {
	{ .compatible = "qcom,msm-dai-tdm", },
	{}
};

MODULE_DEVICE_TABLE(of, msm_dai_tdm_dt_match);

static struct platform_driver msm_dai_tdm_q6 = {
	.probe  = msm_dai_tdm_q6_probe,
	.remove = msm_dai_tdm_q6_remove,
	.driver = {
		.name = "msm-dai-tdm",
		.owner = THIS_MODULE,
		.of_match_table = msm_dai_tdm_dt_match,
	},
};

/*DTM 设备驱动注册*/
rc = platform_driver_register(&msm_dai_q6_tdm_driver);
if (rc) {
    pr_err("%s: fail to register dai TDM dev drv\n", __func__);
    goto dai_q6_tdm_drv_fail;
}
/*DTM驱动注册*/
rc = platform_driver_register(&msm_dai_tdm_q6);
if (rc) {
    pr_err("%s: fail to register dai TDM\n", __func__);
    goto dai_tdm_q6_fail;
}

3.2 声卡驱动(audio back-end (ABE) port 端):kernel/techpack/audio/asoc/sa8155.c

目的:用户态驱动,注册PCM声卡,给User空间调用。

具体详情,请看Linux alsa声卡驱动模型。

/*后端Dai Link 链路配置
  后端 <---> DSP/CODEC <---> DAC/ADC <---> SPK/MIC
*/
static struct snd_soc_dai_link msm_auto_be_dai_links[] = {
	/* Backend DAI Links */
	{
		.name = LPASS_BE_PRI_TDM_RX_1,
		.stream_name = "Primary TDM1 Playback", //名称(播放流)
		.cpu_dai_name = "msm-dai-q6-tdm.36866", //查询DTSI可以查到该dtm设备id
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-rx",
		.no_pcm = 1,
		.dpcm_playback = 1,
		.id = MSM_BACKEND_DAI_PRI_TDM_RX_1,//根据dtsi tdm设备组ID(36866)配置
		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
		.ops = &sa8155_tdm_be_ops,
		.ignore_suspend = 1,
	},
	{
		.name = LPASS_BE_PRI_TDM_RX_2,
		.stream_name = "Primary TDM2 Playback",
		.cpu_dai_name = "msm-dai-q6-tdm.36868",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-rx",
		.no_pcm = 1,
		.dpcm_playback = 1,
		.id = MSM_BACKEND_DAI_PRI_TDM_RX_2,
		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
		.ops = &sa8155_tdm_be_ops,
		.ignore_suspend = 1,
	},

ABE snd_soc_dai_link 如何与 AFE的 snd_soc_dai_driver 关联?

  •  Stream Name关联 
  •  CPU dai name 关联 

 

易混技术点:DPCM (Dynamic PCM)

                     DAPM (Dynamic Audio Power Manager)

Alsa驱动模型参考:

Audio System 三 之 Linux ALSA音频系统分析_|~~~热爱生活、努力学习的小伙汁~~~|-CSDN博客

Linux音频子系统

Linux ALSA | Lucky Boy

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村里小码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值