Linux Audio

Check our new training course

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.8
   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
 
 
  23static void log_quirks(struct device *dev)
  24{
  25	if (SOF_JACK_JDSRC(sof_sdw_quirk))
  26		dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
  27			SOF_JACK_JDSRC(sof_sdw_quirk));
  28	if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
  29		dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n");
  30	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
  31		dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
  32	if (sof_sdw_quirk & SOF_SDW_PCH_DMIC)
  33		dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n");
  34	if (SOF_SSP_GET_PORT(sof_sdw_quirk))
  35		dev_dbg(dev, "SSP port %ld\n",
  36			SOF_SSP_GET_PORT(sof_sdw_quirk));
  37	if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
  38		dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
 
 
 
 
  39}
  40
  41static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
  42{
  43	sof_sdw_quirk = (unsigned long)id->driver_data;
  44	return 1;
  45}
  46
  47static const struct dmi_system_id sof_sdw_quirk_table[] = {
  48	/* CometLake devices */
  49	{
  50		.callback = sof_sdw_quirk_cb,
  51		.matches = {
  52			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  53			DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
  54		},
  55		.driver_data = (void *)SOF_SDW_PCH_DMIC,
  56	},
  57	{
  58		.callback = sof_sdw_quirk_cb,
  59		.matches = {
  60			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  61			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
  62		},
  63		.driver_data = (void *)RT711_JD2,
  64	},
  65	{
  66		/* early version of SKU 09C6 */
  67		.callback = sof_sdw_quirk_cb,
  68		.matches = {
  69			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  70			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
  71		},
  72		.driver_data = (void *)RT711_JD2,
  73	},
  74	{
  75		.callback = sof_sdw_quirk_cb,
  76		.matches = {
  77			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  78			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
  79		},
  80		.driver_data = (void *)(RT711_JD2 |
  81					SOF_SDW_FOUR_SPK),
  82	},
  83	{
  84		.callback = sof_sdw_quirk_cb,
  85		.matches = {
  86			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
  87			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
  88		},
  89		.driver_data = (void *)(RT711_JD2 |
  90					SOF_SDW_FOUR_SPK),
  91	},
  92	/* IceLake devices */
  93	{
  94		.callback = sof_sdw_quirk_cb,
  95		.matches = {
  96			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  97			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
  98		},
  99		.driver_data = (void *)SOF_SDW_PCH_DMIC,
 100	},
 101	/* TigerLake devices */
 102	{
 103		.callback = sof_sdw_quirk_cb,
 104		.matches = {
 105			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 106			DMI_MATCH(DMI_PRODUCT_NAME,
 107				  "Tiger Lake Client Platform"),
 108		},
 109		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 110					RT711_JD1 |
 111					SOF_SDW_PCH_DMIC |
 112					SOF_SSP_PORT(SOF_I2S_SSP2)),
 113	},
 114	{
 115		.callback = sof_sdw_quirk_cb,
 116		.matches = {
 117			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 118			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
 119		},
 120		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 121					RT711_JD2),
 122	},
 123	{
 124		/* another SKU of Dell Latitude 9520 */
 125		.callback = sof_sdw_quirk_cb,
 126		.matches = {
 127			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 128			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
 129		},
 130		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 131					RT711_JD2),
 132	},
 133	{
 134		/* Dell XPS 9710 */
 135		.callback = sof_sdw_quirk_cb,
 136		.matches = {
 137			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 138			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
 139		},
 140		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 141					RT711_JD2 |
 142					SOF_SDW_FOUR_SPK),
 143	},
 144	{
 145		.callback = sof_sdw_quirk_cb,
 146		.matches = {
 147			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 148			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
 149		},
 150		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 151					RT711_JD2 |
 152					SOF_SDW_FOUR_SPK),
 153	},
 154	{
 155		.callback = sof_sdw_quirk_cb,
 156		.matches = {
 157			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 158			DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
 159		},
 160		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 161					SOF_SDW_PCH_DMIC |
 162					SOF_SDW_FOUR_SPK |
 163					SOF_BT_OFFLOAD_SSP(2) |
 164					SOF_SSP_BT_OFFLOAD_PRESENT),
 165	},
 166	{
 167		.callback = sof_sdw_quirk_cb,
 168		.matches = {
 169			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 170			DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
 171		},
 172		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 173					SOF_SDW_PCH_DMIC |
 174					SOF_SDW_FOUR_SPK),
 175	},
 176	{
 177		/*
 178		 * this entry covers multiple HP SKUs. The family name
 179		 * does not seem robust enough, so we use a partial
 180		 * match that ignores the product name suffix
 181		 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
 182		 */
 183		.callback = sof_sdw_quirk_cb,
 184		.matches = {
 185			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 186			DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
 187		},
 188		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 189					SOF_SDW_PCH_DMIC |
 190					RT711_JD1),
 191	},
 192	{
 193		/*
 194		 * this entry covers HP Spectre x360 where the DMI information
 195		 * changed somehow
 196		 */
 197		.callback = sof_sdw_quirk_cb,
 198		.matches = {
 199			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 200			DMI_MATCH(DMI_BOARD_NAME, "8709"),
 201		},
 202		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 203					SOF_SDW_PCH_DMIC |
 204					RT711_JD1),
 205	},
 206	{
 207		/* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
 208		.callback = sof_sdw_quirk_cb,
 209		.matches = {
 210			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 211			DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
 212		},
 213		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 214					SOF_SDW_PCH_DMIC |
 215					RT711_JD1),
 216	},
 217	{
 218		/* NUC15 LAPBC710 skews */
 219		.callback = sof_sdw_quirk_cb,
 220		.matches = {
 221			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 222			DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
 223		},
 224		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 225					SOF_SDW_PCH_DMIC |
 226					RT711_JD1),
 227	},
 228	{
 229		/* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
 230		.callback = sof_sdw_quirk_cb,
 231		.matches = {
 232			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 233			DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
 234		},
 235		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 236					SOF_SDW_PCH_DMIC |
 
 
 
 
 
 
 
 
 
 
 
 237					RT711_JD2_100K),
 238	},
 239	/* TigerLake-SDCA devices */
 240	{
 241		.callback = sof_sdw_quirk_cb,
 242		.matches = {
 243			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 244			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
 245		},
 246		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 247					RT711_JD2 |
 248					SOF_SDW_FOUR_SPK),
 249	},
 250	{
 251		.callback = sof_sdw_quirk_cb,
 252		.matches = {
 253			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 254			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
 255		},
 256		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 257					RT711_JD2),
 258	},
 259	/* AlderLake devices */
 260	{
 261		.callback = sof_sdw_quirk_cb,
 262		.matches = {
 263			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 264			DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
 265		},
 266		.driver_data = (void *)(RT711_JD2_100K |
 267					SOF_SDW_TGL_HDMI |
 268					SOF_BT_OFFLOAD_SSP(2) |
 269					SOF_SSP_BT_OFFLOAD_PRESENT),
 270	},
 271	{
 272		.callback = sof_sdw_quirk_cb,
 273		.matches = {
 
 
 
 
 
 
 
 
 
 274			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 275			DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
 276		},
 277		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 278					SOF_SDW_PCH_DMIC |
 279					SOF_SDW_FOUR_SPK |
 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_SYS_VENDOR, "Dell Inc"),
 287			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
 288		},
 289		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 290					RT711_JD2 |
 291					SOF_SDW_FOUR_SPK),
 292	},
 293	{
 294		.callback = sof_sdw_quirk_cb,
 295		.matches = {
 296			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 297			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
 298		},
 299		/* No Jack */
 300		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 301					SOF_SDW_FOUR_SPK),
 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, "0AFE")
 308		},
 309		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 310					RT711_JD2 |
 311					SOF_SDW_FOUR_SPK),
 312	},
 313	{
 314		.callback = sof_sdw_quirk_cb,
 315		.matches = {
 316			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 317			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
 318		},
 319		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 320					RT711_JD2 |
 321					SOF_SDW_FOUR_SPK),
 322	},
 323	{
 324		.callback = sof_sdw_quirk_cb,
 325		.matches = {
 326			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 327			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
 328		},
 329		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 330					RT711_JD2 |
 331					SOF_SDW_FOUR_SPK),
 332	},
 333	{
 334		.callback = sof_sdw_quirk_cb,
 335		.matches = {
 336			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 337			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
 338		},
 339		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 340					RT711_JD2 |
 341					SOF_SDW_FOUR_SPK),
 342	},
 343	{
 344		.callback = sof_sdw_quirk_cb,
 345		.matches = {
 346			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 347			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
 348		},
 349		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 350					RT711_JD2 |
 351					SOF_SDW_FOUR_SPK),
 352	},
 353	{
 354		.callback = sof_sdw_quirk_cb,
 355		.matches = {
 356			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 357			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
 358		},
 359		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 360					RT711_JD2 |
 361					SOF_SDW_FOUR_SPK),
 362	},
 363	{
 364		.callback = sof_sdw_quirk_cb,
 365		.matches = {
 366			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 367			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
 368		},
 369		/* No Jack */
 370		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 371	},
 372	{
 373		.callback = sof_sdw_quirk_cb,
 374		.matches = {
 375			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 376			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
 377		},
 378		/* No Jack */
 379		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 380	},
 381
 382	{
 383		.callback = sof_sdw_quirk_cb,
 384		.matches = {
 385			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 386			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
 387		},
 388		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 389					RT711_JD2 |
 390					SOF_SDW_FOUR_SPK),
 391	},
 392	{
 393		.callback = sof_sdw_quirk_cb,
 394		.matches = {
 395			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 396			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"),
 397		},
 398		/* No Jack */
 399		.driver_data = (void *)SOF_SDW_TGL_HDMI,
 400	},
 401	{
 402		.callback = sof_sdw_quirk_cb,
 403		.matches = {
 
 
 
 
 
 
 
 
 
 404			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 405			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"),
 406		},
 407		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 408					RT711_JD2),
 409	},
 410	/* RaptorLake devices */
 411	{
 412		.callback = sof_sdw_quirk_cb,
 413		.matches = {
 414			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 415			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")
 416		},
 417		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 418					RT711_JD2 |
 419					SOF_SDW_FOUR_SPK),
 
 
 
 
 
 
 
 
 420	},
 421	{
 422		.callback = sof_sdw_quirk_cb,
 423		.matches = {
 424			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 425			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
 426		},
 427		/* No Jack */
 428		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 429					SOF_SDW_FOUR_SPK),
 430	},
 431	{
 432		.callback = sof_sdw_quirk_cb,
 433		.matches = {
 434			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 435			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
 436		},
 437		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 438					RT711_JD2 |
 439					SOF_SDW_FOUR_SPK),
 440	},
 441	{
 442		.callback = sof_sdw_quirk_cb,
 443		.matches = {
 444			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 445			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
 446		},
 447		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 448					RT711_JD2 |
 449					SOF_SDW_FOUR_SPK),
 450	},
 451	{
 452		.callback = sof_sdw_quirk_cb,
 453		.matches = {
 454			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 455			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
 456		},
 457		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
 458					RT711_JD2 |
 459					SOF_SDW_FOUR_SPK),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 460	},
 461	/* MeteorLake devices */
 462	{
 463		.callback = sof_sdw_quirk_cb,
 464		.matches = {
 465			DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
 466		},
 467		.driver_data = (void *)(RT711_JD1),
 468	},
 469	{
 470		.callback = sof_sdw_quirk_cb,
 471		.matches = {
 472			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 473			DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"),
 474		},
 475		.driver_data = (void *)(RT711_JD2_100K),
 476	},
 477	{
 478		.callback = sof_sdw_quirk_cb,
 479		.matches = {
 480			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 481			DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
 482		},
 483		.driver_data = (void *)(SOF_SDW_PCH_DMIC |
 484					SOF_BT_OFFLOAD_SSP(1) |
 485					SOF_SSP_BT_OFFLOAD_PRESENT),
 486	},
 
 
 
 
 
 
 
 
 
 487	/* LunarLake devices */
 488	{
 489		.callback = sof_sdw_quirk_cb,
 490		.matches = {
 491			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 492			DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
 493		},
 494		.driver_data = (void *)(RT711_JD2),
 495	},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 496	{}
 497};
 498
 499static struct snd_soc_dai_link_component platform_component[] = {
 500	{
 501		/* name might be overridden during probe */
 502		.name = "0000:00:1f.3"
 503	}
 504};
 505
 506/* these wrappers are only needed to avoid typecast compilation errors */
 507int sdw_startup(struct snd_pcm_substream *substream)
 508{
 509	return sdw_startup_stream(substream);
 510}
 
 
 
 511
 512int sdw_prepare(struct snd_pcm_substream *substream)
 513{
 514	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 515	struct sdw_stream_runtime *sdw_stream;
 516	struct snd_soc_dai *dai;
 517
 518	/* Find stream from first CPU DAI */
 519	dai = snd_soc_rtd_to_cpu(rtd, 0);
 520
 521	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 522	if (IS_ERR(sdw_stream)) {
 523		dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
 524		return PTR_ERR(sdw_stream);
 525	}
 526
 527	return sdw_prepare_stream(sdw_stream);
 528}
 529
 530int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
 531{
 532	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 533	struct sdw_stream_runtime *sdw_stream;
 534	struct snd_soc_dai *dai;
 
 
 535	int ret;
 536
 537	/* Find stream from first CPU DAI */
 538	dai = snd_soc_rtd_to_cpu(rtd, 0);
 
 
 
 
 539
 540	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 541	if (IS_ERR(sdw_stream)) {
 542		dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
 543		return PTR_ERR(sdw_stream);
 
 544	}
 545
 546	switch (cmd) {
 547	case SNDRV_PCM_TRIGGER_START:
 548	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 549	case SNDRV_PCM_TRIGGER_RESUME:
 550		ret = sdw_enable_stream(sdw_stream);
 551		break;
 552
 553	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 554	case SNDRV_PCM_TRIGGER_SUSPEND:
 555	case SNDRV_PCM_TRIGGER_STOP:
 556		ret = sdw_disable_stream(sdw_stream);
 557		break;
 558	default:
 559		ret = -EINVAL;
 560		break;
 561	}
 562
 563	if (ret)
 564		dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
 565
 566	return ret;
 567}
 568
 569int sdw_hw_params(struct snd_pcm_substream *substream,
 570		  struct snd_pcm_hw_params *params)
 571{
 572	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 573	struct snd_soc_dai_link_ch_map *ch_maps;
 574	int ch = params_channels(params);
 575	unsigned int ch_mask;
 576	int num_codecs;
 577	int step;
 578	int i;
 579
 580	if (!rtd->dai_link->ch_maps)
 581		return 0;
 582
 583	/* Identical data will be sent to all codecs in playback */
 584	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 585		ch_mask = GENMASK(ch - 1, 0);
 586		step = 0;
 587	} else {
 588		num_codecs = rtd->dai_link->num_codecs;
 589
 590		if (ch < num_codecs || ch % num_codecs != 0) {
 591			dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
 592				ch, num_codecs);
 593			return -EINVAL;
 594		}
 595
 596		ch_mask = GENMASK(ch / num_codecs - 1, 0);
 597		step = hweight_long(ch_mask);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 598
 599	}
 
 
 600
 601	/*
 602	 * The captured data will be combined from each cpu DAI if the dai
 603	 * link has more than one codec DAIs. Set codec channel mask and
 604	 * ASoC will set the corresponding channel numbers for each cpu dai.
 605	 */
 606	for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
 607		ch_maps->ch_mask = ch_mask << (i * step);
 608
 609	return 0;
 610}
 
 611
 612int sdw_hw_free(struct snd_pcm_substream *substream)
 613{
 614	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 615	struct sdw_stream_runtime *sdw_stream;
 616	struct snd_soc_dai *dai;
 617
 618	/* Find stream from first CPU DAI */
 619	dai = snd_soc_rtd_to_cpu(rtd, 0);
 620
 621	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
 622	if (IS_ERR(sdw_stream)) {
 623		dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
 624		return PTR_ERR(sdw_stream);
 625	}
 626
 627	return sdw_deprepare_stream(sdw_stream);
 628}
 629
 630void sdw_shutdown(struct snd_pcm_substream *substream)
 631{
 632	sdw_shutdown_stream(substream);
 633}
 634
 635static const struct snd_soc_ops sdw_ops = {
 636	.startup = sdw_startup,
 637	.prepare = sdw_prepare,
 638	.trigger = sdw_trigger,
 639	.hw_params = sdw_hw_params,
 640	.hw_free = sdw_hw_free,
 641	.shutdown = sdw_shutdown,
 642};
 643
 644static struct sof_sdw_codec_info codec_info_list[] = {
 645	{
 646		.part_id = 0x700,
 647		.dais = {
 648			{
 649				.direction = {true, true},
 650				.dai_name = "rt700-aif1",
 651				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 652				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 653				.init = sof_sdw_rt700_init,
 654			},
 655		},
 656		.dai_num = 1,
 657	},
 658	{
 659		.part_id = 0x711,
 660		.version_id = 3,
 661		.dais = {
 662			{
 663				.direction = {true, true},
 664				.dai_name = "rt711-sdca-aif1",
 665				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 666				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 667				.init = sof_sdw_rt_sdca_jack_init,
 668				.exit = sof_sdw_rt_sdca_jack_exit,
 669			},
 670		},
 671		.dai_num = 1,
 672	},
 673	{
 674		.part_id = 0x711,
 675		.version_id = 2,
 676		.dais = {
 677			{
 678				.direction = {true, true},
 679				.dai_name = "rt711-aif1",
 680				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 681				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 682				.init = sof_sdw_rt711_init,
 683				.exit = sof_sdw_rt711_exit,
 684			},
 685		},
 686		.dai_num = 1,
 687	},
 688	{
 689		.part_id = 0x712,
 690		.version_id = 3,
 691		.dais =	{
 692			{
 693				.direction = {true, true},
 694				.dai_name = "rt712-sdca-aif1",
 695				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 696				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 697				.init = sof_sdw_rt_sdca_jack_init,
 698				.exit = sof_sdw_rt_sdca_jack_exit,
 699			},
 700			{
 701				.direction = {true, false},
 702				.dai_name = "rt712-sdca-aif2",
 703				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 704				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 705				.init = sof_sdw_rt712_spk_init,
 706			},
 707		},
 708		.dai_num = 2,
 709	},
 710	{
 711		.part_id = 0x1712,
 712		.version_id = 3,
 713		.dais =	{
 714			{
 715				.direction = {false, true},
 716				.dai_name = "rt712-sdca-dmic-aif1",
 717				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 718				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 719				.init = sof_sdw_rt712_sdca_dmic_init,
 720			},
 721		},
 722		.dai_num = 1,
 723	},
 724	{
 725		.part_id = 0x713,
 726		.version_id = 3,
 727		.dais =	{
 728			{
 729				.direction = {true, true},
 730				.dai_name = "rt712-sdca-aif1",
 731				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 732				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 733				.init = sof_sdw_rt_sdca_jack_init,
 734				.exit = sof_sdw_rt_sdca_jack_exit,
 735			},
 736		},
 737		.dai_num = 1,
 738	},
 739	{
 740		.part_id = 0x1713,
 741		.version_id = 3,
 742		.dais =	{
 743			{
 744				.direction = {false, true},
 745				.dai_name = "rt712-sdca-dmic-aif1",
 746				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 747				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 748				.init = sof_sdw_rt712_sdca_dmic_init,
 749			},
 750		},
 751		.dai_num = 1,
 752	},
 753	{
 754		.part_id = 0x1308,
 755		.acpi_id = "10EC1308",
 756		.dais = {
 757			{
 758				.direction = {true, false},
 759				.dai_name = "rt1308-aif",
 760				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 761				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 762				.init = sof_sdw_rt_amp_init,
 763				.exit = sof_sdw_rt_amp_exit,
 764			},
 765		},
 766		.dai_num = 1,
 767		.ops = &sof_sdw_rt1308_i2s_ops,
 768	},
 769	{
 770		.part_id = 0x1316,
 771		.dais = {
 772			{
 773				.direction = {true, true},
 774				.dai_name = "rt1316-aif",
 775				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 776				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
 777				.init = sof_sdw_rt_amp_init,
 778				.exit = sof_sdw_rt_amp_exit,
 779			},
 780		},
 781		.dai_num = 1,
 782	},
 783	{
 784		.part_id = 0x1318,
 785		.dais = {
 786			{
 787				.direction = {true, true},
 788				.dai_name = "rt1318-aif",
 789				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 790				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
 791				.init = sof_sdw_rt_amp_init,
 792				.exit = sof_sdw_rt_amp_exit,
 793			},
 794		},
 795		.dai_num = 1,
 796	},
 797	{
 798		.part_id = 0x714,
 799		.version_id = 3,
 800		.ignore_pch_dmic = true,
 801		.dais = {
 802			{
 803				.direction = {false, true},
 804				.dai_name = "rt715-aif2",
 805				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 806				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 807				.init = sof_sdw_rt715_sdca_init,
 808			},
 809		},
 810		.dai_num = 1,
 811	},
 812	{
 813		.part_id = 0x715,
 814		.version_id = 3,
 815		.ignore_pch_dmic = true,
 816		.dais = {
 817			{
 818				.direction = {false, true},
 819				.dai_name = "rt715-aif2",
 820				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 821				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 822				.init = sof_sdw_rt715_sdca_init,
 823			},
 824		},
 825		.dai_num = 1,
 826	},
 827	{
 828		.part_id = 0x714,
 829		.version_id = 2,
 830		.ignore_pch_dmic = true,
 831		.dais = {
 832			{
 833				.direction = {false, true},
 834				.dai_name = "rt715-aif2",
 835				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 836				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 837				.init = sof_sdw_rt715_init,
 838			},
 839		},
 840		.dai_num = 1,
 841	},
 842	{
 843		.part_id = 0x715,
 844		.version_id = 2,
 845		.ignore_pch_dmic = true,
 846		.dais = {
 847			{
 848				.direction = {false, true},
 849				.dai_name = "rt715-aif2",
 850				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 851				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 852				.init = sof_sdw_rt715_init,
 853			},
 854		},
 855		.dai_num = 1,
 856	},
 857	{
 858		.part_id = 0x722,
 859		.version_id = 3,
 860		.dais = {
 861			{
 862				.direction = {true, true},
 863				.dai_name = "rt722-sdca-aif1",
 864				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 865				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 866				.init = sof_sdw_rt_sdca_jack_init,
 867				.exit = sof_sdw_rt_sdca_jack_exit,
 868			},
 869			{
 870				.direction = {true, false},
 871				.dai_name = "rt722-sdca-aif2",
 872				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 873				/* No feedback capability is provided by rt722-sdca codec driver*/
 874				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 875				.init = sof_sdw_rt722_spk_init,
 876			},
 877			{
 878				.direction = {false, true},
 879				.dai_name = "rt722-sdca-aif3",
 880				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 881				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 882				.init = sof_sdw_rt722_sdca_dmic_init,
 883			},
 884		},
 885		.dai_num = 3,
 886	},
 887	{
 888		.part_id = 0x8373,
 889		.dais = {
 890			{
 891				.direction = {true, true},
 892				.dai_name = "max98373-aif1",
 893				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 894				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
 895				.init = sof_sdw_maxim_init,
 896			},
 897		},
 898		.dai_num = 1,
 899	},
 900	{
 901		.part_id = 0x8363,
 902		.dais = {
 903			{
 904				.direction = {true, false},
 905				.dai_name = "max98363-aif1",
 906				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 907				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 908				.init = sof_sdw_maxim_init,
 909			},
 910		},
 911		.dai_num = 1,
 912	},
 913	{
 914		.part_id = 0x5682,
 915		.dais = {
 916			{
 917				.direction = {true, true},
 918				.dai_name = "rt5682-sdw",
 919				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 920				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 921				.init = sof_sdw_rt5682_init,
 922			},
 923		},
 924		.dai_num = 1,
 925	},
 926	{
 927		.part_id = 0x3556,
 928		.dais = {
 929			{
 930				.direction = {true, true},
 931				.dai_name = "cs35l56-sdw1",
 932				.dai_type = SOF_SDW_DAI_TYPE_AMP,
 933				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
 934				.init = sof_sdw_cs_amp_init,
 935			},
 936		},
 937		.dai_num = 1,
 938	},
 939	{
 940		.part_id = 0x4242,
 941		.dais = {
 942			{
 943				.direction = {true, true},
 944				.dai_name = "cs42l42-sdw",
 945				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 946				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 947				.init = sof_sdw_cs42l42_init,
 948			},
 949		},
 950		.dai_num = 1,
 951	},
 952	{
 953		.part_id = 0x4243,
 954		.codec_name = "cs42l43-codec",
 955		.dais = {
 956			{
 957				.direction = {true, false},
 958				.dai_name = "cs42l43-dp5",
 959				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 960				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
 961				.init = sof_sdw_cs42l43_hs_init,
 962			},
 963			{
 964				.direction = {false, true},
 965				.dai_name = "cs42l43-dp1",
 966				.dai_type = SOF_SDW_DAI_TYPE_MIC,
 967				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
 968				.init = sof_sdw_cs42l43_dmic_init,
 969			},
 970			{
 971				.direction = {false, true},
 972				.dai_name = "cs42l43-dp2",
 973				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 974				.dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID},
 975			},
 976		},
 977		.dai_num = 3,
 978	},
 979	{
 980		.part_id = 0xaaaa, /* generic codec mockup */
 981		.version_id = 0,
 982		.dais = {
 983			{
 984				.direction = {true, true},
 985				.dai_name = "sdw-mockup-aif1",
 986				.dai_type = SOF_SDW_DAI_TYPE_JACK,
 987				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
 988				.init = NULL,
 989			},
 990		},
 991		.dai_num = 1,
 992	},
 993	{
 994		.part_id = 0xaa55, /* headset codec mockup */
 995		.version_id = 0,
 996		.dais = {
 997			{
 998				.direction = {true, true},
 999				.dai_name = "sdw-mockup-aif1",
1000				.dai_type = SOF_SDW_DAI_TYPE_JACK,
1001				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
1002				.init = NULL,
1003			},
1004		},
1005		.dai_num = 1,
1006	},
1007	{
1008		.part_id = 0x55aa, /* amplifier mockup */
1009		.version_id = 0,
1010		.dais = {
1011			{
1012				.direction = {true, true},
1013				.dai_name = "sdw-mockup-aif1",
1014				.dai_type = SOF_SDW_DAI_TYPE_AMP,
1015				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
1016				.init = NULL,
1017			},
1018		},
1019		.dai_num = 1,
1020	},
1021	{
1022		.part_id = 0x5555,
1023		.version_id = 0,
1024		.dais = {
1025			{
1026				.dai_name = "sdw-mockup-aif1",
1027				.direction = {false, true},
1028				.dai_type = SOF_SDW_DAI_TYPE_MIC,
1029				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
1030				.init = NULL,
1031			},
1032		},
1033		.dai_num = 1,
1034	},
1035};
1036
1037static inline int find_codec_info_part(const u64 adr)
1038{
1039	unsigned int part_id, sdw_version;
1040	int i;
1041
1042	part_id = SDW_PART_ID(adr);
1043	sdw_version = SDW_VERSION(adr);
1044	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1045		/*
1046		 * A codec info is for all sdw version with the part id if
1047		 * version_id is not specified in the codec info.
1048		 */
1049		if (part_id == codec_info_list[i].part_id &&
1050		    (!codec_info_list[i].version_id ||
1051		     sdw_version == codec_info_list[i].version_id))
1052			return i;
1053
1054	return -EINVAL;
 
 
 
 
 
1055
1056}
 
