RK3288:linux系统中基于TLV320AIC3254Audio音频芯片的驱动调试

 

CPU:RK3288

Kernel:4.4

Systerm:linux(buidroot)

IC:TLV320AIC3254

 

RK3288:linux系统中基于TLV320AIC3254Audio音频芯片的驱动调试_第1张图片

 

 

Linux驱动程序支持TLV320AIC32x系列低功耗立体声编解码器。Linux驱动程序支持通过I2C和SPI总线进行通信,并与Linux DAPM(便携式设备的动态音频电源管理)类接口。

 

支持的设备:

  • tlv320aic32
  • TLV320AIC3204
  • TLV320AIC325

 

 

 

与此设备关联的文件是:

  1. sound/soc/codecs/tlv320aic32x4.c
  2. sound/soc/codecs/tlv320aic32x4-i2c.c
  3. sound/soc/codecs/tlv320aic32x4-spi.c
  4. Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
  5. sound/soc/codecs/tlv320aic32x4.h
  6. include/sound/tlv320aic32x4.h

下载地址如下:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/tlv320aic32x4.c 

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/tlv320aic32x4-i2c.c 

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/tlv320aic32x4-spi.c 

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt 

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/tlv320aic32x4.h 

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/sound/tlv320aic32x4.h

 

Linux设备树文档

Documentation/devicetree/bindings/sound/tlv320aic32x4.txt:

Texas Instruments - tlv320aic32x4 Codec module

The tlv320aic32x4 serial control bus communicates through I2C protocols

Required properties:
 - compatible - "string" - One of:
	"ti,tlv320aic32x4" TLV320AIC3204
	"ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256
 - reg: I2C slave address
 - supply-*: Required supply regulators are:
    "iov" - digital IO power supply
    "ldoin" - LDO power supply
    "dv" - Digital core power supply
    "av" - Analog core power supply
    If you supply ldoin, dv and av are optional. Otherwise they are required
   See regulator/regulator.txt for more information about the detailed binding
   format.

Optional properties:
 - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
 - clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
   See clock/clock-bindings.txt for information about the detailed format.
 - aic32x4-gpio-func - 
	- Types are defined in include/sound/tlv320aic32x4.h


Example:

codec: tlv320aic32x4@18 {
	compatible = "ti,tlv320aic32x4";
	reg = <0x18>;
	clocks = <&clks 201>;
	clock-names = "mclk";
	aic32x4-gpio-func= <
			0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
			0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
			0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */
			0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
			0x08 /* MFP5 AIC32X4_MFP5_GPIO_INPUT */
		>;
};

 

接口解析:
1.  SND_SOC_DAPM_OUTPUT("HPL"),
    SND_SOC_DAPM_OUTPUT("HPR"),
    SND_SOC_DAPM_OUTPUT("LOL"),
    SND_SOC_DAPM_OUTPUT("LOR"),
    SND_SOC_DAPM_INPUT("IN1_L"),
    SND_SOC_DAPM_INPUT("IN1_R"),
    SND_SOC_DAPM_INPUT("IN2_L"),
    SND_SOC_DAPM_INPUT("IN2_R"),
    SND_SOC_DAPM_INPUT("IN3_L"),
    SND_SOC_DAPM_INPUT("IN3_R"),
4.i2c:音频控制线
5.i2s:有5根线:两根音频数据线、三根时钟线
其中:
i2s_lrck是指示当前数据线传输的是左声道还是右声道
i2s_bclk是协调数据线上的数据传输(一个时钟周期,主控、音频编解码芯片从音频线取一bit音频数据)
i2s_mclk是主控供给音频编解码芯片保持正常工作用的时钟
我们看看I2S的官方解释
      I2S(Inter IC Sound)总线, 又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准。
      该总线专责于音频设备之间的数据传输,广泛应用于各种多媒体系统。
它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真。
 一般来说,调试音频需要注意几个参数:
采样率、采样位数、采样通道。

 

 

I2S(Inter-IC Sound)是飞利浦公司针对数字音频设备(如CD播放器、数码音效处理器、数字电视音响系统)之间的音频数据传输而制定的一种总线标准。它采用了独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用。标准的I2S总线电缆是由3根串行导线组成的:1根是时分多路复用(简称TDM)数据线;1根是字选择线;1根是时钟线。

 

 

 

在飞利浦公司的I2S标准中,既规定了硬件接口规范,也规定了数字音频数据的格式。

I2S有3个主要信号

1.串行时钟SCLK,也叫位时钟(BCLK),即对应数字音频的每一位数据,SCLK都有1个脉冲。SCLK的频率=2×采样频率×采样位数。

