linux音频子系统 - ASoC-PCM之codec和platform

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l289123557/article/details/79449940

从前面的文章已经知道platform和codec分别代表不同的组件,对于不同厂家各个芯片,只要注册相应的驱动到codec和platform中,然后具体使用哪个驱动,只要在machine中匹配就好,那么关于platform和codec的注册本文简单说明下

platform说明

struct snd_soc_platform

struct snd_soc_platform {
    const char *name;
    int id;
    struct device *dev;
    const struct snd_soc_platform_driver *driver;
    struct mutex mutex;

    unsigned int suspended:1; /* platform is suspended */
    unsigned int probed:1;

    struct snd_soc_card *card;
    struct list_head list;
    struct list_head card_list;

    struct snd_soc_dapm_context dapm;

#ifdef CONFIG_DEBUG_FS
    struct dentry *debugfs_platform_root;
    struct dentry *debugfs_dapm;
#endif
};

struct snd_soc_platform_driver

struct snd_soc_platform_driver {

    int (*probe)(struct snd_soc_platform *);
    int (*remove)(struct snd_soc_platform *);
    int (*suspend)(struct snd_soc_dai *dai);
    int (*resume)(struct snd_soc_dai *dai);

    /* pcm creation and destruction */
    int (*pcm_new)(struct snd_soc_pcm_runtime *);
    void (*pcm_free)(struct snd_pcm *);

    /* Default control and setup, added after probe() is run */
    const struct snd_kcontrol_new *controls;
    int num_controls;
    const struct snd_soc_dapm_widget *dapm_widgets;
    int num_dapm_widgets;
    const struct snd_soc_dapm_route *dapm_routes;
    int num_dapm_routes;

    /*
     * For platform caused delay reporting.
     * Optional.
     */
    snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
        struct snd_soc_dai *);

    /* platform stream pcm ops */
    const struct snd_pcm_ops *ops;-----------------对于platform中的操作都执行此字段中的函数

    /* platform stream compress ops */
    const struct snd_compr_ops *compr_ops;

    /* platform stream completion event */
    int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);

    /* probe ordering - for components with runtime dependencies */
    int probe_order;
    int remove_order;

    /* platform IO - used for platform DAPM */
    unsigned int (*read)(struct snd_soc_platform *, unsigned int);
    int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
    int (*bespoke_trigger)(struct snd_pcm_substream *, int);
};

platform组件注册

platform注册调用的函数是:

int snd_soc_register_platform(struct device *dev,
        const struct snd_soc_platform_driver *platform_drv)

snd_soc_register_platform会调用函数snd_soc_add_platform:

int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
        const struct snd_soc_platform_driver *platform_drv)
{
    /* create platform component name */
    platform->name = fmt_single_name(dev, &platform->id);
    if (platform->name == NULL) {
        kfree(platform);
        return -ENOMEM;
    }

    platform->dev = dev;
    platform->driver = platform_drv;
    platform->dapm.dev = dev;
    platform->dapm.platform = platform;
    platform->dapm.stream_event = platform_drv->stream_event;
    mutex_init(&platform->mutex);

    mutex_lock(&client_mutex);
    list_add(&platform->list, &platform_list);----------------------将platform对象加入到platform_list全局链表中
    mutex_unlock(&client_mutex);

    dev_dbg(dev, "ASoC: Registered platform '%s'\n", platform->name);

    return 0;
}

codec说明

struct snd_soc_codec

struct snd_soc_codec {
    const char *name;
    const char *name_prefix;
    int id;
    struct device *dev;
    const struct snd_soc_codec_driver *driver;

    struct mutex mutex;
    struct snd_soc_card *card;
    struct list_head list;
    struct list_head card_list;
    int num_dai;
    enum snd_soc_compress_type compress_type;
    size_t reg_size;    /* reg_cache_size * reg_word_size */
    int (*volatile_register)(struct snd_soc_codec *, unsigned int);
    int (*readable_register)(struct snd_soc_codec *, unsigned int);
    int (*writable_register)(struct snd_soc_codec *, unsigned int);

    /* runtime */
    struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
    unsigned int active;
    unsigned int cache_bypass:1; /* Suppress access to the cache */
    unsigned int suspended:1; /* Codec is in suspend PM state */
    unsigned int probed:1; /* Codec has been probed */
    unsigned int ac97_registered:1; /* Codec has been AC97 registered */
    unsigned int ac97_created:1; /* Codec has been created by SoC */
    unsigned int sysfs_registered:1; /* codec has been sysfs registered */
    unsigned int cache_init:1; /* codec cache has been initialized */
    unsigned int using_regmap:1; /* using regmap access */
    u32 cache_only;  /* Suppress writes to hardware */
    u32 cache_sync; /* Cache needs to be synced to hardware */

