首先就不介绍asoc框架了,网上好的资料很多,推荐DroidPhone大神的,写的很全,知识面基本都介绍到了,不过由于写的比较早,没有使用设备树,最近也正好在调相关驱动,写点东西记录一下。

https://blog.csdn.net/droidphone/category_1118446.html

源码我也上传了 有需要的可以下载

https://download.csdn.net/download/qq_17270067/13721398

mpu:imx6q

linux-kernel:4.1.15

1、machine驱动

使用的是设备树中的sound节点

sound {compatible = "fsl,imx-audio-tas2505";model = "tas2505-audio";cpu-dai = <&ssi1>; audio-codec = <&codec>;audio-routing = "Speaker Driver", "DAC Channel" ,"Speaker", "Speaker Driver" ;                 mux-int-port = <1>;mux-ext-port = <3>;
};

cpu-dai:使用的platform节点

audio-codec:使用的codec节点

audio-routing:音频设备连接路径,每两个为一组,第一个为sink,第二个为source。

mux-int-port :使用了内部的哪个ssi。内部ssi接口ssi1,ssi2,ssi3, 分别对应 mux-int-port = <1>,mux-int-port = <2>,mux-int-port = <7>

mux-ext-port:使用了哪个外部AUD接口,有 AUD3,AUD4,AUD5,AUD6,分别对应mux-ext-port = <3>,mux-ext-port = <4>,mux-ext-port = <5>,mux-ext-port = <6>

在修改完了使用的AUDX接口之后,我们也需要将audmux的pinctrl修改成对应的接口

pinctrl_audmux: audmuxgrp {fsl,pins = <MX6QDL_PAD_CSI0_DAT4__AUD3_TXC          0x130b0MX6QDL_PAD_CSI0_DAT5__AUD3_TXD          0x110b0MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS         0x130b0MX6QDL_PAD_CSI0_DAT7__AUD3_RXD          0x130b0>;};&audmux {pinctrl-names = "default";pinctrl-0 = <&pinctrl_audmux>;status = "okay";
};

machine驱动文件中的probe函数如下:

