文章目录

    • 1、术语
    • 2、概述
      • 1)资料快车
    • 3、预备工作
      • 1)codec - UDA1340 - 硬件规格
      • 2)ASOC-ALSA代码重点目录介绍
      • 3)ASOC-ALSA层级介绍
      • 4)了解基本的软硬件架构
    • 4、数据结构
    • 5、代码分析
      • 1)Machine
        • 1、总体流程介绍
        • 2、Machine代码流程图
          • 重点介绍
      • 2)Platform_driver
      • 3)codec

1、术语

1、asoc : alsa on chip  //嵌入式平台下的alsa,对ALSA进一步的封装
2、runtime : 记录substream的一些重要软件和硬件运行的环境和参数
3、DAI : Digital Audio Interface
4、component :组件(可以理解为 面向对象 中的对象)
5、SAI : ALSA Soc Digital Audio Interface(SAI)
6、topology : 拓扑
7、dpcm : dynamic pcm
8、BE :Blackend 后端9、mixer的含义? 在不同层级有不同含义?
1)在tinyalsa下 代表设置寄存器control
2)在硬件上和驱动层,代表mixer混合器(codec中的一个部件)10、component : 组件,可以理解为一个音频处理单元(可以是物理设备也可以是虚拟设备)-面向对象中的对象,每个处理单元都有独立的功能和控制接口,比如一个音频解码器、音频放大器、音频均衡器、DMA都是一个组件,组件化可以提高系统代码的模块化程度和可维护性;component是音频系统中的逻辑单元;

2、概述

1)资料快车

1、linux ALSA ASoc架构: https://blog.csdn.net/weixin_45437140/article/details/128637521

2、alsa框架介绍:https://blog.51cto.com/u_93011/8854396 原文(付费):https://blog.csdn.net/RadianceBlau/article/details/79432661

3、官方网站:https://www.alsa-project.org/main/index.php/ASoC

3、预备工作

1、首先要对硬件尽可能熟悉(专业名词、与主控的数据通信方式、芯片内部的部件作用);

2、深入代码前应该先掌握这套架构的设计对象和设计思想,那样我们才能更高的效率去看代码!

1)codec - UDA1340 - 硬件规格

1)功能框图
在这里插入图片描述

2)引脚介绍
在这里插入图片描述

重点介绍:

1、DSP:codec负责音效处理的单元2、codec中的音频路径是指?有哪些?
不同codec不尽相同,比如UDA1340
1)播放路径:CPU -> DATA(I2S) -> DSP -> INTERPOLATION FILTER -> NOISE SHAPER -> DAC -> VOUTL/VOUTR(DAC output left/right)
2)录音路径:VINL/VINR(ADC input left/right) -> ADC -> DC-CANCELATION FILTER -> DATA(I2S) -> CPU

2)ASOC-ALSA代码重点目录介绍