1057
1058static inline int find_codec_info_acpi(const u8 *acpi_id)
1059{
1060	int i;
1061
1062	if (!acpi_id[0])
1063		return -EINVAL;
1064
1065	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1066		if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
1067			return i;
1068
1069	return -EINVAL;
1070}
1071
1072/*
1073 * get BE dailink number and CPU DAI number based on sdw link adr.
1074 * Since some sdw slaves may be aggregated, the CPU DAI number
1075 * may be larger than the number of BE dailinks.
1076 */
1077static int get_dailink_info(struct device *dev,
1078			    const struct snd_soc_acpi_link_adr *adr_link,
1079			    int *sdw_be_num, int *codecs_num)
1080{
1081	bool group_visited[SDW_MAX_GROUPS];
1082	bool no_aggregation;
1083	int i;
1084	int j;
1085
1086	no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
1087	*sdw_be_num  = 0;
1088
1089	if (!adr_link)
1090		return -EINVAL;
1091
1092	for (i = 0; i < SDW_MAX_GROUPS; i++)
1093		group_visited[i] = false;
1094
1095	for (; adr_link->num_adr; adr_link++) {
1096		const struct snd_soc_acpi_endpoint *endpoint;
1097		struct sof_sdw_codec_info *codec_info;
1098		int codec_index;
1099		int stream;
1100		u64 adr;
1101
1102		/* make sure the link mask has a single bit set */
1103		if (!is_power_of_2(adr_link->mask))
1104			return -EINVAL;
1105
1106		for (i = 0; i < adr_link->num_adr; i++) {
1107			adr = adr_link->adr_d[i].adr;
1108			codec_index = find_codec_info_part(adr);
1109			if (codec_index < 0)
1110				return codec_index;
1111
1112			codec_info = &codec_info_list[codec_index];
1113
1114			*codecs_num += codec_info->dai_num;
1115
1116			if (!adr_link->adr_d[i].name_prefix) {
1117				dev_err(dev, "codec 0x%llx does not have a name prefix\n",
1118					adr_link->adr_d[i].adr);
1119				return -EINVAL;
1120			}
1121
1122			endpoint = adr_link->adr_d[i].endpoints;
1123			if (endpoint->aggregated && !endpoint->group_id) {
1124				dev_err(dev, "invalid group id on link %x\n",
1125					adr_link->mask);
1126				return -EINVAL;
1127			}
1128
1129			for (j = 0; j < codec_info->dai_num; j++) {
1130				/* count DAI number for playback and capture */
1131				for_each_pcm_streams(stream) {
1132					if (!codec_info->dais[j].direction[stream])
1133						continue;
1134
1135					/* count BE for each non-aggregated slave or group */
1136					if (!endpoint->aggregated || no_aggregation ||
1137					    !group_visited[endpoint->group_id])
1138						(*sdw_be_num)++;
1139				}
1140			}
1141
1142			if (endpoint->aggregated)
1143				group_visited[endpoint->group_id] = true;
1144		}
1145	}
1146
1147	return 0;
1148}
1149
1150static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1151			  int *be_id, char *name, int playback, int capture,
1152			  struct snd_soc_dai_link_component *cpus, int cpus_num,
1153			  struct snd_soc_dai_link_component *codecs, int codecs_num,
1154			  int (*init)(struct snd_soc_pcm_runtime *rtd),
1155			  const struct snd_soc_ops *ops)
1156{
1157	dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id);
1158	dai_links->id = (*be_id)++;
1159	dai_links->name = name;
1160	dai_links->platforms = platform_component;
1161	dai_links->num_platforms = ARRAY_SIZE(platform_component);
1162	dai_links->no_pcm = 1;
1163	dai_links->cpus = cpus;
1164	dai_links->num_cpus = cpus_num;
1165	dai_links->codecs = codecs;
1166	dai_links->num_codecs = codecs_num;
1167	dai_links->dpcm_playback = playback;
1168	dai_links->dpcm_capture = capture;
1169	dai_links->init = init;
1170	dai_links->ops = ops;
1171}
1172
1173static int init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1174				int *be_id, char *name, int playback, int capture,
1175				const char *cpu_dai_name,
1176				const char *codec_name, const char *codec_dai_name,
1177				int (*init)(struct snd_soc_pcm_runtime *rtd),
1178				const struct snd_soc_ops *ops)
1179{
1180	struct snd_soc_dai_link_component *dlc;
1181
1182	/* Allocate two DLCs one for the CPU, one for the CODEC */
1183	dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL);
1184	if (!dlc || !name || !cpu_dai_name || !codec_name || !codec_dai_name)
1185		return -ENOMEM;
1186
1187	dlc[0].dai_name = cpu_dai_name;
 
 
 
 
 
 
 
