12fe14ff6SBrent Lu // SPDX-License-Identifier: GPL-2.0-only
22fe14ff6SBrent Lu //
32fe14ff6SBrent Lu // Copyright(c) 2022 Intel Corporation. All rights reserved.
42fe14ff6SBrent Lu
52fe14ff6SBrent Lu /*
62fe14ff6SBrent Lu * sof_ssp_amp.c - ASoc Machine driver for Intel platforms
72fe14ff6SBrent Lu * with RT1308/CS35L41 codec.
82fe14ff6SBrent Lu */
92fe14ff6SBrent Lu
102fe14ff6SBrent Lu #include <linux/acpi.h>
112fe14ff6SBrent Lu #include <linux/delay.h>
12d1c80876SBrent Lu #include <linux/dmi.h>
132fe14ff6SBrent Lu #include <linux/module.h>
142fe14ff6SBrent Lu #include <linux/platform_device.h>
152fe14ff6SBrent Lu #include <sound/core.h>
162fe14ff6SBrent Lu #include <sound/jack.h>
172fe14ff6SBrent Lu #include <sound/pcm.h>
182fe14ff6SBrent Lu #include <sound/pcm_params.h>
192fe14ff6SBrent Lu #include <sound/sof.h>
202fe14ff6SBrent Lu #include "../../codecs/hdac_hdmi.h"
212fe14ff6SBrent Lu #include "hda_dsp_common.h"
222fe14ff6SBrent Lu #include "sof_realtek_common.h"
232fe14ff6SBrent Lu #include "sof_cirrus_common.h"
242fe14ff6SBrent Lu
252fe14ff6SBrent Lu #define NAME_SIZE 32
262fe14ff6SBrent Lu
272fe14ff6SBrent Lu /* SSP port ID for speaker amplifier */
282fe14ff6SBrent Lu #define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0))
292fe14ff6SBrent Lu #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0))
302fe14ff6SBrent Lu
312fe14ff6SBrent Lu /* HDMI capture*/
322fe14ff6SBrent Lu #define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4)
332fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5
342fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5))
352fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \
362fe14ff6SBrent Lu (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
372fe14ff6SBrent Lu
382fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7
392fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7))
402fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_1_SSP(quirk) \
412fe14ff6SBrent Lu (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
422fe14ff6SBrent Lu
432fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10
442fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10))
452fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_2_SSP(quirk) \
462fe14ff6SBrent Lu (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
472fe14ff6SBrent Lu
482fe14ff6SBrent Lu /* HDMI playback */
492fe14ff6SBrent Lu #define SOF_HDMI_PLAYBACK_PRESENT BIT(13)
502fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14
512fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14))
522fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_PLAYBACK(quirk) \
532fe14ff6SBrent Lu (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
542fe14ff6SBrent Lu
552fe14ff6SBrent Lu /* BT audio offload */
562fe14ff6SBrent Lu #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17)
572fe14ff6SBrent Lu #define SOF_BT_OFFLOAD_SSP_SHIFT 18
582fe14ff6SBrent Lu #define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18))
592fe14ff6SBrent Lu #define SOF_BT_OFFLOAD_SSP(quirk) \
602fe14ff6SBrent Lu (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
612fe14ff6SBrent Lu
622fe14ff6SBrent Lu /* Speaker amplifiers */
632fe14ff6SBrent Lu #define SOF_RT1308_SPEAKER_AMP_PRESENT BIT(21)
642fe14ff6SBrent Lu #define SOF_CS35L41_SPEAKER_AMP_PRESENT BIT(22)
652fe14ff6SBrent Lu
662fe14ff6SBrent Lu /* Default: SSP2 */
672fe14ff6SBrent Lu static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
682fe14ff6SBrent Lu
692fe14ff6SBrent Lu struct sof_hdmi_pcm {
702fe14ff6SBrent Lu struct list_head head;
712fe14ff6SBrent Lu struct snd_soc_jack sof_hdmi;
722fe14ff6SBrent Lu struct snd_soc_dai *codec_dai;
732fe14ff6SBrent Lu int device;
742fe14ff6SBrent Lu };
752fe14ff6SBrent Lu
762fe14ff6SBrent Lu struct sof_card_private {
772fe14ff6SBrent Lu struct list_head hdmi_pcm_list;
782fe14ff6SBrent Lu bool common_hdmi_codec_drv;
792fe14ff6SBrent Lu bool idisp_codec;
802fe14ff6SBrent Lu };
812fe14ff6SBrent Lu
82d1c80876SBrent Lu static const struct dmi_system_id chromebook_platforms[] = {
83d1c80876SBrent Lu {
84d1c80876SBrent Lu .ident = "Google Chromebooks",
85d1c80876SBrent Lu .matches = {
86d1c80876SBrent Lu DMI_MATCH(DMI_SYS_VENDOR, "Google"),
87d1c80876SBrent Lu }
88d1c80876SBrent Lu },
89d1c80876SBrent Lu {},
90d1c80876SBrent Lu };
91d1c80876SBrent Lu
922fe14ff6SBrent Lu static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = {
932fe14ff6SBrent Lu SND_SOC_DAPM_MIC("SoC DMIC", NULL),
942fe14ff6SBrent Lu };
952fe14ff6SBrent Lu
962fe14ff6SBrent Lu static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = {
972fe14ff6SBrent Lu /* digital mics */
982fe14ff6SBrent Lu {"DMic", NULL, "SoC DMIC"},
992fe14ff6SBrent Lu };
1002fe14ff6SBrent Lu
sof_card_late_probe(struct snd_soc_card * card)1012fe14ff6SBrent Lu static int sof_card_late_probe(struct snd_soc_card *card)
1022fe14ff6SBrent Lu {
1032fe14ff6SBrent Lu struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
1042fe14ff6SBrent Lu struct snd_soc_component *component = NULL;
1052fe14ff6SBrent Lu char jack_name[NAME_SIZE];
1062fe14ff6SBrent Lu struct sof_hdmi_pcm *pcm;
1072fe14ff6SBrent Lu int err;
1082fe14ff6SBrent Lu
1092fe14ff6SBrent Lu if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
1102fe14ff6SBrent Lu return 0;
1112fe14ff6SBrent Lu
1122fe14ff6SBrent Lu /* HDMI is not supported by SOF on Baytrail/CherryTrail */
1132fe14ff6SBrent Lu if (!ctx->idisp_codec)
1142fe14ff6SBrent Lu return 0;
1152fe14ff6SBrent Lu
1162fe14ff6SBrent Lu if (list_empty(&ctx->hdmi_pcm_list))
1172fe14ff6SBrent Lu return -EINVAL;
1182fe14ff6SBrent Lu
1192fe14ff6SBrent Lu if (ctx->common_hdmi_codec_drv) {
1202fe14ff6SBrent Lu pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
1212fe14ff6SBrent Lu head);
1222fe14ff6SBrent Lu component = pcm->codec_dai->component;
1232fe14ff6SBrent Lu return hda_dsp_hdmi_build_controls(card, component);
1242fe14ff6SBrent Lu }
1252fe14ff6SBrent Lu
1262fe14ff6SBrent Lu list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
1272fe14ff6SBrent Lu component = pcm->codec_dai->component;
1282fe14ff6SBrent Lu snprintf(jack_name, sizeof(jack_name),
1292fe14ff6SBrent Lu "HDMI/DP, pcm=%d Jack", pcm->device);
1302fe14ff6SBrent Lu err = snd_soc_card_jack_new(card, jack_name,
13119aed2d6SAkihiko Odaki SND_JACK_AVOUT, &pcm->sof_hdmi);
1322fe14ff6SBrent Lu
1332fe14ff6SBrent Lu if (err)
1342fe14ff6SBrent Lu return err;
1352fe14ff6SBrent Lu
1362fe14ff6SBrent Lu err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
1372fe14ff6SBrent Lu &pcm->sof_hdmi);
1382fe14ff6SBrent Lu if (err < 0)
1392fe14ff6SBrent Lu return err;
1402fe14ff6SBrent Lu }
1412fe14ff6SBrent Lu
1422fe14ff6SBrent Lu return hdac_hdmi_jack_port_init(component, &card->dapm);
1432fe14ff6SBrent Lu }
1442fe14ff6SBrent Lu
1452fe14ff6SBrent Lu static struct snd_soc_card sof_ssp_amp_card = {
1462fe14ff6SBrent Lu .name = "ssp_amp",
1472fe14ff6SBrent Lu .owner = THIS_MODULE,
1482fe14ff6SBrent Lu .dapm_widgets = sof_ssp_amp_dapm_widgets,
1492fe14ff6SBrent Lu .num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
1502fe14ff6SBrent Lu .dapm_routes = sof_ssp_amp_dapm_routes,
1512fe14ff6SBrent Lu .num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
1522fe14ff6SBrent Lu .fully_routed = true,
1532fe14ff6SBrent Lu .late_probe = sof_card_late_probe,
1542fe14ff6SBrent Lu };
1552fe14ff6SBrent Lu
1562fe14ff6SBrent Lu static struct snd_soc_dai_link_component platform_component[] = {
1572fe14ff6SBrent Lu {
1582fe14ff6SBrent Lu /* name might be overridden during probe */
1592fe14ff6SBrent Lu .name = "0000:00:1f.3"
1602fe14ff6SBrent Lu }
1612fe14ff6SBrent Lu };
1622fe14ff6SBrent Lu
1632fe14ff6SBrent Lu static struct snd_soc_dai_link_component dmic_component[] = {
1642fe14ff6SBrent Lu {
1652fe14ff6SBrent Lu .name = "dmic-codec",
1662fe14ff6SBrent Lu .dai_name = "dmic-hifi",
1672fe14ff6SBrent Lu }
1682fe14ff6SBrent Lu };
1692fe14ff6SBrent Lu
sof_hdmi_init(struct snd_soc_pcm_runtime * rtd)1702fe14ff6SBrent Lu static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
1712fe14ff6SBrent Lu {
1722fe14ff6SBrent Lu struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
1732fe14ff6SBrent Lu struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
1742fe14ff6SBrent Lu struct sof_hdmi_pcm *pcm;
1752fe14ff6SBrent Lu
1762fe14ff6SBrent Lu pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
1772fe14ff6SBrent Lu if (!pcm)
1782fe14ff6SBrent Lu return -ENOMEM;
1792fe14ff6SBrent Lu
1802fe14ff6SBrent Lu /* dai_link id is 1:1 mapped to the PCM device */
1812fe14ff6SBrent Lu pcm->device = rtd->dai_link->id;
1822fe14ff6SBrent Lu pcm->codec_dai = dai;
1832fe14ff6SBrent Lu
1842fe14ff6SBrent Lu list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
1852fe14ff6SBrent Lu
1862fe14ff6SBrent Lu return 0;
1872fe14ff6SBrent Lu }
1882fe14ff6SBrent Lu
1892fe14ff6SBrent Lu #define IDISP_CODEC_MASK 0x4
1902fe14ff6SBrent Lu
sof_card_dai_links_create(struct device * dev,int ssp_codec,int dmic_be_num,int hdmi_num,bool idisp_codec)1912fe14ff6SBrent Lu static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
1922fe14ff6SBrent Lu int ssp_codec,
1932fe14ff6SBrent Lu int dmic_be_num,
1942fe14ff6SBrent Lu int hdmi_num,
1952fe14ff6SBrent Lu bool idisp_codec)
1962fe14ff6SBrent Lu {
1972fe14ff6SBrent Lu struct snd_soc_dai_link_component *idisp_components;
1982fe14ff6SBrent Lu struct snd_soc_dai_link_component *cpus;
1992fe14ff6SBrent Lu struct snd_soc_dai_link *links;
2002fe14ff6SBrent Lu int i, id = 0;
2012fe14ff6SBrent Lu
20209dea5acSye xingchen links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
20309dea5acSye xingchen sizeof(struct snd_soc_dai_link), GFP_KERNEL);
20409dea5acSye xingchen cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
20509dea5acSye xingchen sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
2062fe14ff6SBrent Lu if (!links || !cpus)
2072fe14ff6SBrent Lu return NULL;
2082fe14ff6SBrent Lu
2092fe14ff6SBrent Lu /* HDMI-In SSP */
2102fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
2112fe14ff6SBrent Lu int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
2122fe14ff6SBrent Lu SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
2132fe14ff6SBrent Lu
2142fe14ff6SBrent Lu for (i = 1; i <= num_of_hdmi_ssp; i++) {
2152fe14ff6SBrent Lu int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
2162fe14ff6SBrent Lu SOF_HDMI_CAPTURE_1_SSP_SHIFT :
2172fe14ff6SBrent Lu (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
2182fe14ff6SBrent Lu SOF_HDMI_CAPTURE_2_SSP_SHIFT);
2192fe14ff6SBrent Lu
2202fe14ff6SBrent Lu links[id].cpus = &cpus[id];
2212fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
2222fe14ff6SBrent Lu "SSP%d Pin", port);
2232fe14ff6SBrent Lu if (!links[id].cpus->dai_name)
2242fe14ff6SBrent Lu return NULL;
2252fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
2262fe14ff6SBrent Lu if (!links[id].name)
2272fe14ff6SBrent Lu return NULL;
2282fe14ff6SBrent Lu links[id].id = id;
2291785af9fSKuninori Morimoto links[id].codecs = &asoc_dummy_dlc;
2301785af9fSKuninori Morimoto links[id].num_codecs = 1;
2312fe14ff6SBrent Lu links[id].platforms = platform_component;
2322fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component);
2332fe14ff6SBrent Lu links[id].dpcm_capture = 1;
2342fe14ff6SBrent Lu links[id].no_pcm = 1;
2352fe14ff6SBrent Lu links[id].num_cpus = 1;
2362fe14ff6SBrent Lu id++;
2372fe14ff6SBrent Lu }
2382fe14ff6SBrent Lu }
2392fe14ff6SBrent Lu
2402fe14ff6SBrent Lu /* codec SSP */
2412fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
2422fe14ff6SBrent Lu if (!links[id].name)
2432fe14ff6SBrent Lu return NULL;
2442fe14ff6SBrent Lu
2452fe14ff6SBrent Lu links[id].id = id;
2462fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
2472fe14ff6SBrent Lu sof_rt1308_dai_link(&links[id]);
2482fe14ff6SBrent Lu } else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
2492fe14ff6SBrent Lu cs35l41_set_dai_link(&links[id]);
2502fe14ff6SBrent Lu }
2512fe14ff6SBrent Lu links[id].platforms = platform_component;
2522fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component);
2532fe14ff6SBrent Lu links[id].dpcm_playback = 1;
254b3c00316SPierre-Louis Bossart /* feedback from amplifier or firmware-generated echo reference */
255b3c00316SPierre-Louis Bossart links[id].dpcm_capture = 1;
2562fe14ff6SBrent Lu links[id].no_pcm = 1;
2572fe14ff6SBrent Lu links[id].cpus = &cpus[id];
2582fe14ff6SBrent Lu links[id].num_cpus = 1;
2592fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
2602fe14ff6SBrent Lu if (!links[id].cpus->dai_name)
2612fe14ff6SBrent Lu return NULL;
2622fe14ff6SBrent Lu
2632fe14ff6SBrent Lu id++;
2642fe14ff6SBrent Lu
2652fe14ff6SBrent Lu /* dmic */
2662fe14ff6SBrent Lu if (dmic_be_num > 0) {
2672fe14ff6SBrent Lu /* at least we have dmic01 */
2682fe14ff6SBrent Lu links[id].name = "dmic01";
2692fe14ff6SBrent Lu links[id].cpus = &cpus[id];
2702fe14ff6SBrent Lu links[id].cpus->dai_name = "DMIC01 Pin";
2712fe14ff6SBrent Lu if (dmic_be_num > 1) {
2722fe14ff6SBrent Lu /* set up 2 BE links at most */
2732fe14ff6SBrent Lu links[id + 1].name = "dmic16k";
2742fe14ff6SBrent Lu links[id + 1].cpus = &cpus[id + 1];
2752fe14ff6SBrent Lu links[id + 1].cpus->dai_name = "DMIC16k Pin";
2762fe14ff6SBrent Lu dmic_be_num = 2;
2772fe14ff6SBrent Lu }
2782fe14ff6SBrent Lu }
2792fe14ff6SBrent Lu
2802fe14ff6SBrent Lu for (i = 0; i < dmic_be_num; i++) {
2812fe14ff6SBrent Lu links[id].id = id;
2822fe14ff6SBrent Lu links[id].num_cpus = 1;
2832fe14ff6SBrent Lu links[id].codecs = dmic_component;
2842fe14ff6SBrent Lu links[id].num_codecs = ARRAY_SIZE(dmic_component);
2852fe14ff6SBrent Lu links[id].platforms = platform_component;
2862fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component);
2872fe14ff6SBrent Lu links[id].ignore_suspend = 1;
2882fe14ff6SBrent Lu links[id].dpcm_capture = 1;
2892fe14ff6SBrent Lu links[id].no_pcm = 1;
2902fe14ff6SBrent Lu id++;
2912fe14ff6SBrent Lu }
2922fe14ff6SBrent Lu
2932fe14ff6SBrent Lu /* HDMI playback */
2942fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
2952fe14ff6SBrent Lu /* HDMI */
2962fe14ff6SBrent Lu if (hdmi_num > 0) {
29709dea5acSye xingchen idisp_components = devm_kcalloc(dev,
29809dea5acSye xingchen hdmi_num,
29909dea5acSye xingchen sizeof(struct snd_soc_dai_link_component),
30009dea5acSye xingchen GFP_KERNEL);
3012fe14ff6SBrent Lu if (!idisp_components)
3022fe14ff6SBrent Lu goto devm_err;
3032fe14ff6SBrent Lu }
3042fe14ff6SBrent Lu for (i = 1; i <= hdmi_num; i++) {
3052fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL,
3062fe14ff6SBrent Lu "iDisp%d", i);
3072fe14ff6SBrent Lu if (!links[id].name)
3082fe14ff6SBrent Lu goto devm_err;
3092fe14ff6SBrent Lu
3102fe14ff6SBrent Lu links[id].id = id;
3112fe14ff6SBrent Lu links[id].cpus = &cpus[id];
3122fe14ff6SBrent Lu links[id].num_cpus = 1;
3132fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
3142fe14ff6SBrent Lu "iDisp%d Pin", i);
3152fe14ff6SBrent Lu if (!links[id].cpus->dai_name)
3162fe14ff6SBrent Lu goto devm_err;
3172fe14ff6SBrent Lu
3182fe14ff6SBrent Lu if (idisp_codec) {
3192fe14ff6SBrent Lu idisp_components[i - 1].name = "ehdaudio0D2";
3202fe14ff6SBrent Lu idisp_components[i - 1].dai_name = devm_kasprintf(dev,
3212fe14ff6SBrent Lu GFP_KERNEL,
3222fe14ff6SBrent Lu "intel-hdmi-hifi%d",
3232fe14ff6SBrent Lu i);
3242fe14ff6SBrent Lu if (!idisp_components[i - 1].dai_name)
3252fe14ff6SBrent Lu goto devm_err;
3262fe14ff6SBrent Lu } else {
3271785af9fSKuninori Morimoto idisp_components[i - 1] = asoc_dummy_dlc;
3282fe14ff6SBrent Lu }
3292fe14ff6SBrent Lu
3302fe14ff6SBrent Lu links[id].codecs = &idisp_components[i - 1];
3312fe14ff6SBrent Lu links[id].num_codecs = 1;
3322fe14ff6SBrent Lu links[id].platforms = platform_component;
3332fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component);
3342fe14ff6SBrent Lu links[id].init = sof_hdmi_init;
3352fe14ff6SBrent Lu links[id].dpcm_playback = 1;
3362fe14ff6SBrent Lu links[id].no_pcm = 1;
3372fe14ff6SBrent Lu id++;
3382fe14ff6SBrent Lu }
3392fe14ff6SBrent Lu }
3402fe14ff6SBrent Lu
3412fe14ff6SBrent Lu /* BT audio offload */
3422fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
3432fe14ff6SBrent Lu int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
3442fe14ff6SBrent Lu SOF_BT_OFFLOAD_SSP_SHIFT;
3452fe14ff6SBrent Lu
3462fe14ff6SBrent Lu links[id].id = id;
3472fe14ff6SBrent Lu links[id].cpus = &cpus[id];
3482fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
3492fe14ff6SBrent Lu "SSP%d Pin", port);
3502fe14ff6SBrent Lu if (!links[id].cpus->dai_name)
3512fe14ff6SBrent Lu goto devm_err;
3522fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
3532fe14ff6SBrent Lu if (!links[id].name)
3542fe14ff6SBrent Lu goto devm_err;
3551785af9fSKuninori Morimoto links[id].codecs = &asoc_dummy_dlc;
3561785af9fSKuninori Morimoto links[id].num_codecs = 1;
3572fe14ff6SBrent Lu links[id].platforms = platform_component;
3582fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component);
3592fe14ff6SBrent Lu links[id].dpcm_playback = 1;
3602fe14ff6SBrent Lu links[id].dpcm_capture = 1;
3612fe14ff6SBrent Lu links[id].no_pcm = 1;
3622fe14ff6SBrent Lu links[id].num_cpus = 1;
3632fe14ff6SBrent Lu id++;
3642fe14ff6SBrent Lu }
3652fe14ff6SBrent Lu
3662fe14ff6SBrent Lu return links;
3672fe14ff6SBrent Lu devm_err:
3682fe14ff6SBrent Lu return NULL;
3692fe14ff6SBrent Lu }
3702fe14ff6SBrent Lu
sof_ssp_amp_probe(struct platform_device * pdev)3712fe14ff6SBrent Lu static int sof_ssp_amp_probe(struct platform_device *pdev)
3722fe14ff6SBrent Lu {
3732fe14ff6SBrent Lu struct snd_soc_dai_link *dai_links;
3742fe14ff6SBrent Lu struct snd_soc_acpi_mach *mach;
3752fe14ff6SBrent Lu struct sof_card_private *ctx;
376d1c80876SBrent Lu int dmic_be_num = 0, hdmi_num = 0;
3772fe14ff6SBrent Lu int ret, ssp_codec;
3782fe14ff6SBrent Lu
3792fe14ff6SBrent Lu ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
3802fe14ff6SBrent Lu if (!ctx)
3812fe14ff6SBrent Lu return -ENOMEM;
3822fe14ff6SBrent Lu
3832fe14ff6SBrent Lu if (pdev->id_entry && pdev->id_entry->driver_data)
3842fe14ff6SBrent Lu sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
3852fe14ff6SBrent Lu
3862fe14ff6SBrent Lu mach = pdev->dev.platform_data;
3872fe14ff6SBrent Lu
388d1c80876SBrent Lu if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
389d1c80876SBrent Lu dmic_be_num = 2;
3902fe14ff6SBrent Lu
3912fe14ff6SBrent Lu ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
3922fe14ff6SBrent Lu
3932fe14ff6SBrent Lu /* set number of dai links */
3942fe14ff6SBrent Lu sof_ssp_amp_card.num_links = 1 + dmic_be_num;
3952fe14ff6SBrent Lu
3962fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
3972fe14ff6SBrent Lu sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
3982fe14ff6SBrent Lu SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
3992fe14ff6SBrent Lu
4002fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
4012fe14ff6SBrent Lu hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
4022fe14ff6SBrent Lu SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
4032fe14ff6SBrent Lu /* default number of HDMI DAI's */
4042fe14ff6SBrent Lu if (!hdmi_num)
4052fe14ff6SBrent Lu hdmi_num = 3;
4062fe14ff6SBrent Lu
4072fe14ff6SBrent Lu if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
4082fe14ff6SBrent Lu ctx->idisp_codec = true;
4092fe14ff6SBrent Lu
4102fe14ff6SBrent Lu sof_ssp_amp_card.num_links += hdmi_num;
4112fe14ff6SBrent Lu }
4122fe14ff6SBrent Lu
4132fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
4142fe14ff6SBrent Lu sof_ssp_amp_card.num_links++;
4152fe14ff6SBrent Lu
4162fe14ff6SBrent Lu dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
4172fe14ff6SBrent Lu if (!dai_links)
4182fe14ff6SBrent Lu return -ENOMEM;
4192fe14ff6SBrent Lu
4202fe14ff6SBrent Lu sof_ssp_amp_card.dai_link = dai_links;
4212fe14ff6SBrent Lu
4222fe14ff6SBrent Lu /* update codec_conf */
4232fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
4242fe14ff6SBrent Lu cs35l41_set_codec_conf(&sof_ssp_amp_card);
4252fe14ff6SBrent Lu }
4262fe14ff6SBrent Lu
4272fe14ff6SBrent Lu INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
4282fe14ff6SBrent Lu
4292fe14ff6SBrent Lu sof_ssp_amp_card.dev = &pdev->dev;
4302fe14ff6SBrent Lu
4312fe14ff6SBrent Lu /* set platform name for each dailink */
4322fe14ff6SBrent Lu ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
4332fe14ff6SBrent Lu mach->mach_params.platform);
4342fe14ff6SBrent Lu if (ret)
4352fe14ff6SBrent Lu return ret;
4362fe14ff6SBrent Lu
4372fe14ff6SBrent Lu ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
4382fe14ff6SBrent Lu
4392fe14ff6SBrent Lu snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
4402fe14ff6SBrent Lu
4412fe14ff6SBrent Lu return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
4422fe14ff6SBrent Lu }
4432fe14ff6SBrent Lu
4442fe14ff6SBrent Lu static const struct platform_device_id board_ids[] = {
4452fe14ff6SBrent Lu {
4462fe14ff6SBrent Lu .name = "sof_ssp_amp",
4472fe14ff6SBrent Lu },
4482fe14ff6SBrent Lu {
4492fe14ff6SBrent Lu .name = "tgl_rt1308_hdmi_ssp",
4502fe14ff6SBrent Lu .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
4512fe14ff6SBrent Lu SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
4522fe14ff6SBrent Lu SOF_HDMI_CAPTURE_1_SSP(1) |
4532fe14ff6SBrent Lu SOF_HDMI_CAPTURE_2_SSP(5) |
4542fe14ff6SBrent Lu SOF_SSP_HDMI_CAPTURE_PRESENT |
4552fe14ff6SBrent Lu SOF_RT1308_SPEAKER_AMP_PRESENT),
4562fe14ff6SBrent Lu },
4572fe14ff6SBrent Lu {
4582fe14ff6SBrent Lu .name = "adl_cs35l41",
4592fe14ff6SBrent Lu .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
4602fe14ff6SBrent Lu SOF_NO_OF_HDMI_PLAYBACK(4) |
4612fe14ff6SBrent Lu SOF_HDMI_PLAYBACK_PRESENT |
4622fe14ff6SBrent Lu SOF_BT_OFFLOAD_SSP(2) |
4632fe14ff6SBrent Lu SOF_SSP_BT_OFFLOAD_PRESENT |
4642fe14ff6SBrent Lu SOF_CS35L41_SPEAKER_AMP_PRESENT),
4652fe14ff6SBrent Lu },
4665376d37bSBalamurugan C {
4675376d37bSBalamurugan C .name = "adl_lt6911_hdmi_ssp",
4685376d37bSBalamurugan C .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
4695376d37bSBalamurugan C SOF_HDMI_CAPTURE_1_SSP(0) |
4705376d37bSBalamurugan C SOF_HDMI_CAPTURE_2_SSP(2) |
4715376d37bSBalamurugan C SOF_SSP_HDMI_CAPTURE_PRESENT |
4725376d37bSBalamurugan C SOF_NO_OF_HDMI_PLAYBACK(3) |
4735376d37bSBalamurugan C SOF_HDMI_PLAYBACK_PRESENT),
4745376d37bSBalamurugan C },
475*f7555da7SBalamurugan C {
476*f7555da7SBalamurugan C .name = "rpl_lt6911_hdmi_ssp",
477*f7555da7SBalamurugan C .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
478*f7555da7SBalamurugan C SOF_HDMI_CAPTURE_1_SSP(0) |
479*f7555da7SBalamurugan C SOF_HDMI_CAPTURE_2_SSP(2) |
480*f7555da7SBalamurugan C SOF_SSP_HDMI_CAPTURE_PRESENT |
481*f7555da7SBalamurugan C SOF_NO_OF_HDMI_PLAYBACK(3) |
482*f7555da7SBalamurugan C SOF_HDMI_PLAYBACK_PRESENT),
483*f7555da7SBalamurugan C },
4842fe14ff6SBrent Lu { }
4852fe14ff6SBrent Lu };
4862fe14ff6SBrent Lu MODULE_DEVICE_TABLE(platform, board_ids);
4872fe14ff6SBrent Lu
4882fe14ff6SBrent Lu static struct platform_driver sof_ssp_amp_driver = {
4892fe14ff6SBrent Lu .probe = sof_ssp_amp_probe,
4902fe14ff6SBrent Lu .driver = {
4912fe14ff6SBrent Lu .name = "sof_ssp_amp",
4922fe14ff6SBrent Lu .pm = &snd_soc_pm_ops,
4932fe14ff6SBrent Lu },
4942fe14ff6SBrent Lu .id_table = board_ids,
4952fe14ff6SBrent Lu };
4962fe14ff6SBrent Lu module_platform_driver(sof_ssp_amp_driver);
4972fe14ff6SBrent Lu
4982fe14ff6SBrent Lu MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
4991529d344SBalamurugan C MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>");
5002fe14ff6SBrent Lu MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
5012fe14ff6SBrent Lu MODULE_LICENSE("GPL");
5022fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
5032fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
5042fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
505