ASoC: Splitting cs35l56 SoundWire DAI into separate

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

This series prepares for dissimilar aggregation of CS42L43 + CS35L56
speaker playback. The CS35L56 SoundWire DAI is split into separate
DAIs for playback and capture so they can be routed and aggregated
differently.

The cs_amp driver is also updated to enable different TX (capture)
slots on each CS35L56 on a bus, so that the captures can be aggregated.
This commit is contained in:
Mark Brown 2024-12-03 16:57:11 +00:00
commit 31823f27f8
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
5 changed files with 133 additions and 12 deletions

View File

@ -224,6 +224,8 @@ int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai);
/* MAXIM codec support */
int asoc_sdw_maxim_init(struct snd_soc_card *card,

View File

@ -646,6 +646,12 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
.rates = CS35L56_RATES,
.formats = CS35L56_RX_FORMATS,
},
.symmetric_rate = 1,
.ops = &cs35l56_sdw_dai_ops,
},
{
.name = "cs35l56-sdw1c",
.id = 2,
.capture = {
.stream_name = "SDW1 Capture",
.channels_min = 1,
@ -655,7 +661,7 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
},
.symmetric_rate = 1,
.ops = &cs35l56_sdw_dai_ops,
}
},
};
static int cs35l56_write_cal(struct cs35l56_private *cs35l56)

View File

@ -441,6 +441,66 @@ static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
}
};
static const struct snd_soc_acpi_endpoint cs35l56_l_fb_endpoints[] = {
{ /* Speaker Playback Endpoint */
.num = 0,
.aggregated = 1,
.group_position = 0,
.group_id = 1,
},
{ /* Feedback Capture Endpoint */
.num = 1,
.aggregated = 1,
.group_position = 0,
.group_id = 2,
},
};
static const struct snd_soc_acpi_endpoint cs35l56_r_fb_endpoints[] = {
{ /* Speaker Playback Endpoint */
.num = 0,
.aggregated = 1,
.group_position = 1,
.group_id = 1,
},
{ /* Feedback Capture Endpoint */
.num = 1,
.aggregated = 1,
.group_position = 1,
.group_id = 2,
},
};
static const struct snd_soc_acpi_endpoint cs35l56_2_fb_endpoints[] = {
{ /* Speaker Playback Endpoint */
.num = 0,
.aggregated = 1,
.group_position = 2,
.group_id = 1,
},
{ /* Feedback Capture Endpoint */
.num = 1,
.aggregated = 1,
.group_position = 2,
.group_id = 2,
},
};
static const struct snd_soc_acpi_endpoint cs35l56_3_fb_endpoints[] = {
{ /* Speaker Playback Endpoint */
.num = 0,
.aggregated = 1,
.group_position = 3,
.group_id = 1,
},
{ /* Feedback Capture Endpoint */
.num = 1,
.aggregated = 1,
.group_position = 3,
.group_id = 2,
},
};
static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = {
{
.adr = 0x00013701FA355601ull,
@ -474,14 +534,14 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_adr[] = {
static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = {
{
.adr = 0x00023201FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_r_endpoint,
.num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints),
.endpoints = cs35l56_r_fb_endpoints,
.name_prefix = "AMP3"
},
{
.adr = 0x00023301FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_3_endpoint,
.num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints),
.endpoints = cs35l56_3_fb_endpoints,
.name_prefix = "AMP4"
}
@ -490,14 +550,14 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = {
static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = {
{
.adr = 0x00033001fa355601ull,
.num_endpoints = 1,
.endpoints = &spk_l_endpoint,
.num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints),
.endpoints = cs35l56_l_fb_endpoints,
.name_prefix = "AMP1"
},
{
.adr = 0x00033101fa355601ull,
.num_endpoints = 1,
.endpoints = &spk_2_endpoint,
.num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints),
.endpoints = cs35l56_2_fb_endpoints,
.name_prefix = "AMP2"
}
};

View File

@ -15,6 +15,7 @@
#include <sound/soc_sdw_utils.h>
#define CODEC_NAME_SIZE 8
#define CS_AMP_CHANNELS_PER_AMP 4
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
@ -48,6 +49,51 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai
}
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, SND_SOC_SDW_UTILS);
int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
const struct snd_soc_dai_link *dai_link = rtd->dai_link;
const struct snd_soc_dai_link_ch_map *ch_map;
const struct snd_soc_dai_link_component *codec_dlc;
struct snd_soc_dai *codec_dai;
u8 ch_slot[8] = {};
unsigned int amps_per_bus, ch_per_amp, mask;
int i, ret;
WARN_ON(dai_link->num_cpus > ARRAY_SIZE(ch_slot));
/*
* CS35L56 has 4 TX channels. When the capture is aggregated the
* same bus slots will be allocated to all the amps on a bus. Only
* one amp on that bus can be transmitting in each slot so divide
* the available 4 slots between all the amps on a bus.
*/
amps_per_bus = dai_link->num_codecs / dai_link->num_cpus;
if ((amps_per_bus == 0) || (amps_per_bus > CS_AMP_CHANNELS_PER_AMP)) {
dev_err(rtd->card->dev, "Illegal num_codecs:%u / num_cpus:%u\n",
dai_link->num_codecs, dai_link->num_cpus);
return -EINVAL;
}
ch_per_amp = CS_AMP_CHANNELS_PER_AMP / amps_per_bus;
for_each_rtd_ch_maps(rtd, i, ch_map) {
codec_dlc = snd_soc_link_to_codec(rtd->dai_link, i);
codec_dai = snd_soc_find_dai(codec_dlc);
mask = GENMASK(ch_per_amp - 1, 0) << ch_slot[ch_map->cpu];
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, mask, 4, 32);
if (ret < 0) {
dev_err(rtd->card->dev, "Failed to set TDM slot:%d\n", ret);
return ret;
}
ch_slot[ch_map->cpu] += ch_per_amp;
}
return 0;
}
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_feedback_rtd_init, SND_SOC_SDW_UTILS);
int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,

View File

@ -488,10 +488,10 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.part_id = 0x3556,
.dais = {
{
.direction = {true, true},
.direction = {true, false},
.dai_name = "cs35l56-sdw1",
.dai_type = SOC_SDW_DAI_TYPE_AMP,
.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
.init = asoc_sdw_cs_amp_init,
.rtd_init = asoc_sdw_cs_spk_rtd_init,
.controls = generic_spk_controls,
@ -499,8 +499,15 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.widgets = generic_spk_widgets,
.num_widgets = ARRAY_SIZE(generic_spk_widgets),
},
{
.direction = {false, true},
.dai_name = "cs35l56-sdw1c",
.dai_type = SOC_SDW_DAI_TYPE_AMP,
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
},
},
.dai_num = 1,
.dai_num = 2,
},
{
.part_id = 0x4242,