1188
1189	dlc[1].name = codec_name;
1190	dlc[1].dai_name = codec_dai_name;
 
1191
1192	init_dai_link(dev, dai_links, be_id, name, playback, capture,
1193		      &dlc[0], 1, &dlc[1], 1, init, ops);
1194
1195	return 0;
1196}
1197
1198static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
1199			     unsigned int sdw_version,
1200			     unsigned int mfg_id,
1201			     unsigned int part_id,
1202			     unsigned int class_id,
1203			     int index_in_link)
1204{
1205	int i;
 
1206
1207	for (i = 0; i < adr_link->num_adr; i++) {
1208		unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
1209		u64 adr;
 
 
 
 
 
1210
1211		/* skip itself */
1212		if (i == index_in_link)
1213			continue;
1214
1215		adr = adr_link->adr_d[i].adr;
 
 
 
 
 
 
 
 
1216
1217		sdw1_version = SDW_VERSION(adr);
1218		mfg1_id = SDW_MFG_ID(adr);
1219		part1_id = SDW_PART_ID(adr);
1220		class1_id = SDW_CLASS_ID(adr);
1221
1222		if (sdw_version == sdw1_version &&
1223		    mfg_id == mfg1_id &&
1224		    part_id == part1_id &&
1225		    class_id == class1_id)
1226			return false;
1227	}
1228
1229	return true;
1230}
1231
1232static int fill_sdw_codec_dlc(struct device *dev,
1233			      const struct snd_soc_acpi_link_adr *adr_link,
1234			      struct snd_soc_dai_link_component *codec,
1235			      int adr_index, int dai_index)
1236{
1237	unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id;
1238	u64 adr = adr_link->adr_d[adr_index].adr;
1239	int codec_index;
1240
1241	codec_index = find_codec_info_part(adr);
1242	if (codec_index < 0)
1243		return codec_index;
1244
1245	sdw_version = SDW_VERSION(adr);
1246	link_id = SDW_DISCO_LINK_ID(adr);
1247	unique_id = SDW_UNIQUE_ID(adr);
1248	mfg_id = SDW_MFG_ID(adr);
1249	part_id = SDW_PART_ID(adr);
1250	class_id = SDW_CLASS_ID(adr);
1251
1252	if (codec_info_list[codec_index].codec_name)
1253		codec->name = devm_kstrdup(dev,
1254					   codec_info_list[codec_index].codec_name,
1255					   GFP_KERNEL);
1256	else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
1257				  class_id, adr_index))
1258		codec->name = devm_kasprintf(dev, GFP_KERNEL,
1259					     "sdw:0:%01x:%04x:%04x:%02x", link_id,
1260					     mfg_id, part_id, class_id);
1261	else
1262		codec->name = devm_kasprintf(dev, GFP_KERNEL,
1263					     "sdw:0:%01x:%04x:%04x:%02x:%01x", link_id,
1264					     mfg_id, part_id, class_id, unique_id);
1265
1266	if (!codec->name)
1267		return -ENOMEM;
1268
1269	codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name;
1270
1271	return 0;
1272}
1273
1274static int set_codec_init_func(struct snd_soc_card *card,
1275			       const struct snd_soc_acpi_link_adr *adr_link,
1276			       struct snd_soc_dai_link *dai_links,
1277			       bool playback, int group_id, int adr_index, int dai_index)
1278{
1279	int i = adr_index;
 
 
 
1280
1281	do {
1282		/*
1283		 * Initialize the codec. If codec is part of an aggregated
1284		 * group (group_id>0), initialize all codecs belonging to
1285		 * same group.
1286		 * The first link should start with adr_link->adr_d[adr_index]
1287		 * because that is the device that we want to initialize and
1288		 * we should end immediately if it is not aggregated (group_id=0)
1289		 */
1290		for ( ; i < adr_link->num_adr; i++) {
1291			int codec_index;
1292
1293			codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
1294			if (codec_index < 0)
1295				return codec_index;
1296
1297			/* The group_id is > 0 iff the codec is aggregated */
1298			if (adr_link->adr_d[i].endpoints->group_id != group_id)
1299				continue;
1300
1301			if (codec_info_list[codec_index].dais[dai_index].init)
1302				codec_info_list[codec_index].dais[dai_index].init(card,
1303						adr_link,
1304						dai_links,
1305						&codec_info_list[codec_index],
1306						playback);
1307			if (!group_id)
1308				return 0;
1309		}
1310
1311		i = 0;
1312		adr_link++;
1313	} while (adr_link->mask);
1314
1315	return 0;
1316}
1317
1318/*
1319 * check endpoint status in slaves and gather link ID for all slaves in
1320 * the same group to generate different CPU DAI. Now only support
1321 * one sdw link with all slaves set with only single group id.
1322 *
1323 * one slave on one sdw link with aggregated = 0
1324 * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
1325 *
1326 * two or more slaves on one sdw link with aggregated = 0
1327 * one sdw BE DAI  <---> one-cpu DAI <---> multi-codec DAIs
1328 *
1329 * multiple links with multiple slaves with aggregated = 1
1330 * one sdw BE DAI  <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
1331 */
1332static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
1333			  struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
1334			  int *codec_num, unsigned int *group_id,
1335			  int adr_index)
1336{
1337	bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
1338	int i;
1339
1340	if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) {
1341		cpu_dai_id[0] = ffs(adr_link->mask) - 1;
1342		*cpu_dai_num = 1;
1343		*codec_num = 1;
1344		*group_id = 0;
1345		return 0;
1346	}
1347
1348	*codec_num = 0;
1349	*cpu_dai_num = 0;
1350	*group_id = adr_link->adr_d[adr_index].endpoints->group_id;
1351
1352	/* Count endpoints with the same group_id in the adr_link */
1353	for (; adr_link && adr_link->num_adr; adr_link++) {
1354		unsigned int link_codecs = 0;
1355
1356		for (i = 0; i < adr_link->num_adr; i++) {
1357			if (adr_link->adr_d[i].endpoints->aggregated &&
1358			    adr_link->adr_d[i].endpoints->group_id == *group_id)
1359				link_codecs++;
1360		}
1361
1362		if (link_codecs) {
1363			*codec_num += link_codecs;
1364
1365			if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) {
1366				dev_err(dev, "cpu_dai_id array overflowed\n");
1367				return -EINVAL;
1368			}
1369
1370			cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1;
1371		}
1372	}
1373
1374	return 0;
1375}
1376
1377static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps,
1378			    int codec_num, int cpu_num)
1379{
1380	int step;
1381	int i;
1382
1383	step = codec_num / cpu_num;
1384	for (i = 0; i < codec_num; i++) {
1385		sdw_codec_ch_maps[i].cpu	= i / step;
1386		sdw_codec_ch_maps[i].codec	= i;
1387	}
1388}
1389
1390static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
1391
1392static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
1393			      struct snd_soc_dai_link *dai_links, int sdw_be_num,
1394			      const struct snd_soc_acpi_link_adr *adr_link,
1395			      struct snd_soc_codec_conf *codec_conf,
1396			      int codec_count, int *be_id,
1397			      int *codec_conf_index,
1398			      bool *ignore_pch_dmic,
1399			      bool append_dai_type,
1400			      int adr_index,
1401			      int dai_index)
1402{
1403	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1404	struct device *dev = card->dev;
1405	const struct snd_soc_acpi_link_adr *adr_link_next;
1406	struct snd_soc_dai_link_component *codecs;
1407	struct snd_soc_dai_link_component *cpus;
1408	struct sof_sdw_codec_info *codec_info;
1409	int cpu_dai_id[SDW_MAX_CPU_DAIS];
1410	int cpu_dai_num;
1411	unsigned int group_id;
1412	int codec_dlc_index = 0;
1413	int codec_index;
1414	int codec_num;
1415	int stream;
1416	int i = 0;
1417	int j, k;
1418	int ret;
1419
1420	ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
1421			     &group_id, adr_index);
 
 
 