分为两部分
1、根据芯片厂商或平台进行分类,每个文件夹放置相应硬件平台的音频驱动代码
├─adi //Anolog Devices, Inc
├─amd //Advanced Mircro Devices, Inc
├─atmel //爱特梅尔
├─au1x //AMD下的au1x系统处理器
├─bcm //Broadcom
├─cirrus //Cirrus Logic, Inc
├─davinci //TI下的davinci系列处理器
├─dwc //ST Microelectronics下的dwc
├─fsl //飞思卡尔-Freescale,现为NXP
├─hisilicon //海思
├─img //Imagination Technologies Ltd.
├─intel //英特尔
├─jz4740 //杰睦(Ingenic)JZ4740系列处理器
├─kirkwood
├─mediatek //联发科
├─meson //Amlogic Meson系统
├─mxs //Freescale i.MX系列处理器
├─nuc900 //Nuvoton Nuclias系列处理器
├─omap //德州仪器(TI)OMAP系列处理器
├─pxa //Marvell PXA系列处理器
├─qcom //Qualcomm 高通
├─rockchip //瑞芯微
├─samsung //三星
├─sh //renesas(瑞萨 -日本)SH系列处理器
├─sirf //联发科(MediaTek)旗下的联发科数字(Sirf)音频驱动
├─spear //ST下的SPEAr 系列ARM处理器
├─sti //意法半导体(STMicroelectronics)
├─stm //意法半导体
├─sunxi //全志科技(Allwinner)
├─tegra //英伟达(NVIDIA)Tegra系列处理器
├─txx9  //Renesas(瑞萨 -日本) Txx9系列处理器
├─uniphier //富士通(Fujitsu)
├─ux500 //德州仪器(TI)UX500系列处理器
├─xtensa //Tensilica(现为Cadence)
└─zte //中兴
1) 众多的硬件平台,由此可见soc推出必要性,大大降低重复代码和复用
2) 认识以上厂商或芯片是有必要的,在linux代码中不同厂商和架构随处可见
3)Soc相关的驱动无非就是 I2S/PCM/AC97/I2C/SPDIF 通信接口的驱动代码2、通用类和框架类代码
├─generic //audio-graph-card和simple-card驱动代码,不针对特定硬件平台
├─codecs //通用的codecs驱动代码,不针对特定硬件平台
soc-* //asoc框架核心代码实现

3)ASOC-ALSA层级介绍

在这里插入图片描述

1、ASOC-ALSA是根据嵌入式设备特点,在ALSA基础上再封装一层而来,有了ALSA学习基础,这里就更容易学习AOSC-ALSA;

1)ALSA目前主要应用在个人电脑上的声卡,而ASOC针对嵌入式设备(一般为I2S接口设备的功放);

2)可以理解ALSA为通用的音频框架,ASOC-ALSA为专用于嵌入式设备的音频框架,根据需求来选择基于哪个架构来进行开发;

2、ASOC-ALSA解决什么问题?

1)codec驱动与soc cpu的代码过于紧密,导致不同平台有不同的codec驱动,而在嵌入式纷繁复杂的产品中,各种搭配导致代码冗余 ->

解决方法:将这codec和soc独立为单独的驱动;

2)一旦播放和录音时,驱动使能整个codec(有些codec有多路输入和输出),所有部件处于上电状态,但实际上有些部件是没有用到,对于移动设备来说,会十分浪费不必要的电量 -> 解决方法:设计DAPM解决,将各个寄存器按照 场景来划分 组合;

3)音频事件没有标准的方法来通知用户 -> 解决方法:

3、如何写ASOC? >> 开发时写codec端即可,使用ASOC封装好的API构造声卡设备

4)了解基本的软硬件架构

1)一般平台的音频系统硬件架构(高度抽象)
在这里插入图片描述

2)来看一个嵌入式领域的一个具体例子的硬件模型(基本都长这样),接下来以这个例子来进行学习
在这里插入图片描述

1)以pci - als300为例,上述的i2s/i2c/dma/timer驱动都放在android\kernel\fusion\4.19\sound\pci\als300.c 实现,那么如果换个平台,als300.c就需要重写;

2)如何改进?ASOC-ALSA结合硬件框架模型(满足市面上绝大多数的codec)来设计软件架构,让其通用且可复用;ASOC的做法将其组件化(类似面向对象),然后不同平台自行组装,相同的特性 单独抽离出来统一设计,硬件专有的实现 留接口给厂商自行挂接;那么组件(component) 对象可以分为:

1、platform - cpu的DMA

2、platform -cpu的I2S

3、Codec的I2S

4、Codec的I2C

以上均需要单独实现;

3)有面向对象编程的人不难看出linux音频驱动的结构与类图很像,将变化的东西封装了起来,层次清晰,方便理解和调试:

》内核代码是一直在变化,越高版本的Linux内核,逐渐往面向对象的方向发展;

4)设计对象说明 - 概念介绍