static int imx_tas2505_probe ( struct platform_device* pdev )
{struct device_node* cpu_np, *codec_np,*gpr_np;struct device_node* np = pdev->dev.of_node;struct platform_device* cpu_pdev;struct imx_priv* priv = &card_priv;struct i2c_client* codec_dev;struct device_node* asrc_np;struct imx_tas2505_data* data = NULL;struct platform_device* asrc_pdev = NULL;int int_port, ext_port;int ret;//读取设备树中的mux-int-port属性的值ret = of_property_read_u32 ( np, "mux-int-port", &int_port );if ( ret ){dev_err ( &pdev->dev, "mux-int-port missing or invalid\n" );return ret;}//读取设备树中的mux-ext-port属性的值ret = of_property_read_u32 ( np, "mux-ext-port", &ext_port );if ( ret ){dev_err ( &pdev->dev, "mux-ext-port missing or invalid\n" );return ret;}/** The port numbering in the hardware manual starts at 1, while* the audmux API expects it starts at 0.*/int_port--;ext_port--;//根据codec和cpu的主从关系 配置ssi和aud的连接以及各条线的输入输出 //本质是设置寄存器的值 具体参照数据手册Chapter 15 Digital Audio Multiplexer (AUDMUX)   ret = imx_audmux_v2_configure_port ( ext_port,IMX_AUDMUX_V2_PTCR_SYN |IMX_AUDMUX_V2_PTCR_TFSEL ( int_port ) |IMX_AUDMUX_V2_PTCR_TCSEL ( int_port ) |IMX_AUDMUX_V2_PTCR_TFSDIR |IMX_AUDMUX_V2_PTCR_TCLKDIR,IMX_AUDMUX_V2_PDCR_RXDSEL ( int_port ) );if ( ret ){dev_err ( &pdev->dev, "audmux internal port setup failed\n" );return ret;}ret = imx_audmux_v2_configure_port ( int_port,IMX_AUDMUX_V2_PTCR_SYN,IMX_AUDMUX_V2_PDCR_RXDSEL ( ext_port ) );if ( ret ){dev_err ( &pdev->dev, "audmux external port setup failed\n" );return ret;}priv->pdev = pdev;//获取platform和codec节点cpu_np = of_parse_phandle ( pdev->dev.of_node, "cpu-dai", 0 );codec_np = of_parse_phandle ( pdev->dev.of_node, "audio-codec", 0 );if ( !cpu_np || !codec_np ){dev_err ( &pdev->dev, "phandle missing or invalid\n" );ret = -EINVAL;goto fail;}cpu_pdev = of_find_device_by_node ( cpu_np );if ( !cpu_pdev ){dev_err ( &pdev->dev, "failed to find SSI platform device\n" );ret = -EINVAL;goto fail;}codec_dev = of_find_i2c_device_by_node ( codec_np );if ( !codec_dev || !codec_dev->dev.driver ){dev_err ( &pdev->dev, "failed to find codec platform device\n" );ret = -EINVAL;goto fail;}data = devm_kzalloc ( &pdev->dev, sizeof ( *data ), GFP_KERNEL );if ( !data ){ret = -ENOMEM;goto fail;}//读取设备树codec-master 是否存在if ( of_property_read_bool ( pdev->dev.of_node,"codec-master" ) ){data->is_codec_master = true;}//获取code时钟data->codec_clk = devm_clk_get ( &codec_dev->dev, "mclk" );if ( IS_ERR ( data->codec_clk ) ){ret = PTR_ERR ( data->codec_clk );dev_err ( &pdev->dev, "failed to get codec clk: %d\n", ret );goto fail;}//使能时钟data->clk_frequency = clk_get_rate ( data->codec_clk );ret = clk_prepare_enable ( data->codec_clk );if ( ret ){dev_err ( &codec_dev->dev, "failed to enable codec clk: %d\n", ret );goto fail;}data->dai.name = "HiFi";data->dai.stream_name = "HiFi";data->dai.codec_dai_name = "tas2505-hifi"; //此处名字需与codec中snd_soc_dai_driver结构中的name相同data->dai.cpu_dai_name = dev_name ( &cpu_pdev->dev ); //得到设备的名字 该名字是在设备树转化成platform device被赋予data->dai.codec_of_node = codec_np;data->dai.platform_of_node = cpu_np;printk ( "cpu_dai_name = %s\n",data->dai.cpu_dai_name );data->dai.init = &imx_tas2505_dai_init; //data->dai.ops = &imx_hifi_ops;//设置与codec的通信格式为I2S cpu为主 codec为从  data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |SND_SOC_DAIFMT_CBS_CFS;data->card.dev = &pdev->dev;ret = snd_soc_of_parse_card_name ( &data->card, "model" );if ( ret ){goto fail;}//找到设备树名字为audio-routing的项 并取出sink和sourceret = snd_soc_of_parse_audio_routing ( &data->card, "audio-routing" );if ( ret ){goto fail;}data->card.num_links = 1;data->card.owner = THIS_MODULE;data->card.dai_link = &data->dai;data->card.dapm_widgets = imx_tas2505_dapm_widgets; //注册不由codec寄存器控制的外部器件data->card.num_dapm_widgets = ARRAY_SIZE ( imx_tas2505_dapm_widgets );//设置私有数据platform_set_drvdata ( pdev, &data->card );snd_soc_card_set_drvdata ( &data->card, data );//注册声卡ret = devm_snd_soc_register_card ( &pdev->dev, &data->card );if ( ret ){dev_err ( &pdev->dev, "snd_soc_register_card failed (%d)\n", ret );goto fail;}of_node_put ( cpu_np );of_node_put ( codec_np );return 0;fail:if ( data && !IS_ERR ( data->codec_clk ) ){clk_put ( data->codec_clk );}if ( cpu_np ){of_node_put ( cpu_np );}if ( codec_np ){of_node_put ( codec_np );}return ret;
}