2. 帧时钟LRCK,(也称WS),用于切换左右声道的数据。LRCK为“1”表示正在传输的是右声道的数据,为“0”则表示正在传输的是左声道的数据。LRCK的频率等于采样频率。

3.串行数据SDATA,就是用二进制补码表示的音频数据。

有时为了使系统间能够更好地同步,还需要另外传输一个信号MCLK,称为主时钟,也叫系统时钟(Sys Clock),是采样频率的256倍或384倍。

串行数据(SD)

I2S格式的信号无论有多少位有效数据,数据的最高位总是出现在LRCK变化(也就是一帧开始)后的第2个SCLK脉冲处。这就使得接收端与发送端的有效位数可以不同。如果接收端能处理的有效位数少于发送端,可以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端,可以自行补足剩余的位。这种同步机制使得数字音频设备的互连更加方便,而且不会造成数据错位。

随着技术的发展,在统一的 I2S接口下,出现了多种不同的数据格式。根据SDATA数据相对于LRCK和SCLK的位置不同,分为左对齐(较少使用)、I2S格式(即飞利浦规定的格式)和右对齐(也叫日本格式、普通格式)。

为了保证数字音频信号的正确传输,发送端和接收端应该采用相同的数据格式和长度。当然,对I2S格式来说数据长度可以不同。

 

 

 

 

现在我们来看下设备树的配置:

	sound: sound {                        //machine 匹配层的驱动节点。
		status = "okay";
		compatible = "simple-audio-card";//simple-card framework框架

		simple-audio-card,format = "i2s";
		simple-audio-card,name = "rockchip,tlv320aic32x4-codec";
		simple-audio-card,mclk-fs = <256>;//主控供给编解码芯片用的时钟
		simple-audio-card,widgets =        //指定相关组件
			//"Speaker", "Speaker",        
			"Microphone", "Microphone Jack",//麦克风
			"Headphone", "Headphone Jack";//耳机
		simple-audio-card,routing =        //音频路径,如mic输入、耳机输出走那些通路。
			//"Microphone Jack", "MICBIAS",
			"IN1_L",	"Microphone Jack",		
			"IN1_R",	"Microphone Jack",	
			"IN2_L",	"Microphone Jack",	
			"IN2_R",	"Microphone Jack",
			"IN3_L",	"Microphone Jack",
			"IN3_R",	"Microphone Jack",
			"Headphone Jack", 	"HPL",
			"Headphone Jack", 	"HPR",
			"Headphone Jack", 	"LOL",
			"Headphone Jack", 	"LOR"	;
			//mux-int-port = <2>;
			//mux-ext-port = <3>;		

		simple-audio-card,dai-link@0 {
			format = "i2s";
			cpu {
				sound-dai = <&i2s>;//指定cpu接入音频编解码的dai(数字化接口)
			};

			codec {
				sound-dai = <&tlv320aic32x4>;//指定编解码音频接入cpu的dai(数字化接口)
			};
		};

		simple-audio-card,dai-link@1 {
			format = "i2s";
			cpu {
				sound-dai = <&i2s>;
			};

			codec {
				sound-dai = <&hdmi>;
			};
		};
	};

 

&i2c2 {
	status = "okay";
/*
	rt5640: rt5640@1c {
		status = "disabled";
		#sound-dai-cells = <0>;
		compatible = "realtek,rt5640";
		reg = <0x1c>;
		clocks = <&cru SCLK_I2S0_OUT>;
		clock-names = "mclk";
		interrupt-parent = <&gpio6>;
		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
		pinctrl-names = "default";
		pinctrl-0 = <&i2s0_mclk>;
	};
*/
	
	tlv320aic32x4: tlv320aic32x4@18 {
	status = "okay";
	compatible = "ti,tlv320aic32x4";
	reg = <0x18>;
	iov-supply = <&vcc18_lcd>;//digital IO power supply
	dv-supply = <&vcca_codec>;//Digital core power supply 
	av-supply = <&vcca_codec>;//Analog core power supply
	ldoin-supply = <&vcc18_lcd>;//LDO power supply
	gpio-reset = <&gpio6 11 1>;//GPIO6_B3_D
	clocks = <&cru SCLK_I2S0_OUT>;
	//clocks = <&cru SCLK_I2S_8CH_OUT>;
	clock-names = "mclk";
	pinctrl-names = "default";
	pinctrl-0 = <&i2s0_mclk>;
	//pinctrl-0 = <&i2s_8ch_mclk>;
	//spk-con-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
	//hp-det-gpio = <&gpio7 13 GPIO_ACTIVE_LOW>;
	#sound-dai-cells = <0>;
	aic32x4-gpio-func= <
		0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
		0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
		0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */
		0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
		0x08 /* MFP5 AIC32X4_MFP5_GPIO_INPUT */
	>;
	};
};

 

 