1、Machine
是指某一款机器,可以是某款设备,某款开发板,又或者是某款智能手机,由此可以看出每个Machine上的硬件实现可能都不一样,CPU不一样,Codec不一样,音频的输入、输出设备也不一样,Machine为CPU、Codec、输入输出设备提供了一个载体。Machine驱动 Machine驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个放大器);单独的PlatformCodec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。2、Platform
一般是指某一个SoC平台,即CPU,比如pxaxxx,s3cxxxx,omapxxx等等,与音频相关的通常包含该SoC中的时钟、DMA、I2S、PCM等等,只要指定了SoC,那么我们可以认为它会有一个对应的Platform,它只与SoC相关,与Machine无关,这样我们就可以把Platform抽象出来,使得同一款SoC不用做任何的改动,就可以用在不同的Machine中。实际上,把Platform认为是某个SoC更好理解。Platform驱动包含了该SoC平台的音频DMA和音频接口的配置和控制(I2S,PCM,AC97等等);它也不能包含任何与板子或机器相关的代码。3、Codec
字面上的意思就是编解码器,Codec里面包含了I2S接口、D/A、A/D、Mixer、PA(功放),通常包含多种输入(Mic、Line-in、I2S、PCM)和多个输出(耳机、喇叭、听筒,Line-out),Codec和Platform一样,是可重用的部件,同一个Codec可以被不同的Machine使用。嵌入式Codec通常通过I2C对内部的寄存器进行控制。Codec驱动在ASoC中的一个重要设计原则就是要求Codec驱动是平台无关的,它包含了一些音频的控件(Controls),音频接口,DAMP(动态音频电源管理)的定义和某些Codec IO功能。为了保证平台无关性,任何特定于平台和机器的代码都要尽量移到Platform,所有的Codec驱动都要提供以下特性:
Codec DAI 和 PCM的配置信息;
Codec的IO控制方式(I2C,SPI等);
Mixer和其他的音频控件;
Codec的ALSA音频操作接口;必要时,也可以提供以下功能:
DAPM描述信息;
DAPM事件处理程序;
DAC数字静音控制

4、数据结构

整个ASoc是由一系列的数据结构组成(C语言实现的架构大多数如此),理清里面的数据结构就等同掌握ASoc的工作机理

在linux4.19上数据结构如下:
在这里插入图片描述

1、从ASOC-ALSA架构来看,1/2/3区域分别对应如下

在这里插入图片描述

2、linux4.9上使用component概念来代表cpu或codec,根据之前对于组件的分类:

1)4区域对应:platform - cpu的DMA、Codec的I2C (共用同一个结构体)

2)5区域对应:platform -cpu的I2S、Codec的I2S (共用同一个结构体)

3、所有的数据结构通过snd_soc_card作为总源头,把握这个主线索,串联其它的数据结构,其次在初始化时,根据开发者构造的snd_soc_card,找到选定的cpu和codec信息,将driver/ops放在snd_soc_pcm_runtime里(这部分在Machine里面再展开体现)

4、结构体(作用类似对象)对应一个实际的例子(wm8960) 如下
在这里插入图片描述

重点介绍:

1、machine会根据名字去匹配component (即cpu和codec) 对应的driver/dai,并放进snd_soc_pcm_runtime里面2. machine如何指定cpu和codec?
使用snd_soc_dai_link指定当前平台使用的 cpu 和 codec
struct snd_soc_dai_link *dai_link;  /* predefined links only */3、在旧版驱动中ASoC定义了三个全局的链表头变量:codec_list、dai_list、platform_list;linux 4.19在哪里?
均在snd_soc_pcm_runtime上体现
struct snd_soc_pcm_runtime {struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai;  //一个平台一般只有一个cpu struct snd_soc_dai **codec_dais; //挂接多个codec dai,一个平台或有多个codec,对应dai_listunsigned int num_codecs;struct list_head component_list; //匹配platform_name,对应platform_list 
}4、总体而言,ASoC软件框架分为3部分:
a. platform (用来描述芯片的DAI接口、负责数据传输):DAI: snd_soc_dai_driver, 用来表示支持哪些格式数据, 提供设置格式的函数, 启动数据传输数据传输: snd_soc_component_driverb. codec (用来描述音频编解码芯片, 含有2部分: DAI接口、控制接口):DAI: snd_soc_dai_driver, 用来表示支持哪些格式数据, 提供设置格式的函数, 控制接口: snd_soc_component_driver读写芯片的寄存器c. machine (snd_soc_card, snd_soc_dai_link,用来确定使用哪一个platform, 哪一个codec芯片)最能调用ALSA接口进行分配/设置/注册 snd_card

