File Index
Files and directories
Sign in
FILE

sof_sdw.c

File preview with syntax highlighting.

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