brintos

brintos / linux-shallow public Read only

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