音频可以播放(可以听到声音), 说明音频解码和输出部分基本是正常的, 整个通道已经打通了. 感觉播放速度太快了(或太慢了)说明audio输出部分的频率不对, 太高了或者太低了.audio/sound音频部分涉及的几个频率:* 输出采样频率 fs = 44.1KHz.  (也有其它fs的音源, 但加了resampler后, 都变成44.1KHz输出了). 这是个关键频率.* LRCLK, 就等于fs. (L/R声道信号)* BCLK = 32倍fs = 1411.2KHz = 1.4112MHz. (bit clock). 2声道16bit, 故32倍fs. 若2声道24bit, 则48倍fs.* MCLK是整个audio模块的工作频率, 通常选fs的256, 384, 512倍. 比如: 256倍fs = 11289.6KHz = 11.2896MHz.从频率设置来说, MCLK是个主要频率, 它是整个audio模块的工作频率.通常MCLK是由某个PLL按一定倍数分频得到的, 比如6倍.  (因为MCLK频率只有11.3MHz左右, 如果直接由PLL产生MCLK则频率太低了, PLL不好做). 那么, 这个PLL的输出频率PLLout = 6倍MCLK = 67.7376MHz.那么, 从软件来说要设置两个方面的寄存器: 一是该PLL从晶振频率如何得到PLLout频率(比如P/M/S/k). 二是PLLout如何分频得到audio部分的MCLK.内核audio/sound声卡驱动分析. \sound\soc\s3c24xx\aries-wm8994.c文件module_init(smdkc110_audio_init);static int __init smdkc110_audio_init(void)
{smdkc1xx_snd_device = platform_device_alloc("soc-audio", 0);platform_set_drvdata(smdkc1xx_snd_device, &smdkc1xx_snd_devdata);smdkc1xx_snd_devdata.dev = &smdkc1xx_snd_device->dev;platform_device_add(smdkc1xx_snd_device);
}/* audio subsystem */
static struct snd_soc_device smdkc1xx_snd_devdata= {.card = &smdkc100,.codec_dev = &soc_codec_dev_wm8994,.codec_data = &smdkc110_wm8994_setup,
};struct snd_soc_codec_device soc_codec_dev_wm8994= {.probe =  wm8994_probe,.remove =  wm8994_remove,
#ifdef CONFIG_PM.suspend= wm8994_suspend,.resume= wm8994_resume,
#endif
};static struct wm8994_setup_data smdkc110_wm8994_setup = {.i2c_address = 0x34,.i2c_bus = 2,
};
static struct snd_soc_card smdkc100 = {.name = "smdkc110",.platform = &s3c_dma_wrapper,.dai_link = &smdkc1xx_dai,.num_links = 1,
};struct snd_soc_platform s3c_dma_wrapper = {.name  = "samsung-audio",.pcm_ops  = &s3c_wrpdma_ops,.pcm_new = s3c_wrpdma_pcm_new,.pcm_free = s3c_wrpdma_pcm_free,
};/* digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link smdkc1xx_dai = {.name = "WM8994",.stream_name = "WM8994 HiFi Playback",.cpu_dai = &s3c64xx_i2s_dai[I2S_NUM],  //cpu_dai->ops = &s3c64xx_i2s_dai_ops, 最终指向s5p_i2s_xxxx函数.codec_dai= &wm8994_dai,  //codec_dai->ops = &wm8994_ops.init = smdkc110_wm8994_init,.ops = &smdkc110_ops,  //其中hw_params = smdkc110_hw_params
},
其中cpu_dai为s3c64xx_i2s_dai,其ops为s3c64xx_i2s_dai_ops,由s5p_i2sv5_register_dai最终指向s5p_i2s_xxxx(比如s5p_i2s_set_clkdiv/s5p_i2s_set_sysclk).补充: epll_set_rate调用过程...smdkc110_hw_params (或者smdkc110_audio_init)set_epll_rateclk_set_rates5pv210_setup_clocks {clk_fout_epll.enable = s5pv210_epll_enable;clk_fout_epll.ops = &s5pv210_epll_ops;clk_fout_vpll.enable = s5pv210_vpll_enable;clk_fout_vpll.ops = &s5pv210_vpll_ops;
}static struct clk_ops s5pv210_epll_ops = {.get_rate = s5pv210_epll_get_rate,.set_rate = s5pv210_epll_set_rate,
};s5pv210_epll_set_rate 会查epll_div表格,并写 S5P_EPLL_CON, S5P_EPLL_CON_K寄存器. (注意: 若表格未查到则不设置. 这样感觉不好?)补充: 各个clksrc_clk的定义与ops关联, 参考mach-s5pv210\clock.c及plat-samsung\clock-clksrc.c文件.各个clksrc_clk定义在clock.c文件, 比如 /* HCLK_P 133 */
static struct clksrc_clk clk_hclk_133 = {.clk = {.name  = "hclk_133",.id  = -1,},.sources = &clkset_mout_166,.reg_src = { .reg = S5P_CLK_SRC0, .shift = 24, .size = 1 },.reg_div = { .reg = S5P_CLK_DIV0, .shift = 24, .size = 4 },
};各个clksrc_clk归集在sys_clksrc[] 和clksrcs[]数组, 每个clk的ops可以在定义时指定, 若未指定则通过s5pv210_register_clocks\ s3c_register_clksrc根据情况关联到默认ops, 即clksrc_ops/ clksrc_ops_nodiv/ clksrc_ops_nosrc三者之一. 比如:static struct clk_ops clksrc_ops= {.set_parent = s3c_setparent_clksrc,.get_rate = s3c_getrate_clksrc,.set_rate = s3c_setrate_clksrc,.round_rate = s3c_roundrate_clksrc,
};
PC110之monitor clock "XCLKOUT"脚对应之"clk_out"的定义与ops关联struct clk xclk_out = {.name   = "clk_out",.id     = -1,.ops = &s5pc11x_clkout_ops,   //最终指向.set_rate = s5pc11x_clk_out_set_rate, .set_parent = s5pc11x_clk_out_set_parent,
};补充: 背景知识(自己的理解)audio/sound音频部分涉及的几个频率:* 输出采样频率 fs = 44.1KHz.  (也有其它fs的音源, 但加了resampler后, 都变成44.1KHz输出了). 这是个关键频率.* LRCLK, 就等于fs. (L/R声道信号)* BCLK= 32倍fs = 1411.2KHz = 1.4112MHz. (bit clock). 2声道16bit, 故32倍fs (也可选48fs只是浪费了时间). 若2声道24bit, 则48倍fs.  PC100称SCLK.* MCLK是整个audio模块的工作频率, 通常选fs的256, 384, 512倍. 比如: 256倍fs = 11289.6KHz = 11.2896MHz.  PC100称RCLK(Root clk).从频率设置来说, MCLK是个主要频率, 它是整个audio模块的工作频率.通常MCLK是由某个PLL按一定倍数分频得到的, 比如6倍.  (因为MCLK频率只有11.3MHz左右, 如果直接由PLL产生MCLK则频率太低了, PLL不好做). 那么, 这个PLL的输出频率PLLout = 6倍MCLK = 67.7376MHz.那么, 从软件来说要设置两个方面的寄存器: 一是该PLL从晶振频率如何得到PLLout频率(比如P/M/S/k). 二是PLLout如何分频得到audio部分的MCLK.补充: I2S基础知识PC110Inter-IC Sound(IIS)是一种digital audio interface. IIS使用4根线: SDI, SDO(serial data input/output), LRCLK(left/right channel select clock), SCLK (serial bit clock).IIS有master/slave两种模式, 由master提供LRCLK and SCLK. PC110作master时, 可把RCLK输出到CDCLK (codec clk)脚.‍PC110支持IIS, MSB-justified and LSB-justified三种data format.S5PC110 IIS模块可选clock sources三个: PCLK, EPLL and external codec.‍46.5.2 Play Mode (TX mode) with DMA
3. To operate system in stability, the internal TXFIFO should be almost full before transmission. For TXFIFO to be almost full start DMA operation.
46.5.3 Recording Mode (RX mode) with DMA
3. To operate system in stability, the internal RXFIFO should have at least one data before DMA operation. 为什么???要写I2S驱动,对于硬件也要了解。I2S是一种常用的数字音频接口。总线值处理音频数据,像编码和控制这样的其他信号被转移分开。I2S接口传输或者接受声音数据来自于外部立体声音频编码器。用于传输和接受数据,包括两个32x16FIFO数据结构。总线特征:2通道I2S总线用于DMA装置的音频接口运作。串行,8/16位经通道数据传输支持I2S,MSB-justified和LSB-justifed数据格式。下面是电路原理图:左边的CDCLK,I2SSCLK,I2SLRCK,I2SSDI,I2SDO是i2s总线引脚。CDCLK为音频编码器提供解码时钟,I2SSCLK提供了串行位时钟,I2SLRCK是声道控制时钟,I2SSDI声音数据输入,I2SDO声音数据输出。
另外的L3MODE,L3CLOCK,L3DATA控制声音。
I2S主要通过i2s控制寄存器IISCON,i2s模式寄存器IISMOD,预分频IISPSR,FIFO控制寄存器IISFCON,IISFIFO工作。I2S驱动是ASoc驱动组成的一部分。它是平台驱动那部分。这里就只简单说下ASoc主要的3部分:
(1)Codec驱动。这一部分只关心Codec本身,与CPU平台相关的特性不由此部分操作
(2)平台驱动。这一部分只关心CPU本身,它主要处理两个问题:DMA引擎和SOC集成的PCM,I2S或者ac'97数字接口控制
(3)板驱动。这一部分将平台驱动和CODEC驱动绑定在一起,描述了板一级的硬件特征。具体I2S驱动如下:
这里提供了I2S驱动的注册函数snd_soc_register_dai()所要注册的是snd_soc_dai结构体,
具体为
struct snd_soc_dai s3c24xx_i2s_dai = {.name = "s3c24xx-i2s",.id = 0,.probe = s3c24xx_i2s_probe,初始化.suspend = s3c24xx_i2s_suspend,挂起.resume = s3c24xx_i2s_resume,恢复
放音功能.playback = {.channels_min = 2,DMA通道2.channels_max = 2,.rates = S3C24XX_I2S_RATES,放音速率.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
录音功能.capture = {.channels_min = 2,.channels_max = 2,.rates = S3C24XX_I2S_RATES,录音速率.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},.ops = &s3c24xx_i2s_dai_ops,
};
static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {.trigger = s3c24xx_i2s_trigger,触发.hw_params = s3c24xx_i2s_hw_params,硬件参数设置.set_fmt = s3c24xx_i2s_set_fmt,DAI格式.set_clkdiv = s3c24xx_i2s_set_clkdiv,时钟分频.set_sysclk = s3c24xx_i2s_set_sysclk,系统时钟
};
.probe完成了I2S寄存器映射,时钟获取起用,设置GPIO口得相关引脚为I2S功能引脚。启动I2S,不发送不接受状态。
源代码如下:
------------------------------------------------------------------------------------------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
#include <plat/audio.h>
#include <asm/dma.h>
#include <mach/dma.h>
#include <plat/regs-iis.h>
#include "s3c24xx-pcm.h"
#include "s3c24xx-i2s.h"
static struct s3c2410_dma_client s3c24xx_dma_client_out = {.name = "I2S PCM Stereo out"
};
static struct s3c2410_dma_client s3c24xx_dma_client_in = {.name = "I2S PCM Stereo in"
};
static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = {.client  = &s3c24xx_dma_client_out,.channel = DMACH_I2S_OUT,.dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,.dma_size = 2,
};
static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = {.client  = &s3c24xx_dma_client_in,.channel = DMACH_I2S_IN,.dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,.dma_size = 2,
};
struct s3c24xx_i2s_info {void __iomem *regs;struct clk *iis_clk;u32  iiscon;u32  iismod;u32  iisfcon;u32  iispsr;
};
static struct s3c24xx_i2s_info s3c24xx_i2s;
static void s3c24xx_snd_txctrl(int on)
{u32 iisfcon;u32 iiscon;u32 iismod;pr_debug("Entered %s\n", __func__);iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);if (on) {iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;iiscon  |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;iiscon  &= ~S3C2410_IISCON_TXIDLE;iismod  |= S3C2410_IISMOD_TXMODE;writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);} else {iisfcon &= ~S3C2410_IISFCON_TXENABLE;iisfcon &= ~S3C2410_IISFCON_TXDMA;iiscon  |=  S3C2410_IISCON_TXIDLE;iiscon  &= ~S3C2410_IISCON_TXDMAEN;iismod  &= ~S3C2410_IISMOD_TXMODE;writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);}pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
}
static void s3c24xx_snd_rxctrl(int on)
{u32 iisfcon;u32 iiscon;u32 iismod;pr_debug("Entered %s\n", __func__);iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);if (on) {iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;iiscon  |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;iiscon  &= ~S3C2410_IISCON_RXIDLE;iismod  |= S3C2410_IISMOD_RXMODE;writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);} else {iisfcon &= ~S3C2410_IISFCON_RXENABLE;iisfcon &= ~S3C2410_IISFCON_RXDMA;iiscon  |= S3C2410_IISCON_RXIDLE;iiscon  &= ~S3C2410_IISCON_RXDMAEN;iismod  &= ~S3C2410_IISMOD_RXMODE;writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);}pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
}static int s3c24xx_snd_lrsync(void)
{u32 iiscon;int timeout = 50;pr_debug("Entered %s\n", __func__);while (1) {iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);if (iiscon & S3C2410_IISCON_LRINDEX)break;if (!timeout--)return -ETIMEDOUT;udelay(100);}return 0;
}static inline int s3c24xx_snd_is_clkmaster(void)
{pr_debug("Entered %s\n", __func__);return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
}static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,unsigned int fmt)
{u32 iismod;pr_debug("Entered %s\n", __func__);iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("hw_params r: IISMOD: %x \n", iismod);switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {case SND_SOC_DAIFMT_CBM_CFM:iismod |= S3C2410_IISMOD_SLAVE;break;case SND_SOC_DAIFMT_CBS_CFS:iismod &= ~S3C2410_IISMOD_SLAVE;break;default:return -EINVAL;}switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {case SND_SOC_DAIFMT_LEFT_J:iismod |= S3C2410_IISMOD_MSB;break;case SND_SOC_DAIFMT_I2S:iismod &= ~S3C2410_IISMOD_MSB;break;default:return -EINVAL;}writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("hw_params w: IISMOD: %x \n", iismod);return 0;
}
static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params,struct snd_soc_dai *dai)
{struct snd_soc_pcm_runtime *rtd = substream->private_data;u32 iismod;pr_debug("Entered %s\n", __func__);if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out;elsertd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in;iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("hw_params r: IISMOD: %x\n", iismod);switch (params_format(params)) {case SNDRV_PCM_FORMAT_S8:iismod &= ~S3C2410_IISMOD_16BIT;((struct s3c24xx_pcm_dma_params *)rtd->dai->cpu_dai->dma_data)->dma_size = 1;break;case SNDRV_PCM_FORMAT_S16_LE:iismod |= S3C2410_IISMOD_16BIT;((struct s3c24xx_pcm_dma_params *)rtd->dai->cpu_dai->dma_data)->dma_size = 2;break;default:return -EINVAL;}writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("hw_params w: IISMOD: %x\n", iismod);return 0;
}
static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,struct snd_soc_dai *dai)
{int ret = 0;struct snd_soc_pcm_runtime *rtd = substream->private_data;int channel = ((struct s3c24xx_pcm_dma_params *)rtd->dai->cpu_dai->dma_data)->channel;pr_debug("Entered %s\n", __func__);switch (cmd) {case SNDRV_PCM_TRIGGER_START:case SNDRV_PCM_TRIGGER_RESUME:case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:if (!s3c24xx_snd_is_clkmaster()) {ret = s3c24xx_snd_lrsync();if (ret)goto exit_err;}if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)s3c24xx_snd_rxctrl(1);elses3c24xx_snd_txctrl(1);s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);break;case SNDRV_PCM_TRIGGER_STOP:case SNDRV_PCM_TRIGGER_SUSPEND:case SNDRV_PCM_TRIGGER_PAUSE_PUSH:if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)s3c24xx_snd_rxctrl(0);elses3c24xx_snd_txctrl(0);break;default:ret = -EINVAL;break;}
exit_err:return ret;
}static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,int clk_id, unsigned int freq, int dir)
{u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);pr_debug("Entered %s\n", __func__);iismod &= ~S3C2440_IISMOD_MPLL;switch (clk_id) {case S3C24XX_CLKSRC_PCLK:break;case S3C24XX_CLKSRC_MPLL:iismod |= S3C2440_IISMOD_MPLL;break;default:return -EINVAL;}writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);return 0;
}static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,int div_id, int div)
{u32 reg;pr_debug("Entered %s\n", __func__);switch (div_id) {case S3C24XX_DIV_BCLK:reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);break;case S3C24XX_DIV_MCLK:reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);break;case S3C24XX_DIV_PRESCALER:writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);break;default:return -EINVAL;}return 0;
}u32 s3c24xx_i2s_get_clockrate(void)
{return clk_get_rate(s3c24xx_i2s.iis_clk);
}
EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
static int s3c24xx_i2s_probe(struct platform_device *pdev,struct snd_soc_dai *dai)
{pr_debug("Entered %s\n", __func__);s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);if (s3c24xx_i2s.regs == NULL)return -ENXIO;s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");if (s3c24xx_i2s.iis_clk == NULL) {pr_err("failed to get iis_clock\n");iounmap(s3c24xx_i2s.regs);return -ENODEV;}clk_enable(s3c24xx_i2s.iis_clk);s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);s3c24xx_snd_txctrl(0);s3c24xx_snd_rxctrl(0);return 0;
}
#ifdef CONFIG_PM
static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
{pr_debug("Entered %s\n", __func__);s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);clk_disable(s3c24xx_i2s.iis_clk);return 0;
}
static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
{pr_debug("Entered %s\n", __func__);clk_enable(s3c24xx_i2s.iis_clk);writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);return 0;
}
#else
#define s3c24xx_i2s_suspend NULL
#define s3c24xx_i2s_resume NULL
#endif#define S3C24XX_I2S_RATES \(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {.trigger = s3c24xx_i2s_trigger,.hw_params = s3c24xx_i2s_hw_params,.set_fmt = s3c24xx_i2s_set_fmt,.set_clkdiv = s3c24xx_i2s_set_clkdiv,.set_sysclk = s3c24xx_i2s_set_sysclk,
};
struct snd_soc_dai s3c24xx_i2s_dai = {.name = "s3c24xx-i2s",.id = 0,.probe = s3c24xx_i2s_probe,.suspend = s3c24xx_i2s_suspend,.resume = s3c24xx_i2s_resume,.playback = {.channels_min = 2,.channels_max = 2,.rates = S3C24XX_I2S_RATES,.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},.capture = {.channels_min = 2,.channels_max = 2,.rates = S3C24XX_I2S_RATES,.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},.ops = &s3c24xx_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
static int __init s3c24xx_i2s_init(void)
{return snd_soc_register_dai(&s3c24xx_i2s_dai);
}
module_init(s3c24xx_i2s_init);
static void __exit s3c24xx_i2s_exit(void)
{snd_soc_unregister_dai(&s3c24xx_i2s_dai);
}
module_exit(s3c24xx_i2s_exit);MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
MODULE_LICENSE("GPL");

音频audio/sound声卡驱动分析相关推荐

