Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
v6.13.7
   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");
 
v6.2
   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/device.h>
   9#include <linux/dmi.h>
  10#include <linux/module.h>
  11#include <linux/soundwire/sdw.h>
  12#include <linux/soundwire/sdw_type.h>
  13#include <sound/soc.h>
  14#include <sound/soc-acpi.h>
  15#include "sof_sdw_common.h"
  16#include "../../codecs/rt711.h"
  17
  18unsigned long sof_sdw_quirk = RT711_JD1;
  19static int quirk_override = -1;
  20module_param_named(quirk, quirk_override, int, 0444);
  21MODULE_PARM_DESC(quirk, "Board-specific quirk override");
  22
  23#define INC_ID(BE, CPU, LINK)	do { (BE)++; (CPU)++; (LINK)++; } while (0)
  24
  25static void log_quirks(struct device *dev)
  26{
  27	if (SOF_RT711_JDSRC(sof_sdw_quirk))
  28		dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
  29			SOF_RT711_JDSRC(sof_sdw_quirk));
  30	if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
  31		dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n");
  32	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
  33		dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
  34	if (sof_sdw_quirk & SOF_SDW_PCH_DMIC)
  35		dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n");
  36	if (SOF_SSP_GET_PORT(sof_sdw_quirk))
  37		dev_dbg(dev, "SSP port %ld\n",
  38			SOF_SSP_GET_PORT(sof_sdw_quirk));
  39	if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
  40		dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
 
 
 
 
  41}
  42
  43static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
  44{
  45	sof_sdw_quirk = (unsigned long)id->driver_data;
  46	return 1;
  47}
  48
  49static const struct dmi_system_id sof_sdw_quirk_table[] = {
  50	/* CometLake devices */
  51	{
  52		.callback = sof_sdw_quirk_cb,
  53		.matches = {
  54			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  55			DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
  56		},
  57		.driver_data = (void *)SOF_SDW_PCH_DMIC,
  58	},
  59	{
  60		.callback = sof_sdw_quirk_cb,
  61		.matches = {
  62			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  63			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
  64		},
  65		.driver_data = (void *)RT711_JD2,
  66	},
  67	{
  68		/* early version of SKU 09C6 */
  69		.callback = sof_sdw_quirk_cb,
  70		.matches = {
  71			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  72			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
  73		},
  74		.driver_data = (void *)RT711_JD2,
  75	},
  76	{
  77		.callback = sof_sdw_quirk_cb,
  78		.matches = {
  79			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  80			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
  81		},
  82		.driver_data = (void *)(RT711_JD2 |
  83					SOF_SDW_FOUR_SPK),
  84	},
  85	{
  86		.callback = sof_sdw_quirk_cb,
  87		.matches = {
  88			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  89			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
  90		},
  91		.driver_data = (void *)(RT711_JD2 |
  92					SOF_SDW_FOUR_SPK),
  93	},
  94	/* IceLake devices */
  95	{
  96		.callback = sof_sdw_quirk_cb,
  97		.matches = {
  98			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  99			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
 100		},
 101		.driver_data = (void *)SOF_SDW_PCH_DMIC,
 102	},
 103	/* TigerLake devices */
 104	{
 105		.callback = sof_sdw_quirk_cb,
 106		.matches = {
 107			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 108			DMI_MATCH(DMI_PRODUCT_NAME,
 109				  "Tiger Lake Client Platform"),
 110		},
 111		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 112					RT711_JD1 |
 113					SOF_SDW_PCH_DMIC |
 114					SOF_SSP_PORT(SOF_I2S_SSP2)),
 115	},
 116	{
 117		.callback = sof_sdw_quirk_cb,
 118		.matches = {
 119			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 120			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
 121		},
 122		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 123					RT711_JD2),
 124	},
 125	{
 126		/* another SKU of Dell Latitude 9520 */
 127		.callback = sof_sdw_quirk_cb,
 128		.matches = {
 129			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 130			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
 131		},
 132		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 133					RT711_JD2),
 134	},
 135	{
 136		/* Dell XPS 9710 */
 137		.callback = sof_sdw_quirk_cb,
 138		.matches = {
 139			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 140			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
 141		},
 142		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 143					RT711_JD2 |
 144					SOF_SDW_FOUR_SPK),
 145	},
 146	{
 147		.callback = sof_sdw_quirk_cb,
 148		.matches = {
 149			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 150			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
 151		},
 152		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 153					RT711_JD2 |
 154					SOF_SDW_FOUR_SPK),
 155	},
 156	{
 157		.callback = sof_sdw_quirk_cb,
 158		.matches = {
 159			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 160			DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
 161		},
 162		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 163					SOF_SDW_PCH_DMIC |
 164					SOF_SDW_FOUR_SPK |
 165					SOF_BT_OFFLOAD_SSP(2) |
 166					SOF_SSP_BT_OFFLOAD_PRESENT),
 167	},
 168	{
 169		.callback = sof_sdw_quirk_cb,
 170		.matches = {
 171			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 172			DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
 173		},
 174		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 175					SOF_SDW_PCH_DMIC |
 176					SOF_SDW_FOUR_SPK),
 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					SOF_SDW_PCH_DMIC |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 192					RT711_JD1),
 193	},
 194	{
 195		/* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
 196		.callback = sof_sdw_quirk_cb,
 197		.matches = {
 198			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 199			DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
 200		},
 201		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 202					SOF_SDW_PCH_DMIC |
 203					RT711_JD1),
 204	},
 205	{
 206		/* NUC15 LAPBC710 skews */
 207		.callback = sof_sdw_quirk_cb,
 208		.matches = {
 209			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 210			DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
 211		},
 212		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 213					SOF_SDW_PCH_DMIC |
 214					RT711_JD1),
 215	},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 216	/* TigerLake-SDCA devices */
 217	{
 218		.callback = sof_sdw_quirk_cb,
 219		.matches = {
 220			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 221			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
 222		},
 223		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 224					RT711_JD2 |
 225					SOF_SDW_FOUR_SPK),
 226	},
 227	{
 228		.callback = sof_sdw_quirk_cb,
 229		.matches = {
 230			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 231			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
 232		},
 233		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 234					RT711_JD2),
 235	},
 236	/* AlderLake devices */
 237	{
 238		.callback = sof_sdw_quirk_cb,
 239		.matches = {
 240			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 241			DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
 242		},
 243		.driver_data = (void *)(RT711_JD2_100K |
 244					SOF_SDW_TGL_HDMI |
 245					SOF_BT_OFFLOAD_SSP(2) |
 246					SOF_SSP_BT_OFFLOAD_PRESENT),
 247	},
 248	{
 249		.callback = sof_sdw_quirk_cb,
 250		.matches = {
 
 
 
 
 
 
 
 
 
 251			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 252			DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
 253		},
 254		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 255					SOF_SDW_PCH_DMIC |
 256					SOF_SDW_FOUR_SPK |
 257					SOF_BT_OFFLOAD_SSP(2) |
 258					SOF_SSP_BT_OFFLOAD_PRESENT),
 259	},
 260	{
 261		.callback = sof_sdw_quirk_cb,
 262		.matches = {
 263			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 264			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
 265		},
 266		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 267					RT711_JD2 |
 268					SOF_SDW_FOUR_SPK),
 269	},
 270	{
 271		.callback = sof_sdw_quirk_cb,
 272		.matches = {
 273			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 274			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
 275		},
 276		/* No Jack */
 
 
 
 
 
 
 
 
 277		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 278					SOF_SDW_FOUR_SPK),
 279	},
 280	{
 281		.callback = sof_sdw_quirk_cb,
 282		.matches = {
 283			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 284			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
 285		},
 286		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 287					RT711_JD2 |
 288					SOF_SDW_FOUR_SPK),
 289	},
 290	{
 291		.callback = sof_sdw_quirk_cb,
 292		.matches = {
 293			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 294			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
 295		},
 296		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 297					RT711_JD2 |
 298					SOF_SDW_FOUR_SPK),
 299	},
 300	{
 301		.callback = sof_sdw_quirk_cb,
 302		.matches = {
 303			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 304			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
 305		},
 306		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 307					RT711_JD2 |
 308					SOF_SDW_FOUR_SPK),
 309	},
 310	{
 311		.callback = sof_sdw_quirk_cb,
 312		.matches = {
 313			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 314			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
 315		},
 316		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 317					RT711_JD2 |
 318					SOF_SDW_FOUR_SPK),
 319	},
 320	{
 321		.callback = sof_sdw_quirk_cb,
 322		.matches = {
 323			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 324			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
 325		},
 326		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 327					RT711_JD2 |
 328					SOF_SDW_FOUR_SPK),
 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, "0B13"),
 335		},
 336		/* No Jack */
 337		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 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, "0B29"),
 344		},
 345		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 346					RT711_JD2 |
 347					SOF_SDW_FOUR_SPK),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 348	},
 349	{
 350		.callback = sof_sdw_quirk_cb,
 351		.matches = {
 352			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 353			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
 354		},
 355		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 356					RT711_JD2),
 357	},
 358	/* RaptorLake devices */
 359	{
 360		.callback = sof_sdw_quirk_cb,
 361		.matches = {
 362			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 363			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
 364		},
 365		/* No Jack */
 366		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 367					SOF_SDW_FOUR_SPK),
 368	},
 369	{
 370		.callback = sof_sdw_quirk_cb,
 371		.matches = {
 372			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 373			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
 374		},
 375		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 376					RT711_JD2 |
 377					SOF_SDW_FOUR_SPK),
 378	},
 379	{
 380		.callback = sof_sdw_quirk_cb,
 381		.matches = {
 382			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 383			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
 384		},
 385		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 386					RT711_JD2 |
 387					SOF_SDW_FOUR_SPK),
 388	},
 389	{
 390		.callback = sof_sdw_quirk_cb,
 391		.matches = {
 392			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 393			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
 394		},
 395		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 396					RT711_JD2 |
 397					SOF_SDW_FOUR_SPK),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 398	},
 399	/* MeteorLake devices */
 400	{
 401		.callback = sof_sdw_quirk_cb,
 402		.matches = {
 403			DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
 404		},
 405		.driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 406	},
 407	{}
 408};
 409
 410static struct snd_soc_dai_link_component dmic_component[] = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 411	{
 412		.name = "dmic-codec",
 413		.dai_name = "dmic-hifi",
 414	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 415};
 416
 417static struct snd_soc_dai_link_component platform_component[] = {
 418	{
 419		/* name might be overridden during probe */
 420		.name = "0000:00:1f.3"
 421	}
 422};
 423
 424/* these wrappers are only needed to avoid typecast compilation errors */
 425int sdw_startup(struct snd_pcm_substream *substream)
 426{
 427	return sdw_startup_stream(substream);
 428}
 
 
 
 429
 430int sdw_prepare(struct snd_pcm_substream *substream)
 431{
 432	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 433	struct sdw_stream_runtime *sdw_stream;
 434	struct snd_soc_dai *dai;
 435
 436	/* Find stream from first CPU DAI */
 437	dai = asoc_rtd_to_cpu(rtd, 0);
 438
 439	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 440
 441	if (IS_ERR(sdw_stream)) {
 442		dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
 443		return PTR_ERR(sdw_stream);
 444	}
 445
 446	return sdw_prepare_stream(sdw_stream);
 447}
 448
 449int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
 450{
 451	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 452	struct sdw_stream_runtime *sdw_stream;
 453	struct snd_soc_dai *dai;
 
 
 454	int ret;
 455
 456	/* Find stream from first CPU DAI */
 457	dai = asoc_rtd_to_cpu(rtd, 0);
 
 
 
 
 458
 459	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 460
 461	if (IS_ERR(sdw_stream)) {
 462		dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
 463		return PTR_ERR(sdw_stream);
 464	}
 465
 466	switch (cmd) {
 467	case SNDRV_PCM_TRIGGER_START:
 468	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 469	case SNDRV_PCM_TRIGGER_RESUME:
 470		ret = sdw_enable_stream(sdw_stream);
 471		break;
 472
 473	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 474	case SNDRV_PCM_TRIGGER_SUSPEND:
 475	case SNDRV_PCM_TRIGGER_STOP:
 476		ret = sdw_disable_stream(sdw_stream);
 477		break;
 478	default:
 479		ret = -EINVAL;
 480		break;
 481	}
 482
 483	if (ret)
 484		dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
 485
 486	return ret;
 487}
 488
 489int sdw_hw_free(struct snd_pcm_substream *substream)
 490{
 491	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 492	struct sdw_stream_runtime *sdw_stream;
 493	struct snd_soc_dai *dai;
 494
 495	/* Find stream from first CPU DAI */
 496	dai = asoc_rtd_to_cpu(rtd, 0);
 497
 498	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 499
 500	if (IS_ERR(sdw_stream)) {
 501		dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
 502		return PTR_ERR(sdw_stream);
 503	}
 504
 505	return sdw_deprepare_stream(sdw_stream);
 506}
 
 
 
 
 
 
 
 
 
 
 507
 508void sdw_shutdown(struct snd_pcm_substream *substream)
 509{
 510	sdw_shutdown_stream(substream);
 511}
 512
 513static const struct snd_soc_ops sdw_ops = {
 514	.startup = sdw_startup,
 515	.prepare = sdw_prepare,
 516	.trigger = sdw_trigger,
 517	.hw_free = sdw_hw_free,
 518	.shutdown = sdw_shutdown,
 519};
 520
 521static struct sof_sdw_codec_info codec_info_list[] = {
 522	{
 523		.part_id = 0x700,
 524		.direction = {true, true},
 525		.dai_name = "rt700-aif1",
 526		.init = sof_sdw_rt700_init,
 527		.codec_type = SOF_SDW_CODEC_TYPE_JACK,
 528	},
 529	{
 530		.part_id = 0x711,
 531		.version_id = 3,
 532		.direction = {true, true},
 533		.dai_name = "rt711-sdca-aif1",
 534		.init = sof_sdw_rt711_sdca_init,
 535		.exit = sof_sdw_rt711_sdca_exit,
 536		.codec_type = SOF_SDW_CODEC_TYPE_JACK,
 537	},
 538	{
 539		.part_id = 0x711,
 540		.version_id = 2,
 541		.direction = {true, true},
 542		.dai_name = "rt711-aif1",
 543		.init = sof_sdw_rt711_init,
 544		.exit = sof_sdw_rt711_exit,
 545		.codec_type = SOF_SDW_CODEC_TYPE_JACK,
 546	},
 547	{
 548		.part_id = 0x1308,
 549		.acpi_id = "10EC1308",
 550		.direction = {true, false},
 551		.dai_name = "rt1308-aif",
 552		.ops = &sof_sdw_rt1308_i2s_ops,
 553		.init = sof_sdw_rt_amp_init,
 554		.exit = sof_sdw_rt_amp_exit,
 555		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 556	},
 557	{
 558		.part_id = 0x1316,
 559		.direction = {true, true},
 560		.dai_name = "rt1316-aif",
 561		.init = sof_sdw_rt_amp_init,
 562		.exit = sof_sdw_rt_amp_exit,
 563		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 564	},
 565	{
 566		.part_id = 0x1318,
 567		.direction = {true, true},
 568		.dai_name = "rt1318-aif",
 569		.init = sof_sdw_rt_amp_init,
 570		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 571	},
 572	{
 573		.part_id = 0x714,
 574		.version_id = 3,
 575		.direction = {false, true},
 576		.ignore_pch_dmic = true,
 577		.dai_name = "rt715-aif2",
 578		.init = sof_sdw_rt715_sdca_init,
 579		.codec_type = SOF_SDW_CODEC_TYPE_MIC,
 580	},
 581	{
 582		.part_id = 0x715,
 583		.version_id = 3,
 584		.direction = {false, true},
 585		.ignore_pch_dmic = true,
 586		.dai_name = "rt715-aif2",
 587		.init = sof_sdw_rt715_sdca_init,
 588		.codec_type = SOF_SDW_CODEC_TYPE_MIC,
 589	},
 590	{
 591		.part_id = 0x714,
 592		.version_id = 2,
 593		.direction = {false, true},
 594		.ignore_pch_dmic = true,
 595		.dai_name = "rt715-aif2",
 596		.init = sof_sdw_rt715_init,
 597		.codec_type = SOF_SDW_CODEC_TYPE_MIC,
 598	},
 599	{
 600		.part_id = 0x715,
 601		.version_id = 2,
 602		.direction = {false, true},
 603		.ignore_pch_dmic = true,
 604		.dai_name = "rt715-aif2",
 605		.init = sof_sdw_rt715_init,
 606		.codec_type = SOF_SDW_CODEC_TYPE_MIC,
 607	},
 608	{
 609		.part_id = 0x8373,
 610		.direction = {true, true},
 611		.dai_name = "max98373-aif1",
 612		.init = sof_sdw_mx8373_init,
 613		.codec_card_late_probe = sof_sdw_mx8373_late_probe,
 614		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 615	},
 616	{
 617		.part_id = 0x5682,
 618		.direction = {true, true},
 619		.dai_name = "rt5682-sdw",
 620		.init = sof_sdw_rt5682_init,
 621		.codec_type = SOF_SDW_CODEC_TYPE_JACK,
 622	},
 623	{
 624		.part_id = 0xaaaa, /* generic codec mockup */
 625		.version_id = 0,
 626		.direction = {true, true},
 627		.dai_name = "sdw-mockup-aif1",
 628		.init = NULL,
 629		.codec_type = SOF_SDW_CODEC_TYPE_JACK,
 630	},
 631	{
 632		.part_id = 0xaa55, /* headset codec mockup */
 633		.version_id = 0,
 634		.direction = {true, true},
 635		.dai_name = "sdw-mockup-aif1",
 636		.init = NULL,
 637		.codec_type = SOF_SDW_CODEC_TYPE_JACK,
 638	},
 639	{
 640		.part_id = 0x55aa, /* amplifier mockup */
 641		.version_id = 0,
 642		.direction = {true, false},
 643		.dai_name = "sdw-mockup-aif1",
 644		.init = NULL,
 645		.codec_type = SOF_SDW_CODEC_TYPE_AMP,
 646	},
 647	{
 648		.part_id = 0x5555,
 649		.version_id = 0,
 650		.direction = {false, true},
 651		.dai_name = "sdw-mockup-aif1",
 652		.codec_type = SOF_SDW_CODEC_TYPE_MIC,
 653	},
 654};
 655
 656static inline int find_codec_info_part(u64 adr)
 657{
 658	unsigned int part_id, sdw_version;
 659	int i;
 660
 661	part_id = SDW_PART_ID(adr);
 662	sdw_version = SDW_VERSION(adr);
 663	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
 664		/*
 665		 * A codec info is for all sdw version with the part id if
 666		 * version_id is not specified in the codec info.
 667		 */
 668		if (part_id == codec_info_list[i].part_id &&
 669		    (!codec_info_list[i].version_id ||
 670		     sdw_version == codec_info_list[i].version_id))
 671			return i;
 
 
 672
 673	return -EINVAL;
 
 674
 675}
 
 
 
 676
 677static inline int find_codec_info_acpi(const u8 *acpi_id)
 678{
 679	int i;
 680
 681	if (!acpi_id[0])
 682		return -EINVAL;
 683
 684	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
 685		if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
 686			    ACPI_ID_LEN))
 687			break;
 688
 689	if (i == ARRAY_SIZE(codec_info_list))
 690		return -EINVAL;
 691
 692	return i;
 693}
 694
 695/*
 696 * get BE dailink number and CPU DAI number based on sdw link adr.
 697 * Since some sdw slaves may be aggregated, the CPU DAI number
 698 * may be larger than the number of BE dailinks.
 699 */
 700static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
 701				int *sdw_be_num, int *sdw_cpu_dai_num)
 702{
 703	const struct snd_soc_acpi_link_adr *link;
 704	int _codec_type = SOF_SDW_CODEC_TYPE_JACK;
 705	bool group_visited[SDW_MAX_GROUPS];
 706	bool no_aggregation;
 707	int i;
 708
 709	no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
 710	*sdw_cpu_dai_num = 0;
 711	*sdw_be_num  = 0;
 712
 713	if (!links)
 714		return -EINVAL;
 715
 716	for (i = 0; i < SDW_MAX_GROUPS; i++)
 717		group_visited[i] = false;
 718
 719	for (link = links; link->num_adr; link++) {
 720		const struct snd_soc_acpi_endpoint *endpoint;
 721		int codec_index;
 722		int stream;
 723		u64 adr;
 724
 725		adr = link->adr_d->adr;
 726		codec_index = find_codec_info_part(adr);
 727		if (codec_index < 0)
 728			return codec_index;
 729
 730		if (codec_info_list[codec_index].codec_type < _codec_type)
 731			dev_warn(dev,
 732				 "Unexpected address table ordering. Expected order: jack -> amp -> mic\n");
 733
 734		_codec_type = codec_info_list[codec_index].codec_type;
 735
 736		endpoint = link->adr_d->endpoints;
 737
 738		/* count DAI number for playback and capture */
 739		for_each_pcm_streams(stream) {
 740			if (!codec_info_list[codec_index].direction[stream])
 741				continue;
 742
 743			(*sdw_cpu_dai_num)++;
 744
 745			/* count BE for each non-aggregated slave or group */
 746			if (!endpoint->aggregated || no_aggregation ||
 747			    !group_visited[endpoint->group_id])
 748				(*sdw_be_num)++;
 
 749		}
 750
 751		if (endpoint->aggregated)
 752			group_visited[endpoint->group_id] = true;
 753	}
 754
 755	return 0;
 756}
 757
 758static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
 759			  int be_id, char *name, int playback, int capture,
 760			  struct snd_soc_dai_link_component *cpus, int cpus_num,
 761			  struct snd_soc_dai_link_component *codecs, int codecs_num,
 762			  int (*init)(struct snd_soc_pcm_runtime *rtd),
 763			  const struct snd_soc_ops *ops)
 764{
 765	dev_dbg(dev, "create dai link %s, id %d\n", name, be_id);
 766	dai_links->id = be_id;
 767	dai_links->name = name;
 768	dai_links->platforms = platform_component;
 769	dai_links->num_platforms = ARRAY_SIZE(platform_component);
 770	dai_links->no_pcm = 1;
 771	dai_links->cpus = cpus;
 772	dai_links->num_cpus = cpus_num;
 773	dai_links->codecs = codecs;
 774	dai_links->num_codecs = codecs_num;
 775	dai_links->dpcm_playback = playback;
 776	dai_links->dpcm_capture = capture;
 777	dai_links->init = init;
 778	dai_links->ops = ops;
 779}
 780
 781static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
 782			     unsigned int sdw_version,
 783			     unsigned int mfg_id,
 784			     unsigned int part_id,
 785			     unsigned int class_id,
 786			     int index_in_link
 787			    )
 788{
 789	int i;
 790
 791	for (i = 0; i < link->num_adr; i++) {
 792		unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
 793		u64 adr;
 794
 795		/* skip itself */
 796		if (i == index_in_link)
 797			continue;
 
 798
 799		adr = link->adr_d[i].adr;
 
 
 800
 801		sdw1_version = SDW_VERSION(adr);
 802		mfg1_id = SDW_MFG_ID(adr);
 803		part1_id = SDW_PART_ID(adr);
 804		class1_id = SDW_CLASS_ID(adr);
 805
 806		if (sdw_version == sdw1_version &&
 807		    mfg_id == mfg1_id &&
 808		    part_id == part1_id &&
 809		    class_id == class1_id)
 810			return false;
 811	}
 812
 813	return true;
 814}
 815
 816static int create_codec_dai_name(struct device *dev,
 817				 const struct snd_soc_acpi_link_adr *link,
 818				 struct snd_soc_dai_link_component *codec,
 819				 int offset,
 820				 struct snd_soc_codec_conf *codec_conf,
 821				 int codec_count,
 822				 int *codec_conf_index)
 823{
 824	int i;
 825
 826	/* sanity check */
 827	if (*codec_conf_index + link->num_adr > codec_count) {
 828		dev_err(dev, "codec_conf: out-of-bounds access requested\n");
 829		return -EINVAL;
 830	}
 831
 832	for (i = 0; i < link->num_adr; i++) {
 833		unsigned int sdw_version, unique_id, mfg_id;
 834		unsigned int link_id, part_id, class_id;
 835		int codec_index, comp_index;
 836		char *codec_str;
 837		u64 adr;
 838
 839		adr = link->adr_d[i].adr;
 840
 841		sdw_version = SDW_VERSION(adr);
 842		link_id = SDW_DISCO_LINK_ID(adr);
 843		unique_id = SDW_UNIQUE_ID(adr);
 844		mfg_id = SDW_MFG_ID(adr);
 845		part_id = SDW_PART_ID(adr);
 846		class_id = SDW_CLASS_ID(adr);
 847
 848		comp_index = i + offset;
 849		if (is_unique_device(link, sdw_version, mfg_id, part_id,
 850				     class_id, i)) {
 851			codec_str = "sdw:%01x:%04x:%04x:%02x";
 852			codec[comp_index].name =
 853				devm_kasprintf(dev, GFP_KERNEL, codec_str,
 854					       link_id, mfg_id, part_id,
 855					       class_id);
 856		} else {
 857			codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
 858			codec[comp_index].name =
 859				devm_kasprintf(dev, GFP_KERNEL, codec_str,
 860					       link_id, mfg_id, part_id,
 861					       class_id, unique_id);
 862		}
 863
 864		if (!codec[comp_index].name)
 
 
 
 
 
 865			return -ENOMEM;
 866
 867		codec_index = find_codec_info_part(adr);
 868		if (codec_index < 0)
 869			return codec_index;
 870
 871		codec[comp_index].dai_name =
 872			codec_info_list[codec_index].dai_name;
 
 
 
 
 
 
 873
 874		codec_conf[*codec_conf_index].dlc = codec[comp_index];
 875		codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
 
 876
 877		++*codec_conf_index;
 878	}
 879
 880	return 0;
 881}
 882
 883static int set_codec_init_func(struct snd_soc_card *card,
 884			       const struct snd_soc_acpi_link_adr *link,
 885			       struct snd_soc_dai_link *dai_links,
 886			       bool playback, int group_id)
 887{
 888	int i;
 889
 890	do {
 891		/*
 892		 * Initialize the codec. If codec is part of an aggregated
 893		 * group (group_id>0), initialize all codecs belonging to
 894		 * same group.
 895		 */
 896		for (i = 0; i < link->num_adr; i++) {
 897			int codec_index;
 898
 899			codec_index = find_codec_info_part(link->adr_d[i].adr);
 900
 901			if (codec_index < 0)
 902				return codec_index;
 903			/* The group_id is > 0 iff the codec is aggregated */
 904			if (link->adr_d[i].endpoints->group_id != group_id)
 905				continue;
 906			if (codec_info_list[codec_index].init)
 907				codec_info_list[codec_index].init(card,
 908						link,
 909						dai_links,
 910						&codec_info_list[codec_index],
 911						playback);
 912		}
 913		link++;
 914	} while (link->mask && group_id);
 915
 916	return 0;
 917}
 918
 919/*
 920 * check endpoint status in slaves and gather link ID for all slaves in
 921 * the same group to generate different CPU DAI. Now only support
 922 * one sdw link with all slaves set with only single group id.
 923 *
 924 * one slave on one sdw link with aggregated = 0
 925 * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
 926 *
 927 * two or more slaves on one sdw link with aggregated = 0
 928 * one sdw BE DAI  <---> one-cpu DAI <---> multi-codec DAIs
 929 *
 930 * multiple links with multiple slaves with aggregated = 1
 931 * one sdw BE DAI  <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
 932 */
 933static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
 934			  struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
 935			  int *codec_num, unsigned int *group_id,
 936			  bool *group_generated)
 937{
 938	const struct snd_soc_acpi_adr_device *adr_d;
 939	const struct snd_soc_acpi_link_adr *adr_next;
 940	bool no_aggregation;
 941	int index = 0;
 942
 943	no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
 944	*codec_num = adr_link->num_adr;
 945	adr_d = adr_link->adr_d;
 946
 947	/* make sure the link mask has a single bit set */
 948	if (!is_power_of_2(adr_link->mask))
 949		return -EINVAL;
 950
 951	cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
 952	if (!adr_d->endpoints->aggregated || no_aggregation) {
 953		*cpu_dai_num = 1;
 954		*group_id = 0;
 955		return 0;
 956	}
 957
 958	*group_id = adr_d->endpoints->group_id;
 959
 960	/* gather other link ID of slaves in the same group */
 961	for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
 962		adr_next++) {
 963		const struct snd_soc_acpi_endpoint *endpoint;
 964
 965		endpoint = adr_next->adr_d->endpoints;
 966		if (!endpoint->aggregated ||
 967		    endpoint->group_id != *group_id)
 968			continue;
 969
 970		/* make sure the link mask has a single bit set */
 971		if (!is_power_of_2(adr_next->mask))
 972			return -EINVAL;
 973
 974		if (index >= SDW_MAX_CPU_DAIS) {
 975			dev_err(dev, " cpu_dai_id array overflows");
 976			return -EINVAL;
 977		}
 978
 979		cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
 980		*codec_num += adr_next->num_adr;
 981	}
 982
 983	/*
 984	 * indicate CPU DAIs for this group have been generated
 985	 * to avoid generating CPU DAIs for this group again.
 986	 */
 987	group_generated[*group_id] = true;
 988	*cpu_dai_num = index;
 989
 990	return 0;
 991}
 992
 993static int create_sdw_dailink(struct snd_soc_card *card,
 994			      struct device *dev, int *link_index,
 995			      struct snd_soc_dai_link *dai_links,
 996			      int sdw_be_num, int sdw_cpu_dai_num,
 997			      struct snd_soc_dai_link_component *cpus,
 998			      const struct snd_soc_acpi_link_adr *link,
 999			      int *cpu_id, bool *group_generated,
1000			      struct snd_soc_codec_conf *codec_conf,
1001			      int codec_count, int *link_id,
1002			      int *codec_conf_index,
1003			      bool *ignore_pch_dmic)
1004{
1005	const struct snd_soc_acpi_link_adr *link_next;
1006	struct snd_soc_dai_link_component *codecs;
1007	int cpu_dai_id[SDW_MAX_CPU_DAIS];
1008	int cpu_dai_num, cpu_dai_index;
1009	unsigned int group_id;
1010	int codec_idx = 0;
1011	int i = 0, j = 0;
1012	int codec_index;
1013	int codec_num;
1014	int stream;
1015	int ret;
1016	int k;
1017
1018	ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
1019			     &group_id, group_generated);
 
 
 
 
1020	if (ret)
1021		return ret;
1022
1023	codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
1024	if (!codecs)
1025		return -ENOMEM;
1026
1027	/* generate codec name on different links in the same group */
1028	for (link_next = link; link_next && link_next->num_adr &&
1029	     i < cpu_dai_num; link_next++) {
1030		const struct snd_soc_acpi_endpoint *endpoints;
1031
1032		endpoints = link_next->adr_d->endpoints;
1033		if (group_id && (!endpoints->aggregated ||
1034				 endpoints->group_id != group_id))
1035			continue;
1036
1037		/* skip the link excluded by this processed group */
1038		if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
1039			continue;
1040
1041		ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
1042					    codec_conf, codec_count, codec_conf_index);
1043		if (ret < 0)
1044			return ret;
1045
1046		/* check next link to create codec dai in the processed group */
1047		i++;
1048		codec_idx += link_next->num_adr;
1049	}
 
 
 
 
1050
1051	/* find codec info to create BE DAI */
1052	codec_index = find_codec_info_part(link->adr_d[0].adr);
1053	if (codec_index < 0)
1054		return codec_index;
1055
1056	if (codec_info_list[codec_index].ignore_pch_dmic)
1057		*ignore_pch_dmic = true;
1058
1059	/* Shift the first amplifier's *link_id to SDW_AMP_DAI_ID */
1060	if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_AMP &&
1061	    *link_id < SDW_AMP_DAI_ID)
1062		*link_id = SDW_AMP_DAI_ID;
1063
1064	/*
1065	 * DAI ID is fixed at SDW_DMIC_DAI_ID for MICs to
1066	 * keep sdw DMIC and HDMI setting static in UCM
1067	 */
1068	if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_MIC &&
1069	    *link_id < SDW_DMIC_DAI_ID)
1070		*link_id = SDW_DMIC_DAI_ID;
1071
1072	cpu_dai_index = *cpu_id;
1073	for_each_pcm_streams(stream) {
1074		char *name, *cpu_name;
1075		int playback, capture;
1076		static const char * const sdw_stream_name[] = {
1077			"SDW%d-Playback",
1078			"SDW%d-Capture",
1079		};
1080
1081		if (!codec_info_list[codec_index].direction[stream])
1082			continue;
1083
1084		/* create stream name according to first link id */
1085		name = devm_kasprintf(dev, GFP_KERNEL,
1086				      sdw_stream_name[stream], cpu_dai_id[0]);
1087		if (!name)
1088			return -ENOMEM;
1089
1090		/*
1091		 * generate CPU DAI name base on the sdw link ID and
1092		 * PIN ID with offset of 2 according to sdw dai driver.
1093		 */
1094		for (k = 0; k < cpu_dai_num; k++) {
1095			cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1096						  "SDW%d Pin%d", cpu_dai_id[k],
1097						  j + SDW_INTEL_BIDIR_PDI_BASE);
1098			if (!cpu_name)
1099				return -ENOMEM;
1100
1101			if (cpu_dai_index >= sdw_cpu_dai_num) {
1102				dev_err(dev, "invalid cpu dai index %d",
1103					cpu_dai_index);
1104				return -EINVAL;
1105			}
1106
1107			cpus[cpu_dai_index++].dai_name = cpu_name;
 
 
 
 
 
 
1108		}
1109
1110		/*
1111		 * We create sdw dai links at first stage, so link index should
1112		 * not be larger than sdw_be_num
1113		 */
1114		if (*link_index >= sdw_be_num) {
1115			dev_err(dev, "invalid dai link index %d", *link_index);
1116			return -EINVAL;
1117		}
1118
1119		if (*cpu_id >= sdw_cpu_dai_num) {
1120			dev_err(dev, " invalid cpu dai index %d", *cpu_id);
1121			return -EINVAL;
1122		}
1123
1124		playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
1125		capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
1126		init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
1127			      playback, capture,
1128			      cpus + *cpu_id, cpu_dai_num,
1129			      codecs, codec_num,
1130			      NULL, &sdw_ops);
1131
1132		/*
1133		 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
1134		 * based on wait_for_completion(), tag them as 'nonatomic'.
1135		 */
1136		dai_links[*link_index].nonatomic = true;
1137
1138		ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
1139					  playback, group_id);
1140		if (ret < 0) {
1141			dev_err(dev, "failed to init codec %d", codec_index);
1142			return ret;
1143		}
1144
1145		*cpu_id += cpu_dai_num;
1146		j++;
1147	}
1148
1149	return 0;
1150}
1151
1152#define IDISP_CODEC_MASK	0x4
1153
1154static int sof_card_codec_conf_alloc(struct device *dev,
1155				     struct snd_soc_acpi_mach_params *mach_params,
1156				     struct snd_soc_codec_conf **codec_conf,
1157				     int *codec_conf_count)
1158{
1159	const struct snd_soc_acpi_link_adr *adr_link;
1160	struct snd_soc_codec_conf *c_conf;
1161	int num_codecs = 0;
1162	int i;
1163
1164	adr_link = mach_params->links;
1165	if (!adr_link)
1166		return -EINVAL;
1167
1168	/* generate DAI links by each sdw link */
1169	for (; adr_link->num_adr; adr_link++) {
1170		for (i = 0; i < adr_link->num_adr; i++) {
1171			if (!adr_link->adr_d[i].name_prefix) {
1172				dev_err(dev, "codec 0x%llx does not have a name prefix\n",
1173					adr_link->adr_d[i].adr);
1174				return -EINVAL;
1175			}
1176		}
1177		num_codecs += adr_link->num_adr;
1178	}
1179
1180	c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
1181	if (!c_conf)
1182		return -ENOMEM;
 
 
 
 
1183
1184	*codec_conf = c_conf;
1185	*codec_conf_count = num_codecs;
1186
1187	return 0;
1188}
1189
1190static int sof_card_dai_links_create(struct device *dev,
1191				     struct snd_soc_acpi_mach *mach,
1192				     struct snd_soc_card *card)
1193{
1194	int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
1195	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1196	struct snd_soc_dai_link_component *idisp_components;
1197	struct snd_soc_dai_link_component *ssp_components;
1198	struct snd_soc_acpi_mach_params *mach_params;
1199	const struct snd_soc_acpi_link_adr *adr_link;
1200	struct snd_soc_dai_link_component *cpus;
1201	struct snd_soc_codec_conf *codec_conf;
1202	bool ignore_pch_dmic = false;
1203	int codec_conf_count;
1204	int codec_conf_index = 0;
1205	bool group_generated[SDW_MAX_GROUPS];
1206	int ssp_codec_index, ssp_mask;
1207	struct snd_soc_dai_link *links;
1208	int num_links, link_index = 0;
1209	char *name, *cpu_name;
1210	int total_cpu_dai_num;
1211	int sdw_cpu_dai_num;
1212	int i, j, be_id = 0;
1213	int cpu_id = 0;
1214	int comp_num;
1215	int ret;
1216
1217	mach_params = &mach->mach_params;
 
 
 
 
1218
1219	/* allocate codec conf, will be populated when dailinks are created */
1220	ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
1221	if (ret < 0)
1222		return ret;
 
 
 
 
1223
1224	/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1225	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1226		codec_info_list[i].amp_num = 0;
 
 
 
1227
1228	if (mach_params->codec_mask & IDISP_CODEC_MASK) {
1229		ctx->idisp_codec = true;
 
1230
1231		if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1232			hdmi_num = SOF_TGL_HDMI_COUNT;
1233		else
1234			hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1235	}
1236
1237	ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1238	/*
1239	 * on generic tgl platform, I2S or sdw mode is supported
1240	 * based on board rework. A ACPI device is registered in
1241	 * system only when I2S mode is supported, not sdw mode.
1242	 * Here check ACPI ID to confirm I2S is supported.
1243	 */
1244	ssp_codec_index = find_codec_info_acpi(mach->id);
1245	ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
1246	comp_num = hdmi_num + ssp_num;
 
 
 
 
 
1247
1248	ret = get_sdw_dailink_info(dev, mach_params->links,
1249				   &sdw_be_num, &sdw_cpu_dai_num);
1250	if (ret < 0) {
1251		dev_err(dev, "failed to get sdw link info %d", ret);
1252		return ret;
1253	}
1254
1255	/* enable dmic01 & dmic16k */
1256	dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
1257	comp_num += dmic_num;
 
 
 
 
 
 
 
 
 
 
 
1258
1259	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1260		comp_num++;
1261
1262	dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
1263		dmic_num, ctx->idisp_codec ? hdmi_num : 0);
 
 
 
 
 
 
 
