0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/dmi.h>
0010 #include <linux/module.h>
0011 #include <linux/soundwire/sdw.h>
0012 #include <linux/soundwire/sdw_type.h>
0013 #include <sound/soc.h>
0014 #include <sound/soc-acpi.h>
0015 #include "sof_sdw_common.h"
0016 #include "../../codecs/rt711.h"
0017
0018 unsigned long sof_sdw_quirk = RT711_JD1;
0019 static int quirk_override = -1;
0020 module_param_named(quirk, quirk_override, int, 0444);
0021 MODULE_PARM_DESC(quirk, "Board-specific quirk override");
0022
0023 #define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0)
0024
0025 static void log_quirks(struct device *dev)
0026 {
0027 if (SOF_RT711_JDSRC(sof_sdw_quirk))
0028 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
0029 SOF_RT711_JDSRC(sof_sdw_quirk));
0030 if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
0031 dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n");
0032 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
0033 dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
0034 if (sof_sdw_quirk & SOF_SDW_PCH_DMIC)
0035 dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n");
0036 if (SOF_SSP_GET_PORT(sof_sdw_quirk))
0037 dev_dbg(dev, "SSP port %ld\n",
0038 SOF_SSP_GET_PORT(sof_sdw_quirk));
0039 if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
0040 dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
0041 }
0042
0043 static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
0044 {
0045 sof_sdw_quirk = (unsigned long)id->driver_data;
0046 return 1;
0047 }
0048
0049 static const struct dmi_system_id sof_sdw_quirk_table[] = {
0050
0051 {
0052 .callback = sof_sdw_quirk_cb,
0053 .matches = {
0054 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
0055 DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
0056 },
0057 .driver_data = (void *)SOF_SDW_PCH_DMIC,
0058 },
0059 {
0060 .callback = sof_sdw_quirk_cb,
0061 .matches = {
0062 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0063 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
0064 },
0065 .driver_data = (void *)RT711_JD2,
0066 },
0067 {
0068
0069 .callback = sof_sdw_quirk_cb,
0070 .matches = {
0071 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0072 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
0073 },
0074 .driver_data = (void *)RT711_JD2,
0075 },
0076 {
0077 .callback = sof_sdw_quirk_cb,
0078 .matches = {
0079 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0080 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
0081 },
0082 .driver_data = (void *)(RT711_JD2 |
0083 SOF_SDW_FOUR_SPK),
0084 },
0085 {
0086 .callback = sof_sdw_quirk_cb,
0087 .matches = {
0088 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0089 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
0090 },
0091 .driver_data = (void *)(RT711_JD2 |
0092 SOF_SDW_FOUR_SPK),
0093 },
0094
0095 {
0096 .callback = sof_sdw_quirk_cb,
0097 .matches = {
0098 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
0099 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
0100 },
0101 .driver_data = (void *)SOF_SDW_PCH_DMIC,
0102 },
0103
0104 {
0105 .callback = sof_sdw_quirk_cb,
0106 .matches = {
0107 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
0108 DMI_MATCH(DMI_PRODUCT_NAME,
0109 "Tiger Lake Client Platform"),
0110 },
0111 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0112 RT711_JD1 |
0113 SOF_SDW_PCH_DMIC |
0114 SOF_SSP_PORT(SOF_I2S_SSP2)),
0115 },
0116 {
0117 .callback = sof_sdw_quirk_cb,
0118 .matches = {
0119 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0120 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
0121 },
0122 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0123 RT711_JD2),
0124 },
0125 {
0126
0127 .callback = sof_sdw_quirk_cb,
0128 .matches = {
0129 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0130 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
0131 },
0132 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0133 RT711_JD2),
0134 },
0135 {
0136
0137 .callback = sof_sdw_quirk_cb,
0138 .matches = {
0139 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0140 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
0141 },
0142 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0143 RT711_JD2 |
0144 SOF_SDW_FOUR_SPK),
0145 },
0146 {
0147 .callback = sof_sdw_quirk_cb,
0148 .matches = {
0149 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0150 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
0151 },
0152 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0153 RT711_JD2 |
0154 SOF_SDW_FOUR_SPK),
0155 },
0156 {
0157 .callback = sof_sdw_quirk_cb,
0158 .matches = {
0159 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0160 DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
0161 },
0162 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0163 SOF_SDW_PCH_DMIC |
0164 SOF_SDW_FOUR_SPK |
0165 SOF_BT_OFFLOAD_SSP(2) |
0166 SOF_SSP_BT_OFFLOAD_PRESENT),
0167 },
0168 {
0169 .callback = sof_sdw_quirk_cb,
0170 .matches = {
0171 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0172 DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
0173 },
0174 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0175 SOF_SDW_PCH_DMIC |
0176 SOF_SDW_FOUR_SPK),
0177 },
0178 {
0179
0180
0181
0182
0183
0184
0185 .callback = sof_sdw_quirk_cb,
0186 .matches = {
0187 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
0188 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
0189 },
0190 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0191 SOF_SDW_PCH_DMIC |
0192 RT711_JD1),
0193 },
0194 {
0195
0196 .callback = sof_sdw_quirk_cb,
0197 .matches = {
0198 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
0199 DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
0200 },
0201 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0202 SOF_SDW_PCH_DMIC |
0203 RT711_JD1),
0204 },
0205
0206 {
0207 .callback = sof_sdw_quirk_cb,
0208 .matches = {
0209 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0210 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
0211 },
0212 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0213 RT711_JD2 |
0214 SOF_SDW_FOUR_SPK),
0215 },
0216 {
0217 .callback = sof_sdw_quirk_cb,
0218 .matches = {
0219 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0220 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
0221 },
0222 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0223 RT711_JD2),
0224 },
0225
0226 {
0227 .callback = sof_sdw_quirk_cb,
0228 .matches = {
0229 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
0230 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
0231 },
0232 .driver_data = (void *)(RT711_JD2_100K |
0233 SOF_SDW_TGL_HDMI |
0234 SOF_BT_OFFLOAD_SSP(2) |
0235 SOF_SSP_BT_OFFLOAD_PRESENT),
0236 },
0237 {
0238 .callback = sof_sdw_quirk_cb,
0239 .matches = {
0240 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0241 DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
0242 },
0243 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0244 SOF_SDW_PCH_DMIC |
0245 SOF_SDW_FOUR_SPK |
0246 SOF_BT_OFFLOAD_SSP(2) |
0247 SOF_SSP_BT_OFFLOAD_PRESENT),
0248 },
0249 {
0250 .callback = sof_sdw_quirk_cb,
0251 .matches = {
0252 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0253 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
0254 },
0255 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0256 RT711_JD2 |
0257 SOF_SDW_FOUR_SPK),
0258 },
0259 {
0260 .callback = sof_sdw_quirk_cb,
0261 .matches = {
0262 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0263 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
0264 },
0265
0266 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0267 SOF_SDW_FOUR_SPK),
0268 },
0269 {
0270 .callback = sof_sdw_quirk_cb,
0271 .matches = {
0272 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0273 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
0274 },
0275 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0276 RT711_JD2 |
0277 SOF_SDW_FOUR_SPK),
0278 },
0279 {
0280 .callback = sof_sdw_quirk_cb,
0281 .matches = {
0282 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0283 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
0284 },
0285 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0286 RT711_JD2 |
0287 SOF_SDW_FOUR_SPK),
0288 },
0289 {
0290 .callback = sof_sdw_quirk_cb,
0291 .matches = {
0292 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0293 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
0294 },
0295 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0296 RT711_JD2 |
0297 SOF_SDW_FOUR_SPK),
0298 },
0299 {
0300 .callback = sof_sdw_quirk_cb,
0301 .matches = {
0302 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0303 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
0304 },
0305 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0306 RT711_JD2 |
0307 SOF_SDW_FOUR_SPK),
0308 },
0309 {
0310 .callback = sof_sdw_quirk_cb,
0311 .matches = {
0312 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0313 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
0314 },
0315 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0316 RT711_JD2 |
0317 SOF_SDW_FOUR_SPK),
0318 },
0319 {
0320 .callback = sof_sdw_quirk_cb,
0321 .matches = {
0322 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0323 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
0324 },
0325
0326 .driver_data = (void *)SOF_SDW_TGL_HDMI,
0327 },
0328 {
0329 .callback = sof_sdw_quirk_cb,
0330 .matches = {
0331 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0332 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
0333 },
0334 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0335 RT711_JD2 |
0336 SOF_SDW_FOUR_SPK),
0337 },
0338 {
0339 .callback = sof_sdw_quirk_cb,
0340 .matches = {
0341 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
0342 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
0343 },
0344 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
0345 RT711_JD2),
0346 },
0347
0348 {
0349 .callback = sof_sdw_quirk_cb,
0350 .matches = {
0351 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
0352 },
0353 .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
0354 },
0355 {}
0356 };
0357
0358 static struct snd_soc_dai_link_component dmic_component[] = {
0359 {
0360 .name = "dmic-codec",
0361 .dai_name = "dmic-hifi",
0362 }
0363 };
0364
0365 static struct snd_soc_dai_link_component platform_component[] = {
0366 {
0367
0368 .name = "0000:00:1f.3"
0369 }
0370 };
0371
0372
0373 int sdw_startup(struct snd_pcm_substream *substream)
0374 {
0375 return sdw_startup_stream(substream);
0376 }
0377
0378 int sdw_prepare(struct snd_pcm_substream *substream)
0379 {
0380 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0381 struct sdw_stream_runtime *sdw_stream;
0382 struct snd_soc_dai *dai;
0383
0384
0385 dai = asoc_rtd_to_cpu(rtd, 0);
0386
0387 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
0388
0389 if (IS_ERR(sdw_stream)) {
0390 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
0391 return PTR_ERR(sdw_stream);
0392 }
0393
0394 return sdw_prepare_stream(sdw_stream);
0395 }
0396
0397 int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
0398 {
0399 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0400 struct sdw_stream_runtime *sdw_stream;
0401 struct snd_soc_dai *dai;
0402 int ret;
0403
0404
0405 dai = asoc_rtd_to_cpu(rtd, 0);
0406
0407 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
0408
0409 if (IS_ERR(sdw_stream)) {
0410 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
0411 return PTR_ERR(sdw_stream);
0412 }
0413
0414 switch (cmd) {
0415 case SNDRV_PCM_TRIGGER_START:
0416 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0417 case SNDRV_PCM_TRIGGER_RESUME:
0418 ret = sdw_enable_stream(sdw_stream);
0419 break;
0420
0421 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0422 case SNDRV_PCM_TRIGGER_SUSPEND:
0423 case SNDRV_PCM_TRIGGER_STOP:
0424 ret = sdw_disable_stream(sdw_stream);
0425 break;
0426 default:
0427 ret = -EINVAL;
0428 break;
0429 }
0430
0431 if (ret)
0432 dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
0433
0434 return ret;
0435 }
0436
0437 int sdw_hw_free(struct snd_pcm_substream *substream)
0438 {
0439 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0440 struct sdw_stream_runtime *sdw_stream;
0441 struct snd_soc_dai *dai;
0442
0443
0444 dai = asoc_rtd_to_cpu(rtd, 0);
0445
0446 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
0447
0448 if (IS_ERR(sdw_stream)) {
0449 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
0450 return PTR_ERR(sdw_stream);
0451 }
0452
0453 return sdw_deprepare_stream(sdw_stream);
0454 }
0455
0456 void sdw_shutdown(struct snd_pcm_substream *substream)
0457 {
0458 sdw_shutdown_stream(substream);
0459 }
0460
0461 static const struct snd_soc_ops sdw_ops = {
0462 .startup = sdw_startup,
0463 .prepare = sdw_prepare,
0464 .trigger = sdw_trigger,
0465 .hw_free = sdw_hw_free,
0466 .shutdown = sdw_shutdown,
0467 };
0468
0469 static struct sof_sdw_codec_info codec_info_list[] = {
0470 {
0471 .part_id = 0x700,
0472 .direction = {true, true},
0473 .dai_name = "rt700-aif1",
0474 .init = sof_sdw_rt700_init,
0475 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0476 },
0477 {
0478 .part_id = 0x711,
0479 .version_id = 3,
0480 .direction = {true, true},
0481 .dai_name = "rt711-sdca-aif1",
0482 .init = sof_sdw_rt711_sdca_init,
0483 .exit = sof_sdw_rt711_sdca_exit,
0484 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0485 },
0486 {
0487 .part_id = 0x711,
0488 .version_id = 2,
0489 .direction = {true, true},
0490 .dai_name = "rt711-aif1",
0491 .init = sof_sdw_rt711_init,
0492 .exit = sof_sdw_rt711_exit,
0493 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0494 },
0495 {
0496 .part_id = 0x1308,
0497 .acpi_id = "10EC1308",
0498 .direction = {true, false},
0499 .dai_name = "rt1308-aif",
0500 .ops = &sof_sdw_rt1308_i2s_ops,
0501 .init = sof_sdw_rt1308_init,
0502 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
0503 },
0504 {
0505 .part_id = 0x1316,
0506 .direction = {true, true},
0507 .dai_name = "rt1316-aif",
0508 .init = sof_sdw_rt1316_init,
0509 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
0510 },
0511 {
0512 .part_id = 0x714,
0513 .version_id = 3,
0514 .direction = {false, true},
0515 .ignore_pch_dmic = true,
0516 .dai_name = "rt715-aif2",
0517 .init = sof_sdw_rt715_sdca_init,
0518 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
0519 },
0520 {
0521 .part_id = 0x715,
0522 .version_id = 3,
0523 .direction = {false, true},
0524 .ignore_pch_dmic = true,
0525 .dai_name = "rt715-aif2",
0526 .init = sof_sdw_rt715_sdca_init,
0527 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
0528 },
0529 {
0530 .part_id = 0x714,
0531 .version_id = 2,
0532 .direction = {false, true},
0533 .ignore_pch_dmic = true,
0534 .dai_name = "rt715-aif2",
0535 .init = sof_sdw_rt715_init,
0536 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
0537 },
0538 {
0539 .part_id = 0x715,
0540 .version_id = 2,
0541 .direction = {false, true},
0542 .ignore_pch_dmic = true,
0543 .dai_name = "rt715-aif2",
0544 .init = sof_sdw_rt715_init,
0545 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
0546 },
0547 {
0548 .part_id = 0x8373,
0549 .direction = {true, true},
0550 .dai_name = "max98373-aif1",
0551 .init = sof_sdw_mx8373_init,
0552 .codec_card_late_probe = sof_sdw_mx8373_late_probe,
0553 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
0554 },
0555 {
0556 .part_id = 0x5682,
0557 .direction = {true, true},
0558 .dai_name = "rt5682-sdw",
0559 .init = sof_sdw_rt5682_init,
0560 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0561 },
0562 {
0563 .part_id = 0xaaaa,
0564 .version_id = 0,
0565 .direction = {true, true},
0566 .dai_name = "sdw-mockup-aif1",
0567 .init = NULL,
0568 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0569 },
0570 {
0571 .part_id = 0xaa55,
0572 .version_id = 0,
0573 .direction = {true, true},
0574 .dai_name = "sdw-mockup-aif1",
0575 .init = NULL,
0576 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0577 },
0578 {
0579 .part_id = 0x55aa,
0580 .version_id = 0,
0581 .direction = {true, false},
0582 .dai_name = "sdw-mockup-aif1",
0583 .init = NULL,
0584 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
0585 },
0586 {
0587 .part_id = 0x5555,
0588 .version_id = 0,
0589 .direction = {false, true},
0590 .dai_name = "sdw-mockup-aif1",
0591 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
0592 },
0593 };
0594
0595 static inline int find_codec_info_part(u64 adr)
0596 {
0597 unsigned int part_id, sdw_version;
0598 int i;
0599
0600 part_id = SDW_PART_ID(adr);
0601 sdw_version = SDW_VERSION(adr);
0602 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
0603
0604
0605
0606
0607 if (part_id == codec_info_list[i].part_id &&
0608 (!codec_info_list[i].version_id ||
0609 sdw_version == codec_info_list[i].version_id))
0610 return i;
0611
0612 return -EINVAL;
0613
0614 }
0615
0616 static inline int find_codec_info_acpi(const u8 *acpi_id)
0617 {
0618 int i;
0619
0620 if (!acpi_id[0])
0621 return -EINVAL;
0622
0623 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
0624 if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
0625 ACPI_ID_LEN))
0626 break;
0627
0628 if (i == ARRAY_SIZE(codec_info_list))
0629 return -EINVAL;
0630
0631 return i;
0632 }
0633
0634
0635
0636
0637
0638
0639 static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
0640 int *sdw_be_num, int *sdw_cpu_dai_num)
0641 {
0642 const struct snd_soc_acpi_link_adr *link;
0643 int _codec_type = SOF_SDW_CODEC_TYPE_JACK;
0644 bool group_visited[SDW_MAX_GROUPS];
0645 bool no_aggregation;
0646 int i;
0647
0648 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
0649 *sdw_cpu_dai_num = 0;
0650 *sdw_be_num = 0;
0651
0652 if (!links)
0653 return -EINVAL;
0654
0655 for (i = 0; i < SDW_MAX_GROUPS; i++)
0656 group_visited[i] = false;
0657
0658 for (link = links; link->num_adr; link++) {
0659 const struct snd_soc_acpi_endpoint *endpoint;
0660 int codec_index;
0661 int stream;
0662 u64 adr;
0663
0664 adr = link->adr_d->adr;
0665 codec_index = find_codec_info_part(adr);
0666 if (codec_index < 0)
0667 return codec_index;
0668
0669 if (codec_info_list[codec_index].codec_type < _codec_type)
0670 dev_warn(dev,
0671 "Unexpected address table ordering. Expected order: jack -> amp -> mic\n");
0672
0673 _codec_type = codec_info_list[codec_index].codec_type;
0674
0675 endpoint = link->adr_d->endpoints;
0676
0677
0678 for_each_pcm_streams(stream) {
0679 if (!codec_info_list[codec_index].direction[stream])
0680 continue;
0681
0682 (*sdw_cpu_dai_num)++;
0683
0684
0685 if (!endpoint->aggregated || no_aggregation ||
0686 !group_visited[endpoint->group_id])
0687 (*sdw_be_num)++;
0688 }
0689
0690 if (endpoint->aggregated)
0691 group_visited[endpoint->group_id] = true;
0692 }
0693
0694 return 0;
0695 }
0696
0697 static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
0698 int be_id, char *name, int playback, int capture,
0699 struct snd_soc_dai_link_component *cpus, int cpus_num,
0700 struct snd_soc_dai_link_component *codecs, int codecs_num,
0701 int (*init)(struct snd_soc_pcm_runtime *rtd),
0702 const struct snd_soc_ops *ops)
0703 {
0704 dev_dbg(dev, "create dai link %s, id %d\n", name, be_id);
0705 dai_links->id = be_id;
0706 dai_links->name = name;
0707 dai_links->platforms = platform_component;
0708 dai_links->num_platforms = ARRAY_SIZE(platform_component);
0709 dai_links->no_pcm = 1;
0710 dai_links->cpus = cpus;
0711 dai_links->num_cpus = cpus_num;
0712 dai_links->codecs = codecs;
0713 dai_links->num_codecs = codecs_num;
0714 dai_links->dpcm_playback = playback;
0715 dai_links->dpcm_capture = capture;
0716 dai_links->init = init;
0717 dai_links->ops = ops;
0718 }
0719
0720 static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
0721 unsigned int sdw_version,
0722 unsigned int mfg_id,
0723 unsigned int part_id,
0724 unsigned int class_id,
0725 int index_in_link
0726 )
0727 {
0728 int i;
0729
0730 for (i = 0; i < link->num_adr; i++) {
0731 unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
0732 u64 adr;
0733
0734
0735 if (i == index_in_link)
0736 continue;
0737
0738 adr = link->adr_d[i].adr;
0739
0740 sdw1_version = SDW_VERSION(adr);
0741 mfg1_id = SDW_MFG_ID(adr);
0742 part1_id = SDW_PART_ID(adr);
0743 class1_id = SDW_CLASS_ID(adr);
0744
0745 if (sdw_version == sdw1_version &&
0746 mfg_id == mfg1_id &&
0747 part_id == part1_id &&
0748 class_id == class1_id)
0749 return false;
0750 }
0751
0752 return true;
0753 }
0754
0755 static int create_codec_dai_name(struct device *dev,
0756 const struct snd_soc_acpi_link_adr *link,
0757 struct snd_soc_dai_link_component *codec,
0758 int offset,
0759 struct snd_soc_codec_conf *codec_conf,
0760 int codec_count,
0761 int *codec_conf_index)
0762 {
0763 int i;
0764
0765
0766 if (*codec_conf_index + link->num_adr > codec_count) {
0767 dev_err(dev, "codec_conf: out-of-bounds access requested\n");
0768 return -EINVAL;
0769 }
0770
0771 for (i = 0; i < link->num_adr; i++) {
0772 unsigned int sdw_version, unique_id, mfg_id;
0773 unsigned int link_id, part_id, class_id;
0774 int codec_index, comp_index;
0775 char *codec_str;
0776 u64 adr;
0777
0778 adr = link->adr_d[i].adr;
0779
0780 sdw_version = SDW_VERSION(adr);
0781 link_id = SDW_DISCO_LINK_ID(adr);
0782 unique_id = SDW_UNIQUE_ID(adr);
0783 mfg_id = SDW_MFG_ID(adr);
0784 part_id = SDW_PART_ID(adr);
0785 class_id = SDW_CLASS_ID(adr);
0786
0787 comp_index = i + offset;
0788 if (is_unique_device(link, sdw_version, mfg_id, part_id,
0789 class_id, i)) {
0790 codec_str = "sdw:%01x:%04x:%04x:%02x";
0791 codec[comp_index].name =
0792 devm_kasprintf(dev, GFP_KERNEL, codec_str,
0793 link_id, mfg_id, part_id,
0794 class_id);
0795 } else {
0796 codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
0797 codec[comp_index].name =
0798 devm_kasprintf(dev, GFP_KERNEL, codec_str,
0799 link_id, mfg_id, part_id,
0800 class_id, unique_id);
0801 }
0802
0803 if (!codec[comp_index].name)
0804 return -ENOMEM;
0805
0806 codec_index = find_codec_info_part(adr);
0807 if (codec_index < 0)
0808 return codec_index;
0809
0810 codec[comp_index].dai_name =
0811 codec_info_list[codec_index].dai_name;
0812
0813 codec_conf[*codec_conf_index].dlc = codec[comp_index];
0814 codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
0815
0816 ++*codec_conf_index;
0817 }
0818
0819 return 0;
0820 }
0821
0822 static int set_codec_init_func(struct snd_soc_card *card,
0823 const struct snd_soc_acpi_link_adr *link,
0824 struct snd_soc_dai_link *dai_links,
0825 bool playback, int group_id)
0826 {
0827 int i;
0828
0829 do {
0830
0831
0832
0833
0834
0835 for (i = 0; i < link->num_adr; i++) {
0836 int codec_index;
0837
0838 codec_index = find_codec_info_part(link->adr_d[i].adr);
0839
0840 if (codec_index < 0)
0841 return codec_index;
0842
0843 if (link->adr_d[i].endpoints->group_id != group_id)
0844 continue;
0845 if (codec_info_list[codec_index].init)
0846 codec_info_list[codec_index].init(card,
0847 link,
0848 dai_links,
0849 &codec_info_list[codec_index],
0850 playback);
0851 }
0852 link++;
0853 } while (link->mask && group_id);
0854
0855 return 0;
0856 }
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872 static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
0873 struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
0874 int *codec_num, unsigned int *group_id,
0875 bool *group_generated)
0876 {
0877 const struct snd_soc_acpi_adr_device *adr_d;
0878 const struct snd_soc_acpi_link_adr *adr_next;
0879 bool no_aggregation;
0880 int index = 0;
0881
0882 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
0883 *codec_num = adr_link->num_adr;
0884 adr_d = adr_link->adr_d;
0885
0886
0887 if (!is_power_of_2(adr_link->mask))
0888 return -EINVAL;
0889
0890 cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
0891 if (!adr_d->endpoints->aggregated || no_aggregation) {
0892 *cpu_dai_num = 1;
0893 *group_id = 0;
0894 return 0;
0895 }
0896
0897 *group_id = adr_d->endpoints->group_id;
0898
0899
0900 for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
0901 adr_next++) {
0902 const struct snd_soc_acpi_endpoint *endpoint;
0903
0904 endpoint = adr_next->adr_d->endpoints;
0905 if (!endpoint->aggregated ||
0906 endpoint->group_id != *group_id)
0907 continue;
0908
0909
0910 if (!is_power_of_2(adr_next->mask))
0911 return -EINVAL;
0912
0913 if (index >= SDW_MAX_CPU_DAIS) {
0914 dev_err(dev, " cpu_dai_id array overflows");
0915 return -EINVAL;
0916 }
0917
0918 cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
0919 *codec_num += adr_next->num_adr;
0920 }
0921
0922
0923
0924
0925
0926 group_generated[*group_id] = true;
0927 *cpu_dai_num = index;
0928
0929 return 0;
0930 }
0931
0932 static int create_sdw_dailink(struct snd_soc_card *card,
0933 struct device *dev, int *link_index,
0934 struct snd_soc_dai_link *dai_links,
0935 int sdw_be_num, int sdw_cpu_dai_num,
0936 struct snd_soc_dai_link_component *cpus,
0937 const struct snd_soc_acpi_link_adr *link,
0938 int *cpu_id, bool *group_generated,
0939 struct snd_soc_codec_conf *codec_conf,
0940 int codec_count, int *link_id,
0941 int *codec_conf_index,
0942 bool *ignore_pch_dmic)
0943 {
0944 const struct snd_soc_acpi_link_adr *link_next;
0945 struct snd_soc_dai_link_component *codecs;
0946 int cpu_dai_id[SDW_MAX_CPU_DAIS];
0947 int cpu_dai_num, cpu_dai_index;
0948 unsigned int group_id;
0949 int codec_idx = 0;
0950 int i = 0, j = 0;
0951 int codec_index;
0952 int codec_num;
0953 int stream;
0954 int ret;
0955 int k;
0956
0957 ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
0958 &group_id, group_generated);
0959 if (ret)
0960 return ret;
0961
0962 codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
0963 if (!codecs)
0964 return -ENOMEM;
0965
0966
0967 for (link_next = link; link_next && link_next->num_adr &&
0968 i < cpu_dai_num; link_next++) {
0969 const struct snd_soc_acpi_endpoint *endpoints;
0970
0971 endpoints = link_next->adr_d->endpoints;
0972 if (group_id && (!endpoints->aggregated ||
0973 endpoints->group_id != group_id))
0974 continue;
0975
0976
0977 if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
0978 continue;
0979
0980 ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
0981 codec_conf, codec_count, codec_conf_index);
0982 if (ret < 0)
0983 return ret;
0984
0985
0986 i++;
0987 codec_idx += link_next->num_adr;
0988 }
0989
0990
0991 codec_index = find_codec_info_part(link->adr_d[0].adr);
0992 if (codec_index < 0)
0993 return codec_index;
0994
0995 if (codec_info_list[codec_index].ignore_pch_dmic)
0996 *ignore_pch_dmic = true;
0997
0998
0999 if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_AMP &&
1000 *link_id < SDW_AMP_DAI_ID)
1001 *link_id = SDW_AMP_DAI_ID;
1002
1003
1004
1005
1006
1007 if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_MIC &&
1008 *link_id < SDW_DMIC_DAI_ID)
1009 *link_id = SDW_DMIC_DAI_ID;
1010
1011 cpu_dai_index = *cpu_id;
1012 for_each_pcm_streams(stream) {
1013 char *name, *cpu_name;
1014 int playback, capture;
1015 static const char * const sdw_stream_name[] = {
1016 "SDW%d-Playback",
1017 "SDW%d-Capture",
1018 };
1019
1020 if (!codec_info_list[codec_index].direction[stream])
1021 continue;
1022
1023
1024 name = devm_kasprintf(dev, GFP_KERNEL,
1025 sdw_stream_name[stream], cpu_dai_id[0]);
1026 if (!name)
1027 return -ENOMEM;
1028
1029
1030
1031
1032
1033 for (k = 0; k < cpu_dai_num; k++) {
1034 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1035 "SDW%d Pin%d", cpu_dai_id[k],
1036 j + SDW_INTEL_BIDIR_PDI_BASE);
1037 if (!cpu_name)
1038 return -ENOMEM;
1039
1040 if (cpu_dai_index >= sdw_cpu_dai_num) {
1041 dev_err(dev, "invalid cpu dai index %d",
1042 cpu_dai_index);
1043 return -EINVAL;
1044 }
1045
1046 cpus[cpu_dai_index++].dai_name = cpu_name;
1047 }
1048
1049
1050
1051
1052
1053 if (*link_index >= sdw_be_num) {
1054 dev_err(dev, "invalid dai link index %d", *link_index);
1055 return -EINVAL;
1056 }
1057
1058 if (*cpu_id >= sdw_cpu_dai_num) {
1059 dev_err(dev, " invalid cpu dai index %d", *cpu_id);
1060 return -EINVAL;
1061 }
1062
1063 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
1064 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
1065 init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
1066 playback, capture,
1067 cpus + *cpu_id, cpu_dai_num,
1068 codecs, codec_num,
1069 NULL, &sdw_ops);
1070
1071
1072
1073
1074
1075 dai_links[*link_index].nonatomic = true;
1076
1077 ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
1078 playback, group_id);
1079 if (ret < 0) {
1080 dev_err(dev, "failed to init codec %d", codec_index);
1081 return ret;
1082 }
1083
1084 *cpu_id += cpu_dai_num;
1085 j++;
1086 }
1087
1088 return 0;
1089 }
1090
1091 #define IDISP_CODEC_MASK 0x4
1092
1093 static int sof_card_codec_conf_alloc(struct device *dev,
1094 struct snd_soc_acpi_mach_params *mach_params,
1095 struct snd_soc_codec_conf **codec_conf,
1096 int *codec_conf_count)
1097 {
1098 const struct snd_soc_acpi_link_adr *adr_link;
1099 struct snd_soc_codec_conf *c_conf;
1100 int num_codecs = 0;
1101 int i;
1102
1103 adr_link = mach_params->links;
1104 if (!adr_link)
1105 return -EINVAL;
1106
1107
1108 for (; adr_link->num_adr; adr_link++) {
1109 for (i = 0; i < adr_link->num_adr; i++) {
1110 if (!adr_link->adr_d[i].name_prefix) {
1111 dev_err(dev, "codec 0x%llx does not have a name prefix\n",
1112 adr_link->adr_d[i].adr);
1113 return -EINVAL;
1114 }
1115 }
1116 num_codecs += adr_link->num_adr;
1117 }
1118
1119 c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
1120 if (!c_conf)
1121 return -ENOMEM;
1122
1123 *codec_conf = c_conf;
1124 *codec_conf_count = num_codecs;
1125
1126 return 0;
1127 }
1128
1129 static int sof_card_dai_links_create(struct device *dev,
1130 struct snd_soc_acpi_mach *mach,
1131 struct snd_soc_card *card)
1132 {
1133 int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
1134 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1135 struct snd_soc_dai_link_component *idisp_components;
1136 struct snd_soc_dai_link_component *ssp_components;
1137 struct snd_soc_acpi_mach_params *mach_params;
1138 const struct snd_soc_acpi_link_adr *adr_link;
1139 struct snd_soc_dai_link_component *cpus;
1140 struct snd_soc_codec_conf *codec_conf;
1141 bool ignore_pch_dmic = false;
1142 int codec_conf_count;
1143 int codec_conf_index = 0;
1144 bool group_generated[SDW_MAX_GROUPS];
1145 int ssp_codec_index, ssp_mask;
1146 struct snd_soc_dai_link *links;
1147 int num_links, link_index = 0;
1148 char *name, *cpu_name;
1149 int total_cpu_dai_num;
1150 int sdw_cpu_dai_num;
1151 int i, j, be_id = 0;
1152 int cpu_id = 0;
1153 int comp_num;
1154 int ret;
1155
1156 mach_params = &mach->mach_params;
1157
1158
1159 ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
1160 if (ret < 0)
1161 return ret;
1162
1163
1164 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1165 codec_info_list[i].amp_num = 0;
1166
1167 if (mach_params->codec_mask & IDISP_CODEC_MASK) {
1168 ctx->idisp_codec = true;
1169
1170 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1171 hdmi_num = SOF_TGL_HDMI_COUNT;
1172 else
1173 hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1174 }
1175
1176 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1177
1178
1179
1180
1181
1182
1183 ssp_codec_index = find_codec_info_acpi(mach->id);
1184 ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
1185 comp_num = hdmi_num + ssp_num;
1186
1187 ret = get_sdw_dailink_info(dev, mach_params->links,
1188 &sdw_be_num, &sdw_cpu_dai_num);
1189 if (ret < 0) {
1190 dev_err(dev, "failed to get sdw link info %d", ret);
1191 return ret;
1192 }
1193
1194
1195 dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
1196 comp_num += dmic_num;
1197
1198 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1199 comp_num++;
1200
1201 dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
1202 dmic_num, ctx->idisp_codec ? hdmi_num : 0);
1203
1204
1205 num_links = comp_num + sdw_be_num;
1206 links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
1207
1208
1209 total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
1210 cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
1211 GFP_KERNEL);
1212
1213 if (!links || !cpus)
1214 return -ENOMEM;
1215
1216
1217 if (!sdw_be_num)
1218 goto SSP;
1219
1220 adr_link = mach_params->links;
1221 if (!adr_link)
1222 return -EINVAL;
1223
1224
1225
1226
1227
1228
1229 for (i = 0; i < SDW_MAX_GROUPS; i++)
1230 group_generated[i] = false;
1231
1232
1233 for (; adr_link->num_adr; adr_link++) {
1234 const struct snd_soc_acpi_endpoint *endpoint;
1235
1236 endpoint = adr_link->adr_d->endpoints;
1237 if (endpoint->aggregated && !endpoint->group_id) {
1238 dev_err(dev, "invalid group id on link %x",
1239 adr_link->mask);
1240 continue;
1241 }
1242
1243
1244 if (endpoint->aggregated &&
1245 group_generated[endpoint->group_id])
1246 continue;
1247
1248 ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
1249 sdw_cpu_dai_num, cpus, adr_link,
1250 &cpu_id, group_generated,
1251 codec_conf, codec_conf_count,
1252 &be_id, &codec_conf_index,
1253 &ignore_pch_dmic);
1254 if (ret < 0) {
1255 dev_err(dev, "failed to create dai link %d", link_index);
1256 return ret;
1257 }
1258 }
1259
1260 SSP:
1261
1262 if (!ssp_num)
1263 goto DMIC;
1264
1265 for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
1266 struct sof_sdw_codec_info *info;
1267 int playback, capture;
1268 char *codec_name;
1269
1270 if (!(ssp_mask & 0x1))
1271 continue;
1272
1273 name = devm_kasprintf(dev, GFP_KERNEL,
1274 "SSP%d-Codec", i);
1275 if (!name)
1276 return -ENOMEM;
1277
1278 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1279 if (!cpu_name)
1280 return -ENOMEM;
1281
1282 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1283 GFP_KERNEL);
1284 if (!ssp_components)
1285 return -ENOMEM;
1286
1287 info = &codec_info_list[ssp_codec_index];
1288 codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1289 info->acpi_id, j++);
1290 if (!codec_name)
1291 return -ENOMEM;
1292
1293 ssp_components->name = codec_name;
1294 ssp_components->dai_name = info->dai_name;
1295 cpus[cpu_id].dai_name = cpu_name;
1296
1297 playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
1298 capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
1299 init_dai_link(dev, links + link_index, be_id, name,
1300 playback, capture,
1301 cpus + cpu_id, 1,
1302 ssp_components, 1,
1303 NULL, info->ops);
1304
1305 ret = info->init(card, NULL, links + link_index, info, 0);
1306 if (ret < 0)
1307 return ret;
1308
1309 INC_ID(be_id, cpu_id, link_index);
1310 }
1311
1312 DMIC:
1313
1314 if (dmic_num > 0) {
1315 if (ignore_pch_dmic) {
1316 dev_warn(dev, "Ignoring PCH DMIC\n");
1317 goto HDMI;
1318 }
1319 cpus[cpu_id].dai_name = "DMIC01 Pin";
1320 init_dai_link(dev, links + link_index, be_id, "dmic01",
1321 0, 1,
1322 cpus + cpu_id, 1,
1323 dmic_component, 1,
1324 sof_sdw_dmic_init, NULL);
1325 INC_ID(be_id, cpu_id, link_index);
1326
1327 cpus[cpu_id].dai_name = "DMIC16k Pin";
1328 init_dai_link(dev, links + link_index, be_id, "dmic16k",
1329 0, 1,
1330 cpus + cpu_id, 1,
1331 dmic_component, 1,
1332
1333 NULL, NULL);
1334 INC_ID(be_id, cpu_id, link_index);
1335 }
1336
1337 HDMI:
1338
1339 if (hdmi_num > 0) {
1340 idisp_components = devm_kcalloc(dev, hdmi_num,
1341 sizeof(*idisp_components),
1342 GFP_KERNEL);
1343 if (!idisp_components)
1344 return -ENOMEM;
1345 }
1346
1347 for (i = 0; i < hdmi_num; i++) {
1348 name = devm_kasprintf(dev, GFP_KERNEL,
1349 "iDisp%d", i + 1);
1350 if (!name)
1351 return -ENOMEM;
1352
1353 if (ctx->idisp_codec) {
1354 idisp_components[i].name = "ehdaudio0D2";
1355 idisp_components[i].dai_name = devm_kasprintf(dev,
1356 GFP_KERNEL,
1357 "intel-hdmi-hifi%d",
1358 i + 1);
1359 if (!idisp_components[i].dai_name)
1360 return -ENOMEM;
1361 } else {
1362 idisp_components[i].name = "snd-soc-dummy";
1363 idisp_components[i].dai_name = "snd-soc-dummy-dai";
1364 }
1365
1366 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1367 "iDisp%d Pin", i + 1);
1368 if (!cpu_name)
1369 return -ENOMEM;
1370
1371 cpus[cpu_id].dai_name = cpu_name;
1372 init_dai_link(dev, links + link_index, be_id, name,
1373 1, 0,
1374 cpus + cpu_id, 1,
1375 idisp_components + i, 1,
1376 sof_sdw_hdmi_init, NULL);
1377 INC_ID(be_id, cpu_id, link_index);
1378 }
1379
1380 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1381 int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1382 SOF_BT_OFFLOAD_SSP_SHIFT;
1383
1384 name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1385 if (!name)
1386 return -ENOMEM;
1387
1388 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1389 GFP_KERNEL);
1390 if (!ssp_components)
1391 return -ENOMEM;
1392
1393 ssp_components->name = "snd-soc-dummy";
1394 ssp_components->dai_name = "snd-soc-dummy-dai";
1395
1396 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1397 if (!cpu_name)
1398 return -ENOMEM;
1399
1400 cpus[cpu_id].dai_name = cpu_name;
1401 init_dai_link(dev, links + link_index, be_id, name, 1, 1,
1402 cpus + cpu_id, 1, ssp_components, 1, NULL, NULL);
1403 }
1404
1405 card->dai_link = links;
1406 card->num_links = num_links;
1407
1408 card->codec_conf = codec_conf;
1409 card->num_configs = codec_conf_count;
1410
1411 return 0;
1412 }
1413
1414 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1415 {
1416 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1417 int ret = 0;
1418 int i;
1419
1420 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1421 if (!codec_info_list[i].late_probe)
1422 continue;
1423
1424 ret = codec_info_list[i].codec_card_late_probe(card);
1425 if (ret < 0)
1426 return ret;
1427 }
1428
1429 if (ctx->idisp_codec)
1430 ret = sof_sdw_hdmi_card_late_probe(card);
1431
1432 return ret;
1433 }
1434
1435
1436 static const char sdw_card_long_name[] = "Intel Soundwire SOF";
1437
1438 static struct snd_soc_card card_sof_sdw = {
1439 .name = "soundwire",
1440 .owner = THIS_MODULE,
1441 .late_probe = sof_sdw_card_late_probe,
1442 };
1443
1444 static void mc_dailink_exit_loop(struct snd_soc_card *card)
1445 {
1446 struct snd_soc_dai_link *link;
1447 int ret;
1448 int i, j;
1449
1450 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1451 if (!codec_info_list[i].exit)
1452 continue;
1453
1454
1455
1456
1457 for_each_card_prelinks(card, j, link) {
1458 if (!strcmp(link->codecs[0].dai_name,
1459 codec_info_list[i].dai_name)) {
1460 ret = codec_info_list[i].exit(card, link);
1461 if (ret)
1462 dev_warn(card->dev,
1463 "codec exit failed %d\n",
1464 ret);
1465 break;
1466 }
1467 }
1468 }
1469 }
1470
1471 static int mc_probe(struct platform_device *pdev)
1472 {
1473 struct snd_soc_card *card = &card_sof_sdw;
1474 struct snd_soc_acpi_mach *mach;
1475 struct mc_private *ctx;
1476 int amp_num = 0, i;
1477 int ret;
1478
1479 dev_dbg(&pdev->dev, "Entry\n");
1480
1481 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1482 if (!ctx)
1483 return -ENOMEM;
1484
1485 dmi_check_system(sof_sdw_quirk_table);
1486
1487 if (quirk_override != -1) {
1488 dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
1489 sof_sdw_quirk, quirk_override);
1490 sof_sdw_quirk = quirk_override;
1491 }
1492 log_quirks(&pdev->dev);
1493
1494 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
1495
1496 card->dev = &pdev->dev;
1497 snd_soc_card_set_drvdata(card, ctx);
1498
1499 mach = pdev->dev.platform_data;
1500 ret = sof_card_dai_links_create(&pdev->dev, mach,
1501 card);
1502 if (ret < 0)
1503 return ret;
1504
1505
1506
1507
1508
1509
1510 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1511 amp_num += codec_info_list[i].amp_num;
1512
1513 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1514 "cfg-spk:%d cfg-amp:%d",
1515 (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
1516 ? 4 : 2, amp_num);
1517 if (!card->components)
1518 return -ENOMEM;
1519
1520 if (mach->mach_params.dmic_num) {
1521 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1522 "%s mic:dmic cfg-mics:%d",
1523 card->components,
1524 mach->mach_params.dmic_num);
1525 if (!card->components)
1526 return -ENOMEM;
1527 }
1528
1529 card->long_name = sdw_card_long_name;
1530
1531
1532 ret = devm_snd_soc_register_card(&pdev->dev, card);
1533 if (ret) {
1534 dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
1535 mc_dailink_exit_loop(card);
1536 return ret;
1537 }
1538
1539 platform_set_drvdata(pdev, card);
1540
1541 return ret;
1542 }
1543
1544 static int mc_remove(struct platform_device *pdev)
1545 {
1546 struct snd_soc_card *card = platform_get_drvdata(pdev);
1547
1548 mc_dailink_exit_loop(card);
1549
1550 return 0;
1551 }
1552
1553 static struct platform_driver sof_sdw_driver = {
1554 .driver = {
1555 .name = "sof_sdw",
1556 .pm = &snd_soc_pm_ops,
1557 },
1558 .probe = mc_probe,
1559 .remove = mc_remove,
1560 };
1561
1562 module_platform_driver(sof_sdw_driver);
1563
1564 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1565 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1566 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1567 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1568 MODULE_LICENSE("GPL v2");
1569 MODULE_ALIAS("platform:sof_sdw");
1570 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
1571 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);