    /* codec IO */
    void *control_data; /* codec control (i2c/3wire) data */
    enum snd_soc_control_type control_type;
    hw_write_t hw_write;
    unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
    unsigned int (*read)(struct snd_soc_codec *, unsigned int);
    int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
    int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
    void *reg_cache;
    const void *reg_def_copy;
    const struct snd_soc_cache_ops *cache_ops;
    struct mutex cache_rw_mutex;
    int val_bytes;

    /* dapm */
    struct snd_soc_dapm_context dapm;
    unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */

#ifdef CONFIG_DEBUG_FS
    struct dentry *debugfs_codec_root;
    struct dentry *debugfs_reg;
    struct dentry *debugfs_dapm;
#endif
};

struct snd_soc_codec_driver

struct snd_soc_codec_driver {

    /* driver ops */
    int (*probe)(struct snd_soc_codec *);
    int (*remove)(struct snd_soc_codec *);
    int (*suspend)(struct snd_soc_codec *);
    int (*resume)(struct snd_soc_codec *);

    /* Default control and setup, added after probe() is run */
    const struct snd_kcontrol_new *controls;
    int num_controls;
    const struct snd_soc_dapm_widget *dapm_widgets;
    int num_dapm_widgets;
    const struct snd_soc_dapm_route *dapm_routes;
    int num_dapm_routes;

    /* codec wide operations */
    int (*set_sysclk)(struct snd_soc_codec *codec,
              int clk_id, int source, unsigned int freq, int dir);
    int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,
        unsigned int freq_in, unsigned int freq_out);

    /* codec IO */
    unsigned int (*read)(struct snd_soc_codec *, unsigned int);
    int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
    int (*display_register)(struct snd_soc_codec *, char *,
                size_t, unsigned int);
    int (*volatile_register)(struct snd_soc_codec *, unsigned int);
    int (*readable_register)(struct snd_soc_codec *, unsigned int);
    int (*writable_register)(struct snd_soc_codec *, unsigned int);
    unsigned int reg_cache_size;
    short reg_cache_step;
    short reg_word_size;
    const void *reg_cache_default;
    short reg_access_size;
    const struct snd_soc_reg_access *reg_access_default;
    enum snd_soc_compress_type compress_type;

    /* codec bias level */
    int (*set_bias_level)(struct snd_soc_codec *,
                  enum snd_soc_bias_level level);
    bool idle_bias_off;

    void (*seq_notifier)(struct snd_soc_dapm_context *,
                 enum snd_soc_dapm_type, int);

    /* codec stream completion event */
    int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);

    bool ignore_pmdown_time;  /* Doesn't benefit from pmdown delay */

    /* probe ordering - for components with runtime dependencies */
    int probe_order;
    int remove_order;
};

codec注册

codec注册调用snd_soc_register_codec

int snd_soc_register_codec(struct device *dev,
               const struct snd_soc_codec_driver *codec_drv,
               struct snd_soc_dai_driver *dai_drv,
               int num_dai)
{
    size_t reg_size;
    struct snd_soc_codec *codec;
    int ret, i;

    dev_dbg(dev, "codec register %s\n", dev_name(dev));

    codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
    if (codec == NULL)
        return -ENOMEM;

    /* create CODEC component name */
    codec->name = fmt_single_name(dev, &codec->id);
    if (codec->name == NULL) {
        ret = -ENOMEM;
        goto fail_codec;
    }

    if (codec_drv->compress_type)
        codec->compress_type = codec_drv->compress_type;
    else
        codec->compress_type = SND_SOC_FLAT_COMPRESSION;

    codec->write = codec_drv->write;
    codec->read = codec_drv->read;
    codec->volatile_register = codec_drv->volatile_register;
    codec->readable_register = codec_drv->readable_register;
    codec->writable_register = codec_drv->writable_register;
    codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
    codec->dapm.bias_level = SND_SOC_BIAS_OFF;
    codec->dapm.dev = dev;
    codec->dapm.codec = codec;
    codec->dapm.seq_notifier = codec_drv->seq_notifier;
    codec->dapm.stream_event = codec_drv->stream_event;
    codec->dev = dev;
    codec->driver = codec_drv;
    codec->num_dai = num_dai;
    mutex_init(&codec->mutex);

    /* allocate CODEC register cache */
    if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
        reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
        codec->reg_size = reg_size;
        /* it is necessary to make a copy of the default register cache
         * because in the case of using a compression type that requires
         * the default register cache to be marked as the
         * kernel might have freed the array by the time we initialize
         * the cache.
         */
        if (codec_drv->reg_cache_default) {
            codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
                              reg_size, GFP_KERNEL);
            if (!codec->reg_def_copy) {
                ret = -ENOMEM;
                goto fail_codec_name;
            }
        }
    }

    if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
        if (!codec->volatile_register)
            codec->volatile_register = snd_soc_default_volatile_register;
        if (!codec->readable_register)
            codec->readable_register = snd_soc_default_readable_register;
        if (!codec->writable_register)
            codec->writable_register = snd_soc_default_writable_register;
    }

    for (i = 0; i < num_dai; i++) {
        fixup_codec_formats(&dai_drv[i].playback);
        fixup_codec_formats(&dai_drv[i].capture);
    }

    mutex_lock(&client_mutex);
    list_add(&codec->list, &codec_list);---------------------加入到codec全局链表中
    mutex_unlock(&client_mutex);

    /* register any DAIs */
    ret = snd_soc_register_dais(dev, dai_drv, num_dai);------封装另一个dai结构加入到dai链表中
    if (ret < 0) {
        dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret);
        goto fail_codec_name;
    }

    dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name);
    return 0;