1422	if (ret)
1423		return ret;
1424
1425	codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
1426	if (!codecs)
1427		return -ENOMEM;
1428
1429	/* generate codec name on different links in the same group */
1430	j = adr_index;
1431	for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr &&
1432	     i < cpu_dai_num; adr_link_next++) {
1433		/* skip the link excluded by this processed group */
1434		if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1)
1435			continue;
1436
1437		/* j reset after loop, adr_index only applies to first link */
1438		for (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) {
1439			const struct snd_soc_acpi_endpoint *endpoints;
1440
1441			endpoints = adr_link_next->adr_d[j].endpoints;
1442
1443			if (group_id && (!endpoints->aggregated ||
1444					 endpoints->group_id != group_id))
1445				continue;
1446
1447			/* sanity check */
1448			if (*codec_conf_index >= codec_count) {
1449				dev_err(dev, "codec_conf array overflowed\n");
1450				return -EINVAL;
1451			}
1452
1453			ret = fill_sdw_codec_dlc(dev, adr_link_next,
1454						 &codecs[codec_dlc_index],
1455						 j, dai_index);
1456			if (ret)
1457				return ret;
1458
1459			codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index];
1460			codec_conf[*codec_conf_index].name_prefix =
1461					adr_link_next->adr_d[j].name_prefix;
1462
1463			codec_dlc_index++;
1464			(*codec_conf_index)++;
1465		}
1466		j = 0;
1467
1468		/* check next link to create codec dai in the processed group */
1469		i++;
1470	}
1471
1472	/* find codec info to create BE DAI */
1473	codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr);
1474	if (codec_index < 0)
1475		return codec_index;
1476	codec_info = &codec_info_list[codec_index];
1477
1478	if (codec_info->ignore_pch_dmic)
1479		*ignore_pch_dmic = true;
1480
1481	for_each_pcm_streams(stream) {
1482		struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps;
1483		char *name, *cpu_name;
1484		int playback, capture;
1485		static const char * const sdw_stream_name[] = {
1486			"SDW%d-Playback",
1487			"SDW%d-Capture",
1488			"SDW%d-Playback-%s",
1489			"SDW%d-Capture-%s",
1490		};
1491
1492		if (!codec_info->dais[dai_index].direction[stream])
1493			continue;
1494
1495		*be_id = codec_info->dais[dai_index].dailink[stream];
1496		if (*be_id < 0) {
1497			dev_err(dev, "Invalid dailink id %d\n", *be_id);
1498			return -EINVAL;
1499		}
1500
1501		sdw_codec_ch_maps = devm_kcalloc(dev, codec_num,
1502						 sizeof(*sdw_codec_ch_maps), GFP_KERNEL);
1503		if (!sdw_codec_ch_maps)
1504			return -ENOMEM;
1505
1506		/* create stream name according to first link id */
1507		if (append_dai_type) {
1508			name = devm_kasprintf(dev, GFP_KERNEL,
1509					      sdw_stream_name[stream + 2], cpu_dai_id[0],
1510					      type_strings[codec_info->dais[dai_index].dai_type]);
1511		} else {
1512			name = devm_kasprintf(dev, GFP_KERNEL,
1513					      sdw_stream_name[stream], cpu_dai_id[0]);
1514		}
1515		if (!name)
1516			return -ENOMEM;
1517
1518		cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL);
1519		if (!cpus)
1520			return -ENOMEM;
1521
1522		/*
1523		 * generate CPU DAI name base on the sdw link ID and
1524		 * PIN ID with offset of 2 according to sdw dai driver.
1525		 */
1526		for (k = 0; k < cpu_dai_num; k++) {
1527			cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1528						  "SDW%d Pin%d", cpu_dai_id[k],
1529						  ctx->sdw_pin_index[cpu_dai_id[k]]++);
1530			if (!cpu_name)
1531				return -ENOMEM;
1532
1533			cpus[k].dai_name = cpu_name;
1534		}
1535
1536		/*
1537		 * We create sdw dai links at first stage, so link index should
1538		 * not be larger than sdw_be_num
1539		 */
1540		if (*link_index >= sdw_be_num) {
1541			dev_err(dev, "invalid dai link index %d\n", *link_index);
1542			return -EINVAL;
1543		}
1544
1545		playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
1546		capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
1547
1548		init_dai_link(dev, dai_links + *link_index, be_id, name,
1549			      playback, capture, cpus, cpu_dai_num, codecs, codec_num,
1550			      NULL, &sdw_ops);
1551
1552		/*
1553		 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
1554		 * based on wait_for_completion(), tag them as 'nonatomic'.
1555		 */
1556		dai_links[*link_index].nonatomic = true;
1557
1558		set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
1559		dai_links[*link_index].ch_maps = sdw_codec_ch_maps;
1560		ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
1561					  playback, group_id, adr_index, dai_index);
1562		if (ret < 0) {
1563			dev_err(dev, "failed to init codec %d\n", codec_index);
1564			return ret;
1565		}
1566	}
1567
1568	return 0;
1569}
1570
1571static int sof_card_dai_links_create(struct snd_soc_card *card)
1572{
1573	struct device *dev = card->dev;
1574	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
1575	int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
1576	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 
1577	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1578	const struct snd_soc_acpi_link_adr *adr_link = mach_params->links;
1579	bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION);
1580	struct snd_soc_codec_conf *codec_conf;
1581	bool append_dai_type = false;
1582	bool ignore_pch_dmic = false;
1583	int codec_conf_num = 0;
1584	int codec_conf_index = 0;
1585	bool group_generated[SDW_MAX_GROUPS] = { };
1586	int ssp_codec_index, ssp_mask;
1587	struct snd_soc_dai_link *dai_links;
1588	int num_links, link_index = 0;
1589	char *name, *cpu_dai_name;
1590	char *codec_name, *codec_dai_name;
1591	int i, j, be_id = 0;
1592	int codec_index;
1593	int hdmi_num;
 
