from:http://blog.csdn.net/wby0322/article/details/5996046

前天接个任务,要做0718的i2s的驱动,基于linux的。昨天看了一下三星的代码,把分析结果写上以供参考。

注意:i2s驱动是作为接口驱动,供linux音频驱动使用的,因此它的代码中,必然要有音频驱动的一些东西。分析的时候适当的结合一下音频驱动就好看了。

内容有些乱,都是看代码时候发散出来的。见谅。相对独立的部分中间有空行。

源代码文件位置:
kernel_src/sound/soc/s3c24xx/s3c24xx-i2s.c
kernel_src/sound/soc/s3c24xx/s3c24xx-i2s.h

内核版本号:2.6.32

模块初始化函数,实现了向系统注册"数字音频接口设备-DAI"的操作。
snd_soc_register_dai(&s3c24xx_i2s_dai);

/*
* Digital Audio Interface runtime data.
*
* Holds runtime data for a DAI.
*/
struct snd_soc_dai{}

s3c24xx_i2s_dai 填充了struct 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,
        .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,
};

 

 

主要成员的实现
函数    .probe = s3c24xx_i2s_probe,
结构体    .ops = &s3c24xx_i2s_dai_ops,

函数.probe = s3c24xx_i2s_probe,的主要工作
{
iis寄存器 ioremap;
iis时钟;
配置GPIO引脚;
s3c24xx_snd_txctrl(0);
s3c24xx_snd_rxctrl(0);
}

结构体    .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 format
    .set_clkdiv    = s3c24xx_i2s_set_clkdiv,    时钟分频
    .set_sysclk    = s3c24xx_i2s_set_sysclk,    系统时钟
};

.trigger    = s3c24xx_i2s_trigger,        触发
根据六种情况,对iis进行不同的触发,case语句实现。
触发的内容有三个操作:触发时钟,触发发送接收(s3c24xx_snd_txctrl(0) or s3c24xx_snd_rxctrl(0)),触发DMA通道

.hw_params    = s3c24xx_i2s_hw_params,    硬件参数
决定是8位还是16位传输通道宽度(IIS工作模式),并设定对应的dma宽度。case语句实现。

.set_fmt    = s3c24xx_i2s_set_fmt,        DAI format
决定主从模式。数据最高位。

.set_sysclk    = s3c24xx_i2s_set_sysclk,    系统时钟
设定iis的时钟源

.set_clkdiv    = s3c24xx_i2s_set_clkdiv,    时钟分频
设定iis的时钟分频
串行时钟频率的选择16fs,32fs,48fs
主时钟频率选择256fs,348fs
分频值的设定

 

 

struct snd_soc_dai结构会注册到struct snd_soc_dai_link中,在声卡驱动里面

e.g.
kernel_src/sound/soc/s3c24xx/s3c24xx_uda134x

static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
    .name = "UDA134X",
    .stream_name = "UDA134X",
    .codec_dai = &uda134x_dai,
    .cpu_dai = &s3c24xx_i2s_dai,
    .ops = &s3c24xx_uda134x_ops,
};
这里面我们可以看见iis作为DAI借口是面向cpu的。

 

struct snd_soc_dai_link  {
    char *name;            /* Codec name */
    char *stream_name;        /* Stream name */

    /* DAI */
    struct snd_soc_dai *codec_dai;
    struct snd_soc_dai *cpu_dai;

    /* machine stream operations */
    struct snd_soc_ops *ops;

    /* codec/machine specific init - e.g. add machine controls */
    int (*init)(struct snd_soc_codec *codec);

    /* Symmetry requirements */
    unsigned int symmetric_rates:1;

    /* Symmetry data - only valid if symmetry is being enforced */
    unsigned int rate;

    /* DAI pcm */
    struct snd_pcm *pcm;
};

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