2、codec驱动

pinctrl_i2c2: i2c2grp {fsl,pins = <MX6QDL_PAD_KEY_COL3__I2C2_SCL     0x4001b8b1MX6QDL_PAD_KEY_ROW3__I2C2_SDA     0x4001b8b1MX6QDL_PAD_NANDF_D2__GPIO2_IO02     0x80000000 //reset pin>;};&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog>;......pinctrl_hog: hoggrp {fsl,pins = <....../*CCM_CLKO1 为codec的时钟提供脚*/MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x130b0......>;};......
};&i2c2 {clock-frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c2>;status = "okay";codec: tas2505@18{compatible = "ti,tas2505"; reg = <0x18>;clocks = <&clks IMX6QDL_CLK_CKO>;reset-gpio = <&gpio2 2 1>;        clock-names = "mclk";};};

reg:i2c设备地址,注意设备树中需要的是高7位地址。

clocks:时钟源,IMX6QDL_CLK_CKO定义的时钟源是MCLK,默认频率为24MHz。此时钟实际上也是可以修改的,参照How to change audio clock from 24M to 24.576M。

IMX6QDL_CLK_CKO 定义在include/dt-bindings/clock/imx6qdl-clock.h

设备树中也需要定义codec的时钟提供脚。

reset-gpio:设备的复位引脚

codec驱动中的probe函数如下:

static int tas2505_i2c_probe ( struct i2c_client* client,const struct i2c_device_id* id )
{struct device* dev = &client->dev;struct device_node* np =  dev->of_node;struct tas2505_data* tas2505;int ret;tas2505 = devm_kzalloc ( &client->dev, sizeof ( *tas2505 ), GFP_KERNEL );if ( tas2505 == NULL ){return -ENOMEM;}//获取设备树的中reset-gpio脚tas2505->reset_gpio = of_get_named_gpio ( np, "reset-gpio", 0 );if ( gpio_is_valid ( tas2505->reset_gpio ) ){//设置成输出高ret = devm_gpio_request_one ( dev, tas2505->reset_gpio,GPIOF_OUT_INIT_HIGH,"reset" );if ( ret ){dev_err ( dev, "unable to get reset pin \n" );return ret;}}tas2505->regmap = devm_regmap_init_i2c ( client, &tas2505_regmap_config ); //注册i2c regmapif ( IS_ERR ( tas2505->regmap ) ){ret = PTR_ERR ( tas2505->regmap );dev_err ( dev, "Failed to allocate register map: %d\n",ret );return ret;}tas2505->dev = dev;//设置私有数据 sound核心层需要读取regmap 之后可以使用snd_soc_write等相关函数直接操作寄存器dev_set_drvdata ( tas2505->dev, tas2505 );//注册codecret = snd_soc_register_codec ( dev,&soc_codec_dev_tas2505,tas2505_dai, ARRAY_SIZE ( tas2505_dai ) );if ( ret < 0 ){dev_err ( dev, "Failed to register codec: %d\n", ret );}return ret;
}

platform驱动基本不需要更改,我也没细看,所以就不分析了。