fail_codec_name:
    mutex_lock(&client_mutex);
    list_del(&codec->list);
    mutex_unlock(&client_mutex);

    kfree(codec->name);
fail_codec:
    kfree(codec);
    return ret;
}

对于函数snd_soc_register_dais,主要是由于pcm操作的时候直接调dai中的ops函数

static int snd_soc_register_dais(struct device *dev,
        struct snd_soc_dai_driver *dai_drv, size_t count)
{
    struct snd_soc_codec *codec;
    struct snd_soc_dai *dai;
    int i, ret = 0;

    dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);

    for (i = 0; i < count; i++) {

        dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
        if (dai == NULL) {
            ret = -ENOMEM;
            goto err;
        }

        /* create DAI component name */
        dai->name = fmt_multiple_name(dev, &dai_drv[i]);
        if (dai->name == NULL) {
            kfree(dai);
            ret = -EINVAL;
            goto err;
        }

        dai->dev = dev;
        dai->driver = &dai_drv[i];
        if (dai->driver->id)
            dai->id = dai->driver->id;
        else
            dai->id = i;
        dai->dapm.dev = dev;
        if (!dai->driver->ops)
            dai->driver->ops = &null_dai_ops;

        mutex_lock(&client_mutex);

        list_for_each_entry(codec, &codec_list, list) {
            if (codec->dev == dev) {
                dev_dbg(dev, "ASoC: Mapped DAI %s to "
                    "CODEC %s\n", dai->name, codec->name);
                dai->codec = codec;
                break;
            }
        }

        if (!dai->codec)
            dai->dapm.idle_bias_off = 1;

        list_add(&dai->list, &dai_list);

        mutex_unlock(&client_mutex);

        dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name);
    }

    return 0;

err:
    for (i--; i >= 0; i--)
        snd_soc_unregister_dai(dev);

    return ret;
}

codec-dai

在machine文章中我们知道在匹配的时候,主要是匹配的dai,codec就会封装一个相应的dai结构到链表中

dai结构体

struct snd_soc_dai {
    const char *name;
    int id;
    struct device *dev;
    void *ac97_pdata;   /* platform_data for the ac97 codec */

    /* driver ops */
    struct snd_soc_dai_driver *driver;

    /* DAI runtime info */
    unsigned int capture_active:1;      /* stream is in use */
    unsigned int playback_active:1;     /* stream is in use */
    unsigned int symmetric_rates:1;
    struct snd_pcm_runtime *runtime;
    unsigned int active;
    unsigned char probed:1;

    struct snd_soc_dapm_widget *playback_widget;
    struct snd_soc_dapm_widget *capture_widget;
    struct snd_soc_dapm_context dapm;

    /* DAI DMA data */
    void *playback_dma_data;
    void *capture_dma_data;

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

    /* parent platform/codec */
    struct snd_soc_platform *platform;
    struct snd_soc_codec *codec;

    struct snd_soc_card *card;

    struct list_head list;
    struct list_head card_list;
};

struct snd_soc_dai_driver

具体执行的操作函数在结构体snd_soc_dai_driver中表示:

struct snd_soc_dai_driver {
    /* DAI description */
    const char *name;
    unsigned int id;
    int ac97_control;
    unsigned int base;

    /* DAI driver callbacks */
    int (*probe)(struct snd_soc_dai *dai);
    int (*remove)(struct snd_soc_dai *dai);
    int (*suspend)(struct snd_soc_dai *dai);
    int (*resume)(struct snd_soc_dai *dai);
    /* compress dai */
    bool compress_dai;

    /* ops */
    const struct snd_soc_dai_ops *ops;-----------pcm会操作此函数

    /* DAI capabilities */
    struct snd_soc_pcm_stream capture;
    struct snd_soc_pcm_stream playback;
    unsigned int symmetric_rates:1;

    /* probe ordering - for components with runtime dependencies */
    int probe_order;
    int remove_order;
};

猜你喜欢

转载自blog.csdn.net/l289123557/article/details/79449940