0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/acpi.h>
0011 #include <linux/delay.h>
0012 #include <linux/dmi.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <sound/core.h>
0016 #include <sound/jack.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/sof.h>
0020 #include "../../codecs/hdac_hdmi.h"
0021 #include "hda_dsp_common.h"
0022 #include "sof_realtek_common.h"
0023 #include "sof_cirrus_common.h"
0024
0025 #define NAME_SIZE 32
0026
0027
0028 #define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0))
0029 #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0))
0030
0031
0032 #define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4)
0033 #define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5
0034 #define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5))
0035 #define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \
0036 (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
0037
0038 #define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7
0039 #define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7))
0040 #define SOF_HDMI_CAPTURE_1_SSP(quirk) \
0041 (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
0042
0043 #define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10
0044 #define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10))
0045 #define SOF_HDMI_CAPTURE_2_SSP(quirk) \
0046 (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
0047
0048
0049 #define SOF_HDMI_PLAYBACK_PRESENT BIT(13)
0050 #define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14
0051 #define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14))
0052 #define SOF_NO_OF_HDMI_PLAYBACK(quirk) \
0053 (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
0054
0055
0056 #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17)
0057 #define SOF_BT_OFFLOAD_SSP_SHIFT 18
0058 #define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18))
0059 #define SOF_BT_OFFLOAD_SSP(quirk) \
0060 (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
0061
0062
0063 #define SOF_RT1308_SPEAKER_AMP_PRESENT BIT(21)
0064 #define SOF_CS35L41_SPEAKER_AMP_PRESENT BIT(22)
0065
0066
0067 static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
0068
0069 struct sof_hdmi_pcm {
0070 struct list_head head;
0071 struct snd_soc_jack sof_hdmi;
0072 struct snd_soc_dai *codec_dai;
0073 int device;
0074 };
0075
0076 struct sof_card_private {
0077 struct list_head hdmi_pcm_list;
0078 bool common_hdmi_codec_drv;
0079 bool idisp_codec;
0080 };
0081
0082 static const struct dmi_system_id chromebook_platforms[] = {
0083 {
0084 .ident = "Google Chromebooks",
0085 .matches = {
0086 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0087 }
0088 },
0089 {},
0090 };
0091
0092 static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = {
0093 SND_SOC_DAPM_MIC("SoC DMIC", NULL),
0094 };
0095
0096 static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = {
0097
0098 {"DMic", NULL, "SoC DMIC"},
0099 };
0100
0101 static int sof_card_late_probe(struct snd_soc_card *card)
0102 {
0103 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
0104 struct snd_soc_component *component = NULL;
0105 char jack_name[NAME_SIZE];
0106 struct sof_hdmi_pcm *pcm;
0107 int err;
0108 int i;
0109
0110 if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
0111 return 0;
0112
0113
0114 if (!ctx->idisp_codec)
0115 return 0;
0116
0117 if (list_empty(&ctx->hdmi_pcm_list))
0118 return -EINVAL;
0119
0120 if (ctx->common_hdmi_codec_drv) {
0121 pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
0122 head);
0123 component = pcm->codec_dai->component;
0124 return hda_dsp_hdmi_build_controls(card, component);
0125 }
0126
0127 i = 0;
0128 list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
0129 component = pcm->codec_dai->component;
0130 snprintf(jack_name, sizeof(jack_name),
0131 "HDMI/DP, pcm=%d Jack", pcm->device);
0132 err = snd_soc_card_jack_new(card, jack_name,
0133 SND_JACK_AVOUT, &pcm->sof_hdmi);
0134
0135 if (err)
0136 return err;
0137
0138 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
0139 &pcm->sof_hdmi);
0140 if (err < 0)
0141 return err;
0142
0143 i++;
0144 }
0145
0146 return hdac_hdmi_jack_port_init(component, &card->dapm);
0147 }
0148
0149 static struct snd_soc_card sof_ssp_amp_card = {
0150 .name = "ssp_amp",
0151 .owner = THIS_MODULE,
0152 .dapm_widgets = sof_ssp_amp_dapm_widgets,
0153 .num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
0154 .dapm_routes = sof_ssp_amp_dapm_routes,
0155 .num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
0156 .fully_routed = true,
0157 .late_probe = sof_card_late_probe,
0158 };
0159
0160 static struct snd_soc_dai_link_component platform_component[] = {
0161 {
0162
0163 .name = "0000:00:1f.3"
0164 }
0165 };
0166
0167 static struct snd_soc_dai_link_component dmic_component[] = {
0168 {
0169 .name = "dmic-codec",
0170 .dai_name = "dmic-hifi",
0171 }
0172 };
0173
0174 static struct snd_soc_dai_link_component dummy_component[] = {
0175 {
0176 .name = "snd-soc-dummy",
0177 .dai_name = "snd-soc-dummy-dai",
0178 }
0179 };
0180
0181 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
0182 {
0183 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
0184 struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
0185 struct sof_hdmi_pcm *pcm;
0186
0187 pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
0188 if (!pcm)
0189 return -ENOMEM;
0190
0191
0192 pcm->device = rtd->dai_link->id;
0193 pcm->codec_dai = dai;
0194
0195 list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
0196
0197 return 0;
0198 }
0199
0200 #define IDISP_CODEC_MASK 0x4
0201
0202 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
0203 int ssp_codec,
0204 int dmic_be_num,
0205 int hdmi_num,
0206 bool idisp_codec)
0207 {
0208 struct snd_soc_dai_link_component *idisp_components;
0209 struct snd_soc_dai_link_component *cpus;
0210 struct snd_soc_dai_link *links;
0211 int i, id = 0;
0212
0213 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
0214 sof_ssp_amp_card.num_links, GFP_KERNEL);
0215 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
0216 sof_ssp_amp_card.num_links, GFP_KERNEL);
0217 if (!links || !cpus)
0218 return NULL;
0219
0220
0221 if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
0222 int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
0223 SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
0224
0225 for (i = 1; i <= num_of_hdmi_ssp; i++) {
0226 int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
0227 SOF_HDMI_CAPTURE_1_SSP_SHIFT :
0228 (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
0229 SOF_HDMI_CAPTURE_2_SSP_SHIFT);
0230
0231 links[id].cpus = &cpus[id];
0232 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
0233 "SSP%d Pin", port);
0234 if (!links[id].cpus->dai_name)
0235 return NULL;
0236 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
0237 if (!links[id].name)
0238 return NULL;
0239 links[id].id = id;
0240 links[id].codecs = dummy_component;
0241 links[id].num_codecs = ARRAY_SIZE(dummy_component);
0242 links[id].platforms = platform_component;
0243 links[id].num_platforms = ARRAY_SIZE(platform_component);
0244 links[id].dpcm_capture = 1;
0245 links[id].no_pcm = 1;
0246 links[id].num_cpus = 1;
0247 id++;
0248 }
0249 }
0250
0251
0252 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
0253 if (!links[id].name)
0254 return NULL;
0255
0256 links[id].id = id;
0257 if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
0258 sof_rt1308_dai_link(&links[id]);
0259 } else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
0260 cs35l41_set_dai_link(&links[id]);
0261
0262
0263 links[id].dpcm_capture = 1;
0264 }
0265 links[id].platforms = platform_component;
0266 links[id].num_platforms = ARRAY_SIZE(platform_component);
0267 links[id].dpcm_playback = 1;
0268 links[id].no_pcm = 1;
0269 links[id].cpus = &cpus[id];
0270 links[id].num_cpus = 1;
0271 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
0272 if (!links[id].cpus->dai_name)
0273 return NULL;
0274
0275 id++;
0276
0277
0278 if (dmic_be_num > 0) {
0279
0280 links[id].name = "dmic01";
0281 links[id].cpus = &cpus[id];
0282 links[id].cpus->dai_name = "DMIC01 Pin";
0283 if (dmic_be_num > 1) {
0284
0285 links[id + 1].name = "dmic16k";
0286 links[id + 1].cpus = &cpus[id + 1];
0287 links[id + 1].cpus->dai_name = "DMIC16k Pin";
0288 dmic_be_num = 2;
0289 }
0290 }
0291
0292 for (i = 0; i < dmic_be_num; i++) {
0293 links[id].id = id;
0294 links[id].num_cpus = 1;
0295 links[id].codecs = dmic_component;
0296 links[id].num_codecs = ARRAY_SIZE(dmic_component);
0297 links[id].platforms = platform_component;
0298 links[id].num_platforms = ARRAY_SIZE(platform_component);
0299 links[id].ignore_suspend = 1;
0300 links[id].dpcm_capture = 1;
0301 links[id].no_pcm = 1;
0302 id++;
0303 }
0304
0305
0306 if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
0307
0308 if (hdmi_num > 0) {
0309 idisp_components = devm_kzalloc(dev,
0310 sizeof(struct snd_soc_dai_link_component) *
0311 hdmi_num, GFP_KERNEL);
0312 if (!idisp_components)
0313 goto devm_err;
0314 }
0315 for (i = 1; i <= hdmi_num; i++) {
0316 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
0317 "iDisp%d", i);
0318 if (!links[id].name)
0319 goto devm_err;
0320
0321 links[id].id = id;
0322 links[id].cpus = &cpus[id];
0323 links[id].num_cpus = 1;
0324 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
0325 "iDisp%d Pin", i);
0326 if (!links[id].cpus->dai_name)
0327 goto devm_err;
0328
0329 if (idisp_codec) {
0330 idisp_components[i - 1].name = "ehdaudio0D2";
0331 idisp_components[i - 1].dai_name = devm_kasprintf(dev,
0332 GFP_KERNEL,
0333 "intel-hdmi-hifi%d",
0334 i);
0335 if (!idisp_components[i - 1].dai_name)
0336 goto devm_err;
0337 } else {
0338 idisp_components[i - 1].name = "snd-soc-dummy";
0339 idisp_components[i - 1].dai_name = "snd-soc-dummy-dai";
0340 }
0341
0342 links[id].codecs = &idisp_components[i - 1];
0343 links[id].num_codecs = 1;
0344 links[id].platforms = platform_component;
0345 links[id].num_platforms = ARRAY_SIZE(platform_component);
0346 links[id].init = sof_hdmi_init;
0347 links[id].dpcm_playback = 1;
0348 links[id].no_pcm = 1;
0349 id++;
0350 }
0351 }
0352
0353
0354 if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
0355 int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
0356 SOF_BT_OFFLOAD_SSP_SHIFT;
0357
0358 links[id].id = id;
0359 links[id].cpus = &cpus[id];
0360 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
0361 "SSP%d Pin", port);
0362 if (!links[id].cpus->dai_name)
0363 goto devm_err;
0364 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
0365 if (!links[id].name)
0366 goto devm_err;
0367 links[id].codecs = dummy_component;
0368 links[id].num_codecs = ARRAY_SIZE(dummy_component);
0369 links[id].platforms = platform_component;
0370 links[id].num_platforms = ARRAY_SIZE(platform_component);
0371 links[id].dpcm_playback = 1;
0372 links[id].dpcm_capture = 1;
0373 links[id].no_pcm = 1;
0374 links[id].num_cpus = 1;
0375 id++;
0376 }
0377
0378 return links;
0379 devm_err:
0380 return NULL;
0381 }
0382
0383 static int sof_ssp_amp_probe(struct platform_device *pdev)
0384 {
0385 struct snd_soc_dai_link *dai_links;
0386 struct snd_soc_acpi_mach *mach;
0387 struct sof_card_private *ctx;
0388 int dmic_be_num = 0, hdmi_num = 0;
0389 int ret, ssp_codec;
0390
0391 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
0392 if (!ctx)
0393 return -ENOMEM;
0394
0395 if (pdev->id_entry && pdev->id_entry->driver_data)
0396 sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
0397
0398 mach = pdev->dev.platform_data;
0399
0400 if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
0401 dmic_be_num = 2;
0402
0403 ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
0404
0405
0406 sof_ssp_amp_card.num_links = 1 + dmic_be_num;
0407
0408 if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
0409 sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
0410 SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
0411
0412 if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
0413 hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
0414 SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
0415
0416 if (!hdmi_num)
0417 hdmi_num = 3;
0418
0419 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
0420 ctx->idisp_codec = true;
0421
0422 sof_ssp_amp_card.num_links += hdmi_num;
0423 }
0424
0425 if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
0426 sof_ssp_amp_card.num_links++;
0427
0428 dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
0429 if (!dai_links)
0430 return -ENOMEM;
0431
0432 sof_ssp_amp_card.dai_link = dai_links;
0433
0434
0435 if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
0436 cs35l41_set_codec_conf(&sof_ssp_amp_card);
0437 }
0438
0439 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
0440
0441 sof_ssp_amp_card.dev = &pdev->dev;
0442
0443
0444 ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
0445 mach->mach_params.platform);
0446 if (ret)
0447 return ret;
0448
0449 ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
0450
0451 snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
0452
0453 return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
0454 }
0455
0456 static const struct platform_device_id board_ids[] = {
0457 {
0458 .name = "sof_ssp_amp",
0459 },
0460 {
0461 .name = "tgl_rt1308_hdmi_ssp",
0462 .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
0463 SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
0464 SOF_HDMI_CAPTURE_1_SSP(1) |
0465 SOF_HDMI_CAPTURE_2_SSP(5) |
0466 SOF_SSP_HDMI_CAPTURE_PRESENT |
0467 SOF_RT1308_SPEAKER_AMP_PRESENT),
0468 },
0469 {
0470 .name = "adl_cs35l41",
0471 .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
0472 SOF_NO_OF_HDMI_PLAYBACK(4) |
0473 SOF_HDMI_PLAYBACK_PRESENT |
0474 SOF_BT_OFFLOAD_SSP(2) |
0475 SOF_SSP_BT_OFFLOAD_PRESENT |
0476 SOF_CS35L41_SPEAKER_AMP_PRESENT),
0477 },
0478 { }
0479 };
0480 MODULE_DEVICE_TABLE(platform, board_ids);
0481
0482 static struct platform_driver sof_ssp_amp_driver = {
0483 .probe = sof_ssp_amp_probe,
0484 .driver = {
0485 .name = "sof_ssp_amp",
0486 .pm = &snd_soc_pm_ops,
0487 },
0488 .id_table = board_ids,
0489 };
0490 module_platform_driver(sof_ssp_amp_driver);
0491
0492 MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
0493 MODULE_AUTHOR("balamurugan.c <balamurugan.c@intel.com>");
0494 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
0495 MODULE_LICENSE("GPL");
0496 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
0497 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
0498 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);