1594	int ret;
1595
1596	ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num);
1597	if (ret < 0) {
1598		dev_err(dev, "failed to get sdw link info %d\n", ret);
1599		return ret;
1600	}
1601
1602	/*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1603	 * on generic tgl platform, I2S or sdw mode is supported
1604	 * based on board rework. A ACPI device is registered in
1605	 * system only when I2S mode is supported, not sdw mode.
1606	 * Here check ACPI ID to confirm I2S is supported.
1607	 */
1608	ssp_codec_index = find_codec_info_acpi(mach->id);
1609	if (ssp_codec_index >= 0) {
1610		ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1611		ssp_num = hweight_long(ssp_mask);
1612	}
1613
1614	if (mach_params->codec_mask & IDISP_CODEC_MASK)
1615		ctx->hdmi.idisp_codec = true;
1616
1617	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1618		hdmi_num = SOF_TGL_HDMI_COUNT;
1619	else
1620		hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1621
1622	/* enable dmic01 & dmic16k */
1623	if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num)
 
 
 
 
 
1624		dmic_num = 2;
 
 
 
 
 
 
1625
1626	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1627		bt_num = 1;
1628
1629	dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
1630		sdw_be_num, ssp_num, dmic_num,
1631		ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
 
 
 
 
 
 
1632
1633	/* allocate BE dailinks */
1634	num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
1635	dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
1636	if (!dai_links)
1637		return -ENOMEM;
 
 
1638
1639	/* allocate codec conf, will be populated when dailinks are created */
1640	codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf),
1641				  GFP_KERNEL);
1642	if (!codec_conf)
1643		return -ENOMEM;
1644
1645	/* SDW */
1646	if (!sdw_be_num)
1647		goto SSP;
1648
1649	for (i = 0; i < SDW_MAX_LINKS; i++)
1650		ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
1651
1652	for (; adr_link->num_adr; adr_link++) {
1653		/*
1654		 * If there are two or more different devices on the same sdw link, we have to
1655		 * append the codec type to the dai link name to prevent duplicated dai link name.
1656		 * The same type devices on the same sdw link will be in the same
1657		 * snd_soc_acpi_adr_device array. They won't be described in different adr_links.
1658		 */
1659		for (i = 0; i < adr_link->num_adr; i++) {
1660			/* find codec info to get dai_num */
1661			codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
1662			if (codec_index < 0)
1663				return codec_index;
1664			if (codec_info_list[codec_index].dai_num > 1) {
1665				append_dai_type = true;
1666				goto out;
1667			}
1668			for (j = 0; j < i; j++) {
1669				if ((SDW_PART_ID(adr_link->adr_d[i].adr) !=
1670				    SDW_PART_ID(adr_link->adr_d[j].adr)) ||
1671				    (SDW_MFG_ID(adr_link->adr_d[i].adr) !=
1672				    SDW_MFG_ID(adr_link->adr_d[j].adr))) {
1673					append_dai_type = true;
1674					goto out;
1675				}
1676			}
1677		}
1678	}
1679out:
1680
1681	/* generate DAI links by each sdw link */
1682	for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) {
1683		for (i = 0; i < adr_link->num_adr; i++) {
1684			const struct snd_soc_acpi_endpoint *endpoint;
1685
1686			endpoint = adr_link->adr_d[i].endpoints;
1687
1688			/* this group has been generated */
1689			if (endpoint->aggregated &&
1690			    group_generated[endpoint->group_id])
1691				continue;
1692
1693			/* find codec info to get dai_num */
1694			codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
1695			if (codec_index < 0)
1696				return codec_index;
1697
1698			for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) {
1699				ret = create_sdw_dailink(card, &link_index, dai_links,
1700							 sdw_be_num, adr_link,
1701							 codec_conf, codec_conf_num,
1702							 &be_id, &codec_conf_index,
1703							 &ignore_pch_dmic, append_dai_type, i, j);
1704				if (ret < 0) {
1705					dev_err(dev, "failed to create dai link %d\n", link_index);
1706					return ret;
1707				}
1708			}
1709
1710			if (aggregation && endpoint->aggregated)
1711				group_generated[endpoint->group_id] = true;
1712		}
1713	}
1714
1715SSP:
1716	/* SSP */
1717	if (!ssp_num)
1718		goto DMIC;
1719
1720	for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
1721		struct sof_sdw_codec_info *info;
1722		int playback, capture;
1723
1724		if (!(ssp_mask & 0x1))
1725			continue;
1726
1727		info = &codec_info_list[ssp_codec_index];
1728
1729		name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
1730		cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1731		codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1732					    info->acpi_id, j++);
1733
1734		playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
1735		capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
1736
1737		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name,
1738					   playback, capture, cpu_dai_name,
1739					   codec_name, info->dais[0].dai_name,
1740					   NULL, info->ops);
1741		if (ret)
1742			return ret;
1743
1744		ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0);
1745		if (ret < 0)
1746			return ret;
1747
1748		link_index++;
1749	}
1750
1751DMIC:
1752	/* dmic */
1753	if (dmic_num > 0) {
1754		if (ignore_pch_dmic) {
1755			dev_warn(dev, "Ignoring PCH DMIC\n");
1756			goto HDMI;
1757		}
1758
1759		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic01",
1760					   0, 1, // DMIC only supports capture
1761					   "DMIC01 Pin", "dmic-codec", "dmic-hifi",
1762					   sof_sdw_dmic_init, NULL);
1763		if (ret)
1764			return ret;
1765
1766		link_index++;
1767
1768		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic16k",
1769					   0, 1, // DMIC only supports capture
1770					   "DMIC16k Pin", "dmic-codec", "dmic-hifi",
1771					   /* don't call sof_sdw_dmic_init() twice */
1772					   NULL, NULL);
1773		if (ret)
1774			return ret;
1775
1776		link_index++;
1777	}
1778
1779HDMI:
1780	/* HDMI */
1781	for (i = 0; i < hdmi_num; i++) {
1782		name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
1783		cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
1784
1785		if (ctx->hdmi.idisp_codec) {
1786			codec_name = "ehdaudio0D2";
1787			codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
1788							"intel-hdmi-hifi%d", i + 1);
1789		} else {
1790			codec_name = "snd-soc-dummy";
1791			codec_dai_name = "snd-soc-dummy-dai";
1792		}
1793
1794		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name,
1795					   1, 0, // HDMI only supports playback
1796					   cpu_dai_name, codec_name, codec_dai_name,
1797					   i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
1798		if (ret)
1799			return ret;
1800
1801		link_index++;
1802	}
1803
 