1264
1265	/* allocate BE dailinks */
1266	num_links = comp_num + sdw_be_num;
1267	links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
 
 
 
 
1268
1269	/* allocated CPU DAIs */
1270	total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
1271	cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
1272			    GFP_KERNEL);
1273
1274	if (!links || !cpus)
1275		return -ENOMEM;
1276
1277	/* SDW */
1278	if (!sdw_be_num)
1279		goto SSP;
1280
1281	adr_link = mach_params->links;
1282	if (!adr_link)
1283		return -EINVAL;
1284
1285	/*
1286	 * SoundWire Slaves aggregated in the same group may be
1287	 * located on different hardware links. Clear array to indicate
1288	 * CPU DAIs for this group have not been generated.
1289	 */
1290	for (i = 0; i < SDW_MAX_GROUPS; i++)
1291		group_generated[i] = false;
1292
1293	/* generate DAI links by each sdw link */
1294	for (; adr_link->num_adr; adr_link++) {
1295		const struct snd_soc_acpi_endpoint *endpoint;
1296
1297		endpoint = adr_link->adr_d->endpoints;
1298		if (endpoint->aggregated && !endpoint->group_id) {
1299			dev_err(dev, "invalid group id on link %x",
1300				adr_link->mask);
1301			continue;
1302		}
1303
1304		/* this group has been generated */
1305		if (endpoint->aggregated &&
1306		    group_generated[endpoint->group_id])
1307			continue;
1308
1309		ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
1310					 sdw_cpu_dai_num, cpus, adr_link,
1311					 &cpu_id, group_generated,
1312					 codec_conf, codec_conf_count,
1313					 &be_id, &codec_conf_index,
1314					 &ignore_pch_dmic);
1315		if (ret < 0) {
1316			dev_err(dev, "failed to create dai link %d", link_index);
1317			return ret;
1318		}
1319	}
1320
1321SSP:
1322	/* SSP */
1323	if (!ssp_num)
1324		goto DMIC;
1325
1326	for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
1327		struct sof_sdw_codec_info *info;
1328		int playback, capture;
1329		char *codec_name;
1330
1331		if (!(ssp_mask & 0x1))
1332			continue;
1333
1334		name = devm_kasprintf(dev, GFP_KERNEL,
1335				      "SSP%d-Codec", i);
1336		if (!name)
1337			return -ENOMEM;
1338
1339		cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1340		if (!cpu_name)
1341			return -ENOMEM;
1342
1343		ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1344					      GFP_KERNEL);
1345		if (!ssp_components)
1346			return -ENOMEM;
1347
1348		info = &codec_info_list[ssp_codec_index];
1349		codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1350					    info->acpi_id, j++);
1351		if (!codec_name)
1352			return -ENOMEM;
1353
1354		ssp_components->name = codec_name;
1355		ssp_components->dai_name = info->dai_name;
1356		cpus[cpu_id].dai_name = cpu_name;
1357
1358		playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
1359		capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
1360		init_dai_link(dev, links + link_index, be_id, name,
1361			      playback, capture,
1362			      cpus + cpu_id, 1,
1363			      ssp_components, 1,
1364			      NULL, info->ops);
1365
1366		ret = info->init(card, NULL, links + link_index, info, 0);
1367		if (ret < 0)
1368			return ret;
1369
1370		INC_ID(be_id, cpu_id, link_index);
1371	}
1372
1373DMIC:
1374	/* dmic */
1375	if (dmic_num > 0) {
1376		if (ignore_pch_dmic) {
1377			dev_warn(dev, "Ignoring PCH DMIC\n");
1378			goto HDMI;
1379		}
1380		cpus[cpu_id].dai_name = "DMIC01 Pin";
1381		init_dai_link(dev, links + link_index, be_id, "dmic01",
1382			      0, 1, // DMIC only supports capture
1383			      cpus + cpu_id, 1,
1384			      dmic_component, 1,
1385			      sof_sdw_dmic_init, NULL);
1386		INC_ID(be_id, cpu_id, link_index);
1387
1388		cpus[cpu_id].dai_name = "DMIC16k Pin";
1389		init_dai_link(dev, links + link_index, be_id, "dmic16k",
1390			      0, 1, // DMIC only supports capture
1391			      cpus + cpu_id, 1,
1392			      dmic_component, 1,
1393			      /* don't call sof_sdw_dmic_init() twice */
1394			      NULL, NULL);
1395		INC_ID(be_id, cpu_id, link_index);
1396	}
1397
1398HDMI:
1399	/* HDMI */
1400	if (hdmi_num > 0) {
1401		idisp_components = devm_kcalloc(dev, hdmi_num,
1402						sizeof(*idisp_components),
1403						GFP_KERNEL);
1404		if (!idisp_components)
1405			return -ENOMEM;
1406	}
1407
1408	for (i = 0; i < hdmi_num; i++) {
1409		name = devm_kasprintf(dev, GFP_KERNEL,
1410				      "iDisp%d", i + 1);
1411		if (!name)
1412			return -ENOMEM;
1413
1414		if (ctx->idisp_codec) {
1415			idisp_components[i].name = "ehdaudio0D2";
1416			idisp_components[i].dai_name = devm_kasprintf(dev,
1417								      GFP_KERNEL,
1418								      "intel-hdmi-hifi%d",
1419								      i + 1);
1420			if (!idisp_components[i].dai_name)
1421				return -ENOMEM;
1422		} else {
1423			idisp_components[i].name = "snd-soc-dummy";
1424			idisp_components[i].dai_name = "snd-soc-dummy-dai";
1425		}
1426
1427		cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1428					  "iDisp%d Pin", i + 1);
1429		if (!cpu_name)
1430			return -ENOMEM;
1431
1432		cpus[cpu_id].dai_name = cpu_name;
1433		init_dai_link(dev, links + link_index, be_id, name,
1434			      1, 0, // HDMI only supports playback
1435			      cpus + cpu_id, 1,
1436			      idisp_components + i, 1,
1437			      sof_sdw_hdmi_init, NULL);
1438		INC_ID(be_id, cpu_id, link_index);
1439	}
1440
 