  1. S3C2440 音频解码芯片WM8976声卡驱动移植、测试以及madplay播放mp3文件(三十一)

    https://www.cnblogs.com/lifexy/p/7867782.html 本节学习: 分析linux中的OOS声卡系统 修改s3c2410-uda1341.c的控制部分,移植wm89 ...

  2. s3c2440 uda1341声卡驱动分析

    1,驱动架构: 驱动分两个层次,上层是平台设备驱动,底层是audio驱动与mixer驱动. (1)标准的平台设备驱动结构,probe与remove两个函数. probe: 获得平台资源->申请内 ...

  3. 瑞昱Realtek(Realtek HD Audio Driver)音频声卡驱动R2.49 for Win7_Vista

    不管是在高端系列主板上,还是在低端系列主板上,我们都能看到Realtek瑞昱的身影,Realtek HD Audio Driver能够支持所有的Realtek HD Audio音频驱动.Realtek ...

  4. linux音频驱动程序测试,Linux声卡驱动移植和测试

    一.分析驱动程序,根据开发板修改代码 代码太长,就不贴了,几个注意点: 1. 查看开发板原理图和S3C2410的datasheet,UDA1341的L3MODE.L3DATA.L3CLOCK分别与S3 ...

  5. linux内核声卡管理,浅析linux 2.6.30.4内核中uda134x声卡驱动源码 - audio和bluetooth

