Skip to content

Commit 74d4c78

Browse files
rfvirgilranj063
authored andcommitted
ASoC: sdw_utils: cs_amp: Assign non-overlapping TDM masks for each codec on a bus
Use snd_soc_dai_set_tdm_slot() on capture DAIs to prevent multiple aggregated amps from trying to send data at the same time. When the capture DAIs of multiple amps on a bus are aggregated they will all be sharing the same bit slots for transmitted audio. This would lead to bus errors if all channels on all amps were enabled, because multiple amps would be trying to send data at the same time. To prevent this, the available channels are divided between the amps on a bus so that only one amp will be sending data for each channel position. A CS35L56 has 4 TX channels, which must be split between all the amps on a bus so that no two amps are using the same channel. This is done simply by dividing by the number of amps on the bus, so that 1 amp can use all 4 channels, 2 amps can use 2 channels each, and 3 or 4 amps can only use 1 channel each. The amps are usually aggregated across multiple SoundWire buses. In this case there will be multiple cpu DAIs in the dailink. The channel mapping is used to determine which amps are on each bus. The allocation of the 4 channels is done separately for each bus (only amps on the same bus can interfere with each other). Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
1 parent b101a00 commit 74d4c78

3 files changed

Lines changed: 49 additions & 0 deletions

File tree

include/sound/soc_sdw_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
224224
struct snd_soc_dai_link *dai_links,
225225
struct asoc_sdw_codec_info *info,
226226
bool playback);
227+
int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd,
228+
struct snd_soc_dai *dai);
227229

228230
/* MAXIM codec support */
229231
int asoc_sdw_maxim_init(struct snd_soc_card *card,

sound/soc/sdw_utils/soc_sdw_cs_amp.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <sound/soc_sdw_utils.h>
1616

1717
#define CODEC_NAME_SIZE 8
18+
#define CS_AMP_CHANNELS_PER_AMP 4
1819

1920
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
2021
{
@@ -48,6 +49,51 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai
4849
}
4950
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, SND_SOC_SDW_UTILS);
5051

52+
int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
53+
{
54+
const struct snd_soc_dai_link *dai_link = rtd->dai_link;
55+
const struct snd_soc_dai_link_ch_map *ch_map;
56+
const struct snd_soc_dai_link_component *codec_dlc;
57+
struct snd_soc_dai *codec_dai;
58+
u8 ch_slot[8] = {};
59+
unsigned int amps_per_bus, ch_per_amp, mask;
60+
int i, ret;
61+
62+
WARN_ON(dai_link->num_cpus > ARRAY_SIZE(ch_slot));
63+
64+
/*
65+
* CS35L56 has 4 TX channels. When the capture is aggregated the
66+
* same bus slots will be allocated to all the amps on a bus. Only
67+
* one amp on that bus can be transmitting in each slot so divide
68+
* the available 4 slots between all the amps on a bus.
69+
*/
70+
amps_per_bus = dai_link->num_codecs / dai_link->num_cpus;
71+
if ((amps_per_bus == 0) || (amps_per_bus > CS_AMP_CHANNELS_PER_AMP)) {
72+
dev_err(rtd->card->dev, "Illegal num_codecs:%u / num_cpus:%u\n",
73+
dai_link->num_codecs, dai_link->num_cpus);
74+
return -EINVAL;
75+
}
76+
77+
ch_per_amp = CS_AMP_CHANNELS_PER_AMP / amps_per_bus;
78+
79+
for_each_rtd_ch_maps(rtd, i, ch_map) {
80+
codec_dlc = snd_soc_link_to_codec(rtd->dai_link, i);
81+
codec_dai = snd_soc_find_dai(codec_dlc);
82+
mask = GENMASK(ch_per_amp - 1, 0) << ch_slot[ch_map->cpu];
83+
84+
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, mask, 4, 32);
85+
if (ret < 0) {
86+
dev_err(rtd->card->dev, "Failed to set TDM slot:%d\n", ret);
87+
return ret;
88+
}
89+
90+
ch_slot[ch_map->cpu] += ch_per_amp;
91+
}
92+
93+
return 0;
94+
}
95+
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_feedback_rtd_init, SND_SOC_SDW_UTILS);
96+
5197
int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
5298
struct snd_soc_dai_link *dai_links,
5399
struct asoc_sdw_codec_info *info,

sound/soc/sdw_utils/soc_sdw_utils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
504504
.dai_name = "cs35l56-sdw1c",
505505
.dai_type = SOC_SDW_DAI_TYPE_AMP,
506506
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
507+
.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
507508
},
508509
},
509510
.dai_num = 2,

0 commit comments

Comments
 (0)