1441	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1442		int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1443				SOF_BT_OFFLOAD_SSP_SHIFT;
1444
1445		name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1446		if (!name)
1447			return -ENOMEM;
1448
1449		ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1450						GFP_KERNEL);
1451		if (!ssp_components)
1452			return -ENOMEM;
1453
1454		ssp_components->name = "snd-soc-dummy";
1455		ssp_components->dai_name = "snd-soc-dummy-dai";
1456
1457		cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1458		if (!cpu_name)
1459			return -ENOMEM;
1460
1461		cpus[cpu_id].dai_name = cpu_name;
1462		init_dai_link(dev, links + link_index, be_id, name, 1, 1,
1463				cpus + cpu_id, 1, ssp_components, 1, NULL, NULL);
1464	}
1465
1466	card->dai_link = links;
1467	card->num_links = num_links;
 
 
 
 
 
1468
1469	card->codec_conf = codec_conf;
1470	card->num_configs = codec_conf_count;
1471
1472	return 0;
1473}
1474
1475static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1476{
1477	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 
1478	int ret = 0;
1479	int i;
1480
1481	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1482		if (!codec_info_list[i].late_probe)
1483			continue;
1484
1485		ret = codec_info_list[i].codec_card_late_probe(card);
1486		if (ret < 0)
1487			return ret;
1488	}
1489
1490	if (ctx->idisp_codec)
1491		ret = sof_sdw_hdmi_card_late_probe(card);
1492
1493	return ret;
1494}
1495
1496/* SoC card */
1497static const char sdw_card_long_name[] = "Intel Soundwire SOF";
1498
1499static struct snd_soc_card card_sof_sdw = {
1500	.name = "soundwire",
1501	.owner = THIS_MODULE,
1502	.late_probe = sof_sdw_card_late_probe,
1503};
1504
1505static void mc_dailink_exit_loop(struct snd_soc_card *card)
1506{
1507	struct snd_soc_dai_link *link;
1508	int ret;
1509	int i, j;
1510
1511	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1512		if (!codec_info_list[i].exit)
1513			continue;
1514		/*
1515		 * We don't need to call .exit function if there is no matched
1516		 * dai link found.
1517		 */
1518		for_each_card_prelinks(card, j, link) {
1519			if (!strcmp(link->codecs[0].dai_name,
1520				    codec_info_list[i].dai_name)) {
1521				ret = codec_info_list[i].exit(card, link);
1522				if (ret)
1523					dev_warn(card->dev,
1524						 "codec exit failed %d\n",
1525						 ret);
1526				break;
1527			}
1528		}
1529	}
1530}
1531
1532static int mc_probe(struct platform_device *pdev)
1533{
1534	struct snd_soc_card *card = &card_sof_sdw;
1535	struct snd_soc_acpi_mach *mach;
1536	struct mc_private *ctx;
 
1537	int amp_num = 0, i;
1538	int ret;
1539
1540	dev_dbg(&pdev->dev, "Entry\n");
1541
 
 
 
 
1542	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1543	if (!ctx)
1544		return -ENOMEM;
1545
 
 
 
 
 
 
 
 
 
 
1546	dmi_check_system(sof_sdw_quirk_table);
1547
1548	if (quirk_override != -1) {
1549		dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
1550			 sof_sdw_quirk, quirk_override);
1551		sof_sdw_quirk = quirk_override;
1552	}
1553	log_quirks(&pdev->dev);
1554
1555	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
1556
1557	card->dev = &pdev->dev;
1558	snd_soc_card_set_drvdata(card, ctx);
 
 
 
 
 
 
 
 
1559
1560	mach = pdev->dev.platform_data;
1561	ret = sof_card_dai_links_create(&pdev->dev, mach,
1562					card);
1563	if (ret < 0)
1564		return ret;
1565
1566	/*
1567	 * the default amp_num is zero for each codec and
1568	 * amp_num will only be increased for active amp
1569	 * codecs on used platform
1570	 */
1571	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1572		amp_num += codec_info_list[i].amp_num;
1573
1574	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1575					  "cfg-spk:%d cfg-amp:%d",
1576					  (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
1577					  ? 4 : 2, amp_num);
1578	if (!card->components)
1579		return -ENOMEM;
1580
1581	if (mach->mach_params.dmic_num) {
1582		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1583						  "%s mic:dmic cfg-mics:%d",
1584						  card->components,
1585						  mach->mach_params.dmic_num);
1586		if (!card->components)
1587			return -ENOMEM;
1588	}
1589
1590	card->long_name = sdw_card_long_name;
1591
1592	/* Register the card */
1593	ret = devm_snd_soc_register_card(&pdev->dev, card);
1594	if (ret) {
1595		dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
1596		mc_dailink_exit_loop(card);
1597		return ret;
1598	}
1599
1600	platform_set_drvdata(pdev, card);
1601
1602	return ret;
1603}
1604
1605static int mc_remove(struct platform_device *pdev)
1606{
1607	struct snd_soc_card *card = platform_get_drvdata(pdev);
1608
1609	mc_dailink_exit_loop(card);
 
1610
1611	return 0;
1612}
 
 
 
1613
1614static struct platform_driver sof_sdw_driver = {
1615	.driver = {
1616		.name = "sof_sdw",
1617		.pm = &snd_soc_pm_ops,
1618	},
1619	.probe = mc_probe,
1620	.remove = mc_remove,
 
1621};
1622
1623module_platform_driver(sof_sdw_driver);
1624
1625MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1626MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1627MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1628MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1629MODULE_LICENSE("GPL v2");
1630MODULE_ALIAS("platform:sof_sdw");
1631MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
1632MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);