Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
   1// SPDX-License-Identifier: GPL-2.0-only
   2// Copyright (c) 2020 Intel Corporation
   3
   4/*
   5 *  sof_sdw - ASOC Machine driver for Intel SoundWire platforms
   6 */
   7
   8#include <linux/acpi.h>
   9#include <linux/bitmap.h>
  10#include <linux/device.h>
  11#include <linux/dmi.h>
  12#include <linux/module.h>
  13#include <linux/soundwire/sdw.h>
  14#include <linux/soundwire/sdw_type.h>
  15#include <linux/soundwire/sdw_intel.h>
  16#include <sound/soc-acpi.h>
  17#include "sof_sdw_common.h"
  18#include "../../codecs/rt711.h"
  19
  20static unsigned long sof_sdw_quirk = RT711_JD1;
  21static int quirk_override = -1;
  22module_param_named(quirk, quirk_override, int, 0444);
  23MODULE_PARM_DESC(quirk, "Board-specific quirk override");
  24
  25#define DMIC_DEFAULT_CHANNELS 2
  26
  27static void log_quirks(struct device *dev)
  28{
  29	if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk))
  30		dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
  31			SOC_SDW_JACK_JDSRC(sof_sdw_quirk));
  32	if (sof_sdw_quirk & SOC_SDW_FOUR_SPK)
  33		dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n");
  34	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
  35		dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
  36	if (sof_sdw_quirk & SOC_SDW_PCH_DMIC)
  37		dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n");
  38	if (SOF_SSP_GET_PORT(sof_sdw_quirk))
  39		dev_dbg(dev, "SSP port %ld\n",
  40			SOF_SSP_GET_PORT(sof_sdw_quirk));
  41	if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION)
  42		dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n");
  43	if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR)
  44		dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n");
  45	if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS)
  46		dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n");
  47}
  48
  49static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
  50{
  51	sof_sdw_quirk = (unsigned long)id->driver_data;
  52	return 1;
  53}
  54
  55static const struct dmi_system_id sof_sdw_quirk_table[] = {
  56	/* CometLake devices */
  57	{
  58		.callback = sof_sdw_quirk_cb,
  59		.matches = {
  60			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  61			DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
  62		},
  63		.driver_data = (void *)SOC_SDW_PCH_DMIC,
  64	},
  65	{
  66		.callback = sof_sdw_quirk_cb,
  67		.matches = {
  68			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  69			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
  70		},
  71		.driver_data = (void *)RT711_JD2,
  72	},
  73	{
  74		/* early version of SKU 09C6 */
  75		.callback = sof_sdw_quirk_cb,
  76		.matches = {
  77			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  78			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
  79		},
  80		.driver_data = (void *)RT711_JD2,
  81	},
  82	{
  83		.callback = sof_sdw_quirk_cb,
  84		.matches = {
  85			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  86			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
  87		},
  88		.driver_data = (void *)(RT711_JD2),
  89	},
  90	{
  91		.callback = sof_sdw_quirk_cb,
  92		.matches = {
  93			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  94			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
  95		},
  96		.driver_data = (void *)(RT711_JD2),
  97	},
  98	/* IceLake devices */
  99	{
 100		.callback = sof_sdw_quirk_cb,
 101		.matches = {
 102			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 103			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
 104		},
 105		.driver_data = (void *)SOC_SDW_PCH_DMIC,
 106	},
 107	/* TigerLake devices */
 108	{
 109		.callback = sof_sdw_quirk_cb,
 110		.matches = {
 111			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 112			DMI_MATCH(DMI_PRODUCT_NAME,
 113				  "Tiger Lake Client Platform"),
 114		},
 115		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 116					RT711_JD1 |
 117					SOC_SDW_PCH_DMIC |
 118					SOF_SSP_PORT(SOF_I2S_SSP2)),
 119	},
 120	{
 121		.callback = sof_sdw_quirk_cb,
 122		.matches = {
 123			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 124			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
 125		},
 126		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 127					RT711_JD2),
 128	},
 129	{
 130		/* another SKU of Dell Latitude 9520 */
 131		.callback = sof_sdw_quirk_cb,
 132		.matches = {
 133			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 134			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
 135		},
 136		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 137					RT711_JD2),
 138	},
 139	{
 140		/* Dell XPS 9710 */
 141		.callback = sof_sdw_quirk_cb,
 142		.matches = {
 143			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 144			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
 145		},
 146		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 147					RT711_JD2),
 148	},
 149	{
 150		.callback = sof_sdw_quirk_cb,
 151		.matches = {
 152			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 153			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
 154		},
 155		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 156					RT711_JD2),
 157	},
 158	{
 159		.callback = sof_sdw_quirk_cb,
 160		.matches = {
 161			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 162			DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
 163		},
 164		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 165					SOC_SDW_PCH_DMIC |
 166					SOF_BT_OFFLOAD_SSP(2) |
 167					SOF_SSP_BT_OFFLOAD_PRESENT),
 168	},
 169	{
 170		.callback = sof_sdw_quirk_cb,
 171		.matches = {
 172			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 173			DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
 174		},
 175		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 176					SOC_SDW_PCH_DMIC),
 177	},
 178	{
 179		/*
 180		 * this entry covers multiple HP SKUs. The family name
 181		 * does not seem robust enough, so we use a partial
 182		 * match that ignores the product name suffix
 183		 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
 184		 */
 185		.callback = sof_sdw_quirk_cb,
 186		.matches = {
 187			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 188			DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
 189		},
 190		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 191					SOC_SDW_PCH_DMIC |
 192					RT711_JD1),
 193	},
 194	{
 195		/*
 196		 * this entry covers HP Spectre x360 where the DMI information
 197		 * changed somehow
 198		 */
 199		.callback = sof_sdw_quirk_cb,
 200		.matches = {
 201			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 202			DMI_MATCH(DMI_BOARD_NAME, "8709"),
 203		},
 204		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 205					SOC_SDW_PCH_DMIC |
 206					RT711_JD1),
 207	},
 208	{
 209		/* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
 210		.callback = sof_sdw_quirk_cb,
 211		.matches = {
 212			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 213			DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
 214		},
 215		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 216					SOC_SDW_PCH_DMIC |
 217					RT711_JD1),
 218	},
 219	{
 220		/* NUC15 LAPBC710 skews */
 221		.callback = sof_sdw_quirk_cb,
 222		.matches = {
 223			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 224			DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
 225		},
 226		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 227					SOC_SDW_PCH_DMIC |
 228					RT711_JD1),
 229	},
 230	{
 231		/* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
 232		.callback = sof_sdw_quirk_cb,
 233		.matches = {
 234			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 235			DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
 236		},
 237		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 238					SOC_SDW_PCH_DMIC |
 239					RT711_JD2_100K),
 240	},
 241	{
 242		/* NUC15 LAPRC710 skews */
 243		.callback = sof_sdw_quirk_cb,
 244		.matches = {
 245			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 246			DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
 247		},
 248		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 249					SOC_SDW_PCH_DMIC |
 250					RT711_JD2_100K),
 251	},
 252	/* TigerLake-SDCA devices */
 253	{
 254		.callback = sof_sdw_quirk_cb,
 255		.matches = {
 256			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 257			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
 258		},
 259		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 260					RT711_JD2),
 261	},
 262	{
 263		.callback = sof_sdw_quirk_cb,
 264		.matches = {
 265			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 266			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
 267		},
 268		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 269					RT711_JD2),
 270	},
 271	/* AlderLake devices */
 272	{
 273		.callback = sof_sdw_quirk_cb,
 274		.matches = {
 275			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 276			DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
 277		},
 278		.driver_data = (void *)(RT711_JD2_100K |
 279					SOF_SDW_TGL_HDMI |
 280					SOF_BT_OFFLOAD_SSP(2) |
 281					SOF_SSP_BT_OFFLOAD_PRESENT),
 282	},
 283	{
 284		.callback = sof_sdw_quirk_cb,
 285		.matches = {
 286			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 287			DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"),
 288		},
 289		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 290					RT711_JD2_100K),
 291	},
 292	{
 293		.callback = sof_sdw_quirk_cb,
 294		.matches = {
 295			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 296			DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
 297		},
 298		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 299					SOC_SDW_PCH_DMIC |
 300					SOF_BT_OFFLOAD_SSP(2) |
 301					SOF_SSP_BT_OFFLOAD_PRESENT),
 302	},
 303	{
 304		.callback = sof_sdw_quirk_cb,
 305		.matches = {
 306			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 307			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
 308		},
 309		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 310					RT711_JD2),
 311	},
 312	{
 313		.callback = sof_sdw_quirk_cb,
 314		.matches = {
 315			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 316			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
 317		},
 318		/* No Jack */
 319		.driver_data = (void *)(SOF_SDW_TGL_HDMI),
 320	},
 321	{
 322		.callback = sof_sdw_quirk_cb,
 323		.matches = {
 324			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 325			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
 326		},
 327		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 328					RT711_JD2),
 329	},
 330	{
 331		.callback = sof_sdw_quirk_cb,
 332		.matches = {
 333			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 334			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
 335		},
 336		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 337					RT711_JD2),
 338	},
 339	{
 340		.callback = sof_sdw_quirk_cb,
 341		.matches = {
 342			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 343			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
 344		},
 345		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 346					RT711_JD2),
 347	},
 348	{
 349		.callback = sof_sdw_quirk_cb,
 350		.matches = {
 351			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 352			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
 353		},
 354		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 355					RT711_JD2),
 356	},
 357	{
 358		.callback = sof_sdw_quirk_cb,
 359		.matches = {
 360			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 361			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
 362		},
 363		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 364					RT711_JD2),
 365	},
 366	{
 367		.callback = sof_sdw_quirk_cb,
 368		.matches = {
 369			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 370			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
 371		},
 372		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 373					RT711_JD2),
 374	},
 375	{
 376		.callback = sof_sdw_quirk_cb,
 377		.matches = {
 378			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 379			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
 380		},
 381		/* No Jack */
 382		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 383	},
 384	{
 385		.callback = sof_sdw_quirk_cb,
 386		.matches = {
 387			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 388			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
 389		},
 390		/* No Jack */
 391		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 392	},
 393
 394	{
 395		.callback = sof_sdw_quirk_cb,
 396		.matches = {
 397			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 398			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
 399		},
 400		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 401					RT711_JD2),
 402	},
 403	{
 404		.callback = sof_sdw_quirk_cb,
 405		.matches = {
 406			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 407			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"),
 408		},
 409		/* No Jack */
 410		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 411	},
 412	{
 413		.callback = sof_sdw_quirk_cb,
 414		.matches = {
 415			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 416			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"),
 417		},
 418		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 419					RT711_JD2),
 420	},
 421	{
 422		.callback = sof_sdw_quirk_cb,
 423		.matches = {
 424			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 425			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"),
 426		},
 427		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 428					RT711_JD2),
 429	},
 430	/* RaptorLake devices */
 431	{
 432		.callback = sof_sdw_quirk_cb,
 433		.matches = {
 434			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 435			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")
 436		},
 437		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 438					RT711_JD2),
 439	},
 440	{
 441		.callback = sof_sdw_quirk_cb,
 442		.matches = {
 443			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 444			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F")
 445		},
 446		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 447					RT711_JD2),
 448	},
 449	{
 450		.callback = sof_sdw_quirk_cb,
 451		.matches = {
 452			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 453			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
 454		},
 455		/* No Jack */
 456		.driver_data = (void *)(SOF_SDW_TGL_HDMI),
 457	},
 458	{
 459		.callback = sof_sdw_quirk_cb,
 460		.matches = {
 461			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 462			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
 463		},
 464		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 465					RT711_JD2),
 466	},
 467	{
 468		.callback = sof_sdw_quirk_cb,
 469		.matches = {
 470			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 471			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
 472		},
 473		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 474					RT711_JD2),
 475	},
 476	{
 477		.callback = sof_sdw_quirk_cb,
 478		.matches = {
 479			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 480			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
 481		},
 482		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 483					RT711_JD2),
 484	},
 485	{
 486		.callback = sof_sdw_quirk_cb,
 487		.matches = {
 488			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 489			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6")
 490		},
 491		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 492	},
 493	{
 494		.callback = sof_sdw_quirk_cb,
 495		.matches = {
 496			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 497			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9")
 498		},
 499		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 500	},
 501	{
 502		.callback = sof_sdw_quirk_cb,
 503		.matches = {
 504			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 505			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA")
 506		},
 507		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 508	},
 509	/* MeteorLake devices */
 510	{
 511		.callback = sof_sdw_quirk_cb,
 512		.matches = {
 513			DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
 514		},
 515		.driver_data = (void *)(RT711_JD1),
 516	},
 517	{
 518		.callback = sof_sdw_quirk_cb,
 519		.matches = {
 520			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 521			DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"),
 522		},
 523		.driver_data = (void *)(RT711_JD2_100K),
 524	},
 525	{
 526		.callback = sof_sdw_quirk_cb,
 527		.matches = {
 528			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 529			DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
 530		},
 531		.driver_data = (void *)(SOC_SDW_PCH_DMIC |
 532					SOF_BT_OFFLOAD_SSP(1) |
 533					SOF_SSP_BT_OFFLOAD_PRESENT),
 534	},
 535	{
 536		.callback = sof_sdw_quirk_cb,
 537		.matches = {
 538			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 539			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"),
 540		},
 541		.driver_data = (void *)(RT711_JD2),
 542	},
 543
 544	/* LunarLake devices */
 545	{
 546		.callback = sof_sdw_quirk_cb,
 547		.matches = {
 548			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 549			DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
 550		},
 551		.driver_data = (void *)(RT711_JD2),
 552	},
 553	{
 554		.callback = sof_sdw_quirk_cb,
 555		.matches = {
 556			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 557			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3")
 558		},
 559		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
 560	},
 561	{
 562		.callback = sof_sdw_quirk_cb,
 563		.matches = {
 564			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 565			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4")
 566		},
 567		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
 568	},
 569	{
 570		.callback = sof_sdw_quirk_cb,
 571		.matches = {
 572			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 573			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB")
 574		},
 575		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 576	},
 577	{
 578		.callback = sof_sdw_quirk_cb,
 579		.matches = {
 580			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 581			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC")
 582		},
 583		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 584	},
 585	{
 586		.callback = sof_sdw_quirk_cb,
 587		.matches = {
 588			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 589			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD")
 590		},
 591		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 592	},
 593	{
 594		.callback = sof_sdw_quirk_cb,
 595		.matches = {
 596			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 597			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36")
 598		},
 599		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 600	},
 601	{
 602		.callback = sof_sdw_quirk_cb,
 603		.matches = {
 604			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 605			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8")
 606		},
 607		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 608	},
 609	{
 610		.callback = sof_sdw_quirk_cb,
 611		.matches = {
 612			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 613			DMI_MATCH(DMI_PRODUCT_NAME, "83JX")
 614		},
 615		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
 616	},
 617	{
 618		.callback = sof_sdw_quirk_cb,
 619		.matches = {
 620			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 621			DMI_MATCH(DMI_PRODUCT_NAME, "83LC")
 622		},
 623		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
 624	},
 625	{
 626		.callback = sof_sdw_quirk_cb,
 627		.matches = {
 628			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 629			DMI_MATCH(DMI_PRODUCT_NAME, "83MC")
 630		},
 631		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
 632	},	{
 633		.callback = sof_sdw_quirk_cb,
 634		.matches = {
 635			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 636			DMI_MATCH(DMI_PRODUCT_NAME, "83NM")
 637		},
 638		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
 639	},
 640	{
 641		.callback = sof_sdw_quirk_cb,
 642		.matches = {
 643			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 644			DMI_MATCH(DMI_PRODUCT_NAME, "83HM")
 645		},
 646		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS |
 647					SOC_SDW_CODEC_MIC),
 648	},
 649	{
 650		.callback = sof_sdw_quirk_cb,
 651		.matches = {
 652			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 653			DMI_MATCH(DMI_PRODUCT_NAME, "21QB")
 654		},
 655		/* Note this quirk excludes the CODEC mic */
 656		.driver_data = (void *)(SOC_SDW_CODEC_MIC),
 657	},
 658	{
 659		.callback = sof_sdw_quirk_cb,
 660		.matches = {
 661			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 662			DMI_MATCH(DMI_PRODUCT_NAME, "21QA")
 663		},
 664		/* Note this quirk excludes the CODEC mic */
 665		.driver_data = (void *)(SOC_SDW_CODEC_MIC),
 666	},
 667	{
 668		.callback = sof_sdw_quirk_cb,
 669		.matches = {
 670			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 671			DMI_MATCH(DMI_PRODUCT_NAME, "21Q6")
 672		},
 673		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
 674	},
 675	{
 676		.callback = sof_sdw_quirk_cb,
 677		.matches = {
 678			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 679			DMI_MATCH(DMI_PRODUCT_NAME, "21Q7")
 680		},
 681		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
 682	},
 683
 684	/* ArrowLake devices */
 685	{
 686		.callback = sof_sdw_quirk_cb,
 687		.matches = {
 688			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 689			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8")
 690		},
 691		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 692	},
 693	{
 694		.callback = sof_sdw_quirk_cb,
 695		.matches = {
 696			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 697			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1")
 698		},
 699		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 700	},
 701	{
 702		.callback = sof_sdw_quirk_cb,
 703		.matches = {
 704			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 705			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7")
 706		},
 707		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 708	},
 709	{
 710		.callback = sof_sdw_quirk_cb,
 711		.matches = {
 712			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 713			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0")
 714		},
 715		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 716	},
 717	{
 718		.callback = sof_sdw_quirk_cb,
 719		.matches = {
 720			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 721			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3")
 722		},
 723		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 724	},
 725	{
 726		.callback = sof_sdw_quirk_cb,
 727		.matches = {
 728			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 729			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4")
 730		},
 731		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 732	},
 733	{
 734		.callback = sof_sdw_quirk_cb,
 735		.matches = {
 736			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 737			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5")
 738		},
 739		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
 740	},
 741	/* Pantherlake devices*/
 742	{
 743		.callback = sof_sdw_quirk_cb,
 744		.matches = {
 745			DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"),
 746		},
 747		.driver_data = (void *)(SOC_SDW_PCH_DMIC),
 748	},
 749	{}
 750};
 751
 752static struct snd_soc_dai_link_component platform_component[] = {
 753	{
 754		/* name might be overridden during probe */
 755		.name = "0000:00:1f.3"
 756	}
 757};
 758
 759static const struct snd_soc_ops sdw_ops = {
 760	.startup = asoc_sdw_startup,
 761	.prepare = asoc_sdw_prepare,
 762	.trigger = asoc_sdw_trigger,
 763	.hw_params = asoc_sdw_hw_params,
 764	.hw_free = asoc_sdw_hw_free,
 765	.shutdown = asoc_sdw_shutdown,
 766};
 767
 768static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
 769
 770static int create_sdw_dailink(struct snd_soc_card *card,
 771			      struct asoc_sdw_dailink *sof_dai,
 772			      struct snd_soc_dai_link **dai_links,
 773			      int *be_id, struct snd_soc_codec_conf **codec_conf)
 774{
 775	struct device *dev = card->dev;
 776	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
 777	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
 778	struct asoc_sdw_endpoint *sof_end;
 779	int stream;
 780	int ret;
 781
 782	list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
 783		if (sof_end->name_prefix) {
 784			(*codec_conf)->dlc.name = sof_end->codec_name;
 785			(*codec_conf)->name_prefix = sof_end->name_prefix;
 786			(*codec_conf)++;
 787		}
 788
 789		if (sof_end->include_sidecar) {
 790			ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
 791			if (ret)
 792				return ret;
 793		}
 794	}
 795
 796	for_each_pcm_streams(stream) {
 797		static const char * const sdw_stream_name[] = {
 798			"SDW%d-Playback",
 799			"SDW%d-Capture",
 800			"SDW%d-Playback-%s",
 801			"SDW%d-Capture-%s",
 802		};
 803		struct snd_soc_dai_link_ch_map *codec_maps;
 804		struct snd_soc_dai_link_component *codecs;
 805		struct snd_soc_dai_link_component *cpus;
 806		int num_cpus = hweight32(sof_dai->link_mask[stream]);
 807		int num_codecs = sof_dai->num_devs[stream];
 808		int playback, capture;
 809		int cur_link = 0;
 810		int i = 0, j = 0;
 811		char *name;
 812
 813		if (!sof_dai->num_devs[stream])
 814			continue;
 815
 816		sof_end = list_first_entry(&sof_dai->endpoints,
 817					   struct asoc_sdw_endpoint, list);
 818
 819		*be_id = sof_end->dai_info->dailink[stream];
 820		if (*be_id < 0) {
 821			dev_err(dev, "Invalid dailink id %d\n", *be_id);
 822			return -EINVAL;
 823		}
 824
 825		/* create stream name according to first link id */
 826		if (ctx->append_dai_type)
 827			name = devm_kasprintf(dev, GFP_KERNEL,
 828					      sdw_stream_name[stream + 2],
 829					      ffs(sof_end->link_mask) - 1,
 830					      type_strings[sof_end->dai_info->dai_type]);
 831		else
 832			name = devm_kasprintf(dev, GFP_KERNEL,
 833					      sdw_stream_name[stream],
 834					      ffs(sof_end->link_mask) - 1);
 835		if (!name)
 836			return -ENOMEM;
 837
 838		cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
 839		if (!cpus)
 840			return -ENOMEM;
 841
 842		codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
 843		if (!codecs)
 844			return -ENOMEM;
 845
 846		codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
 847		if (!codec_maps)
 848			return -ENOMEM;
 849
 850		list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
 851			if (!sof_end->dai_info->direction[stream])
 852				continue;
 853
 854			if (cur_link != sof_end->link_mask) {
 855				int link_num = ffs(sof_end->link_mask) - 1;
 856				int pin_num = intel_ctx->sdw_pin_index[link_num]++;
 857
 858				cur_link = sof_end->link_mask;
 859
 860				cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
 861								  "SDW%d Pin%d",
 862								  link_num, pin_num);
 863				if (!cpus[i].dai_name)
 864					return -ENOMEM;
 865				i++;
 866			}
 867
 868			codec_maps[j].cpu = i - 1;
 869			codec_maps[j].codec = j;
 870
 871			codecs[j].name = sof_end->codec_name;
 872			codecs[j].dai_name = sof_end->dai_info->dai_name;
 873			j++;
 874		}
 875
 876		WARN_ON(i != num_cpus || j != num_codecs);
 877
 878		playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
 879		capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
 880
 881		asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
 882				       cpus, num_cpus, platform_component,
 883				       ARRAY_SIZE(platform_component), codecs, num_codecs,
 884				       1, asoc_sdw_rtd_init, &sdw_ops);
 885
 886		/*
 887		 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
 888		 * based on wait_for_completion(), tag them as 'nonatomic'.
 889		 */
 890		(*dai_links)->nonatomic = true;
 891		(*dai_links)->ch_maps = codec_maps;
 892
 893		list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
 894			if (sof_end->dai_info->init)
 895				sof_end->dai_info->init(card, *dai_links,
 896							sof_end->codec_info,
 897							playback);
 898		}
 899
 900		(*dai_links)++;
 901	}
 902
 903	return 0;
 904}
 905
 906static int create_sdw_dailinks(struct snd_soc_card *card,
 907			       struct snd_soc_dai_link **dai_links, int *be_id,
 908			       struct asoc_sdw_dailink *sof_dais,
 909			       struct snd_soc_codec_conf **codec_conf)
 910{
 911	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
 912	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
 913	int ret, i;
 914
 915	for (i = 0; i < SDW_INTEL_MAX_LINKS; i++)
 916		intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE;
 917
 918	/* generate DAI links by each sdw link */
 919	while (sof_dais->initialised) {
 920		int current_be_id;
 921
 922		ret = create_sdw_dailink(card, sof_dais, dai_links,
 923					 &current_be_id, codec_conf);
 924		if (ret)
 925			return ret;
 926
 927		/* Update the be_id to match the highest ID used for SDW link */
 928		if (*be_id < current_be_id)
 929			*be_id = current_be_id;
 930
 931		sof_dais++;
 932	}
 933
 934	return 0;
 935}
 936
 937static int create_ssp_dailinks(struct snd_soc_card *card,
 938			       struct snd_soc_dai_link **dai_links, int *be_id,
 939			       struct asoc_sdw_codec_info *ssp_info,
 940			       unsigned long ssp_mask)
 941{
 942	struct device *dev = card->dev;
 943	int i, j = 0;
 944	int ret;
 945
 946	for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
 947		char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
 948		char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
 949		char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
 950						  ssp_info->acpi_id, j++);
 951		if (!name || !cpu_dai_name || !codec_name)
 952			return -ENOMEM;
 953
 954		int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
 955		int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
 956
 957		ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
 958						    playback, capture, cpu_dai_name,
 959						    platform_component->name,
 960						    ARRAY_SIZE(platform_component), codec_name,
 961						    ssp_info->dais[0].dai_name, 1, NULL,
 962						    ssp_info->ops);
 963		if (ret)
 964			return ret;
 965
 966		ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
 967		if (ret < 0)
 968			return ret;
 969
 970		(*dai_links)++;
 971	}
 972
 973	return 0;
 974}
 975
 976static int create_dmic_dailinks(struct snd_soc_card *card,
 977				struct snd_soc_dai_link **dai_links, int *be_id)
 978{
 979	struct device *dev = card->dev;
 980	int ret;
 981
 982	ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
 983					    0, 1, // DMIC only supports capture
 984					    "DMIC01 Pin", platform_component->name,
 985					    ARRAY_SIZE(platform_component),
 986					    "dmic-codec", "dmic-hifi", 1,
 987					    asoc_sdw_dmic_init, NULL);
 988	if (ret)
 989		return ret;
 990
 991	(*dai_links)++;
 992
 993	ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
 994					    0, 1, // DMIC only supports capture
 995					    "DMIC16k Pin", platform_component->name,
 996					    ARRAY_SIZE(platform_component),
 997					    "dmic-codec", "dmic-hifi", 1,
 998					    /* don't call asoc_sdw_dmic_init() twice */
 999					    NULL, NULL);
