首页 > 其他 > 详细

ASOC 驱动架构

时间:2021-02-02 11:25:29      阅读:25      评论:0      收藏:0      [点我收藏+]

前言

针对嵌入式设备,linux在ALSA的基础上又封装了一层,名为ASOC(ALSA system on chip)。使用ASOC就不需要自己调用snd_card_create、snd_ctrl_create等函数自己来创建声卡。ASOC将驱动程序分为3部分:

1)machine:单板相关的内容。

a. 表明platform是哪一个, CPU DAI是哪一个,DMA是哪一个,即哪个DMA负责数据传输。

b. 表明codec是哪一个,codec DAI是哪一个

2)platform

a. DAI:设置接口

b. DMA:传送数据

3)codec

a. DAI

b. 控制接口

在Linux驱动中,肯定有多个platform和codec。对于某个单板,使用哪款主芯片(platform),哪款codec芯片在machine中指定。

内核中带有UDA1341的驱动程序,但是没有WM8976的驱动程序。首先分析UDA1341的驱动程序

1. machine

/sound/soc/samsung/S3c24xx_uda134x.c

static struct platform_driver s3c24xx_uda134x_driver = {
    .probe  = s3c24xx_uda134x_probe,
    .remove = s3c24xx_uda134x_remove,
    .driver = {
        .name = "s3c24xx_uda134x",
        .owner = THIS_MODULE,
    },
};

有平台driver,肯定有同名的平台device(这是一种老的方式,现在都使用设备树了),搜索s3c24xx_uda134x

arch/arm/mach-s3c24xx/Mach-mini2440.c

static struct platform_device mini2440_audio = {
    .name        = "s3c24xx_uda134x",
    .id        = 0,
    .dev        = {
        .platform_data    = &mini2440_audio_pins,
    },
};

当内核中有同名的平台driver和平台device时,platform_driver 中的probe函数将会调用。

static int s3c24xx_uda134x_probe(struct platform_device *pdev)
{
    int ret;

    printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
    
    ......
    s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
    
    platform_set_drvdata(s3c24xx_uda134x_snd_device,
                 &snd_soc_s3c24xx_uda134x);
    platform_device_add_data(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x, sizeof(s3c24xx_uda134x));
    ret = platform_device_add(s3c24xx_uda134x_snd_device);
    
    return ret;
}

又出现了平台device soc-audio,在内核中搜索soc-audio

/sound/soc/Soc-core.c

/* ASoC platform driver */
static struct platform_driver soc_driver = {
    .driver        = {
        .name        = "soc-audio",
        .owner        = THIS_MODULE,
        .pm        = &snd_soc_pm_ops,
    },
    .probe        = soc_probe,
    .remove        = soc_remove,
};

soc_probe函数将被调用

/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
    struct snd_soc_card *card = platform_get_drvdata(pdev);
    int ret = 0;
    ........
    card->dev = &pdev->dev;

    ret = snd_soc_register_card(card);

    return 0;
}

注册一个snd_soc_card的结构体。该结构体具体指哪一个?就是snd_soc_s3c24xx_uda134x

/sound/soc/samsung/S3c24xx_uda134x.c

static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
    .name = "S3C24XX_UDA134X",
    .owner = THIS_MODULE,
    .dai_link = &s3c24xx_uda134x_dai_link,
    .num_links = 1,
};
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
    .name = "UDA134X",
    .stream_name = "UDA134X",
    .codec_name = "uda134x-codec",//用哪一个codec
    .codec_dai_name = "uda134x-hifi",//codec芯片中的哪一个DAI,因为有些codec中有多个数字接口
    .cpu_dai_name = "s3c24xx-iis",//2440的DAI接口
    .ops = &s3c24xx_uda134x_ops,
    .platform_name    = "samsung-audio",//DMA
};

 

static struct snd_soc_ops s3c24xx_uda134x_ops = {
    .startup = s3c24xx_uda134x_startup,
    .shutdown = s3c24xx_uda134x_shutdown,
    .hw_params = s3c24xx_uda134x_hw_params,
};

machine部分到此结束,它主要就是构造了一个snd_soc_card结构体 。在该结构体中有一个dai_link,在dai_link中指定了codec_name,code_dai_name,cpu_dai_name以及platform_name.

2. platform

2.1 cpu dai

搜索s3c24xx-iis

/sound/soc/samsung/S3c24xx-i2s.c

static struct platform_driver s3c24xx_iis_driver = {
    .probe  = s3c24xx_iis_dev_probe,
    .remove = __devexit_p(s3c24xx_iis_dev_remove),
    .driver = {
        .name = "s3c24xx-iis",
        .owner = THIS_MODULE,
    },
};

有平台driver,必然有同名的平台device

/arch/arm/plat-samsung/Devs.c

struct platform_device s3c_device_iis = {
    .name        = "s3c24xx-iis",
    .id        = -1,
    .num_resources    = ARRAY_SIZE(s3c_iis_resource),
    .resource    = s3c_iis_resource,
    .dev        = {
        .dma_mask        = &samsung_device_dma_mask,
        .coherent_dma_mask    = DMA_BIT_MASK(32),
    }
};

因此函数s3c24xx_iis_dev_probe将被调用,

static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
{
    return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
}

 

static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
    .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,
};

至此,platform中最重要的cpu DAI接口——> snd_soc_dai_driver 就出现了

static const 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,
};

 

2.2 DMA

根据结构体snd_soc_dai_link中的  platform_name = "samsung-audio",在代码中搜索samsung-audio

/sound/soc/samsung/Dma.c

static struct platform_driver asoc_dma_driver = {
    .driver = {
        .name = "samsung-audio",
        .owner = THIS_MODULE,
    },

    .probe = samsung_asoc_platform_probe,
    .remove = __devexit_p(samsung_asoc_platform_remove),
};

又出现了一个平台driver,要想这个平台driver起作用,必定会有一个平台device.

/arch/arm/plat-samsung/Devs.c

/* ASOC DMA */

struct platform_device samsung_asoc_dma = {
    .name        = "samsung-audio",
    .id        = -1,
    .dev        = {
        .dma_mask        = &samsung_device_dma_mask,
        .coherent_dma_mask    = DMA_BIT_MASK(32),
    }
};

/sound/soc/samsung/Dma.c

static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)
{
    return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
}

 

static struct snd_soc_platform_driver samsung_asoc_platform = {
    .ops        = &dma_ops,
    .pcm_new    = dma_new,
    .pcm_free    = dma_free_dma_buffers,
};

 

static struct snd_pcm_ops dma_ops = {
    .open        = dma_open,
    .close        = dma_close,
    .ioctl        = snd_pcm_lib_ioctl,
    .hw_params    = dma_hw_params,
    .hw_free    = dma_hw_free,
    .prepare    = dma_prepare,
    .trigger    = dma_trigger,
    .pointer    = dma_pointer,
    .mmap        = dma_mmap,
};

至此,platform的DMA这部分分析完毕,这部分主要就是注册了一个snd_soc_platform_driver的结构体。

3. codec

 

ASOC 驱动架构

原文:https://www.cnblogs.com/-glb/p/14359899.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!