mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 08:01:59 +00:00
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:
parent
eb82bae1a0
commit
3cb97cf3a6
@ -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),
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user