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

从前面的文章已经知道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;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值