mbox series

[0/2] ASoC: audio_graph_card2: Support variable slot widths

Message ID 20220216171408.265605-1-rf@opensource.cirrus.com
Headers show
Series ASoC: audio_graph_card2: Support variable slot widths | expand

Message

Richard Fitzgerald Feb. 16, 2022, 5:14 p.m. UTC
This adds support for I2S/TDM links where the slot width varies
depending on the sample width, in a way that cannot be guessed by
component hw_params().

A typical example is:

- 16-bit samples use 16-bit slots
- 24-bit samples use 32-bit slots

There is no way for a component hw_params() to deduce from the information
it is passed that 24-bit samples will be in 32-bit slots.

Some audio hardware cannot support a fixed slot width or a slot width
equal to the sample width in all cases. This is usually due either to
limitations of the audio serial port or system clocking restrictions.

These two patches add support for defining a mapping between sample widths
and sample slots. This allows audio_graph_card2 to be used in these
situations instead of having to write a custom machine driver.

Richard Fitzgerald (2):
  ASoC: dt-bindings: audio-graph-port: Add dai-tdm-slot-width-map
  ASoC: audio_graph_card2: Add support for variable slot widths

 .../bindings/sound/audio-graph-port.yaml      |  7 ++
 include/sound/simple_card_utils.h             | 11 +++
 sound/soc/generic/audio-graph-card2.c         |  4 +
 sound/soc/generic/simple-card-utils.c         | 95 +++++++++++++++++++
 4 files changed, 117 insertions(+)

Comments

Kuninori Morimoto Feb. 17, 2022, 12:23 a.m. UTC | #1
Hi Richard

Thank you for your patch.
One comment from me.

>  struct asoc_simple_dai {
>  	const char *name;
>  	unsigned int sysclk;
> @@ -26,6 +31,9 @@ struct asoc_simple_dai {
>  	unsigned int rx_slot_mask;
>  	struct clk *clk;
>  	bool clk_fixed;
> +	struct asoc_simple_tdm_width_map *tdm_width_map;
> +	int n_tdm_widths;
> +	struct snd_soc_dai *dai;
>  };
(snip)
> +	ret = snd_soc_dai_set_tdm_slot(simple_dai->dai,
> +				       simple_dai->tx_slot_mask,
> +				       simple_dai->rx_slot_mask,
> +				       simple_dai->slots,
> +				       slot_width);
(snip)
> +	for_each_prop_dai_codec(props, i, pdai) {
> +		ret = asoc_simple_set_tdm(pdai, params);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	for_each_prop_dai_cpu(props, i, pdai) {
> +		ret = asoc_simple_set_tdm(pdai, params);
> +		if (ret < 0)
> +			return ret;
> +	}
(snip)
> @@ -386,6 +479,8 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
>  	if (!simple_dai)
>  		return 0;
>  
> +	simple_dai->dai = dai;

Indeed the relationship between asoc_simple_dai and snd_soc_dai are
very mystery, and current utils is using confusable naming.
We want to have some better solution about there.

Having snd_soc_dai pointer inside asoc_simple_dai itself is not bad idea.
But we can get snd_soc_dai pointer without it.

Please check asoc_simple_dai_init().
Not tested, but we can replace the code like this ?

=>	struct snd_soc_dai *dai;

	for_each_prop_dai_codec(props, i, pdai) {
=>		dai = asoc_rtd_to_codec(rtd, i);
		ret = asoc_simple_set_tdm(dai, pdai, params);
		if (ret < 0)
			return ret;
	}


Thank you for your help !!

Best regards
---
Kuninori Morimoto
Richard Fitzgerald Feb. 17, 2022, 12:51 p.m. UTC | #2
On 17/02/2022 00:23, Kuninori Morimoto wrote:
> 
> Hi Richard
> 
> Thank you for your patch.
> One comment from me.
> 
>>   struct asoc_simple_dai {
>>   	const char *name;
>>   	unsigned int sysclk;
>> @@ -26,6 +31,9 @@ struct asoc_simple_dai {
>>   	unsigned int rx_slot_mask;
>>   	struct clk *clk;
>>   	bool clk_fixed;
>> +	struct asoc_simple_tdm_width_map *tdm_width_map;
>> +	int n_tdm_widths;
>> +	struct snd_soc_dai *dai;
>>   };
> (snip)

(snip)

> (snip)
>> @@ -386,6 +479,8 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
>>   	if (!simple_dai)
>>   		return 0;
>>   
>> +	simple_dai->dai = dai;
> 
> Indeed the relationship between asoc_simple_dai and snd_soc_dai are
> very mystery, and current utils is using confusable naming.
> We want to have some better solution about there.
> 
> Having snd_soc_dai pointer inside asoc_simple_dai itself is not bad idea.
> But we can get snd_soc_dai pointer without it.
> 
> Please check asoc_simple_dai_init().
> Not tested, but we can replace the code like this ?
> 
> =>	struct snd_soc_dai *dai;
> 
> 	for_each_prop_dai_codec(props, i, pdai) {
> =>		dai = asoc_rtd_to_codec(rtd, i);
> 		ret = asoc_simple_set_tdm(dai, pdai, params);
> 		if (ret < 0)
> 			return ret;
> 	}
> 
> 
I first thought about doing it like that. But I was not sure whether it
is safe to assume [i] is the same entry for both arrays. If it is ok,
then I can use that and do not need to add the snd_soc_dai * to struct
asoc_simple_dai.

I will look at this and send a V2 set if it is ok.