5、代码分析

1)Machine

1、总体流程介绍
1、Machine代码示例(命名规则一般为:平台/芯片_codec)
1)android\kernel\fusion\4.19\sound\soc\samsung\rx1950_uda1380.c
//rx1950_uda1380.c命名解析:rx1950开发板_uda1380是codec音频芯片
2)android\kernel\fusion\4.19\sound\soc\samsung\smdk_wm8994.c
3)android\kernel\fusion\4.19\sound\soc\samsung\s3c24xx_uda134x.c
//s3c24xx 三星CPU + uda134x Philips codec
采用s3c24xx_uda134x.c作为主要的介绍(例子应该尽可能简单些,才更好地掌握框架内容,然后再由易及难,循序渐进)一、Machine
1.旧驱动写法
1)platform driver
module_init(rx1950_init);
static int __init rx1950_init(void){1. platform_device_alloc会触发soc-core.c里的同名platform_driver,最终调用snd_soc_register_card完成声卡的创建注册s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); 
}
2)对应的platform device
android\kernel\fusion\4.19\sound\soc\soc-core.c
/* ASoC platform driver */
static struct platform_driver soc_driver = {.driver		= {.name		= "soc-audio",.pm		= &snd_soc_pm_ops,},.probe		= soc_probe,.remove		= soc_remove,
};static int soc_probe(struct platform_deivce *pdev)
{snd_soc_register_card(card); //将Machine驱动的配置注册到ASOC的核心,触发Codec和platform driver的初始化
}2.较新的驱动里使用devm_snd_soc_register_card完成声卡的创建注册
static int s3c24xx_uda134x_probe(struct platform_device *pdev)
{struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;struct s3c24xx_uda134x *priv;priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);card->dev = &pdev->dev;snd_soc_card_set_drvdata(card, priv);ret = devm_snd_soc_register_card(&pdev->dev, card);
}int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card)
{struct snd_soc_card **ptr;1.将release挂到card里面去devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL);2.注册soc cardsnd_soc_register_card(card);3.添加到dev res里统一管理devres_add(dev, ptr);
}
EXPORT_SYMBOL_GPL(devm_snd_soc_register_card);使用devres_alloc() / devres_add()管理声卡资源,在设备卸载时自动注销声卡,简化驱动代码,降低泄漏资源的风险3.指定platform和codec
1)snd_soc_card (Machine所对应的数据结构体)
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {.name = "S3C24XX_UDA134X",.owner = THIS_MODULE,.dai_link = &s3c24xx_uda134x_dai_link,.num_links = 1,
};2)snd_soc_dai_link参数详细说明
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {.name = "UDA134X",.stream_name = "UDA134X",.codec_name = "uda134x-codec", //1.对应platform_driver uda134x_codec_driver()- 控制接口(uda134×使用的是L3接口).codec_dai_name = "uda134x-hifi",  //2.对应snd_soc_dai_driver uda134x_dai() - 数据传输.cpu_dai_name = "s3c24xx-iis",   //3. 对应platform_driver s3c24xx_iis_driver() - soc端的I2S驱动.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBS_CFS,.ops = &s3c24xx_uda134x_ops,.platform_name	= "s3c24xx-iis", //4.对应platform_driver s3c24xx_iis_driver()- 使用soc的哪个部件来传送音频数据,这个是可选的,预留给需要更多部件操作的soc填充;这里其实是需要用到dma,s3c24xx-iis里面封装了dma相关操作(如果还需要初始化更多soc部件,比如timer,也可以放这里去进行初始化),所以填s3c24xx-iis
};static const struct snd_soc_ops s3c24xx_uda134x_ops = {.startup = s3c24xx_uda134x_startup,.shutdown = s3c24xx_uda134x_shutdown,.hw_params = s3c24xx_uda134x_hw_params, //初始化platform端的硬件-这里主要是设置cpu端的I2S时钟
};小结:
1)由于machine代码涉及数据的匹配,C语言代码实现起来是相当复杂的(用C语言实现面向对象),这块需要好好啃下!
2)snd_soc_dai_link中填充platform、cpu dai、codec、codec_dai,稍后Machine驱动将会利用这些名字去匹配已经在系统中注册的platform,codec,dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义的,这样看来,Machine驱动的设备初始化代码无非就是选择Platform和Codec以及dai
2、Machine代码流程图

