SSI Audio Driver
音频驱动的文章网上有很多,分析的也很具体,这里只记录本人在调试音频驱动的过程和理解。调试一个驱动,最主要的还是从本质上去理解它的工作原理,包括时钟,数据,中断,寄存器配置等。或许并不需要全部知道,但是追根到底会对以后的驱动有很大帮助。
Audio driver
linux音频驱动的结构我个人感觉做得很漂亮,有面向对象编程的人不难看出这个结构与类图很想,将变化的东西封装了起来,层次清晰,方便理解和调试:
CPU driver: Bus driver, such as I2S,SSI,AC97,ESAI,SPDIF. Encapsulates the configuration of the bus, such as the settings for master-slave mode.
Codec driver: Encoder driver, corresponding to the decoding chip, encapsulating the operation of the decoder chip, including setting registers and so on.
Machine driver: The CPU drive and codec drive mix up, some people compare machine driver to socket, I feel very image, machine driver is the corresponding CPU and codec plug into the board.
1. board File
在板级文件中添加音频支持。
Static structPlatform_device Mxc_uda134x_device = {. Name="imx-3stack-uda134x",};Static structMxc_audio_platform_data Uda134x_data = {. Ssi_num=1,. Src_port=2,. Ext_port=5,. Init= Mxc_uda134x_init,};Static intMxc_uda134x_init (void){structCLK *ssi_ext1;structCLK *SSI_SYS_CLK; U32 rate; Ssi_ext1 = Clk_get (NULL,"SSI_EXT1_CLK");if(Is_err (SSI_EXT1))return-1; Rate = Clk_round_rate (SSI_EXT1,3000000);if(Rate <2000000|| Rate >24000000) {PRINTK (kern_err"error:uda134x mclk freq%d out of range!\n", rate); Clk_put (SSI_EXT1);return-1; } clk_set_rate (Ssi_ext1, rate); Clk_enable (SSI_EXT1); Uda134x_data. SYSCLK= rate;return 0;} Here the ssi_num corresponds to SSI's channel number, SSI bus function configuration Mx53_pad_key_col0__audmux_aud5_txc, MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD, MX53_PA D_KEY_COL1__AUDMUX_AUD5_TXFS, Mx53_pad_key_row1__audmux_aud5_rxd,
AUDMUX5 refers to the external port of the Audmux (that is, the port connected to codec), which is ext_num, and src_num refers to the internal port (that is, the port connected to the CPU). The connection rules for ports can be found on the chip manual. Very strange, the system clock is set to 3M can play normally, 4M there is no sound, and then 20M and there is a sound, but the noise is very big, have to know the reason also please inform.
The connection is as follows:
2. Clock:
SSI's Clock:
You can see that the SSI_EXT1_CLK can be generated by PLL3,PLL2,SSI_LP_APM_CLK, and the registers associated with it are CCM_CCGR3. The clock configuration does not require us to deal with, we just need to understand just fine. The configuration of SSI is as follows
_REGISTER_CLOCK("mxc_ssi.0"NULL, ssi1_clk[0]), _REGISTER_CLOCK("mxc_ssi.1"NULL, ssi2_clk[0]), _REGISTER_CLOCK("mxc_ssi.2"NULL, ssi3_clk[0]), _REGISTER_CLOCK(NULL"ssi_ext1_clk", ssi_ext1_clk), _REGISTER_CLOCK(NULL"ssi_ext2_clk", ssi_ext2_clk),
Here's _register_clock macro I don't quite understand the meaning of the first two parameters. Tell me if you have any trouble knowing.
3, Machine Drive
Most of the machine driver can refer to other audio drivers, because the main body is the same, and uda1341 has a little difference, it has a L3 bus, L3 Bus Drive Linux has already, we need to do is to specify the corresponding pin (can refer to S3c24xx_ UDA1341.C).
The 2 functions that need to be highlighted are:
1, Imx_3stack_init_dam
Static voidImx_3stack_init_dam (intSsi_port,intDai_port) {unsigned intSSI_PTCR =0;unsigned intDAI_PTCR =0;unsigned intSSI_PDCR =0;unsigned intDAI_PDCR =0;/ * uda134x uses SSI1 via Audmux port Dai_port for audio * / / * Reset Port Ssi_port & Dai_port * /__raw_writel (0, DAM_PTCR (Ssi_port)); __raw_writel (0, DAM_PTCR (Dai_port)); __raw_writel (0, DAM_PDCR (Ssi_port)); __raw_writel (0, DAM_PDCR (Dai_port));/ * Set to synchronous * /SSI_PTCR |= Audmux_ptcr_syn; DAI_PTCR |= Audmux_ptcr_syn;/ * Set Rx sources ssi_port <--> dai_port * /SSI_PDCR |= Audmux_pdcr_rxdsel (dai_port); DAI_PDCR |= Audmux_pdcr_rxdsel (ssi_port);/ * Set Tx frame direction and source Dai_port--ssi_port output * /DAI_PTCR |= Audmux_ptcr_tfsdir; DAI_PTCR |= Audmux_ptcr_tfssel (AUDMUX_FROM_TXFS, Ssi_port);/ * Set Tx Clock direction and source dai_port--> ssi_port output * /DAI_PTCR |= Audmux_ptcr_tclkdir; DAI_PTCR |= Audmux_ptcr_tcsel (AUDMUX_FROM_TXFS, Ssi_port); __raw_writel (SSI_PTCR, DAM_PTCR (Ssi_port)); __raw_writel (DAI_PTCR, DAM_PTCR (Dai_port)); __raw_writel (SSI_PDCR, DAM_PDCR (Ssi_port)); __raw_writel (DAI_PDCR, DAM_PDCR (Dai_port));}
SSI bus is compatible with I2S, so it is also necessary to set master/slave mode. And uda1341 can only work in slave mode, so we need to set SSI to main mode. The above function is actually the direction of the data flow in the configuration Audmux.
The default Port-to-port connections is as follows:
? Port 1 to Port 6
? Port 6 provides the clock and frame sync.
? Port 2 to Port 5
? Port 5 provides the clock and frame sync.
? Port 3 to Port 4
? Port 4 provides the clock and frame sync.
? Port 7 to Port 7 (in data loopback mode)
? Clock and frame syncs are inputs.
From the documentation we see that the signals such as BCLK and frame sync are provided by PORT5, which means that we need to configure the PORT5 as an output mode, while PORT2 is configured as an input mode. is to configure the PTCR register.
2, Imx_3stack_audio_hw_params
Static intImx_3stack_audio_hw_params (structSnd_pcm_substream *substream,structSnd_pcm_hw_params *params){structSnd_soc_pcm_runtime *RTD = substream->private_data;structSnd_soc_dai_link *machine = rtd->dai;structSnd_soc_dai *cpu_dai = machine->cpu_dai;structSnd_soc_dai *codec_dai = machine->codec_dai; UnsignedintRate = Params_rate (params);structImx_ssi *ssi_mode = (structImx_ssi *) cpu_dai->private_data;intRET =0; U32 Dai_format;intBitsintChannels = Params_channels (params); Dai_format = Snd_soc_daifmt_i2s | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; Ssi_mode->sync_mode =1; Ssi_mode->network_mode =1;/ * Set CPU DAI configuration * /ret = SND_SOC_DAI_SET_FMT (Cpu_dai, Dai_format);if(Ret <0)returnRet/ * set I. mx Active slot Mask * /Snd_soc_dai_set_tdm_slot (cpu_dai, channels = =1?0xFFFFFFFE:0XFFFFFFFC, channels = =1?0xFFFFFFFE:0XFFFFFFFC,2, +);/ * Set the SSI clock div * ///Snd_soc_dai_set_clkdiv (Cpu_dai, imx_ssi_tx_div_2, 0);//Snd_soc_dai_set_clkdiv (Cpu_dai, IMX_SSI_TX_DIV_PSR, 0);//Snd_soc_dai_set_clkdiv (Cpu_dai, imx_ssi_tx_div_pm, 23°c);//Snd_soc_dai_set_clkdiv (Cpu_dai, imx_ssi_rx_div_2, 0);//Snd_soc_dai_set_clkdiv (Cpu_dai, IMX_SSI_RX_DIV_PSR, 0);//Snd_soc_dai_set_clkdiv (Cpu_dai, imx_ssi_rx_div_pm, 23°c); / * Set the SSI system clock as output * /SND_SOC_DAI_SET_SYSCLK (Cpu_dai, IMX_SSP_SYS_CLK,0, snd_soc_clock_out);/ * Set codec DAI configuration * /Snd_soc_dai_set_fmt (Codec_dai, Dai_format);/ * Set codec clock*/SND_SOC_DAI_SET_SYSCLK (Codec_dai, uda134x_sysclk,rate*384, snd_soc_clock_out);return 0;}
这个函数的功能主要是在播放之前配置SSI和CODEC,要理解它们的含义需要结合imx_ssi.c和uda1341.c。首先SSI部分配置模式,SND_SOC_DAIFMT_CBS_CFS在imx_ssi.c中其实是配置成主模式。然后是codec的系统时钟,需要查看手册,uda1341的系统时钟是256fs、384fs、512fs。fs表示采样率。
This audio driver has been on and off for a long time, to fully understand the need to combine the manual a little bit of look. But finally found that the transplant is still very simple, as long as the attention of a few places is enough.
1, board-level files in the audio structure, including the port settings, SSI's number. Codec the system clock settings.
2, the Audmux port function configuration. Note the direction of the data flow, and the difference between master and slave modes.
3, the Hw_param function in the DAI configuration. Need to combine Cpu_dai and Codec_dai source code to control.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
UDA1341 SSI Audio Driver