1804	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1805		int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1806				SOF_BT_OFFLOAD_SSP_SHIFT;
1807
1808		name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1809		cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1810
1811		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name,
1812					   1, 1, cpu_dai_name, snd_soc_dummy_dlc.name,
1813					   snd_soc_dummy_dlc.dai_name, NULL, NULL);
1814		if (ret)
1815			return ret;
1816	}
1817
1818	card->dai_link = dai_links;
1819	card->num_links = num_links;
1820
1821	card->codec_conf = codec_conf;
1822	card->num_configs = codec_conf_num;
 
 
1823
1824	return 0;
1825}
1826
1827static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1828{
1829	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 
1830	int ret = 0;
1831	int i;
1832
1833	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1834		if (codec_info_list[i].codec_card_late_probe) {
1835			ret = codec_info_list[i].codec_card_late_probe(card);
1836
1837			if (ret < 0)
1838				return ret;
1839		}
1840	}
1841
1842	if (ctx->hdmi.idisp_codec)
1843		ret = sof_sdw_hdmi_card_late_probe(card);
1844
1845	return ret;
1846}
1847
1848/* SoC card */
1849static const char sdw_card_long_name[] = "Intel Soundwire SOF";
1850
1851static struct snd_soc_card card_sof_sdw = {
1852	.name = "soundwire",
1853	.owner = THIS_MODULE,
1854	.late_probe = sof_sdw_card_late_probe,
1855};
1856
1857/* helper to get the link that the codec DAI is used */
1858static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
1859						       const char *dai_name)
1860{
1861	struct snd_soc_dai_link *dai_link;
1862	int i;
1863	int j;
1864
1865	for_each_card_prelinks(card, i, dai_link) {
1866		for (j = 0; j < dai_link->num_codecs; j++) {
1867			/* Check each codec in a link */
1868			if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
1869				return dai_link;
1870		}
1871	}
1872	return NULL;
1873}
1874
1875static void mc_dailink_exit_loop(struct snd_soc_card *card)
1876{
1877	struct snd_soc_dai_link *dai_link;
1878	int ret;
1879	int i, j;
1880
1881	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1882		for (j = 0; j < codec_info_list[i].dai_num; j++) {
1883			/* Check each dai in codec_info_lis to see if it is used in the link */
1884			if (!codec_info_list[i].dais[j].exit)
1885				continue;
1886			/*
1887			 * We don't need to call .exit function if there is no matched
1888			 * dai link found.
1889			 */
1890			dai_link = mc_find_codec_dai_used(card,
1891							  codec_info_list[i].dais[j].dai_name);
1892			if (dai_link) {
1893				/* Do the .exit function if the codec dai is used in the link */
1894				ret = codec_info_list[i].dais[j].exit(card, dai_link);
1895				if (ret)
1896					dev_warn(card->dev,
1897						 "codec exit failed %d\n",
1898						 ret);
1899				break;
1900			}
1901		}
1902	}
1903}
1904
1905static int mc_probe(struct platform_device *pdev)
1906{
1907	struct snd_soc_card *card = &card_sof_sdw;
1908	struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
1909	struct mc_private *ctx;
 
 
1910	int amp_num = 0, i;
1911	int ret;
1912
1913	card->dev = &pdev->dev;
1914
1915	dev_dbg(card->dev, "Entry\n");
 
 
1916
1917	ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL);
1918	if (!ctx)
1919		return -ENOMEM;
1920
 
 
 
 
 
 
 
 
1921	snd_soc_card_set_drvdata(card, ctx);
1922
1923	dmi_check_system(sof_sdw_quirk_table);
1924
1925	if (quirk_override != -1) {
1926		dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
1927			 sof_sdw_quirk, quirk_override);
1928		sof_sdw_quirk = quirk_override;
1929	}
1930
1931	log_quirks(card->dev);
1932
 
