ASoC: Intel: sof_cs42l42: support arbitrary DAI link sequence

Currently there are two types of DAI Link sequences defined in
topology files, one starts from speaker link and the other starts from
headphone link.

Type 1: SPK - HP - DMIC - HDMI
Type 2: HP - DMIC - HDMI - SPK

Here we add a macro SOF_CS42L42_DAILINK to define the DAI Link
sequence in quirk and refactor the sof_card_dai_links_create()
function to support arbitrary DAI Link sequence.

Reviewed-by: Bard Liao <bard.liao@intel.com>
Signed-off-by: Brent Lu <brent.lu@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20210712203240.46960-2-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Brent Lu 2021-07-12 15:32:34 -05:00 committed by Mark Brown
parent eb82bae1a0
commit 3cb97cf3a6
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -37,7 +37,19 @@
#define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7))
#define SOF_CS42L42_NUM_HDMIDEV(quirk) \
(((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(10)
#define SOF_CS42L42_DAILINK_SHIFT 10
#define SOF_CS42L42_DAILINK_MASK (GENMASK(24, 10))
#define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(25)
enum {
LINK_NONE = 0,
LINK_HP = 1,
LINK_SPK = 2,
LINK_DMIC = 3,
LINK_HDMI = 4,
};
/* Default: SSP2 */
static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
@ -265,133 +277,166 @@ static struct snd_soc_dai_link_component dmic_component[] = {
}
};
static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
int ssp_codec,
int ssp_amp,
int dmic_be_num,
int hdmi_num)
static int create_spk_amp_dai_links(struct device *dev,
struct snd_soc_dai_link *links,
struct snd_soc_dai_link_component *cpus,
int *id, int ssp_amp)
{
struct snd_soc_dai_link_component *idisp_components;
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link *links;
int i, id = 0;
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
sof_audio_card_cs42l42.num_links, GFP_KERNEL);
cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
sof_audio_card_cs42l42.num_links, GFP_KERNEL);
if (!links || !cpus)
goto devm_err;
int ret = 0;
/* speaker amp */
if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT) {
links[id].name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d-Codec", ssp_amp);
if (!links[id].name)
goto devm_err;
if (!(sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT))
return 0;
links[id].id = id;
if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) {
max_98357a_dai_link(&links[id]);
} else {
dev_err(dev, "no amp defined\n");
goto devm_err;
}
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].dpcm_playback = 1;
links[id].no_pcm = 1;
links[id].cpus = &cpus[id];
links[id].num_cpus = 1;
links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d Pin",
ssp_amp);
if (!links[id].cpus->dai_name)
goto devm_err;
id++;
links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
ssp_amp);
if (!links[*id].name) {
ret = -ENOMEM;
goto devm_err;
}
links[*id].id = *id;
if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) {
max_98357a_dai_link(&links[*id]);
} else {
dev_err(dev, "no amp defined\n");
ret = -EINVAL;
goto devm_err;
}
links[*id].platforms = platform_component;
links[*id].num_platforms = ARRAY_SIZE(platform_component);
links[*id].dpcm_playback = 1;
links[*id].no_pcm = 1;
links[*id].cpus = &cpus[*id];
links[*id].num_cpus = 1;
links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d Pin", ssp_amp);
if (!links[*id].cpus->dai_name) {
ret = -ENOMEM;
goto devm_err;
}
(*id)++;
devm_err:
return ret;
}
static int create_hp_codec_dai_links(struct device *dev,
struct snd_soc_dai_link *links,
struct snd_soc_dai_link_component *cpus,
int *id, int ssp_codec)
{
/* codec SSP */
links[id].name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d-Codec", ssp_codec);
if (!links[id].name)
links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
ssp_codec);
if (!links[*id].name)
goto devm_err;
links[id].id = id;
links[id].codecs = cs42l42_component;
links[id].num_codecs = ARRAY_SIZE(cs42l42_component);
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].init = sof_cs42l42_init;
links[id].exit = sof_cs42l42_exit;
links[id].ops = &sof_cs42l42_ops;
links[id].dpcm_playback = 1;
links[id].dpcm_capture = 1;
links[id].no_pcm = 1;
links[id].cpus = &cpus[id];
links[id].num_cpus = 1;
links[*id].id = *id;
links[*id].codecs = cs42l42_component;
links[*id].num_codecs = ARRAY_SIZE(cs42l42_component);
links[*id].platforms = platform_component;
links[*id].num_platforms = ARRAY_SIZE(platform_component);
links[*id].init = sof_cs42l42_init;
links[*id].exit = sof_cs42l42_exit;
links[*id].ops = &sof_cs42l42_ops;
links[*id].dpcm_playback = 1;
links[*id].dpcm_capture = 1;
links[*id].no_pcm = 1;
links[*id].cpus = &cpus[*id];
links[*id].num_cpus = 1;
links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d Pin",
ssp_codec);
if (!links[id].cpus->dai_name)
links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d Pin",
ssp_codec);
if (!links[*id].cpus->dai_name)
goto devm_err;
id++;
(*id)++;
return 0;
devm_err:
return -ENOMEM;
}
static int create_dmic_dai_links(struct device *dev,
struct snd_soc_dai_link *links,
struct snd_soc_dai_link_component *cpus,
int *id, int dmic_be_num)
{
int i;
/* dmic */
if (dmic_be_num > 0) {
/* at least we have dmic01 */
links[id].name = "dmic01";
links[id].cpus = &cpus[id];
links[id].cpus->dai_name = "DMIC01 Pin";
links[id].init = dmic_init;
if (dmic_be_num > 1) {
/* set up 2 BE links at most */
links[id + 1].name = "dmic16k";
links[id + 1].cpus = &cpus[id + 1];
links[id + 1].cpus->dai_name = "DMIC16k Pin";
dmic_be_num = 2;
}
if (dmic_be_num <= 0)
return 0;
/* at least we have dmic01 */
links[*id].name = "dmic01";
links[*id].cpus = &cpus[*id];
links[*id].cpus->dai_name = "DMIC01 Pin";
links[*id].init = dmic_init;
if (dmic_be_num > 1) {
/* set up 2 BE links at most */
links[*id + 1].name = "dmic16k";
links[*id + 1].cpus = &cpus[*id + 1];
links[*id + 1].cpus->dai_name = "DMIC16k Pin";
dmic_be_num = 2;
}
for (i = 0; i < dmic_be_num; i++) {
links[id].id = id;
links[id].num_cpus = 1;
links[id].codecs = dmic_component;
links[id].num_codecs = ARRAY_SIZE(dmic_component);
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].ignore_suspend = 1;
links[id].dpcm_capture = 1;
links[id].no_pcm = 1;
id++;
links[*id].id = *id;
links[*id].num_cpus = 1;
links[*id].codecs = dmic_component;
links[*id].num_codecs = ARRAY_SIZE(dmic_component);
links[*id].platforms = platform_component;
links[*id].num_platforms = ARRAY_SIZE(platform_component);
links[*id].ignore_suspend = 1;
links[*id].dpcm_capture = 1;
links[*id].no_pcm = 1;
(*id)++;
}
return 0;
}
static int create_hdmi_dai_links(struct device *dev,
struct snd_soc_dai_link *links,
struct snd_soc_dai_link_component *cpus,
int *id, int hdmi_num)
{
struct snd_soc_dai_link_component *idisp_components;
int i;
/* HDMI */
if (hdmi_num > 0) {
idisp_components = devm_kzalloc(dev,
sizeof(struct snd_soc_dai_link_component) *
hdmi_num, GFP_KERNEL);
if (!idisp_components)
goto devm_err;
}
if (hdmi_num <= 0)
return 0;
idisp_components = devm_kzalloc(dev,
sizeof(struct snd_soc_dai_link_component) *
hdmi_num, GFP_KERNEL);
if (!idisp_components)
goto devm_err;
for (i = 1; i <= hdmi_num; i++) {
links[id].name = devm_kasprintf(dev, GFP_KERNEL,
"iDisp%d", i);
if (!links[id].name)
links[*id].name = devm_kasprintf(dev, GFP_KERNEL,
"iDisp%d", i);
if (!links[*id].name)
goto devm_err;
links[id].id = id;
links[id].cpus = &cpus[id];
links[id].num_cpus = 1;
links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"iDisp%d Pin", i);
if (!links[id].cpus->dai_name)
links[*id].id = *id;
links[*id].cpus = &cpus[*id];
links[*id].num_cpus = 1;
links[*id].cpus->dai_name = devm_kasprintf(dev,
GFP_KERNEL,
"iDisp%d Pin",
i);
if (!links[*id].cpus->dai_name)
goto devm_err;
idisp_components[i - 1].name = "ehdaudio0D2";
@ -402,14 +447,86 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
if (!idisp_components[i - 1].dai_name)
goto devm_err;
links[id].codecs = &idisp_components[i - 1];
links[id].num_codecs = 1;
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].init = sof_hdmi_init;
links[id].dpcm_playback = 1;
links[id].no_pcm = 1;
id++;
links[*id].codecs = &idisp_components[i - 1];
links[*id].num_codecs = 1;
links[*id].platforms = platform_component;
links[*id].num_platforms = ARRAY_SIZE(platform_component);
links[*id].init = sof_hdmi_init;
links[*id].dpcm_playback = 1;
links[*id].no_pcm = 1;
(*id)++;
}
return 0;
devm_err:
return -ENOMEM;
}
static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
int ssp_codec,
int ssp_amp,
int dmic_be_num,
int hdmi_num)
{
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link *links;
int ret, id = 0, link_seq;
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
sof_audio_card_cs42l42.num_links, GFP_KERNEL);
cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
sof_audio_card_cs42l42.num_links, GFP_KERNEL);
if (!links || !cpus)
goto devm_err;
link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT;
while (link_seq) {
int link_type = link_seq & 0x07;
switch (link_type) {
case LINK_HP:
ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec);
if (ret < 0) {
dev_err(dev, "fail to create hp codec dai links, ret %d\n",
ret);
goto devm_err;
}
break;
case LINK_SPK:
ret = create_spk_amp_dai_links(dev, links, cpus, &id, ssp_amp);
if (ret < 0) {
dev_err(dev, "fail to create spk amp dai links, ret %d\n",
ret);
goto devm_err;
}
break;
case LINK_DMIC:
ret = create_dmic_dai_links(dev, links, cpus, &id, dmic_be_num);
if (ret < 0) {
dev_err(dev, "fail to create dmic dai links, ret %d\n",
ret);
goto devm_err;
}
break;
case LINK_HDMI:
ret = create_hdmi_dai_links(dev, links, cpus, &id, hdmi_num);
if (ret < 0) {
dev_err(dev, "fail to create hdmi dai links, ret %d\n",
ret);
goto devm_err;
}
break;
case LINK_NONE:
/* caught here if it's not used as terminator in macro */
default:
dev_err(dev, "invalid link type %d\n", link_type);
goto devm_err;
}
link_seq >>= 3;
}
return links;
@ -490,7 +607,8 @@ static const struct platform_device_id board_ids[] = {
.driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
SOF_SPEAKER_AMP_PRESENT |
SOF_MAX98357A_SPEAKER_AMP_PRESENT |
SOF_CS42L42_SSP_AMP(1)),
SOF_CS42L42_SSP_AMP(1)) |
SOF_CS42L42_DAILINK(LINK_SPK, LINK_HP, LINK_DMIC, LINK_HDMI, LINK_NONE),
},
{ }
};