    文件:sound/soc/s3c24xx/s3c24xx_uda134x.c static int __init s3c24xx_uda134x_init(void) { return platfor ...

  6. SM8150 Audio驱动分析

    1. TDM硬件接口介绍: I2S只能传2个声道的数据,PCM可以传多达16路数据,采用时分复用的方式,就是TDM. TDM不像I2S有统一的标准,不同的IC厂商在应用TDM时可能略有差异,这些差异表 ...

  7. linux centos fedora audio root 普通用户声卡驱动安装 加载 声音

    linux  centos fedora Audio root 及普通用户声卡及声音的问题 大家用linux大部分当作服务器用的,谁用这玩意听歌,看电影啊,毕竟是玩吗,玩来玩去,声音给浪丢了,那也不能 ...

  8. 装声卡驱动时出现英文VIA AC97 Audio Chipset is not found on this system!的解决方法

    (半转载半原创)原因是没有把声卡驱动卸载完全!!! 解决方法: 手动删除Windows HD总线驱动,然后再安装厂商驱动,这样一来就不会因为Windows HD总线驱动的存在而产生冲突了. 分为五个步 ...

  9. 关于Realtek HD Audio声卡驱动与系统HD总线驱动冲突的问题

    历时两天,可算把一个麻烦的问题解决了,就是关于Realtek HD Audio声卡驱动与系统HD总线驱动冲突的问题.现详细说说问题的产生及解决方法. 问题的产生: 先说下什么是HD Audio.&qu ...

最新文章

  1. Linux的视频编程(V4L2编程)【转】
  2. 指纹图谱相似度评价软件_远志与炆远志指纹图谱比较
  3. 13.MATLAB的while、for、break、continue循环操作
  4. 学习记录-交叉编译环境的设置
  5. 【.NET 遇上 GraphQL】使用 Hot Chocolate 构建 GraphQL 服务
  6. python如果选择不在列表里_Python-list.remove(x)x不在列表中
  7. python中read和readline的区别_Python中read()、readline()和readlines()三者间的区别和用法...
  8. linux 测试cpu计算圆周率_Linux下测试CPU性能
  9. 拉勾数据分析岗数据分析报告
  10. nfc加密卡pm3和pm5区别_【黑科技】NFC模拟门卡门禁
  11. Go操作MySQL数据库库
  12. 2020-10-05 Python编程从入门到实践 第16章 下载数据 动手试一试 16-2 比较锡特卡和死亡谷的气温 习题练习
  13. MindSpore21天实战营(1):基于MindSpore Lite开发目标检测的安卓APP实战
  14. 杰理AC692N---芯片烧录方法和常用的更新固件方法
  15. 多媒体卡和SD卡的卡识别过程
  16. BundleFusion的实现——RealSense D435i+Win10+VS2013+cuda8.0
  17. 关于面试总结1-SQL学生表
  18. SpringBoot设置默认主页
  19. 青源Seminar丨NAACL专场:Language Modeling Summarization
  20. 凡科网站是php类型么,建网站?那要搞清楚网站类型

热门文章

  1. java学习笔记之线程(一)
  2. iOS核心动画详解swift版----基础动画
  3. diamond专题(一)– 简介和快速使用
  4. swing Ctrl+S 保存配置
  5. 【Objective-C】08-self关键字
  6. Ubuntu安装cacti步骤
  7. [K/3Cloud] 调用其他界面时通过Session传递对象参数
  8. 十法则打造安全无线局域网
  9. 本地缓存到分布式缓存( Guava, Caffeine, Memcached, Redis)
  10. NLP--- 将改变你未来沟通方式的7种NLP技术(第二部分)