把设备树修改后,重新编译烧录,开机后串口如下打印:

[    4.056922] ALSA device list: 
[    4.059891]   #0: rockchip,tlv320aic32x4-codec 
表示声卡注册好了

但是会打印报错,报错如下:

[root@rk3288:/]# [   65.850876] aic32x4: invalid frequency to set DAI system clock
[   65.856714] audio freq is 11289600 
[   65.860256] asoc-simple-card sound: ASoC: machine hw_params failed: -22
[   65.866931] aic32x4: invalid frequency to set DAI system clock
[   65.872770] audio freq is 11289600 
[   65.876263] asoc-simple-card sound: ASoC: machine hw_params failed: -22
[   65.882975] aic32x4: invalid frequency to set DAI system clock
[   65.888814] audio freq is 11289600 
[   65.888820] asoc-simple-card sound: ASoC: machine hw_params failed: -22

这个说明MCLK,也就是CPU出来的系统时钟出现了问题。后来询问RK的FAE,得到RK的MCLK是:

256fs, 11289600, 12288000

然后查看驱动,发现10年没有更新啦。所以修改驱动代码:

tlv320aic32x4.h中增加如下代码:

#define AIC32X4_FREQ_12000000 12000000
#define AIC32X4_FREQ_24000000 24000000
#define AIC32X4_FREQ_25000000 25000000
#define AIC32X4_FREQ_11289600 11289600
#define	AIC32X4_FREQ_12288000 12288000

tlv320aic32x4.c中增加如下代码:

static const struct aic32x4_rate_divs aic32x4_divs[] = {
	/*mclk;rate;p_val;pll_j;pll_d;dosr;ndac;mdac;aosr;nadc;madc;blck_N;*/
	/* 8k rate */
	{AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
	{AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
	{AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
	{AIC32X4_FREQ_11289600, 8000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 8000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	/* 11.025k rate */
	{AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
	{AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
	{AIC32X4_FREQ_11289600, 11025, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 11025, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	/* 16k rate */
	{AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
	{AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
	{AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
	{AIC32X4_FREQ_11289600, 16000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 16000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	/* 22.05k rate */
	{AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
	{AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
	{AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
	{AIC32X4_FREQ_11289600, 22000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 22000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	/* 32k rate */
	{AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
	{AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
	{AIC32X4_FREQ_11289600, 32000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 32000, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	/* 44.1k rate */
	{AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
	{AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
	{AIC32X4_FREQ_11289600, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
	/* 48k rate */
	{AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
	{AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
	{AIC32X4_FREQ_11289600, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
	{AIC32X4_FREQ_12288000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
};
static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
				  int clk_id, unsigned int freq, int dir)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);

	switch (freq) {
	case AIC32X4_FREQ_12000000:
	case AIC32X4_FREQ_24000000:
	case AIC32X4_FREQ_25000000:
	case AIC32X4_FREQ_11289600:
	case AIC32X4_FREQ_12288000:
		aic32x4->sysclk = freq;
		return 0;
	}
	printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
	printk(KERN_ERR "audio freq is %d \n",freq);//11289600
	return -EINVAL;
}

添加了RK对应的MCLK后,播放WAV文件就不会报错啦。

 

 

声卡注册好了以后,进去调试阶段:

 

1.通过如下命令确认声卡是否注册成功

[root@rk3288:/]# cat /proc/asound/cards
 0 [rockchiptlv320a]: rockchip_tlv320 - rockchip,tlv320aic32x4-codec
                      rockchip,tlv320aic32x4-codec
[root@rk3288:/]# 

[root@rk3288:/]# ls -l /dev/snd/
drwxr-xr-x    2 root     root            60 Jan 18 13:08 by-path
crw-rw----    1 root     audio     116,   2 Jan 18 13:08 controlC0
crw-rw----    1 root     audio     116,   4 Jan 18 13:08 pcmC0D0c
crw-rw----    1 root     audio     116,   3 Jan 18 13:08 pcmC0D0p
crw-rw----    1 root     audio     116,   5 Jan 18 13:08 pcmC0D1p
crw-rw----    1 root     audio     116,   1 Jan 18 13:08 seq
crw-rw----    1 root     audio     116,  33 Jan 18 13:08 timer
[root@rk3288:/]# 

2. 通过命令行播放录制调试声卡:
播放:一般播放 1khz 0db 正弦波,然后在 codec 输出端示波器简单测量是否失真,杂音,然
后再使用音频分析仪测试指标

3. 通过命令行调试声卡的通路:

4. tinymix 调试通路:

 

 

 

 

你可能感兴趣的:(RK3288驱动开发,音频驱动)