在这里插入图片描述

重点介绍
总入口函数devm_snd_soc_register_card,基本所有核心操作均在此函数实现1、
int snd_soc_register_card(struct snd_soc_card *card){1.检查link是否都设置了soc_init_dai_link(card, link); 2.初始化card里面的链表widgets/paths/dapm_list/aux_comp_list/component_dev_listsnd_soc_initialize_card_lists(card);INIT_LIST_HEAD(&card->dai_link_list); //dai_link listINIT_LIST_HEAD(&card->rtd_list); //rtd(runtime) list3.实例化card,将里面的设置的platform/codec等,根据name去其它驱动里面找出合适的驱动或实例,挂到card结构体里面snd_soc_instantiate_card(card);
}2、
snd_soc_instantiate_card()
{1. 找到cpu/codec的component -> pcm_runtime -> cardsoc_bind_dai_link(card, &card->dai_link[i]);soc_new_pcm_runtime(card, dai_link); //构造runtimesnd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); //将cpu_dai component挂到rtd中去snd_soc_rtdcom_add(rtd, codec_dais[i]->component); //将codec_dais component挂到rtd中去snd_soc_rtdcom_add(rtd, component);/ /将platform component挂到rtd中去soc_add_pcm_runtime(card, rtd); //然后挂到card->rtd_list上2. 使用构造好的card,调用ALSA接口创建alsa cardsnd_card_new()3.执行各个snd_soc_component_driver的probesoc_probe_link_components(card, rtd, order);--soc_probe_component(card, component);----component->driver->probe(component); //调用各个snd_soc_component_driver *driver的probe4.执行各个snd_soc_dai的probesoc_probe_link_dais(card, rtd, order);--soc_probe_dai(cpu_dai, order); //cpu dai probe--soc_probe_dai(rtd->codec_dais[i], order); //codec dai probe5.调用ALSA接口注册声卡snd_card_register(card->snd_card);
}

2)Platform_driver

1、s3c24xx_uda134x.c对应的Platform代码位置
android\kernel\fusion\4.19\sound\soc\samsung\s3c24xx-i2s.c2、Platform要实现以下:
1)实现数据传输 - I2S(传数据给codec);
2)platform数据处理 - 一般是将用户空间传下来的数据保存在DMA,然后启动I2S,取出DMA数据发送给codec;3、代码介绍
static struct platform_driver s3c24xx_iis_driver = {.probe  = s3c24xx_iis_dev_probe,.driver = {.name = "s3c24xx-iis",},
};
module_platform_driver(s3c24xx_iis_driver);static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
{1. ioremaps3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res);2. dmasamsung_asoc_dma_platform_register(&pdev->dev, NULL, NULL, NULL);3.注册 snd_soc_component_driver(s3c24xx_i2s_component - 一般是dma) 和 snd_soc_dai_driver (s3c24xx_i2s_dai - i2s),挂接到snd_soc_component中去devm_snd_soc_register_component(&pdev->dev,&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
}2、两类driver的实现
1)platform数据处理 -dma
static const struct snd_soc_component_driver s3c24xx_i2s_component = {.name		= "s3c24xx-i2s", //这里是空的实现,因为新版本驱动把dma挪到i2s下
};2)数据传输dai -I2S
static struct snd_soc_dai_driver s3c24xx_i2s_dai = {.probe = s3c24xx_i2s_probe,.suspend = s3c24xx_i2s_suspend,.resume = s3c24xx_i2s_resume,.playback = {  //描述playback的能力.channels_min = 2,.channels_max = 2,.rates = S3C24XX_I2S_RATES,.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},.capture = {  //描述capture的能力.channels_min = 2,.channels_max = 2,.rates = S3C24XX_I2S_RATES,.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},.ops = &s3c24xx_i2s_dai_ops, //capture和playback对应的ops
};static const struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {.trigger	= s3c24xx_i2s_trigger, //启动数据传输.hw_params	= s3c24xx_i2s_hw_params, //设置硬件参数.set_fmt	= s3c24xx_i2s_set_fmt,.set_clkdiv	= s3c24xx_i2s_set_clkdiv,.set_sysclk	= s3c24xx_i2s_set_sysclk,
};2、s3c24xx_i2s_hw_params设置硬件参数
static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params,struct snd_soc_dai *dai)
{struct snd_dmaengine_dai_dma_data *dma_data;dma_data = snd_soc_dai_get_dma_data(dai, substream);writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
}