imx6q 音频芯片驱动开发--相关设备树以及代码中的对应设置相关推荐

  1. 【Linux驱动开发】设备树详解(二)设备树语法详解

    ​ 活动地址:CSDN21天学习挑战赛 [Linux驱动开发]设备树详解(一)设备树基础介绍 [Linux驱动开发]设备树详解(二)设备树语法详解 [Linux驱动开发]设备树详解(三)设备树Kern ...

  2. i.MX6ULL驱动开发 | 04-Linux设备树基本语法与实例解析

    文章目录 一.设备树简介 1. 设备树在ARM架构的引入 2. 什么是设备树 3. DTS.DTSI.DTB 4. 设备树编译 二.设备树语法 1. 设备树版本 2. 设备树节点 3. 设备树节点标准 ...

  3. Linux驱动开发:设备树节点与属性

    目录 1.设备节点(node) 2.属性(property) 3.节点的一些特性 4.节点的一些标准属性 4.1 compatible属性 4.2 model属性 4.3 status属性 4.4 r ...

  4. iTOP-iMX6开发板-设备树内核-注册驱动例程

    本文档主要讲解在迅为iTOP-iMX6Q/D/PLUS 开发板的设备树内核(4.1.15)源码中,设备树注册 驱动和非设备树的类似. 1 注册驱动源码分析 设备树的内核驱动中,platform_dri ...

  5. firefly-rk3288j开发板--设备树下的 LED 驱动

    firefly-rk3288j开发板–设备树下的 LED 驱动 1 准备工作 开发板:aio-rk3288j SDK版本:rk3288_linux_release_20210304 下载工具:Linu ...

  6. Linux 设备驱动开发 —— platform设备驱动应用实例解析

    前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 -- platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platfor ...

  7. STM32MP157驱动开发——蜂鸣器设备驱动

    STM32MP157驱动开发--蜂鸣器设备驱动 0.相关知识 一.驱动程序开发 1.设备树修改 2.启动程序编写 3.测试程序编写 二.编译及运行测试 0.相关知识   蜂鸣器常用于计算机.打印机.报 ...

  8. STM32MP157驱动开发——platform设备驱动(中)

    STM32MP157驱动开发--platform设备驱动(中) 0.前言 一.platform设备模块--设备信息解析 二.platform驱动模块--加载设备 三.测试App 四.编译及运行 相关文 ...

  9. STM32MP157驱动开发——USB设备驱动

    STM32MP157驱动开发--USB设备驱动 一.简介 1.电气属性 2.USB OTG 3.STM32MP1 USB 接口简介 4.Type-C 电气属性 二.USB HOST 驱动开发 1.US ...

最新文章

  1. python的with语句
  2. LeetCode 489. Robot Room Cleaner--C++,Python解法
  3. [文摘]Maven安装jar包的命令
  4. 配置IPsec Tunnel With TACACS+ User Authentication
  5. php 监控文件夹变化,swoole 开发中监听目录文件变化, 自动重启项目
  6. windows下注册和取消pg服务的命令
  7. 宝塔linux面板安装seafile,Centos7 安装seafile 企业共享网盘
  8. solr4.3纠错源码学习二——基于主索引
  9. SD-WAN技术分析
  10. 学习笔记---Web服务、Remoting、WCF (上) --- Web服务
  11. shiro框架实现权限管理
  12. win10可以登录QQ微信 浏览器不能打开网页
  13. Linux修改文件出现错误E45:“readonly” option is set(add ! to override)退出不了vim
  14. CCIE一年后的心语-------寄WOLF实验室的兄弟
  15. Navicat for mysql 在WIN10下导入SQL不成功解决办法
  16. gerrit 描述信息批量导入导出
  17. 学大伟业:2019年生物竞赛学习方法
  18. Linux中删除文件夹和文件的命令(☆)
  19. VUE3中使用proj4,实现坐标投影转换
  20. GIT客户端32位安装版Git-2.34.0-32-bit.exe

热门文章

  1. 360卫士防止自动广告弹窗设置方法
  2. zeromq: hwm; high water mark: 高水位线
  3. DS007-二叉树-伪指针表示法-先根-中根-后根遍历
  4. unity小球吃金币小游戏
  5. 网络安全行业“专业术语”!
  6. 低成本网站渗透测试怎么找
  7. 开源JavaScript插件和库速查表
  8. C6软件测试大乐,软件测试大作业——社团管理系统
  9. hp 战99 G1开启显示设置面板
  10. ​酷炫二重奏:6个案例向你展示AI如何帮助金融技术发展