brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · 0266ede Raw
667 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2021-2022 Intel Corporation4//5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>6//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>7//8 9#include <linux/acpi.h>10#include <linux/module.h>11#include <linux/dmi.h>12#include <linux/pci.h>13#include <acpi/nhlt.h>14#include <linux/platform_device.h>15#include <sound/hda_codec.h>16#include <sound/hda_register.h>17#include <sound/soc-acpi.h>18#include <sound/soc-component.h>19#include "avs.h"20 21static bool i2s_test;22module_param(i2s_test, bool, 0444);23MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");24 25static const struct dmi_system_id kbl_dmi_table[] = {26	{27		.matches = {28			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),29			DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),30		},31	},32	{33		.matches = {34			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),35			DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),36		},37	},38	{}39};40 41static const struct dmi_system_id kblr_dmi_table[] = {42	{43		.matches = {44			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),45			DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),46		},47	},48	{}49};50 51static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)52{53	struct snd_soc_acpi_mach *mach = arg;54	const struct dmi_system_id *dmi_id;55	struct dmi_system_id *dmi_table;56 57	if (mach->quirk_data == NULL)58		return mach;59 60	dmi_table = (struct dmi_system_id *)mach->quirk_data;61 62	dmi_id = dmi_first_match(dmi_table);63	if (!dmi_id)64		return NULL;65 66	return mach;67}68 69#define AVS_SSP(x)		(BIT(x))70#define AVS_SSP_RANGE(a, b)	(GENMASK(b, a))71 72/* supported I2S board codec configurations */73static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {74	{75		.id = "INT343A",76		.drv_name = "avs_rt286",77		.mach_params = {78			.i2s_link_mask = AVS_SSP(0),79		},80		.tplg_filename = "rt286-tplg.bin",81	},82	{83		.id = "10508825",84		.drv_name = "avs_nau8825",85		.mach_params = {86			.i2s_link_mask = AVS_SSP(1),87		},88		.tplg_filename = "nau8825-tplg.bin",89	},90	{91		.id = "INT343B",92		.drv_name = "avs_ssm4567",93		.mach_params = {94			.i2s_link_mask = AVS_SSP(0),95		},96		.tplg_filename = "ssm4567-tplg.bin",97	},98	{99		.id = "MX98357A",100		.drv_name = "avs_max98357a",101		.mach_params = {102			.i2s_link_mask = AVS_SSP(0),103		},104		.tplg_filename = "max98357a-tplg.bin",105	},106	{},107};108 109static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {110	{111		.id = "INT343A",112		.drv_name = "avs_rt286",113		.mach_params = {114			.i2s_link_mask = AVS_SSP(0),115		},116		.quirk_data = &kbl_dmi_table,117		.machine_quirk = dmi_match_quirk,118		.tplg_filename = "rt286-tplg.bin",119	},120	{121		.id = "INT343A",122		.drv_name = "avs_rt298",123		.mach_params = {124			.i2s_link_mask = AVS_SSP(0),125		},126		.quirk_data = &kblr_dmi_table,127		.machine_quirk = dmi_match_quirk,128		.tplg_filename = "rt298-tplg.bin",129	},130	{131		.id = "MX98927",132		.drv_name = "avs_max98927",133		.mach_params = {134			.i2s_link_mask = AVS_SSP(0),135		},136		.tplg_filename = "max98927-tplg.bin",137	},138	{139		.id = "10EC5514",140		.drv_name = "avs_rt5514",141		.mach_params = {142			.i2s_link_mask = AVS_SSP(0),143		},144		.pdata = (unsigned long[]){ 0x2, 0, 0, 0, 0, 0 }, /* SSP0 TDMs */145		.tplg_filename = "rt5514-tplg.bin",146	},147	{148		.id = "10EC5663",149		.drv_name = "avs_rt5663",150		.mach_params = {151			.i2s_link_mask = AVS_SSP(1),152		},153		.tplg_filename = "rt5663-tplg.bin",154	},155	{156		.id = "MX98373",157		.drv_name = "avs_max98373",158		.mach_params = {159			.i2s_link_mask = AVS_SSP(0),160		},161		.tplg_filename = "max98373-tplg.bin",162	},163	{164		.id = "MX98357A",165		.drv_name = "avs_max98357a",166		.mach_params = {167			.i2s_link_mask = AVS_SSP(0),168		},169		.tplg_filename = "max98357a-tplg.bin",170	},171	{172		.id = "DLGS7219",173		.drv_name = "avs_da7219",174		.mach_params = {175			.i2s_link_mask = AVS_SSP(1),176		},177		.tplg_filename = "da7219-tplg.bin",178	},179	{180		.id = "ESSX8336",181		.drv_name = "avs_es8336",182		.mach_params = {183			.i2s_link_mask = AVS_SSP(0),184		},185		.tplg_filename = "es8336-tplg.bin",186	},187	{},188};189 190static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {191	{192		.id = "INT343A",193		.drv_name = "avs_rt298",194		.mach_params = {195			.i2s_link_mask = AVS_SSP(5),196		},197		.tplg_filename = "rt298-tplg.bin",198	},199	{200		.id = "INT34C3",201		.drv_name = "avs_tdf8532",202		.mach_params = {203			.i2s_link_mask = AVS_SSP_RANGE(0, 5),204		},205		.pdata = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }, /* SSP2 TDMs */206		.tplg_filename = "tdf8532-tplg.bin",207	},208	{209		.id = "MX98357A",210		.drv_name = "avs_max98357a",211		.mach_params = {212			.i2s_link_mask = AVS_SSP(5),213		},214		.tplg_filename = "max98357a-tplg.bin",215	},216	{217		.id = "DLGS7219",218		.drv_name = "avs_da7219",219		.mach_params = {220			.i2s_link_mask = AVS_SSP(1),221		},222		.tplg_filename = "da7219-tplg.bin",223	},224	{},225};226 227static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {228	{229		.id = "INT343A",230		.drv_name = "avs_rt298",231		.mach_params = {232			.i2s_link_mask = AVS_SSP(2),233		},234		.tplg_filename = "rt298-tplg.bin",235	},236	{},237};238 239static struct snd_soc_acpi_mach avs_cnl_i2s_machines[] = {240	{241		.id = "INT34C2",242		.drv_name = "avs_rt274",243		.mach_params = {244			.i2s_link_mask = AVS_SSP(0),245		},246		.tplg_filename = "rt274-tplg.bin",247	},248	{249		.id = "10EC5682",250		.drv_name = "avs_rt5682",251		.mach_params = {252			.i2s_link_mask = AVS_SSP(1),253		},254		.tplg_filename = "rt5682-tplg.bin",255	},256	{},257};258 259static struct snd_soc_acpi_mach avs_icl_i2s_machines[] = {260	{261		.id = "INT343A",262		.drv_name = "avs_rt298",263		.mach_params = {264			.i2s_link_mask = AVS_SSP(0),265		},266		.tplg_filename = "rt298-tplg.bin",267	},268	{269		.id = "INT34C2",270		.drv_name = "avs_rt274",271		.mach_params = {272			.i2s_link_mask = AVS_SSP(0),273		},274		.tplg_filename = "rt274-tplg.bin",275	},276	{},277};278 279static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {280	{281		.id = "INT34C2",282		.drv_name = "avs_rt274",283		.mach_params = {284			.i2s_link_mask = AVS_SSP(0),285		},286		.tplg_filename = "rt274-tplg.bin",287	},288	{289		.id = "10EC0298",290		.drv_name = "avs_rt298",291		.mach_params = {292			.i2s_link_mask = AVS_SSP(0),293		},294		.tplg_filename = "rt298-tplg.bin",295	},296	{297		.id = "10EC1308",298		.drv_name = "avs_rt1308",299		.mach_params = {300			.i2s_link_mask = AVS_SSP(1),301		},302		.tplg_filename = "rt1308-tplg.bin",303	},304	{305		.id = "ESSX8336",306		.drv_name = "avs_es8336",307		.mach_params = {308			.i2s_link_mask = AVS_SSP(0),309		},310		.tplg_filename = "es8336-tplg.bin",311	},312	{},313};314 315static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {316	{317		.drv_name = "avs_i2s_test",318		.mach_params = {319			.i2s_link_mask = AVS_SSP(0),320		},321		.tplg_filename = "i2s-test-tplg.bin",322	},323	{324		.drv_name = "avs_i2s_test",325		.mach_params = {326			.i2s_link_mask = AVS_SSP(1),327		},328		.tplg_filename = "i2s-test-tplg.bin",329	},330	{331		.drv_name = "avs_i2s_test",332		.mach_params = {333			.i2s_link_mask = AVS_SSP(2),334		},335		.tplg_filename = "i2s-test-tplg.bin",336	},337	{338		.drv_name = "avs_i2s_test",339		.mach_params = {340			.i2s_link_mask = AVS_SSP(3),341		},342		.tplg_filename = "i2s-test-tplg.bin",343	},344	{345		.drv_name = "avs_i2s_test",346		.mach_params = {347			.i2s_link_mask = AVS_SSP(4),348		},349		.tplg_filename = "i2s-test-tplg.bin",350	},351	{352		.drv_name = "avs_i2s_test",353		.mach_params = {354			.i2s_link_mask = AVS_SSP(5),355		},356		.tplg_filename = "i2s-test-tplg.bin",357	},358	/* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */359};360 361struct avs_acpi_boards {362	int id;363	struct snd_soc_acpi_mach *machs;364};365 366#define AVS_MACH_ENTRY(_id, _mach) \367	{ .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }368 369/* supported I2S boards per platform */370static const struct avs_acpi_boards i2s_boards[] = {371	AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),372	AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),373	AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),374	AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),375	AVS_MACH_ENTRY(HDA_CNL_LP,	avs_cnl_i2s_machines),376	AVS_MACH_ENTRY(HDA_CNL_H,	avs_cnl_i2s_machines),377	AVS_MACH_ENTRY(HDA_CML_LP,	avs_cnl_i2s_machines),378	AVS_MACH_ENTRY(HDA_ICL_LP,	avs_icl_i2s_machines),379	AVS_MACH_ENTRY(HDA_TGL_LP,	avs_tgl_i2s_machines),380	AVS_MACH_ENTRY(HDA_EHL_0,	avs_tgl_i2s_machines),381	AVS_MACH_ENTRY(HDA_ADL_P,	avs_tgl_i2s_machines),382	AVS_MACH_ENTRY(HDA_RPL_P_0,	avs_tgl_i2s_machines),383	AVS_MACH_ENTRY(HDA_RPL_M,	avs_tgl_i2s_machines),384	{},385};386 387static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)388{389	int id, i;390 391	id = adev->base.pci->device;392	for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)393		if (i2s_boards[i].id == id)394			return &i2s_boards[i];395	return NULL;396}397 398/* platform devices owned by AVS audio are removed with this hook */399static void board_pdev_unregister(void *data)400{401	platform_device_unregister(data);402}403 404static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)405{406	struct platform_device *board;407	struct snd_soc_acpi_mach mach = {{0}};408	int ret;409 410	ret = avs_probe_platform_register(adev, "probe-platform");411	if (ret < 0)412		return ret;413 414	mach.mach_params.platform = "probe-platform";415 416	board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,417					      (const void *)&mach, sizeof(mach));418	if (IS_ERR(board)) {419		dev_err(adev->dev, "probe board register failed\n");420		return PTR_ERR(board);421	}422 423	ret = devm_add_action(adev->dev, board_pdev_unregister, board);424	if (ret < 0) {425		platform_device_unregister(board);426		return ret;427	}428	return 0;429}430 431static int avs_register_dmic_board(struct avs_dev *adev)432{433	struct platform_device *codec, *board;434	struct snd_soc_acpi_mach mach = {{0}};435	int ret;436 437	if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {438		dev_dbg(adev->dev, "no DMIC endpoints present\n");439		return 0;440	}441 442	codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);443	if (IS_ERR(codec)) {444		dev_err(adev->dev, "dmic codec register failed\n");445		return PTR_ERR(codec);446	}447 448	ret = devm_add_action(adev->dev, board_pdev_unregister, codec);449	if (ret < 0) {450		platform_device_unregister(codec);451		return ret;452	}453 454	ret = avs_dmic_platform_register(adev, "dmic-platform");455	if (ret < 0)456		return ret;457 458	mach.tplg_filename = "dmic-tplg.bin";459	mach.mach_params.platform = "dmic-platform";460 461	board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,462					(const void *)&mach, sizeof(mach));463	if (IS_ERR(board)) {464		dev_err(adev->dev, "dmic board register failed\n");465		return PTR_ERR(board);466	}467 468	ret = devm_add_action(adev->dev, board_pdev_unregister, board);469	if (ret < 0) {470		platform_device_unregister(board);471		return ret;472	}473 474	return 0;475}476 477static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)478{479	struct platform_device *board;480	int num_ssps;481	char *name;482	int ret;483 484	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;485	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {486		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",487			num_ssps, mach->drv_name,488			(unsigned long)__fls(mach->mach_params.i2s_link_mask));489		return -ENODEV;490	}491 492	name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,493			      mach->mach_params.i2s_link_mask);494	if (!name)495		return -ENOMEM;496 497	ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);498	if (ret < 0)499		return ret;500 501	mach->mach_params.platform = name;502 503	board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,504					      (const void *)mach, sizeof(*mach));505	if (IS_ERR(board)) {506		dev_err(adev->dev, "ssp board register failed\n");507		return PTR_ERR(board);508	}509 510	ret = devm_add_action(adev->dev, board_pdev_unregister, board);511	if (ret < 0) {512		platform_device_unregister(board);513		return ret;514	}515 516	return 0;517}518 519static int avs_register_i2s_boards(struct avs_dev *adev)520{521	const struct avs_acpi_boards *boards;522	struct snd_soc_acpi_mach *mach;523	int ret;524 525	if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) {526		dev_dbg(adev->dev, "no I2S endpoints present\n");527		return 0;528	}529 530	if (i2s_test) {531		int i, num_ssps;532 533		num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;534		/* constrain just in case FW says there can be more SSPs than possible */535		num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);536 537		mach = avs_test_i2s_machines;538 539		for (i = 0; i < num_ssps; i++) {540			ret = avs_register_i2s_board(adev, &mach[i]);541			if (ret < 0)542				dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,543					 ret);544		}545		return 0;546	}547 548	boards = avs_get_i2s_boards(adev);549	if (!boards) {550		dev_dbg(adev->dev, "no I2S endpoints supported\n");551		return 0;552	}553 554	for (mach = boards->machs; mach->id[0]; mach++) {555		if (!acpi_dev_present(mach->id, mach->uid, -1))556			continue;557 558		if (mach->machine_quirk)559			if (!mach->machine_quirk(mach))560				continue;561 562		ret = avs_register_i2s_board(adev, mach);563		if (ret < 0)564			dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);565	}566 567	return 0;568}569 570static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)571{572	struct snd_soc_acpi_mach mach = {{0}};573	struct platform_device *board;574	struct hdac_device *hdev = &codec->core;575	char *pname;576	int ret, id;577 578	pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));579	if (!pname)580		return -ENOMEM;581 582	ret = avs_hda_platform_register(adev, pname);583	if (ret < 0)584		return ret;585 586	mach.pdata = codec;587	mach.mach_params.platform = pname;588	mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",589					    hdev->vendor_id);590	if (!mach.tplg_filename)591		return -ENOMEM;592 593	id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;594	board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,595					      sizeof(mach));596	if (IS_ERR(board)) {597		dev_err(adev->dev, "hda board register failed\n");598		return PTR_ERR(board);599	}600 601	ret = devm_add_action(adev->dev, board_pdev_unregister, board);602	if (ret < 0) {603		platform_device_unregister(board);604		return ret;605	}606 607	return 0;608}609 610static int avs_register_hda_boards(struct avs_dev *adev)611{612	struct hdac_bus *bus = &adev->base.core;613	struct hdac_device *hdev;614	int ret;615 616	if (!bus->num_codecs) {617		dev_dbg(adev->dev, "no HDA endpoints present\n");618		return 0;619	}620 621	list_for_each_entry(hdev, &bus->codec_list, list) {622		struct hda_codec *codec;623 624		codec = dev_to_hda_codec(&hdev->dev);625 626		ret = avs_register_hda_board(adev, codec);627		if (ret < 0)628			dev_warn(adev->dev, "register hda-%08x failed: %d\n",629				 codec->core.vendor_id, ret);630	}631 632	return 0;633}634 635int avs_register_all_boards(struct avs_dev *adev)636{637	int ret;638 639#ifdef CONFIG_DEBUG_FS640	ret = avs_register_probe_board(adev);641	if (ret < 0)642		dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);643#endif644 645	ret = avs_register_dmic_board(adev);646	if (ret < 0)647		dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",648			 ret);649 650	ret = avs_register_i2s_boards(adev);651	if (ret < 0)652		dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",653			 ret);654 655	ret = avs_register_hda_boards(adev);656	if (ret < 0)657		dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",658			 ret);659 660	return 0;661}662 663void avs_unregister_all_boards(struct avs_dev *adev)664{665	snd_soc_unregister_component(adev->dev);666}667