3)codec

1、s3c24xx_uda134x.c对应的codec代码位置:
android\kernel\fusion\4.19\sound\soc\codecs\uda134x.c2、codec要实现什么功能?
1)DAI接口的操作;- I2S (传录音数据给CPU) 谁来控制?
2)控制接口的操作;- I2C/L33、代码介绍
codec的probe
static int uda134x_codec_probe(struct platform_device *pdev)
{1. 使用regmap来read/write寄存器,linux3.1引进的操作寄存器接口struct uda134x_priv *uda134x;uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, &uda134x_regmap_config);2.注册snd_soc_component_driver(soc_component_dev_uda134x - L3) 和 snd_soc_dai_driver(uda134x_dai - I2S),,挂接到snd_soc_component中去return devm_snd_soc_register_component(&pdev->dev,&soc_component_dev_uda134x, &uda134x_dai, 1);
}static const struct regmap_config uda134x_regmap_config = {.reg_bits = 8,.val_bits = 8,.max_register = UDA134X_DATA1,.reg_defaults = uda134x_reg_defaults,.num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),.cache_type = REGCACHE_RBTREE,.reg_write = uda134x_regmap_write, //寄存器的读写
};2、两类driver的实现
1)一个是dai (I2S)-数据
static struct snd_soc_dai_driver uda134x_dai = {.name = "uda134x-hifi",/* playback capabilities */.playback = {.stream_name = "Playback",.channels_min = 1,.channels_max = 2,.rates = UDA134X_RATES,.formats = UDA134X_FORMATS,},/* capture capabilities */.capture = {.stream_name = "Capture",.channels_min = 1,.channels_max = 2,.rates = UDA134X_RATES,.formats = UDA134X_FORMATS,},/* pcm operations */.ops = &uda134x_dai_ops,
};static const struct snd_soc_dai_ops uda134x_dai_ops = {.startup	= uda134x_startup,.shutdown	= uda134x_shutdown,.hw_params	= uda134x_hw_params,.digital_mute	= uda134x_mute,.set_sysclk	= uda134x_set_dai_sysclk,.set_fmt	= uda134x_set_dai_fmt,
};2)一个是codec(L3)-控制
为啥是放在codec里面实现?L3跟codec走,不是跟platform-CPU走,理论上应该与codec一起走
static const struct snd_soc_component_driver soc_component_dev_uda134x = {.probe			= uda134x_soc_probe,.set_bias_level		= uda134x_set_bias_level,.dapm_widgets		= uda134x_dapm_widgets,.num_dapm_widgets	= ARRAY_SIZE(uda134x_dapm_widgets),.dapm_routes		= uda134x_dapm_routes,.num_dapm_routes	= ARRAY_SIZE(uda134x_dapm_routes),.suspend_bias_off	= 1,.idle_bias_on		= 1,.use_pmdown_time	= 1,.endianness		= 1,.non_legacy_dai_naming	= 1,
};
使用DAPM/widgets/routes/kcontrol这套框架来进行控制,DAPM相关后续单独介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/911791.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/911791.shtml
英文地址,请注明出处:http://en.pswp.cn/news/911791.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零基础入门Java+大模型(持续更新)

