基于imx6q-Android6.0的ASOC架构 -- codec部分(二)

arm平台:IMX6Q
内核:Linux4.1.15
系统:Android6.0
codec:wm8960
主要内容为Machine、Platform和Codec三大部分之间的关系和实现。文章中的举例和代码均为imx6q-Android6.0源码和文件。
文章中如有错误和不严谨内容,欢迎指正。

在设备中,Codec的作用可以归结为4种,分别是:
1).对PCM等信号进行D/A转换,把数字的音频信号转换为模拟信号
2).对Mic、Linein或者其他输入源的模拟信号进行A/D转换,把模拟的声音信号转变CPU能够处理的数字信号
3).对音频通路进行控制,比如播放音乐,收听调频收音机,又或者接听电话时,音频信号在codec内的流通路线是不一样的
4).对音频信号做出相应的处理,例如音量控制,功率放大,EQ控制等等
ASoC对Codec的这些功能都定义好了一系列的相应的接口,以方便地对Codec进行控制。ASoC对Codec驱动的一个基本要求是:驱动程序的代码必须要做到平台无关性,以方便同一个Codec的代码不经修改即可用在不同的平台上

1、snd_soc_codec_driver和snd_soc_dai_driver

kernel_imx/sound/soc/codecs/wm8960.c

static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
        .probe =        wm8960_probe,
        .set_bias_level = wm8960_set_bias_level,
        .suspend_bias_off = true,
};
static const struct snd_soc_dai_ops wm8960_dai_ops = {
        .hw_params = wm8960_hw_params,
        .hw_free = wm8960_hw_free,
        .digital_mute = wm8960_mute,
        .set_fmt = wm8960_set_dai_fmt,
        .set_clkdiv = wm8960_set_dai_clkdiv,
        .set_pll = wm8960_set_dai_pll,
        .set_sysclk = wm8960_set_dai_sysclk,
};

static struct snd_soc_dai_driver wm8960_dai = {
        .name = "wm8960-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM8960_RATES,
                .formats = WM8960_FORMATS,},
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM8960_RATES,
                .formats = WM8960_FORMATS,},
        .ops = &wm8960_dai_ops,
        .symmetric_rates = 1,
};
/*注册*/
snd_soc_register_codec(&i2c->dev,&soc_codec_dev_wm8960, &wm8960_dai, 1);

2、snd_soc_register_codec

int snd_soc_register_codec(struct device *dev,
                           const struct snd_soc_codec_driver *codec_drv,
                           struct snd_soc_dai_driver *dai_drv,
                           int num_dai)
{
/*分配一个snd_soc_codec实例*/
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
        if (codec == NULL)
                return -ENOMEM;
/*用snd_soc_codec_driver来填充snd_soc_codec结构体*/
       if (codec_drv->controls) {
                codec->component.controls = codec_drv->controls;
                codec->component.num_controls = codec_drv->num_controls;
        }
        if (codec_drv->dapm_widgets) {
                codec->component.dapm_widgets = codec_drv->dapm_widgets;
                codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
        }
        if (codec_drv->dapm_routes) {
                codec->component.dapm_routes = codec_drv->dapm_routes;
                codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
        }

        if (codec_drv->probe)
                codec->component.probe = snd_soc_codec_drv_probe;
        if (codec_drv->remove)
                codec->component.remove = snd_soc_codec_drv_remove;
        if (codec_drv->write)
                codec->component.write = snd_soc_codec_drv_write;
        if (codec_drv->read)
                codec->component.read = snd_soc_codec_drv_read;
        codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
        codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
        codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;

/*snd_soc_register_dais函数其实和snd_soc_register_codec类似,先是为每个snd_soc_dai实例分配内存,
确定dai的名字,用snd_soc_dai_driver实例的字段对它进行必要初始化,最后把该dai链接到全局链表dai_list中*/
		snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
/*把codec添加到全局链表codec_list中*/
		list_add(&codec->list, &codec_list);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值