1933	/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1934	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1935		codec_info_list[i].amp_num = 0;
1936
1937	if (mach->mach_params.subsystem_id_set) {
1938		snd_soc_card_set_pci_ssid(card,
1939					  mach->mach_params.subsystem_vendor,
1940					  mach->mach_params.subsystem_device);
1941	}
1942
1943	ret = sof_card_dai_links_create(card);
1944	if (ret < 0)
1945		return ret;
1946
1947	/*
1948	 * the default amp_num is zero for each codec and
1949	 * amp_num will only be increased for active amp
1950	 * codecs on used platform
1951	 */
1952	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1953		amp_num += codec_info_list[i].amp_num;
1954
1955	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1956					  "cfg-spk:%d cfg-amp:%d",
1957					  (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
1958					  ? 4 : 2, amp_num);
1959	if (!card->components)
1960		return -ENOMEM;
1961
1962	if (mach->mach_params.dmic_num) {
1963		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1964						  "%s mic:dmic cfg-mics:%d",
1965						  card->components,
1966						  mach->mach_params.dmic_num);
1967		if (!card->components)
1968			return -ENOMEM;
1969	}
1970
1971	card->long_name = sdw_card_long_name;
1972
1973	/* Register the card */
1974	ret = devm_snd_soc_register_card(card->dev, card);
1975	if (ret) {
1976		dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
1977		mc_dailink_exit_loop(card);
1978		return ret;
1979	}
1980
1981	platform_set_drvdata(pdev, card);
1982
1983	return ret;
1984}
1985
1986static void mc_remove(struct platform_device *pdev)
1987{
1988	struct snd_soc_card *card = platform_get_drvdata(pdev);
1989
1990	mc_dailink_exit_loop(card);
1991}
1992
1993static const struct platform_device_id mc_id_table[] = {
1994	{ "sof_sdw", },
1995	{}
1996};
1997MODULE_DEVICE_TABLE(platform, mc_id_table);
1998
1999static struct platform_driver sof_sdw_driver = {
2000	.driver = {
2001		.name = "sof_sdw",
2002		.pm = &snd_soc_pm_ops,
2003	},
2004	.probe = mc_probe,
2005	.remove_new = mc_remove,
2006	.id_table = mc_id_table,
2007};
2008
2009module_platform_driver(sof_sdw_driver);
2010
2011MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
2012MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
2013MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
2014MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
2015MODULE_LICENSE("GPL v2");
2016MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
2017MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);