0.初始一些常见的概念 AI:人工智能 大模型划分:(本章了解一下这个就行)NLP模型-->自然语言模型(AI现在爆火的原因,就是自然语言模型这一块取得了很大的成就)。 LLM:大语言模型…

数据库系统总结

数据库系统概述 数据库系统(Database System, DBS)是用于高效管理、存储和检索数据的软件系统。 数据库系统的组成包括:数据库、硬件、软件、人员。 三级模式-两级映像 内模式:管理如何存储物理的数据,对数据的存储…

2026-软件工程-《软件质量测试与保证》-期末复习—习题汇总

题量: 20 满分: 100 作答时间:06-04 17:30至06-22 23:59 智能分析 80分 一. 单选题(共10题,50分) (单选题)白盒测试设计测试用例的依据是( )。 A. 代码逻辑结构 B. 代码注释说明 C. 需求规格说明书 D. 用户使用场景 我的答案:A:代码逻辑结构…

量化面试绿皮书:35. 蒙蒂霍尔问题

文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。 35. 蒙蒂霍尔问题 蒙提霍尔问题是一个基于美国老电视节目《让我们做个交易》的概率谜题,该问题以该节目的主持人命名。假设你现在…

如何防范 SQL 注入攻击以及SQL 注入防范技巧

在互联网高度发展的时代,网络安全问题日益突出,SQL 注入攻击成为众多网站和应用程序面临的严重威胁之一。本文将详细介绍如何防范 SQL 注入攻击,通过多个关键方面的详细阐述,帮助开发者和网站管理者构建更安全的网络环境&#xff…

k8s从入门到放弃之数据存储

k8s从入门到放弃之数据存储 在Kubernetes中,数据存储主要通过持久卷(Persistent Volumes, PVs)和持久卷声明(Persistent Volume Claims, PVCs)机制来实现。这种设计允许存储与计算分离,使得容器可以根据需…

用户体验驱动的3D设计:从功能实现到情感共鸣的设计升级

你有没有想过: 为什么有些产品看起来“平平无奇”,却能赢得用户喜爱?同样是3D建模,为什么有些人做的模型总让人觉得“有温度”?设计师只是关注功能和结构就够了吗?还是应该让作品“打动人心”?…

【图床配置记录】——pigo+gitee+typroa

