cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acp-mach-common.c (18613B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
      2//
      3// This file is provided under a dual BSD/GPLv2 license. When using or
      4// redistributing this file, you may do so under either license.
      5//
      6// Copyright(c) 2021 Advanced Micro Devices, Inc.
      7//
      8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
      9//	    Vijendar Mukunda <Vijendar.Mukunda@amd.com>
     10//
     11
     12/*
     13 * Machine Driver Interface for ACP HW block
     14 */
     15
     16#include <sound/core.h>
     17#include <sound/jack.h>
     18#include <sound/pcm_params.h>
     19#include <sound/soc-dapm.h>
     20#include <sound/soc.h>
     21#include <linux/input.h>
     22#include <linux/module.h>
     23
     24#include "../../codecs/rt5682.h"
     25#include "../../codecs/rt1019.h"
     26#include "../../codecs/rt5682s.h"
     27#include "acp-mach.h"
     28
     29#define PCO_PLAT_CLK 48000000
     30#define RT5682_PLL_FREQ (48000 * 512)
     31#define DUAL_CHANNEL	2
     32#define FOUR_CHANNEL	4
     33
     34static struct snd_soc_jack pco_jack;
     35
     36static const unsigned int channels[] = {
     37	DUAL_CHANNEL,
     38};
     39
     40static const unsigned int rates[] = {
     41	48000,
     42};
     43
     44static const struct snd_pcm_hw_constraint_list constraints_rates = {
     45	.count = ARRAY_SIZE(rates),
     46	.list  = rates,
     47	.mask = 0,
     48};
     49
     50static const struct snd_pcm_hw_constraint_list constraints_channels = {
     51	.count = ARRAY_SIZE(channels),
     52	.list = channels,
     53	.mask = 0,
     54};
     55
     56static int acp_clk_enable(struct acp_card_drvdata *drvdata)
     57{
     58	clk_set_rate(drvdata->wclk, 48000);
     59	clk_set_rate(drvdata->bclk, 48000 * 64);
     60
     61	return clk_prepare_enable(drvdata->wclk);
     62}
     63
     64/* Declare RT5682 codec components */
     65SND_SOC_DAILINK_DEF(rt5682,
     66	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
     67
     68static const struct snd_soc_dapm_route rt5682_map[] = {
     69	{ "Headphone Jack", NULL, "HPOL" },
     70	{ "Headphone Jack", NULL, "HPOR" },
     71	{ "IN1P", NULL, "Headset Mic" },
     72};
     73
     74/* Define card ops for RT5682 CODEC */
     75static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
     76{
     77	struct snd_soc_card *card = rtd->card;
     78	struct acp_card_drvdata *drvdata = card->drvdata;
     79	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     80	struct snd_soc_component *component = codec_dai->component;
     81	int ret;
     82
     83	dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
     84
     85	if (drvdata->hs_codec_id != RT5682)
     86		return -EINVAL;
     87
     88	ret =  snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
     89				   | SND_SOC_DAIFMT_CBP_CFP);
     90	if (ret < 0) {
     91		dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
     92		return ret;
     93	}
     94
     95	ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
     96				  PCO_PLAT_CLK, RT5682_PLL_FREQ);
     97	if (ret < 0) {
     98		dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
     99		return ret;
    100	}
    101
    102	ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
    103				     RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
    104	if (ret < 0) {
    105		dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
    106		return ret;
    107	}
    108
    109	/* Set tdm/i2s1 master bclk ratio */
    110	ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
    111	if (ret < 0) {
    112		dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
    113		return ret;
    114	}
    115
    116	drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
    117	drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
    118
    119	ret = snd_soc_card_jack_new(card, "Headset Jack",
    120				    SND_JACK_HEADSET | SND_JACK_LINEOUT |
    121				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
    122				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
    123				    &pco_jack);
    124	if (ret) {
    125		dev_err(card->dev, "HP jack creation failed %d\n", ret);
    126		return ret;
    127	}
    128
    129	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
    130	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
    131	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
    132	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
    133
    134	ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
    135	if (ret) {
    136		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
    137		return ret;
    138	}
    139
    140	return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
    141}
    142
    143static int acp_card_hs_startup(struct snd_pcm_substream *substream)
    144{
    145	struct snd_pcm_runtime *runtime = substream->runtime;
    146	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    147	struct snd_soc_card *card = rtd->card;
    148	struct acp_card_drvdata *drvdata = card->drvdata;
    149	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    150	int ret;
    151
    152	ret =  snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
    153				   | SND_SOC_DAIFMT_CBP_CFP);
    154	if (ret < 0) {
    155		dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
    156		return ret;
    157	}
    158
    159	runtime->hw.channels_max = DUAL_CHANNEL;
    160	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
    161				      &constraints_channels);
    162	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
    163				      &constraints_rates);
    164
    165	ret = acp_clk_enable(drvdata);
    166	if (ret < 0)
    167		dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
    168
    169	return ret;
    170}
    171
    172static void acp_card_shutdown(struct snd_pcm_substream *substream)
    173{
    174	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    175	struct snd_soc_card *card = rtd->card;
    176	struct acp_card_drvdata *drvdata = card->drvdata;
    177
    178	clk_disable_unprepare(drvdata->wclk);
    179}
    180
    181static const struct snd_soc_ops acp_card_rt5682_ops = {
    182	.startup = acp_card_hs_startup,
    183	.shutdown = acp_card_shutdown,
    184};
    185
    186/* Define RT5682S CODEC component*/
    187SND_SOC_DAILINK_DEF(rt5682s,
    188		    DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
    189
    190static const struct snd_soc_dapm_route rt5682s_map[] = {
    191	{ "Headphone Jack", NULL, "HPOL" },
    192	{ "Headphone Jack", NULL, "HPOR" },
    193	{ "IN1P", NULL, "Headset Mic" },
    194};
    195
    196static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
    197{
    198	struct snd_soc_card *card = rtd->card;
    199	struct acp_card_drvdata *drvdata = card->drvdata;
    200	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    201	struct snd_soc_component *component = codec_dai->component;
    202	int ret;
    203
    204	dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
    205
    206	if (drvdata->hs_codec_id != RT5682S)
    207		return -EINVAL;
    208
    209	ret =  snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
    210				   | SND_SOC_DAIFMT_CBP_CFP);
    211	if (ret < 0) {
    212		dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
    213		return ret;
    214	}
    215
    216	ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,
    217				  PCO_PLAT_CLK, RT5682_PLL_FREQ);
    218	if (ret < 0) {
    219		dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
    220		return ret;
    221	}
    222
    223	ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,
    224				     RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
    225	if (ret < 0) {
    226		dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
    227		return ret;
    228	}
    229
    230	/* Set tdm/i2s1 master bclk ratio */
    231	ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
    232	if (ret < 0) {
    233		dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
    234		return ret;
    235	}
    236
    237	drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
    238	drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
    239
    240	ret = snd_soc_card_jack_new(card, "Headset Jack",
    241				    SND_JACK_HEADSET | SND_JACK_LINEOUT |
    242				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
    243				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
    244				    &pco_jack);
    245	if (ret) {
    246		dev_err(card->dev, "HP jack creation failed %d\n", ret);
    247		return ret;
    248	}
    249
    250	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
    251	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
    252	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
    253	snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
    254
    255	ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
    256	if (ret) {
    257		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
    258		return ret;
    259	}
    260
    261	return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
    262}
    263
    264static const struct snd_soc_ops acp_card_rt5682s_ops = {
    265	.startup = acp_card_hs_startup,
    266	.shutdown = acp_card_shutdown,
    267};
    268
    269static const unsigned int dmic_channels[] = {
    270	DUAL_CHANNEL, FOUR_CHANNEL,
    271};
    272
    273static const struct snd_pcm_hw_constraint_list dmic_constraints_channels = {
    274	.count = ARRAY_SIZE(dmic_channels),
    275	.list = dmic_channels,
    276	.mask = 0,
    277};
    278
    279static int acp_card_dmic_startup(struct snd_pcm_substream *substream)
    280{
    281	struct snd_pcm_runtime *runtime = substream->runtime;
    282
    283	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
    284				   &dmic_constraints_channels);
    285	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
    286				   &constraints_rates);
    287
    288	return 0;
    289}
    290
    291static const struct snd_soc_ops acp_card_dmic_ops = {
    292	.startup = acp_card_dmic_startup,
    293};
    294
    295/* Declare RT1019 codec components */
    296SND_SOC_DAILINK_DEF(rt1019,
    297	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
    298			  COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
    299
    300static const struct snd_soc_dapm_route rt1019_map_lr[] = {
    301	{ "Left Spk", NULL, "Left SPO" },
    302	{ "Right Spk", NULL, "Right SPO" },
    303};
    304
    305static struct snd_soc_codec_conf rt1019_conf[] = {
    306	{
    307		 .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
    308		 .name_prefix = "Left",
    309	},
    310	{
    311		 .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
    312		 .name_prefix = "Right",
    313	},
    314};
    315
    316static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
    317{
    318	struct snd_soc_card *card = rtd->card;
    319	struct acp_card_drvdata *drvdata = card->drvdata;
    320
    321	if (drvdata->amp_codec_id != RT1019)
    322		return -EINVAL;
    323
    324	return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
    325				       ARRAY_SIZE(rt1019_map_lr));
    326}
    327
    328static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
    329				     struct snd_pcm_hw_params *params)
    330{
    331	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    332	struct snd_soc_card *card = rtd->card;
    333	struct acp_card_drvdata *drvdata = card->drvdata;
    334	struct snd_soc_dai *codec_dai;
    335	int srate, i, ret = 0;
    336
    337	srate = params_rate(params);
    338
    339	if (drvdata->amp_codec_id != RT1019)
    340		return -EINVAL;
    341
    342	for_each_rtd_codec_dais(rtd, i, codec_dai) {
    343		if (strcmp(codec_dai->name, "rt1019-aif"))
    344			continue;
    345
    346		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
    347					  64 * srate, 256 * srate);
    348		if (ret < 0)
    349			return ret;
    350
    351		ret = snd_soc_dai_set_sysclk(codec_dai, RT1019_SCLK_S_PLL,
    352					     256 * srate, SND_SOC_CLOCK_IN);
    353		if (ret < 0)
    354			return ret;
    355	}
    356
    357	return 0;
    358}
    359
    360static int acp_card_amp_startup(struct snd_pcm_substream *substream)
    361{
    362	struct snd_pcm_runtime *runtime = substream->runtime;
    363	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    364	struct snd_soc_card *card = rtd->card;
    365	struct acp_card_drvdata *drvdata = card->drvdata;
    366	int ret;
    367
    368	runtime->hw.channels_max = DUAL_CHANNEL;
    369	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
    370				      &constraints_channels);
    371	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
    372				      &constraints_rates);
    373
    374	ret = acp_clk_enable(drvdata);
    375	if (ret < 0)
    376		dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
    377
    378	return ret;
    379}
    380
    381static const struct snd_soc_ops acp_card_rt1019_ops = {
    382	.startup = acp_card_amp_startup,
    383	.shutdown = acp_card_shutdown,
    384	.hw_params = acp_card_rt1019_hw_params,
    385};
    386
    387/* Declare Maxim codec components */
    388SND_SOC_DAILINK_DEF(max98360a,
    389	DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
    390
    391static const struct snd_soc_dapm_route max98360a_map[] = {
    392	{"Spk", NULL, "Speaker"},
    393};
    394
    395static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
    396{
    397	struct snd_soc_card *card = rtd->card;
    398	struct acp_card_drvdata *drvdata = card->drvdata;
    399
    400	if (drvdata->amp_codec_id != MAX98360A)
    401		return -EINVAL;
    402
    403	return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
    404				       ARRAY_SIZE(max98360a_map));
    405}
    406
    407static const struct snd_soc_ops acp_card_maxim_ops = {
    408	.startup = acp_card_amp_startup,
    409	.shutdown = acp_card_shutdown,
    410};
    411
    412/* Declare DMIC codec components */
    413SND_SOC_DAILINK_DEF(dmic_codec,
    414		DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
    415
    416/* Declare ACP CPU components */
    417static struct snd_soc_dai_link_component dummy_codec[] = {
    418	{
    419		.name = "snd-soc-dummy",
    420		.dai_name = "snd-soc-dummy-dai",
    421	}
    422};
    423
    424static struct snd_soc_dai_link_component platform_component[] = {
    425	{
    426		 .name = "acp_asoc_renoir.0",
    427	}
    428};
    429
    430static struct snd_soc_dai_link_component sof_component[] = {
    431	{
    432		 .name = "0000:04:00.5",
    433	}
    434};
    435
    436SND_SOC_DAILINK_DEF(i2s_sp,
    437	DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
    438SND_SOC_DAILINK_DEF(sof_sp,
    439	DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
    440SND_SOC_DAILINK_DEF(sof_dmic,
    441	DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
    442SND_SOC_DAILINK_DEF(pdm_dmic,
    443	DAILINK_COMP_ARRAY(COMP_CPU("acp-pdm-dmic")));
    444
    445int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
    446{
    447	struct snd_soc_dai_link *links;
    448	struct device *dev = card->dev;
    449	struct acp_card_drvdata *drv_data = card->drvdata;
    450	int i = 0, num_links = 0;
    451
    452	if (drv_data->hs_cpu_id)
    453		num_links++;
    454	if (drv_data->amp_cpu_id)
    455		num_links++;
    456	if (drv_data->dmic_cpu_id)
    457		num_links++;
    458
    459	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
    460	if (!links)
    461		return -ENOMEM;
    462
    463	if (drv_data->hs_cpu_id == I2S_SP) {
    464		links[i].name = "acp-headset-codec";
    465		links[i].id = HEADSET_BE_ID;
    466		links[i].cpus = sof_sp;
    467		links[i].num_cpus = ARRAY_SIZE(sof_sp);
    468		links[i].platforms = sof_component;
    469		links[i].num_platforms = ARRAY_SIZE(sof_component);
    470		links[i].dpcm_playback = 1;
    471		links[i].dpcm_capture = 1;
    472		links[i].nonatomic = true;
    473		links[i].no_pcm = 1;
    474		if (!drv_data->hs_codec_id) {
    475			/* Use dummy codec if codec id not specified */
    476			links[i].codecs = dummy_codec;
    477			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
    478		}
    479		if (drv_data->hs_codec_id == RT5682) {
    480			links[i].codecs = rt5682;
    481			links[i].num_codecs = ARRAY_SIZE(rt5682);
    482			links[i].init = acp_card_rt5682_init;
    483			links[i].ops = &acp_card_rt5682_ops;
    484		}
    485		if (drv_data->hs_codec_id == RT5682S) {
    486			links[i].codecs = rt5682s;
    487			links[i].num_codecs = ARRAY_SIZE(rt5682s);
    488			links[i].init = acp_card_rt5682s_init;
    489			links[i].ops = &acp_card_rt5682s_ops;
    490		}
    491		i++;
    492	}
    493
    494	if (drv_data->amp_cpu_id == I2S_SP) {
    495		links[i].name = "acp-amp-codec";
    496		links[i].id = AMP_BE_ID;
    497		links[i].cpus = sof_sp;
    498		links[i].num_cpus = ARRAY_SIZE(sof_sp);
    499		links[i].platforms = sof_component;
    500		links[i].num_platforms = ARRAY_SIZE(sof_component);
    501		links[i].dpcm_playback = 1;
    502		links[i].nonatomic = true;
    503		links[i].no_pcm = 1;
    504		if (!drv_data->amp_codec_id) {
    505			/* Use dummy codec if codec id not specified */
    506			links[i].codecs = dummy_codec;
    507			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
    508		}
    509		if (drv_data->amp_codec_id == RT1019) {
    510			links[i].codecs = rt1019;
    511			links[i].num_codecs = ARRAY_SIZE(rt1019);
    512			links[i].ops = &acp_card_rt1019_ops;
    513			links[i].init = acp_card_rt1019_init;
    514			card->codec_conf = rt1019_conf;
    515			card->num_configs = ARRAY_SIZE(rt1019_conf);
    516		}
    517		if (drv_data->amp_codec_id == MAX98360A) {
    518			links[i].codecs = max98360a;
    519			links[i].num_codecs = ARRAY_SIZE(max98360a);
    520			links[i].ops = &acp_card_maxim_ops;
    521			links[i].init = acp_card_maxim_init;
    522		}
    523		i++;
    524	}
    525
    526	if (drv_data->dmic_cpu_id == DMIC) {
    527		links[i].name = "acp-dmic-codec";
    528		links[i].id = DMIC_BE_ID;
    529		links[i].codecs = dmic_codec;
    530		links[i].num_codecs = ARRAY_SIZE(dmic_codec);
    531		links[i].cpus = sof_dmic;
    532		links[i].num_cpus = ARRAY_SIZE(sof_dmic);
    533		links[i].platforms = sof_component;
    534		links[i].num_platforms = ARRAY_SIZE(sof_component);
    535		links[i].dpcm_capture = 1;
    536		links[i].nonatomic = true;
    537		links[i].no_pcm = 1;
    538	}
    539
    540	card->dai_link = links;
    541	card->num_links = num_links;
    542
    543	return 0;
    544}
    545EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH);
    546
    547int acp_legacy_dai_links_create(struct snd_soc_card *card)
    548{
    549	struct snd_soc_dai_link *links;
    550	struct device *dev = card->dev;
    551	struct acp_card_drvdata *drv_data = card->drvdata;
    552	int i = 0, num_links = 0;
    553
    554	if (drv_data->hs_cpu_id)
    555		num_links++;
    556	if (drv_data->amp_cpu_id)
    557		num_links++;
    558	if (drv_data->dmic_cpu_id)
    559		num_links++;
    560
    561	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
    562	if (!links)
    563		return -ENOMEM;
    564
    565	if (drv_data->hs_cpu_id == I2S_SP) {
    566		links[i].name = "acp-headset-codec";
    567		links[i].id = HEADSET_BE_ID;
    568		links[i].cpus = i2s_sp;
    569		links[i].num_cpus = ARRAY_SIZE(i2s_sp);
    570		links[i].platforms = platform_component;
    571		links[i].num_platforms = ARRAY_SIZE(platform_component);
    572		links[i].dpcm_playback = 1;
    573		links[i].dpcm_capture = 1;
    574		if (!drv_data->hs_codec_id) {
    575			/* Use dummy codec if codec id not specified */
    576			links[i].codecs = dummy_codec;
    577			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
    578		}
    579		if (drv_data->hs_codec_id == RT5682) {
    580			links[i].codecs = rt5682;
    581			links[i].num_codecs = ARRAY_SIZE(rt5682);
    582			links[i].init = acp_card_rt5682_init;
    583			links[i].ops = &acp_card_rt5682_ops;
    584		}
    585		if (drv_data->hs_codec_id == RT5682S) {
    586			links[i].codecs = rt5682s;
    587			links[i].num_codecs = ARRAY_SIZE(rt5682s);
    588			links[i].init = acp_card_rt5682s_init;
    589			links[i].ops = &acp_card_rt5682s_ops;
    590		}
    591		i++;
    592	}
    593
    594	if (drv_data->amp_cpu_id == I2S_SP) {
    595		links[i].name = "acp-amp-codec";
    596		links[i].id = AMP_BE_ID;
    597		links[i].cpus = i2s_sp;
    598		links[i].num_cpus = ARRAY_SIZE(i2s_sp);
    599		links[i].platforms = platform_component;
    600		links[i].num_platforms = ARRAY_SIZE(platform_component);
    601		links[i].dpcm_playback = 1;
    602		if (!drv_data->amp_codec_id) {
    603			/* Use dummy codec if codec id not specified */
    604			links[i].codecs = dummy_codec;
    605			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
    606		}
    607		if (drv_data->amp_codec_id == RT1019) {
    608			links[i].codecs = rt1019;
    609			links[i].num_codecs = ARRAY_SIZE(rt1019);
    610			links[i].ops = &acp_card_rt1019_ops;
    611			links[i].init = acp_card_rt1019_init;
    612			card->codec_conf = rt1019_conf;
    613			card->num_configs = ARRAY_SIZE(rt1019_conf);
    614		}
    615		if (drv_data->amp_codec_id == MAX98360A) {
    616			links[i].codecs = max98360a;
    617			links[i].num_codecs = ARRAY_SIZE(max98360a);
    618			links[i].ops = &acp_card_maxim_ops;
    619			links[i].init = acp_card_maxim_init;
    620		}
    621		i++;
    622	}
    623
    624	if (drv_data->dmic_cpu_id == DMIC) {
    625		links[i].name = "acp-dmic-codec";
    626		links[i].id = DMIC_BE_ID;
    627		if (drv_data->dmic_codec_id == DMIC) {
    628			links[i].codecs = dmic_codec;
    629			links[i].num_codecs = ARRAY_SIZE(dmic_codec);
    630		} else {
    631			/* Use dummy codec if codec id not specified */
    632			links[i].codecs = dummy_codec;
    633			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
    634		}
    635		links[i].cpus = pdm_dmic;
    636		links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
    637		links[i].platforms = platform_component;
    638		links[i].num_platforms = ARRAY_SIZE(platform_component);
    639		links[i].ops = &acp_card_dmic_ops;
    640		links[i].dpcm_capture = 1;
    641	}
    642
    643	card->dai_link = links;
    644	card->num_links = num_links;
    645
    646	return 0;
    647}
    648EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH);
    649
    650MODULE_LICENSE("GPL v2");