1000	if (ret)
1001		return ret;
1002
1003	(*dai_links)++;
1004
1005	return 0;
1006}
1007
1008static int create_hdmi_dailinks(struct snd_soc_card *card,
1009				struct snd_soc_dai_link **dai_links, int *be_id,
1010				int hdmi_num)
1011{
1012	struct device *dev = card->dev;
1013	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1014	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1015	int i, ret;
1016
1017	for (i = 0; i < hdmi_num; i++) {
1018		char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
1019		char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
1020		if (!name || !cpu_dai_name)
1021			return -ENOMEM;
1022
1023		char *codec_name, *codec_dai_name;
1024
1025		if (intel_ctx->hdmi.idisp_codec) {
1026			codec_name = "ehdaudio0D2";
1027			codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
1028							"intel-hdmi-hifi%d", i + 1);
1029		} else {
1030			codec_name = "snd-soc-dummy";
1031			codec_dai_name = "snd-soc-dummy-dai";
1032		}
1033
1034		if (!codec_dai_name)
1035			return -ENOMEM;
1036
1037		ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1038						    1, 0, // HDMI only supports playback
1039						    cpu_dai_name, platform_component->name,
1040						    ARRAY_SIZE(platform_component),
1041						    codec_name, codec_dai_name, 1,
1042						    i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
1043		if (ret)
1044			return ret;
1045
1046		(*dai_links)++;
1047	}
1048
1049	return 0;
1050}
1051
1052static int create_bt_dailinks(struct snd_soc_card *card,
1053			      struct snd_soc_dai_link **dai_links, int *be_id)
1054{
1055	struct device *dev = card->dev;
1056	int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1057			SOF_BT_OFFLOAD_SSP_SHIFT;
1058	char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1059	char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1060	if (!name || !cpu_dai_name)
1061		return -ENOMEM;
1062
1063	int ret;
1064
1065	ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1066					    1, 1, cpu_dai_name, platform_component->name,
1067					    ARRAY_SIZE(platform_component),
1068					    snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1069					    1, NULL, NULL);
1070	if (ret)
1071		return ret;
1072
1073	(*dai_links)++;
1074
1075	return 0;
1076}
1077
1078static int sof_card_dai_links_create(struct snd_soc_card *card)
1079{
1080	struct device *dev = card->dev;
1081	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
1082	int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
1083	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1084	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1085	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1086	struct snd_soc_codec_conf *codec_conf;
1087	struct asoc_sdw_codec_info *ssp_info;
1088	struct asoc_sdw_endpoint *sof_ends;
1089	struct asoc_sdw_dailink *sof_dais;
1090	int num_devs = 0;
1091	int num_ends = 0;
1092	struct snd_soc_dai_link *dai_links;
1093	int num_links;
1094	int be_id = 0;
1095	int hdmi_num;
1096	unsigned long ssp_mask;
1097	int ret;
1098
1099	ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends);
1100	if (ret < 0) {
1101		dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
1102		return ret;
1103	}
1104
1105	/*
1106	 * One per DAI link, worst case is a DAI link for every endpoint, also
1107	 * add one additional to act as a terminator such that code can iterate
1108	 * until it hits an uninitialised DAI.
1109	 */
1110	sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL);
1111	if (!sof_dais)
1112		return -ENOMEM;
1113
1114	/* One per endpoint, ie. each DAI on each codec/amp */
1115	sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
1116	if (!sof_ends) {
1117		ret = -ENOMEM;
1118		goto err_dai;
1119	}
1120
1121	ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs);
1122	if (ret < 0)
1123		goto err_end;
1124
1125	sdw_be_num = ret;
1126
1127	/*
1128	 * on generic tgl platform, I2S or sdw mode is supported
1129	 * based on board rework. A ACPI device is registered in
1130	 * system only when I2S mode is supported, not sdw mode.
1131	 * Here check ACPI ID to confirm I2S is supported.
1132	 */
1133	ssp_info = asoc_sdw_find_codec_info_acpi(mach->id);
1134	if (ssp_info) {
1135		ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1136		ssp_num = hweight_long(ssp_mask);
1137	}
1138
1139	if (mach_params->codec_mask & IDISP_CODEC_MASK)
1140		intel_ctx->hdmi.idisp_codec = true;
1141
1142	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1143		hdmi_num = SOF_TGL_HDMI_COUNT;
1144	else
1145		hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1146
1147	/* enable dmic01 & dmic16k */
1148	if (ctx->ignore_internal_dmic) {
1149		dev_warn(dev, "Ignoring internal DMIC\n");
1150		mach_params->dmic_num = 0;
1151	} else if (mach_params->dmic_num) {
1152		dmic_num = 2;
1153	} else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) {
1154		dmic_num = 2;
1155		/*
1156		 * mach_params->dmic_num will be used to set the cfg-mics value of
1157		 * card->components string. Set it to the default value.
1158		 */
1159		mach_params->dmic_num = DMIC_DEFAULT_CHANNELS;
1160	}
1161
1162	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1163		bt_num = 1;
1164
1165	dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
1166		sdw_be_num, ssp_num, dmic_num,
1167		intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
1168
1169	codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
1170	if (!codec_conf) {
1171		ret = -ENOMEM;
1172		goto err_end;
1173	}
1174
1175	/* allocate BE dailinks */
1176	num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
1177	dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
1178	if (!dai_links) {
1179		ret = -ENOMEM;
1180		goto err_end;
1181	}
1182
1183	card->codec_conf = codec_conf;
1184	card->num_configs = num_devs;
1185	card->dai_link = dai_links;
1186	card->num_links = num_links;
1187
1188	/* SDW */
1189	if (sdw_be_num) {
1190		ret = create_sdw_dailinks(card, &dai_links, &be_id,
1191					  sof_dais, &codec_conf);
1192		if (ret)
1193			goto err_end;
1194	}
1195
1196	/* SSP */
1197	if (ssp_num) {
1198		ret = create_ssp_dailinks(card, &dai_links, &be_id,
1199					  ssp_info, ssp_mask);
1200		if (ret)
1201			goto err_end;
1202	}
1203
1204	/* dmic */
1205	if (dmic_num) {
1206		ret = create_dmic_dailinks(card, &dai_links, &be_id);
1207		if (ret)
1208			goto err_end;
1209	}
1210
1211	/* HDMI */
1212	ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
1213	if (ret)
1214		goto err_end;
1215
1216	/* BT */
1217	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1218		ret = create_bt_dailinks(card, &dai_links, &be_id);
1219		if (ret)
1220			goto err_end;
1221	}
1222
1223	WARN_ON(codec_conf != card->codec_conf + card->num_configs);
1224	WARN_ON(dai_links != card->dai_link + card->num_links);
1225
1226err_end:
1227	kfree(sof_ends);
1228err_dai:
1229	kfree(sof_dais);
1230
1231	return ret;
1232}
1233
1234static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1235{
1236	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1237	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1238	int ret = 0;
1239
1240	ret = asoc_sdw_card_late_probe(card);
1241	if (ret < 0)
1242		return ret;
1243
1244	if (intel_ctx->hdmi.idisp_codec)
1245		ret = sof_sdw_hdmi_card_late_probe(card);
1246
1247	return ret;
1248}
1249
1250static int mc_probe(struct platform_device *pdev)
1251{
1252	struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
1253	struct snd_soc_card *card;
1254	struct asoc_sdw_mc_private *ctx;
1255	struct intel_mc_ctx *intel_ctx;
1256	int amp_num = 0, i;
1257	int ret;
1258
1259	dev_dbg(&pdev->dev, "Entry\n");
1260
1261	intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL);
1262	if (!intel_ctx)
1263		return -ENOMEM;
1264
1265	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1266	if (!ctx)
1267		return -ENOMEM;
1268
1269	ctx->private = intel_ctx;
1270	ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
1271	card = &ctx->card;
1272	card->dev = &pdev->dev;
1273	card->name = "soundwire";
1274	card->owner = THIS_MODULE;
1275	card->late_probe = sof_sdw_card_late_probe;
1276
1277	snd_soc_card_set_drvdata(card, ctx);
1278
1279	dmi_check_system(sof_sdw_quirk_table);
1280
1281	if (quirk_override != -1) {
1282		dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
1283			 sof_sdw_quirk, quirk_override);
1284		sof_sdw_quirk = quirk_override;
1285	}
1286
1287	log_quirks(card->dev);
1288
1289	ctx->mc_quirk = sof_sdw_quirk;
1290	/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1291	for (i = 0; i < ctx->codec_info_list_count; i++)
1292		codec_info_list[i].amp_num = 0;
1293
1294	if (mach->mach_params.subsystem_id_set) {
1295		snd_soc_card_set_pci_ssid(card,
1296					  mach->mach_params.subsystem_vendor,
1297					  mach->mach_params.subsystem_device);
1298	}
1299
1300	ret = sof_card_dai_links_create(card);
1301	if (ret < 0)
1302		return ret;
1303
1304	/*
1305	 * the default amp_num is zero for each codec and
1306	 * amp_num will only be increased for active amp
1307	 * codecs on used platform
1308	 */
1309	for (i = 0; i < ctx->codec_info_list_count; i++)
1310		amp_num += codec_info_list[i].amp_num;
1311
1312	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1313					  " cfg-amp:%d", amp_num);
1314	if (!card->components)
1315		return -ENOMEM;
1316
1317	if (mach->mach_params.dmic_num) {
1318		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1319						  "%s mic:dmic cfg-mics:%d",
1320						  card->components,
1321						  mach->mach_params.dmic_num);
1322		if (!card->components)
1323			return -ENOMEM;
1324	}
1325
1326	/* Register the card */
1327	ret = devm_snd_soc_register_card(card->dev, card);
1328	if (ret) {
1329		dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
1330		asoc_sdw_mc_dailink_exit_loop(card);
1331		return ret;
1332	}
1333
1334	platform_set_drvdata(pdev, card);
1335
1336	return ret;
1337}
1338
1339static void mc_remove(struct platform_device *pdev)
1340{
1341	struct snd_soc_card *card = platform_get_drvdata(pdev);
1342
1343	asoc_sdw_mc_dailink_exit_loop(card);
1344}
1345
1346static const struct platform_device_id mc_id_table[] = {
1347	{ "sof_sdw", },
1348	{}
1349};
1350MODULE_DEVICE_TABLE(platform, mc_id_table);
1351
1352static struct platform_driver sof_sdw_driver = {
1353	.driver = {
1354		.name = "sof_sdw",
1355		.pm = &snd_soc_pm_ops,
1356	},
1357	.probe = mc_probe,
1358	.remove = mc_remove,
1359	.id_table = mc_id_table,
1360};
1361
1362module_platform_driver(sof_sdw_driver);
1363
1364MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1365MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1366MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1367MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1368MODULE_LICENSE("GPL v2");
1369MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
1370MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");