记录一下安装的过程 基本上blog1可以解决 blog1 但是如果pigo上面没有gitee 或者下载gitee没啥反应 手动安装,在c:/用户/用户名/AppData/Roaming/picgo这个目录下,以管理员身份打开powershell(或cmd; 文件——以管理员打开ps——输入npm in…

Python问题汇总(发个库存)

常见问题: 文章目录 IDE与1.如何注释2.python运行代码后没有输出,但无报错,有exit code 0标志3.导入txt文件,但是出现错误:UnicodeDecodeError: gbk codec cant decode byte 0x80 in position 205: illegal multibyte…

Java课后习题(编程题)

第一题&#xff1a; import java.util.Scanner;class Test {public static void main(String args[]) {Scanner scnew Scanner(System.in);System.out.println("请输入一个x值&#xff1a;");int xsc.nextInt();int y0;if(x>0){y3*x-1;}else if(x<0){y2*x-1;}e…

Spring--spring事务在什么情况下会失效,以及对应的解决方案

前言 一般失效是使用了Transaction注解的情况下&#xff0c;这篇博客就带你详解一下&#xff0c;哪些情况下注解会失效&#xff0c;在开发过程中要避免这些问题和可以及时发现这些问题&#xff0c;并且知道如何去规避和解决 一、Spring事务的基本原理 在深入了解事务失效的场…

在智慧教育行业中,OPS插拔式电脑启到什么作用

在全球数字化浪潮的推动下&#xff0c;教育行业正经历前所未有的深刻变革。目前&#xff0c;智慧校园已不再是简单的信息化升级&#xff0c;而是涵盖AI、云计算、大数据、物联网等技术的系统性创新。而作为智慧教育发展的助手之一——国产OPS插拔式电脑&#xff0c;能助力传统教…

Windows 配置 Qt 环境变量全指南

Windows 配置 Qt 环境变量全指南 适用于 Qt 5.x / 6.x, MSVC / MinGW, Qt Creator / CLion / CMake GUI 等环境 一. 为什么需要配置 Qt 环境变量 Qt 是一个跨平台 C 开发框架&#xff0c;包含 GUI、网络、SQL、多媒体等模块&#xff0c;安装后自带丰富工具链&#xff0c;如&am…

SpringBoot项目快速开发框架JeecgBoot——项目简介及系统架构!

项目简介及系统架构 Jeecg Boot是一款基于Spring Boot的开发平台&#xff0c;它采用前后端分离架构&#xff0c;集成的框架有Spring Boot 2.x、Spring Cloud、Ant Design of Vue、Mybatis-plus、Shiro和JWT&#xff0c;而且它支持微服务开发。Jeecg Boot还有强大的代码生成功能…

工业设计软件的范式革命:对象模型与五维市场驱动的未来

工业设计软件的技术洗牌本质 破局关键:万物对象模型的应用 工业设计的对象化重构 class IndustrialDesignObject:def __init__(self, obj_type, attributes):self.metadata = {"type": obj_type,"version": "1.0","entropy_rating"…

VMware 安装Windows 虚拟机,Windows 虚拟机可 ping 通本地电脑,但本地电脑无法 ping 通虚拟机 IP 的解决思路和操作步骤

VMware 安装Windows 虚拟机&#xff0c;Windows 虚拟机可 ping 通本地电脑&#xff0c;但本地电脑无法 ping 通虚拟机 IP 的问题如下图所示&#xff1a; 解决办法&#xff1a; 一、网络连接模式与网段一致性 确认虚拟机网络模式 若用 VMware 等软件&#xff0c;常见模式有 NA…

高精度RTK定位导航模块软硬件协同设计

高精度RTK定位导航模块软硬件协同设计 下载链接:摘要1.1 RTK技术背景与发展现状1.1.1 RTK技术原理与背景1.1.2 技术发展里程碑1.1.3 当前技术挑战与突破1.1.4 应用场景扩展1.1.5 标准化进展1.2.1 高精度定位的计算瓶颈1.2.2 功耗优化需求1.2.3 系统可靠性与实时性保障1.2.4 典型…

【软考高级系统架构论文】论多源数据集成及应用

论文真题 在如今信息爆炸的时代,企业、组织和个人面临着大量的数据。这些数据来自不同的渠道和资源,包括传感器、社交媒体、销售记录等,它们各自具有不同的数据格式、分布和存储方式。因此如何收集、整理和清洗数据,以建立一个一致、完整的数据集尤为重要。多源数据集成可…

如何将这些 SQL 插入语句批量执行?

要批量执行这些SQL插入语句&#xff0c;可根据使用的数据库管理系统(DBMS)选择不同的方法。以下是几种常见的批量执行方式&#xff1a; 1. 使用数据库客户端工具 MySQL / MariaDB 命令行&#xff1a;将所有SQL语句保存到文件(如cities.sql)&#xff0c;然后执行&#xff1a; 登…

RedisVL EmbeddingsCache深度实践与最佳指南

一、为什么需要 EmbeddingsCache 减少重复计算 对同一段文本&#xff0c;向量化模型会每次返回相同的嵌入。借助缓存&#xff0c;首次计算后无论后续何时再请求&#xff0c;都能直接复用上次结果。 降低业务延迟 嵌入模型推理耗时&#xff08;数十毫秒到百毫秒不等&#xff09…