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

sof_nau8825.c (18188B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright(c) 2021 Intel Corporation.
      3// Copyright(c) 2021 Nuvoton Corporation.
      4
      5/*
      6 * Intel SOF Machine Driver with Nuvoton headphone codec NAU8825
      7 * and speaker codec RT1019P MAX98360a or MAX98373
      8 */
      9#include <linux/i2c.h>
     10#include <linux/input.h>
     11#include <linux/module.h>
     12#include <linux/platform_device.h>
     13#include <linux/dmi.h>
     14#include <sound/core.h>
     15#include <sound/jack.h>
     16#include <sound/pcm.h>
     17#include <sound/pcm_params.h>
     18#include <sound/soc.h>
     19#include <sound/sof.h>
     20#include <sound/soc-acpi.h>
     21#include "../../codecs/nau8825.h"
     22#include "../common/soc-intel-quirks.h"
     23#include "hda_dsp_common.h"
     24#include "sof_realtek_common.h"
     25#include "sof_maxim_common.h"
     26
     27#define NAME_SIZE 32
     28
     29#define SOF_NAU8825_SSP_CODEC(quirk)		((quirk) & GENMASK(2, 0))
     30#define SOF_NAU8825_SSP_CODEC_MASK		(GENMASK(2, 0))
     31#define SOF_SPEAKER_AMP_PRESENT		BIT(3)
     32#define SOF_NAU8825_SSP_AMP_SHIFT		4
     33#define SOF_NAU8825_SSP_AMP_MASK		(GENMASK(6, 4))
     34#define SOF_NAU8825_SSP_AMP(quirk)	\
     35	(((quirk) << SOF_NAU8825_SSP_AMP_SHIFT) & SOF_NAU8825_SSP_AMP_MASK)
     36#define SOF_NAU8825_NUM_HDMIDEV_SHIFT		7
     37#define SOF_NAU8825_NUM_HDMIDEV_MASK		(GENMASK(9, 7))
     38#define SOF_NAU8825_NUM_HDMIDEV(quirk)	\
     39	(((quirk) << SOF_NAU8825_NUM_HDMIDEV_SHIFT) & SOF_NAU8825_NUM_HDMIDEV_MASK)
     40
     41/* BT audio offload: reserve 3 bits for future */
     42#define SOF_BT_OFFLOAD_SSP_SHIFT		10
     43#define SOF_BT_OFFLOAD_SSP_MASK		(GENMASK(12, 10))
     44#define SOF_BT_OFFLOAD_SSP(quirk)	\
     45	(((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
     46#define SOF_SSP_BT_OFFLOAD_PRESENT		BIT(13)
     47#define SOF_RT1019P_SPEAKER_AMP_PRESENT	BIT(14)
     48#define SOF_MAX98373_SPEAKER_AMP_PRESENT	BIT(15)
     49#define SOF_MAX98360A_SPEAKER_AMP_PRESENT	BIT(16)
     50
     51static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
     52
     53struct sof_hdmi_pcm {
     54	struct list_head head;
     55	struct snd_soc_dai *codec_dai;
     56	int device;
     57};
     58
     59struct sof_card_private {
     60	struct clk *mclk;
     61	struct snd_soc_jack sof_headset;
     62	struct list_head hdmi_pcm_list;
     63};
     64
     65static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
     66{
     67	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
     68	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
     69	struct sof_hdmi_pcm *pcm;
     70
     71	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
     72	if (!pcm)
     73		return -ENOMEM;
     74
     75	/* dai_link id is 1:1 mapped to the PCM device */
     76	pcm->device = rtd->dai_link->id;
     77	pcm->codec_dai = dai;
     78
     79	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
     80
     81	return 0;
     82}
     83
     84static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
     85{
     86	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
     87	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
     88
     89	struct snd_soc_jack *jack;
     90	int ret;
     91
     92	/*
     93	 * Headset buttons map to the google Reference headset.
     94	 * These can be configured by userspace.
     95	 */
     96	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
     97				    SND_JACK_HEADSET | SND_JACK_BTN_0 |
     98				    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
     99				    SND_JACK_BTN_3,
    100				    &ctx->sof_headset);
    101	if (ret) {
    102		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
    103		return ret;
    104	}
    105
    106	jack = &ctx->sof_headset;
    107
    108	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
    109	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
    110	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
    111	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
    112	ret = snd_soc_component_set_jack(component, jack, NULL);
    113
    114	if (ret) {
    115		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
    116		return ret;
    117	}
    118
    119	return ret;
    120};
    121
    122static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
    123{
    124	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
    125
    126	snd_soc_component_set_jack(component, NULL, NULL);
    127}
    128
    129static int sof_nau8825_hw_params(struct snd_pcm_substream *substream,
    130				 struct snd_pcm_hw_params *params)
    131{
    132	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    133	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    134	int clk_freq, ret;
    135
    136	clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
    137
    138	if (clk_freq <= 0) {
    139		dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
    140		return -EINVAL;
    141	}
    142
    143	/* Configure clock for codec */
    144	ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
    145				     SND_SOC_CLOCK_IN);
    146	if (ret < 0) {
    147		dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
    148		return ret;
    149	}
    150
    151	/* Configure pll for codec */
    152	ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
    153				  params_rate(params) * 256);
    154	if (ret < 0) {
    155		dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
    156		return ret;
    157	}
    158
    159	return ret;
    160}
    161
    162static struct snd_soc_ops sof_nau8825_ops = {
    163	.hw_params = sof_nau8825_hw_params,
    164};
    165
    166static struct snd_soc_dai_link_component platform_component[] = {
    167	{
    168		/* name might be overridden during probe */
    169		.name = "0000:00:1f.3"
    170	}
    171};
    172
    173static int sof_card_late_probe(struct snd_soc_card *card)
    174{
    175	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
    176	struct snd_soc_dapm_context *dapm = &card->dapm;
    177	struct sof_hdmi_pcm *pcm;
    178	int err;
    179
    180	if (list_empty(&ctx->hdmi_pcm_list))
    181		return -EINVAL;
    182
    183	pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
    184
    185	if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
    186		/* Disable Left and Right Spk pin after boot */
    187		snd_soc_dapm_disable_pin(dapm, "Left Spk");
    188		snd_soc_dapm_disable_pin(dapm, "Right Spk");
    189		err = snd_soc_dapm_sync(dapm);
    190		if (err < 0)
    191			return err;
    192	}
    193
    194	return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
    195}
    196
    197static const struct snd_kcontrol_new sof_controls[] = {
    198	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
    199	SOC_DAPM_PIN_SWITCH("Headset Mic"),
    200	SOC_DAPM_PIN_SWITCH("Left Spk"),
    201	SOC_DAPM_PIN_SWITCH("Right Spk"),
    202};
    203
    204static const struct snd_kcontrol_new speaker_controls[] = {
    205	SOC_DAPM_PIN_SWITCH("Spk"),
    206};
    207
    208static const struct snd_soc_dapm_widget sof_widgets[] = {
    209	SND_SOC_DAPM_HP("Headphone Jack", NULL),
    210	SND_SOC_DAPM_MIC("Headset Mic", NULL),
    211	SND_SOC_DAPM_SPK("Left Spk", NULL),
    212	SND_SOC_DAPM_SPK("Right Spk", NULL),
    213};
    214
    215static const struct snd_soc_dapm_widget speaker_widgets[] = {
    216	SND_SOC_DAPM_SPK("Spk", NULL),
    217};
    218
    219static const struct snd_soc_dapm_widget dmic_widgets[] = {
    220	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
    221};
    222
    223static const struct snd_soc_dapm_route sof_map[] = {
    224	/* HP jack connectors - unknown if we have jack detection */
    225	{ "Headphone Jack", NULL, "HPOL" },
    226	{ "Headphone Jack", NULL, "HPOR" },
    227
    228	/* other jacks */
    229	{ "MIC", NULL, "Headset Mic" },
    230};
    231
    232static const struct snd_soc_dapm_route speaker_map[] = {
    233	/* speaker */
    234	{ "Spk", NULL, "Speaker" },
    235};
    236
    237static const struct snd_soc_dapm_route dmic_map[] = {
    238	/* digital mics */
    239	{"DMic", NULL, "SoC DMIC"},
    240};
    241
    242static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
    243{
    244	struct snd_soc_card *card = rtd->card;
    245	int ret;
    246
    247	ret = snd_soc_dapm_new_controls(&card->dapm, speaker_widgets,
    248					ARRAY_SIZE(speaker_widgets));
    249	if (ret) {
    250		dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
    251		/* Don't need to add routes if widget addition failed */
    252		return ret;
    253	}
    254
    255	ret = snd_soc_add_card_controls(card, speaker_controls,
    256					ARRAY_SIZE(speaker_controls));
    257	if (ret) {
    258		dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
    259		return ret;
    260	}
    261
    262	ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map,
    263				      ARRAY_SIZE(speaker_map));
    264
    265	if (ret)
    266		dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
    267	return ret;
    268}
    269
    270static int dmic_init(struct snd_soc_pcm_runtime *rtd)
    271{
    272	struct snd_soc_card *card = rtd->card;
    273	int ret;
    274
    275	ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
    276					ARRAY_SIZE(dmic_widgets));
    277	if (ret) {
    278		dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
    279		/* Don't need to add routes if widget addition failed */
    280		return ret;
    281	}
    282
    283	ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
    284				      ARRAY_SIZE(dmic_map));
    285
    286	if (ret)
    287		dev_err(card->dev, "DMic map addition failed: %d\n", ret);
    288
    289	return ret;
    290}
    291
    292/* sof audio machine driver for nau8825 codec */
    293static struct snd_soc_card sof_audio_card_nau8825 = {
    294	.name = "nau8825", /* the sof- prefix is added by the core */
    295	.owner = THIS_MODULE,
    296	.controls = sof_controls,
    297	.num_controls = ARRAY_SIZE(sof_controls),
    298	.dapm_widgets = sof_widgets,
    299	.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
    300	.dapm_routes = sof_map,
    301	.num_dapm_routes = ARRAY_SIZE(sof_map),
    302	.fully_routed = true,
    303	.late_probe = sof_card_late_probe,
    304};
    305
    306static struct snd_soc_dai_link_component nau8825_component[] = {
    307	{
    308		.name = "i2c-10508825:00",
    309		.dai_name = "nau8825-hifi",
    310	}
    311};
    312
    313static struct snd_soc_dai_link_component dmic_component[] = {
    314	{
    315		.name = "dmic-codec",
    316		.dai_name = "dmic-hifi",
    317	}
    318};
    319
    320static struct snd_soc_dai_link_component rt1019p_component[] = {
    321	{
    322		.name = "RTL1019:00",
    323		.dai_name = "HiFi",
    324	}
    325};
    326
    327static struct snd_soc_dai_link_component dummy_component[] = {
    328	{
    329		.name = "snd-soc-dummy",
    330		.dai_name = "snd-soc-dummy-dai",
    331	}
    332};
    333
    334static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
    335							  int ssp_codec,
    336							  int ssp_amp,
    337							  int dmic_be_num,
    338							  int hdmi_num)
    339{
    340	struct snd_soc_dai_link_component *idisp_components;
    341	struct snd_soc_dai_link_component *cpus;
    342	struct snd_soc_dai_link *links;
    343	int i, id = 0;
    344
    345	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
    346			     sof_audio_card_nau8825.num_links, GFP_KERNEL);
    347	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
    348			     sof_audio_card_nau8825.num_links, GFP_KERNEL);
    349	if (!links || !cpus)
    350		goto devm_err;
    351
    352	/* codec SSP */
    353	links[id].name = devm_kasprintf(dev, GFP_KERNEL,
    354					"SSP%d-Codec", ssp_codec);
    355	if (!links[id].name)
    356		goto devm_err;
    357
    358	links[id].id = id;
    359	links[id].codecs = nau8825_component;
    360	links[id].num_codecs = ARRAY_SIZE(nau8825_component);
    361	links[id].platforms = platform_component;
    362	links[id].num_platforms = ARRAY_SIZE(platform_component);
    363	links[id].init = sof_nau8825_codec_init;
    364	links[id].exit = sof_nau8825_codec_exit;
    365	links[id].ops = &sof_nau8825_ops;
    366	links[id].dpcm_playback = 1;
    367	links[id].dpcm_capture = 1;
    368	links[id].no_pcm = 1;
    369	links[id].cpus = &cpus[id];
    370	links[id].num_cpus = 1;
    371
    372	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
    373						  "SSP%d Pin",
    374						  ssp_codec);
    375	if (!links[id].cpus->dai_name)
    376		goto devm_err;
    377
    378	id++;
    379
    380	/* dmic */
    381	if (dmic_be_num > 0) {
    382		/* at least we have dmic01 */
    383		links[id].name = "dmic01";
    384		links[id].cpus = &cpus[id];
    385		links[id].cpus->dai_name = "DMIC01 Pin";
    386		links[id].init = dmic_init;
    387		if (dmic_be_num > 1) {
    388			/* set up 2 BE links at most */
    389			links[id + 1].name = "dmic16k";
    390			links[id + 1].cpus = &cpus[id + 1];
    391			links[id + 1].cpus->dai_name = "DMIC16k Pin";
    392			dmic_be_num = 2;
    393		}
    394	}
    395
    396	for (i = 0; i < dmic_be_num; i++) {
    397		links[id].id = id;
    398		links[id].num_cpus = 1;
    399		links[id].codecs = dmic_component;
    400		links[id].num_codecs = ARRAY_SIZE(dmic_component);
    401		links[id].platforms = platform_component;
    402		links[id].num_platforms = ARRAY_SIZE(platform_component);
    403		links[id].ignore_suspend = 1;
    404		links[id].dpcm_capture = 1;
    405		links[id].no_pcm = 1;
    406		id++;
    407	}
    408
    409	/* HDMI */
    410	if (hdmi_num > 0) {
    411		idisp_components = devm_kzalloc(dev,
    412						sizeof(struct snd_soc_dai_link_component) *
    413						hdmi_num, GFP_KERNEL);
    414		if (!idisp_components)
    415			goto devm_err;
    416	}
    417	for (i = 1; i <= hdmi_num; i++) {
    418		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
    419						"iDisp%d", i);
    420		if (!links[id].name)
    421			goto devm_err;
    422
    423		links[id].id = id;
    424		links[id].cpus = &cpus[id];
    425		links[id].num_cpus = 1;
    426		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
    427							  "iDisp%d Pin", i);
    428		if (!links[id].cpus->dai_name)
    429			goto devm_err;
    430
    431		idisp_components[i - 1].name = "ehdaudio0D2";
    432		idisp_components[i - 1].dai_name = devm_kasprintf(dev,
    433								  GFP_KERNEL,
    434								  "intel-hdmi-hifi%d",
    435								  i);
    436		if (!idisp_components[i - 1].dai_name)
    437			goto devm_err;
    438
    439		links[id].codecs = &idisp_components[i - 1];
    440		links[id].num_codecs = 1;
    441		links[id].platforms = platform_component;
    442		links[id].num_platforms = ARRAY_SIZE(platform_component);
    443		links[id].init = sof_hdmi_init;
    444		links[id].dpcm_playback = 1;
    445		links[id].no_pcm = 1;
    446		id++;
    447	}
    448
    449	/* speaker amp */
    450	if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) {
    451		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
    452						"SSP%d-Codec", ssp_amp);
    453		if (!links[id].name)
    454			goto devm_err;
    455
    456		links[id].id = id;
    457		if (sof_nau8825_quirk & SOF_RT1019P_SPEAKER_AMP_PRESENT) {
    458			links[id].codecs = rt1019p_component;
    459			links[id].num_codecs = ARRAY_SIZE(rt1019p_component);
    460			links[id].init = speaker_codec_init;
    461		} else if (sof_nau8825_quirk &
    462				SOF_MAX98373_SPEAKER_AMP_PRESENT) {
    463			links[id].codecs = max_98373_components;
    464			links[id].num_codecs = ARRAY_SIZE(max_98373_components);
    465			links[id].init = max_98373_spk_codec_init;
    466			links[id].ops = &max_98373_ops;
    467			/* feedback stream */
    468			links[id].dpcm_capture = 1;
    469		} else if (sof_nau8825_quirk &
    470				SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
    471			max_98360a_dai_link(&links[id]);
    472		} else {
    473			goto devm_err;
    474		}
    475
    476		links[id].platforms = platform_component;
    477		links[id].num_platforms = ARRAY_SIZE(platform_component);
    478		links[id].dpcm_playback = 1;
    479		links[id].no_pcm = 1;
    480		links[id].cpus = &cpus[id];
    481		links[id].num_cpus = 1;
    482		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
    483							  "SSP%d Pin",
    484							  ssp_amp);
    485		if (!links[id].cpus->dai_name)
    486			goto devm_err;
    487		id++;
    488	}
    489
    490	/* BT audio offload */
    491	if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
    492		int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
    493				SOF_BT_OFFLOAD_SSP_SHIFT;
    494
    495		links[id].id = id;
    496		links[id].cpus = &cpus[id];
    497		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
    498							  "SSP%d Pin", port);
    499		if (!links[id].cpus->dai_name)
    500			goto devm_err;
    501		links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
    502		if (!links[id].name)
    503			goto devm_err;
    504		links[id].codecs = dummy_component;
    505		links[id].num_codecs = ARRAY_SIZE(dummy_component);
    506		links[id].platforms = platform_component;
    507		links[id].num_platforms = ARRAY_SIZE(platform_component);
    508		links[id].dpcm_playback = 1;
    509		links[id].dpcm_capture = 1;
    510		links[id].no_pcm = 1;
    511		links[id].num_cpus = 1;
    512	}
    513
    514	return links;
    515devm_err:
    516	return NULL;
    517}
    518
    519static int sof_audio_probe(struct platform_device *pdev)
    520{
    521	struct snd_soc_dai_link *dai_links;
    522	struct snd_soc_acpi_mach *mach;
    523	struct sof_card_private *ctx;
    524	int dmic_be_num, hdmi_num;
    525	int ret, ssp_amp, ssp_codec;
    526
    527	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
    528	if (!ctx)
    529		return -ENOMEM;
    530
    531	if (pdev->id_entry && pdev->id_entry->driver_data)
    532		sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data;
    533
    534	mach = pdev->dev.platform_data;
    535
    536	/* A speaker amp might not be present when the quirk claims one is.
    537	 * Detect this via whether the machine driver match includes quirk_data.
    538	 */
    539	if ((sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data)
    540		sof_nau8825_quirk &= ~SOF_SPEAKER_AMP_PRESENT;
    541
    542	dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk);
    543
    544	/* default number of DMIC DAI's */
    545	dmic_be_num = 2;
    546	hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >>
    547			SOF_NAU8825_NUM_HDMIDEV_SHIFT;
    548	/* default number of HDMI DAI's */
    549	if (!hdmi_num)
    550		hdmi_num = 3;
    551
    552	ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >>
    553			SOF_NAU8825_SSP_AMP_SHIFT;
    554
    555	ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK;
    556
    557	/* compute number of dai links */
    558	sof_audio_card_nau8825.num_links = 1 + dmic_be_num + hdmi_num;
    559
    560	if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT)
    561		sof_audio_card_nau8825.num_links++;
    562
    563	if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
    564		max_98373_set_codec_conf(&sof_audio_card_nau8825);
    565
    566	if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
    567		sof_audio_card_nau8825.num_links++;
    568
    569	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
    570					      dmic_be_num, hdmi_num);
    571	if (!dai_links)
    572		return -ENOMEM;
    573
    574	sof_audio_card_nau8825.dai_link = dai_links;
    575
    576	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
    577
    578	sof_audio_card_nau8825.dev = &pdev->dev;
    579
    580	/* set platform name for each dailink */
    581	ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_nau8825,
    582						    mach->mach_params.platform);
    583	if (ret)
    584		return ret;
    585
    586	snd_soc_card_set_drvdata(&sof_audio_card_nau8825, ctx);
    587
    588	return devm_snd_soc_register_card(&pdev->dev,
    589					  &sof_audio_card_nau8825);
    590}
    591
    592static const struct platform_device_id board_ids[] = {
    593	{
    594		.name = "sof_nau8825",
    595		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
    596					SOF_NAU8825_NUM_HDMIDEV(4) |
    597					SOF_BT_OFFLOAD_SSP(2) |
    598					SOF_SSP_BT_OFFLOAD_PRESENT),
    599
    600	},
    601	{
    602		.name = "adl_rt1019p_nau8825",
    603		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
    604					SOF_SPEAKER_AMP_PRESENT |
    605					SOF_RT1019P_SPEAKER_AMP_PRESENT |
    606					SOF_NAU8825_SSP_AMP(2) |
    607					SOF_NAU8825_NUM_HDMIDEV(4)),
    608	},
    609	{
    610		.name = "adl_max98373_nau8825",
    611		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
    612					SOF_SPEAKER_AMP_PRESENT |
    613					SOF_MAX98373_SPEAKER_AMP_PRESENT |
    614					SOF_NAU8825_SSP_AMP(1) |
    615					SOF_NAU8825_NUM_HDMIDEV(4) |
    616					SOF_BT_OFFLOAD_SSP(2) |
    617					SOF_SSP_BT_OFFLOAD_PRESENT),
    618	},
    619	{
    620		/* The limitation of length of char array, shorten the name */
    621		.name = "adl_mx98360a_nau8825",
    622		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
    623					SOF_SPEAKER_AMP_PRESENT |
    624					SOF_MAX98360A_SPEAKER_AMP_PRESENT |
    625					SOF_NAU8825_SSP_AMP(1) |
    626					SOF_NAU8825_NUM_HDMIDEV(4) |
    627					SOF_BT_OFFLOAD_SSP(2) |
    628					SOF_SSP_BT_OFFLOAD_PRESENT),
    629
    630	},
    631	{ }
    632};
    633MODULE_DEVICE_TABLE(platform, board_ids);
    634
    635static struct platform_driver sof_audio = {
    636	.probe = sof_audio_probe,
    637	.driver = {
    638		.name = "sof_nau8825",
    639		.pm = &snd_soc_pm_ops,
    640	},
    641	.id_table = board_ids,
    642};
    643module_platform_driver(sof_audio)
    644
    645/* Module information */
    646MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825");
    647MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
    648MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
    649MODULE_LICENSE("GPL");
    650MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
    651MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);