[alsa-devel] [PATCH v3] ASOC: dapm: add code to configure dai link parameters

Vinod Koul vinod.koul at intel.com
Thu Aug 7 16:16:05 CEST 2014


On Wed, Aug 06, 2014 at 05:16:26PM +0100, Nikesh Oswal wrote:
> dai-link params for codec-codec links were fixed. The fixed
> link between codec and another chip which may be another codec,
> baseband, bluetooth codec etc may require run time configuaration
> changes. This change provides an optional alsa control to select
> one of the params from a list of params.

Sorry haven't followed the previous versions, so excuse me if questions were
discussed already.

I was thinking about this as well a while back, wont it make sense to let
machine driver expose meaningful controls for this. Just like we have fixup
for back-ends, we can add fixups for codec-codec links and let machine tell
you the parameters to configure.

Thoughts...?

-- 
~Vinod

> 
> Signed-off-by: Nikesh Oswal <nikesh at opensource.wolfsonmicro.com>
> ---
>  include/sound/soc-dapm.h |    3 +
>  include/sound/soc.h      |    1 +
>  sound/soc/soc-core.c     |    4 +-
>  sound/soc/soc-dapm.c     |  140 ++++++++++++++++++++++++++++++++++++++++++++--
>  4 files changed, 141 insertions(+), 7 deletions(-)
> 
> diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
> index 6b59471..3ee031e 100644
> --- a/include/sound/soc-dapm.h
> +++ b/include/sound/soc-dapm.h
> @@ -378,6 +378,7 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
>  void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
>  int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
>  			 const struct snd_soc_pcm_stream *params,
> +			 unsigned int num_params,
>  			 struct snd_soc_dapm_widget *source,
>  			 struct snd_soc_dapm_widget *sink);
>  
> @@ -531,6 +532,8 @@ struct snd_soc_dapm_widget {
>  	void *priv;				/* widget specific data */
>  	struct regulator *regulator;		/* attached regulator */
>  	const struct snd_soc_pcm_stream *params; /* params for dai links */
> +	unsigned int num_params; /* number of params for dai links */
> +	unsigned int params_select; /* currently selected param for dai link */
>  
>  	/* dapm control */
>  	int reg;				/* negative reg = no direct dapm */
> diff --git a/include/sound/soc.h b/include/sound/soc.h
> index ed9e2d7..51c6c4f 100644
> --- a/include/sound/soc.h
> +++ b/include/sound/soc.h
> @@ -906,6 +906,7 @@ struct snd_soc_dai_link {
>  	int be_id;	/* optional ID for machine driver BE identification */
>  
>  	const struct snd_soc_pcm_stream *params;
> +	unsigned int num_params;
>  
>  	unsigned int dai_fmt;           /* format to set on init */
>  
> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
> index b87d7d8..db1572a 100644
> --- a/sound/soc/soc-core.c
> +++ b/sound/soc/soc-core.c
> @@ -1461,7 +1461,7 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
>  	capture_w = cpu_dai->capture_widget;
>  	if (play_w && capture_w) {
>  		ret = snd_soc_dapm_new_pcm(card, dai_link->params,
> -					   capture_w, play_w);
> +					   dai_link->num_params, capture_w, play_w);
>  		if (ret != 0) {
>  			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
>  				play_w->name, capture_w->name, ret);
> @@ -1473,7 +1473,7 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
>  	capture_w = codec_dai->capture_widget;
>  	if (play_w && capture_w) {
>  		ret = snd_soc_dapm_new_pcm(card, dai_link->params,
> -					   capture_w, play_w);
> +					   dai_link->num_params, capture_w, play_w);
>  		if (ret != 0) {
>  			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
>  				play_w->name, capture_w->name, ret);
> diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
> index cdc837e..41f835b 100644
> --- a/sound/soc/soc-dapm.c
> +++ b/sound/soc/soc-dapm.c
> @@ -729,6 +729,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
>  	return 0;
>  }
>  
> +/* create new dapm dai link control */
> +static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
> +{
> +	int i, ret;
> +	struct snd_kcontrol *kcontrol;
> +	struct snd_soc_dapm_context *dapm = w->dapm;
> +	struct snd_card *card = dapm->card->snd_card;
> +
> +
> +	/* add kcontrol */
> +	for (i = 0; i < w->num_kcontrols; i++) {
> +		kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
> +		w->name, NULL);
> +		ret = snd_ctl_add(card, kcontrol);
> +		if (ret < 0) {
> +			dev_err(dapm->dev,
> +			"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
> +			w->name, w->kcontrol_news[i].name, ret);
> +			return ret;
> +		}
> +		kcontrol->private_data = w;
> +		w->kcontrols[i] = kcontrol;
> +	}
> +
> +	return 0;
> +}
> +
>  /* reset 'walked' bit for each dapm path */
>  static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
>  				   struct list_head *sink)
> @@ -2664,6 +2691,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
>  		case snd_soc_dapm_out_drv:
>  			dapm_new_pga(w);
>  			break;
> +		case snd_soc_dapm_dai_link:
> +			dapm_new_dai_link(w);
> +			break;
>  		default:
>  			break;
>  		}
> @@ -3142,6 +3172,9 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
>  	source = source_p->source->priv;
>  	sink = sink_p->sink->priv;
>  
> +	/* Select the configuration set by alsa control */
> +	config += w->params_select;
> +
>  	/* Be a little careful as we don't want to overflow the mask array */
>  	if (config->formats) {
>  		fmt = ffs(config->formats) - 1;
> @@ -3222,8 +3255,35 @@ out:
>  	return ret;
>  }
>  
> +static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
> +			  struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
> +
> +	ucontrol->value.integer.value[0] = w->params_select;
> +
> +	return 0;
> +}
> +
> +static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
> +			  struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
> +
> +	if (ucontrol->value.integer.value[0] == w->params_select)
> +		return 0;
> +
> +	if (ucontrol->value.integer.value[0] >= w->num_params)
> +		return -EINVAL;
> +
> +	w->params_select = ucontrol->value.integer.value[0];
> +
> +	return 0;
> +}
> +
>  int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
>  			 const struct snd_soc_pcm_stream *params,
> +			 unsigned int num_params,
>  			 struct snd_soc_dapm_widget *source,
>  			 struct snd_soc_dapm_widget *sink)
>  {
> @@ -3231,12 +3291,44 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
>  	struct snd_soc_dapm_widget *w;
>  	size_t len;
>  	char *link_name;
> -	int ret;
> +	int ret, count;
> +	unsigned long private_value;
> +	char **w_param_text;
> +	struct soc_enum w_param_enum[] = {
> +		SOC_ENUM_SINGLE(0, 0, 0, NULL),
> +	};
> +	struct snd_kcontrol_new kcontrol_dai_link[] = {
> +		SOC_ENUM_EXT(NULL, w_param_enum[0],
> +			     snd_soc_dapm_dai_link_get, snd_soc_dapm_dai_link_put),
> +	};
> +	const struct snd_soc_pcm_stream *config = params;
> +
> +	w_param_text = kzalloc(sizeof(char *) * num_params, GFP_KERNEL);
> +	if (!w_param_text)
> +		return -ENOMEM;
> +
> +	for (count = 0 ; count < num_params; count++) {
> +		w_param_text[count] =  kzalloc(sizeof(char) * 100, GFP_KERNEL);
> +		if (!w_param_text) {
> +			ret = -ENOMEM;
> +			goto  outfree_w_param;
> +		}
> +
> +		sprintf(w_param_text[count], "SampleRate=%d:Channels=%d:BitsPerSample=%d",
> +			config->rate_min, config->channels_min,
> +			snd_pcm_format_width(ffs(config->formats) - 1));
> +		config++;
> +	}
> +	w_param_enum[0].items = num_params;
> +	w_param_enum[0].texts = (const char * const *) w_param_text;
>  
>  	len = strlen(source->name) + strlen(sink->name) + 2;
>  	link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
> -	if (!link_name)
> -		return -ENOMEM;
> +	if (!link_name) {
> +		ret = -ENOMEM;
> +		goto  outfree_w_param;
> +	}
> +
>  	snprintf(link_name, len, "%s-%s", source->name, sink->name);
>  
>  	memset(&template, 0, sizeof(template));
> @@ -3246,6 +3338,25 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
>  	template.event = snd_soc_dai_link_event;
>  	template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
>  		SND_SOC_DAPM_PRE_PMD;
> +	template.num_kcontrols = 1;
> +	private_value =
> +	(unsigned long) kmemdup((void *)(kcontrol_dai_link[0].private_value),
> +	sizeof(struct soc_enum), GFP_KERNEL);
> +	if (!private_value) {
> +		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
> +			link_name);
> +		ret = -ENOMEM;
> +		goto outfree_link_name;
> +	}
> +	kcontrol_dai_link[0].private_value = private_value;
> +	template.kcontrol_news = kmemdup(&kcontrol_dai_link[0],
> +			sizeof(struct snd_kcontrol_new), GFP_KERNEL);
> +	if (!template.kcontrol_news) {
> +		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
> +			link_name);
> +		ret = -ENOMEM;
> +		goto outfree_private_value;
> +	}
>  
>  	dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
>  
> @@ -3253,15 +3364,34 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
>  	if (!w) {
>  		dev_err(card->dev, "ASoC: Failed to create %s widget\n",
>  			link_name);
> -		return -ENOMEM;
> +		ret = -ENOMEM;
> +		goto outfree_kcontrol_news;
>  	}
>  
>  	w->params = params;
> +	w->num_params = num_params;
>  
>  	ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
>  	if (ret)
> -		return ret;
> +		goto outfree_w;
>  	return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
> +
> +outfree_w:
> +	kfree(w);
> +outfree_kcontrol_news:
> +	kfree(template.kcontrol_news);
> +outfree_private_value:
> +	kfree((void *)private_value);
> +outfree_link_name:
> +	kfree(link_name);
> +outfree_w_param:
> +	for (count = 0 ; count < num_params; count++) {
> +		if (w_param_text[count])
> +			kfree(w_param_text[count]);
> +	}
> +	kfree(w_param_text);
> +
> +	return ret;
>  }
>  
>  int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

-- 


More information about the Alsa-devel mailing list