msm audio machine 代码跟踪
sound/soc/msm/msm8952.c
// 注册平台设备
static int __init msm8952_machine_init(void)
{
return platform_driver_register(&msm8952_asoc_machine_driver);
}
late_initcall(msm8952_machine_init);
// 驱动和设备的匹配表
static const struct of_device_id msm8952_asoc_machine_of_match[] = {
{ .compatible = "qcom,msm8952-audio-codec", },
{},
};
static struct platform_driver msm8952_asoc_machine_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = msm8952_asoc_machine_of_match,
},
.probe = msm8952_asoc_machine_probe,
.remove = msm8952_asoc_machine_remove,
};
static int msm8952_asoc_machine_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
struct msm8916_asoc_mach_data *pdata = NULL;
const char *hs_micbias_type = "qcom,msm-hs-micbias-type";
const char *ext_pa = "qcom,msm-ext-pa";
const char *mclk = "qcom,msm-mclk-freq";
const char *wsa = "asoc-wsa-codec-names";
const char *wsa_prefix = "asoc-wsa-codec-prefixes";
const char *type = NULL;
const char *ext_pa_str = NULL;
const char *wsa_str = NULL;
const char *wsa_prefix_str = NULL;
int num_strings;
int ret, id, i, val;
struct resource *muxsel;
char *temp_str = NULL;
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct msm8916_asoc_mach_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"csr_gp_io_mux_mic_ctl");
if (!muxsel) {
dev_err(&pdev->dev, "MUX addr invalid for MI2S\n");
ret = -ENODEV;
goto err1;
}
pdata->vaddr_gpio_mux_mic_ctl =
ioremap(muxsel->start, resource_size(muxsel));
if (pdata->vaddr_gpio_mux_mic_ctl == NULL) {
pr_err("%s ioremap failure for muxsel virt addr\n",
__func__);
ret = -ENOMEM;
goto err1;
}
muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"csr_gp_io_mux_spkr_ctl");
if (!muxsel) {
dev_err(&pdev->dev, "MUX addr invalid for MI2S\n");
ret = -ENODEV;
goto err;
}
pdata->vaddr_gpio_mux_spkr_ctl =
ioremap(muxsel->start, resource_size(muxsel));
if (pdata->vaddr_gpio_mux_spkr_ctl == NULL) {
pr_err("%s ioremap failure for muxsel virt addr\n",
__func__);
ret = -ENOMEM;
goto err;
}
muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel");
if (!muxsel) {
dev_err(&pdev->dev, "MUX addr invalid for MI2S\n");
ret = -ENODEV;
goto err;
}
pdata->vaddr_gpio_mux_pcm_ctl =
ioremap(muxsel->start, resource_size(muxsel));
if (pdata->vaddr_gpio_mux_pcm_ctl == NULL) {
pr_err("%s ioremap failure for muxsel virt addr\n",
__func__);
ret = -ENOMEM;
goto err;
}
muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"csr_gp_io_mux_quin_ctl");
if (!muxsel) {
dev_dbg(&pdev->dev, "MUX addr invalid for MI2S\n");
goto parse_mclk_freq;
}
pdata->vaddr_gpio_mux_quin_ctl =
ioremap(muxsel->start, resource_size(muxsel));
if (pdata->vaddr_gpio_mux_quin_ctl == NULL) {
pr_err("%s ioremap failure for muxsel virt addr\n",
__func__);
ret = -ENOMEM;
goto err;
}
parse_mclk_freq:
// 获取时钟
ret = of_property_read_u32(pdev->dev.of_node, mclk, &id);
if (ret) {
dev_err(&pdev->dev,
"%s: missing %s in dt node\n", __func__, mclk);
id = DEFAULT_MCLK_RATE;
}
pdata->mclk_freq = id;
/*reading the gpio configurations from dtsi file*/
ret = msm_gpioset_initialize(CLIENT_WCD_INT, &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev,
"%s: error reading dtsi files%d\n", __func__, ret);
goto err;
}
num_strings = of_property_count_strings(pdev->dev.of_node,
wsa);
if (num_strings > 0) {
if (wsa881x_get_probing_count() < 2) {
ret = -EPROBE_DEFER;
goto err;
} else if (wsa881x_get_presence_count() == num_strings) {
bear_card.aux_dev = msm8952_aux_dev;
bear_card.num_aux_devs = num_strings;
bear_card.codec_conf = msm8952_codec_conf;
bear_card.num_configs = num_strings;
for (i = 0; i < num_strings; i++) {
ret = of_property_read_string_index(
pdev->dev.of_node, wsa,
i, &wsa_str);
if (ret) {
dev_err(&pdev->dev,
"%s:of read string %s i %d error %d\n",
__func__, wsa, i, ret);
goto err;
}
temp_str = kstrdup(wsa_str, GFP_KERNEL);
if (!temp_str) {
ret = -ENOMEM;
goto err;
}
msm8952_aux_dev[i].codec_name = temp_str;
temp_str = NULL;
temp_str = kstrdup(wsa_str, GFP_KERNEL);
if (!temp_str) {
ret = -ENOMEM;
goto err;
}
msm8952_codec_conf[i].dev_name = temp_str;
temp_str = NULL;
ret = of_property_read_string_index(
pdev->dev.of_node, wsa_prefix,
i, &wsa_prefix_str);
if (ret) {
dev_err(&pdev->dev,
"%s:of read string %s i %d error %d\n",
__func__, wsa_prefix, i, ret);
goto err;
}
temp_str = kstrdup(wsa_prefix_str, GFP_KERNEL);
if (!temp_str) {
ret = -ENOMEM;
goto err;
}
msm8952_codec_conf[i].name_prefix = temp_str;
temp_str = NULL;
}
ret = msm8952_init_wsa_switch_supply(pdev, pdata);
if (ret < 0) {
pr_err("%s: failed to init wsa_switch vdd supply %d\n",
__func__, ret);
goto err;
}
wsa881x_set_mclk_callback(msm8952_enable_wsa_mclk);
/* update the internal speaker boost usage */
msm8x16_update_int_spk_boost(false);
}
}
// 获取dai_links
card = msm8952_populate_sndcard_dailinks(&pdev->dev);
dev_info(&pdev->dev, "default codec configured\n");
num_strings = of_property_count_strings(pdev->dev.of_node,
ext_pa);
if (num_strings < 0) {
dev_err(&pdev->dev,
"%s: missing %s in dt node or length is incorrect\n",
__func__, ext_pa);
goto err;
}
for (i = 0; i < num_strings; i++) {
ret = of_property_read_string_index(pdev->dev.of_node,
ext_pa, i, &ext_pa_str);
if (ret) {
dev_err(&pdev->dev, "%s:of read string %s i %d error %d\n",
__func__, ext_pa, i, ret);
goto err;
}
if (!strcmp(ext_pa_str, "primary"))
pdata->ext_pa = (pdata->ext_pa | PRI_MI2S_ID);
else if (!strcmp(ext_pa_str, "secondary"))
pdata->ext_pa = (pdata->ext_pa | SEC_MI2S_ID);
else if (!strcmp(ext_pa_str, "tertiary"))
pdata->ext_pa = (pdata->ext_pa | TER_MI2S_ID);
else if (!strcmp(ext_pa_str, "quaternary"))
pdata->ext_pa = (pdata->ext_pa | QUAT_MI2S_ID);
else if (!strcmp(ext_pa_str, "quinary"))
pdata->ext_pa = (pdata->ext_pa | QUIN_MI2S_ID);
}
pr_debug("%s: ext_pa = %d\n", __func__, pdata->ext_pa);
ret = is_us_eu_switch_gpio_support(pdev, pdata);
if (ret < 0) {
pr_err("%s: failed to is_us_eu_switch_gpio_support %d\n",
__func__, ret);
goto err;
}
ret = is_ext_spk_gpio_support(pdev, pdata);
if (ret < 0)
pr_err("%s: doesn't support external speaker pa\n",
__func__);
get_dev_by_boardid(model_name);
if(0 == strcmp(model_name,"eda71")){
enable_aw8738 = of_property_read_bool(pdev->dev.of_node , "action,enable-aw8738");
if(enable_aw8738)
{
gpio_request(pdata->spk_ext_pa_gpio, "AW8738_EN");
gpio_direction_output(pdata->spk_ext_pa_gpio,0);
}
}
//printk("enable_aw8738:%d model_name:%s.\n",enable_aw8738,model_name);
// 查看micbias类型
ret = of_property_read_string(pdev->dev.of_node,
hs_micbias_type, &type);
if (ret) {
dev_err(&pdev->dev, "%s: missing %s in dt node\n",
__func__, hs_micbias_type);
goto err;
}
// 使用内部还是外部的micbias
if (!strcmp(type, "external")) {
dev_dbg(&pdev->dev, "Headset is using external micbias\n");
mbhc_cfg.hs_ext_micbias = true;
} else {
dev_dbg(&pdev->dev, "Headset is using internal micbias\n");
mbhc_cfg.hs_ext_micbias = false;
}
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,msm-afe-clk-ver", &val);
if (ret)
pdata->afe_clk_ver = AFE_CLK_VERSION_V2;
else
pdata->afe_clk_ver = val;
/* initialize the mclk */
pdata->digital_cdc_clk.i2s_cfg_minor_version =
AFE_API_VERSION_I2S_CONFIG;
pdata->digital_cdc_clk.clk_val = pdata->mclk_freq;
pdata->digital_cdc_clk.clk_root = 5;
pdata->digital_cdc_clk.reserved = 0;
/* initialize the digital codec core clk */
pdata->digital_cdc_core_clk.clk_set_minor_version =
AFE_API_VERSION_I2S_CONFIG;
pdata->digital_cdc_core_clk.clk_id =
Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE;
pdata->digital_cdc_core_clk.clk_freq_in_hz =
pdata->mclk_freq;
pdata->digital_cdc_core_clk.clk_attri =
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
pdata->digital_cdc_core_clk.clk_root =
Q6AFE_LPASS_CLK_ROOT_DEFAULT;
pdata->digital_cdc_core_clk.enable = 1;
/* Initialize loopback mode to false */
pdata->lb_mode = false;
msm8952_dt_parse_cap_info(pdev, pdata);
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, pdata);
// 解析设备数中声卡的名称, qcom,model = "msm8953-snd-card-mtp";
ret = snd_soc_of_parse_card_name(card, "qcom,model");
if (ret)
goto err;
/* initialize timer */
INIT_DELAYED_WORK(&pdata->disable_mclk_work, msm8952_disable_mclk);
mutex_init(&pdata->cdc_mclk_mutex);
atomic_set(&pdata->mclk_rsc_ref, 0);
if (card->aux_dev) {
mutex_init(&pdata->wsa_mclk_mutex);
atomic_set(&pdata->wsa_mclk_rsc_ref, 0);
}
atomic_set(&pdata->mclk_enabled, false);
atomic_set(&quat_mi2s_clk_ref, 0);
atomic_set(&quin_mi2s_clk_ref, 0);
atomic_set(&auxpcm_mi2s_clk_ref, 0);
// 声卡的routing
ret = snd_soc_of_parse_audio_routing(card,
"qcom,audio-routing");
if (ret)
goto err;
ret = msm8952_populate_dai_link_component_of_node(card);
if (ret) {
ret = -EPROBE_DEFER;
goto err;
}
// 注册声卡
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
goto err;
}
return 0;
err:
if (pdata->vaddr_gpio_mux_spkr_ctl)
iounmap(pdata->vaddr_gpio_mux_spkr_ctl);
if (pdata->vaddr_gpio_mux_mic_ctl)
iounmap(pdata->vaddr_gpio_mux_mic_ctl);
if (pdata->vaddr_gpio_mux_pcm_ctl)
iounmap(pdata->vaddr_gpio_mux_pcm_ctl);
if (pdata->vaddr_gpio_mux_quin_ctl)
iounmap(pdata->vaddr_gpio_mux_quin_ctl);
if (bear_card.num_aux_devs > 0) {
for (i = 0; i < bear_card.num_aux_devs; i++) {
kfree(msm8952_aux_dev[i].codec_name);
kfree(msm8952_codec_conf[i].dev_name);
kfree(msm8952_codec_conf[i].name_prefix);
}
}
err1:
devm_kfree(&pdev->dev, pdata);
return ret;
}
static struct snd_soc_card *msm8952_populate_sndcard_dailinks(
struct device *dev)
{
struct snd_soc_card *card = &bear_card;
struct snd_soc_dai_link *dailink;
int len1;
card->name = dev_name(dev);
len1 = ARRAY_SIZE(msm8952_dai);
// dai_links复制给snd_soc_card, 注册的时候会用到
memcpy(msm8952_dai_links, msm8952_dai, sizeof(msm8952_dai));
dailink = msm8952_dai_links;
if (of_property_read_bool(dev->of_node,
"qcom,hdmi-dba-codec-rx")) {
dev_dbg(dev, "%s(): hdmi audio support present\n",
__func__);
memcpy(dailink + len1, msm8952_hdmi_dba_dai_link,
sizeof(msm8952_hdmi_dba_dai_link));
len1 += ARRAY_SIZE(msm8952_hdmi_dba_dai_link);
} else {
dev_dbg(dev, "%s(): No hdmi dba present, add quin dai\n",
__func__);
memcpy(dailink + len1, msm8952_quin_dai_link,
sizeof(msm8952_quin_dai_link));
len1 += ARRAY_SIZE(msm8952_quin_dai_link);
}
if (of_property_read_bool(dev->of_node,
"qcom,split-a2dp")) {
dev_dbg(dev, "%s(): split a2dp support present\n",
__func__);
memcpy(dailink + len1, msm8952_split_a2dp_dai_link,
sizeof(msm8952_split_a2dp_dai_link));
len1 += ARRAY_SIZE(msm8952_split_a2dp_dai_link);
}
card->dai_link = dailink;
card->num_links = len1;
return card;
}
// machine驱动会用这些参数去匹配platform,codec,adi.
// 都是在platform,codec中定义
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm8952_dai[] = {
/* FrontEnd DAI Links */
{/* hw:x,0 */
.name = "MSM8952 Media1", // Media1 播放链路
.stream_name = "MultiMedia1", // 匹配pcm id
.cpu_dai_name = "MultiMedia1", // 匹配cpu dai driver
.platform_name = "msm-pcm-dsp.0", // 匹配platform driver
.dynamic = 1,
.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
.dpcm_playback = 1,
.dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai", // 匹配codec dai driver
.codec_name = "snd-soc-dummy", // 匹配codec driver
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
},
{/* hw:x,1 */
.name = "MSM8952 Media2", // Media2播放链路
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
.platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
},
{/* hw:x,2 */
.name = "Circuit-Switch Voice",
.stream_name = "CS-Voice",
.cpu_dai_name = "CS-VOICE",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_CS_VOICE,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
...
}
msm audio machine 代码跟踪的更多相关文章
- MSM8953 audio dts 代码跟踪
跟一下msm8953音频的dts. msm8953-audio-mtp.dtsi &int_codec { status = "okay"; qcom,model = &q ...
- AM335x tscadc platform driver 相关代码跟踪
TI AM335x ti am335x_tsc.c 代码跟踪 在kernel 首层目录: 先运行make ARCH=arm tags 这个作用是建立tags文件,只含有arm架构的,利用ctag即可进 ...
- openstack学习笔记一 虚拟机启动过程代码跟踪
openstack学习笔记一 虚拟机启动过程代码跟踪 本文主要通过对虚拟机创建过程的代码跟踪.观察虚拟机启动任务状态的变化,来透彻理解openstack各组件之间的作用过程. 当从horizon界面发 ...
- 简单 php 代码跟踪调试实现
简单 php 代码跟踪调试实现 debug_backtrace:生成回溯 debug_print_backtrace:打印回溯 1. debug_backtrace ($options = DEBUG ...
- msm audio platform 驱动代码跟踪
sound/soc/soc-core.c static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS snd_soc_debugfs_r ...
- msm codec 代码跟踪
sound/soc/codecs/msm8x16-wcd.c static struct spmi_device_id msm8x16_wcd_spmi_id_table[] = { {"w ...
- trace与代码跟踪服务
首先开篇引用<MVC2 2 in action>里面一段关于这个跟踪服务的话 When you called Trace.Write() in Web Forms, you were in ...
- Linux 内核高-低端内存设置代码跟踪(ARM构架)
对于ARM中内核如何在启动的时候设置高低端内存的分界线(也是逻辑地址与虚拟地址分界线(虚拟地址)减去那个固定的偏移),这里我稍微引导下(内核分析使用Linux-3.0): 首先定位设置内核虚拟地址起始 ...
- saiku执行过程代码跟踪
使用了很久的saiku,决定跟踪一下代码,看看它的执行核心过程: 一.入口controller代码 1.1.页面打开之后,会发送一个ajax请求 Request URL: http://l-tdata ...
随机推荐
- 第二章 STM32的结构和组成
2.5 芯片里面有什么 STM32F103采用的是Cortex-M3内核,内核即CPU,由ARM公司设计. ARM公司并不生产芯片,而是出售其芯片技术授权. 芯片生产厂商(SOC)如ST.TI.Fre ...
- Python爱好者社区历史文章列表(每周append更新一次)
2月22日更新: 0.Python从零开始系列连载: Python从零开始系列连载(1)——安装环境 Python从零开始系列连载(2)——jupyter的常用操作 Python从零开始系列连载( ...
- BZOJ3253 : 改编
设$f[x][y]$表示从x和y出发相遇的期望长度,则$f[x][x]=0$,且$f[x][y]$对称,共$C(n,2)$个未知量. 列出方程组$G$,得到$G\times F=B$. 高斯消元求出$ ...
- 配置魔药 [NOIP模拟] [DP] [费用流]
问题描述在<Harry Potter and the Chamber of Secrets>中,Ron 的魔杖因为坐他老爸的 Flying Car 撞到了打人柳,不幸被打断了,从此之后,他 ...
- Flask路由
@app.route() methods:当前url地址,允许访问的请求方式 @app.route("/info", methods=["GET", " ...
- html页面布局之table布局:
table布局: table来做整体页面的布局,布局技巧归纳如下: (1)按照设计图的尺寸设置表格的宽高以及单元格的宽高 (2)将表格的border.cellpadding.cellspacing全部 ...
- java第二周的学习知识4(对原码,补码,反码和java中浮点数计算不准确的总结)
原码:一个正数,转换为二进制位就是这个正数的原码.负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码. 但是原码有几个缺点,零分两种 +0 和 -0 .很奇怪是吧!还有,在进行不同符号的加法运 ...
- web的几种轮播
我们在开发当中经常用到轮播.我在这里总结了一下几种,仅供参考: 第一种: 1.jQuery:用display :none/block控制的一种轮播: // CSS部分 #igs { margin: 3 ...
- 【枚举】珠心算测验[c++]
题目描述 珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术.珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及. 某学校的珠心算老师采用一种快速考察珠心算加 ...
- [Python设计模式] 第12章 基金理财更省事——外观模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟股民直接炒股的代码,比如股民投资了股票1,股票2,股票3,国债 ...