162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 462306a36Sopenharmony_ci// redistributing this file, you may do so under either license. 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved. 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 962306a36Sopenharmony_ci// 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/firmware.h> 1262306a36Sopenharmony_ci#include <linux/dmi.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/pci.h> 1562306a36Sopenharmony_ci#include <linux/platform_data/x86/soc.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci#include <sound/soc-acpi.h> 1862306a36Sopenharmony_ci#include <sound/soc-acpi-intel-match.h> 1962306a36Sopenharmony_ci#include <sound/sof.h> 2062306a36Sopenharmony_ci#include "ops.h" 2162306a36Sopenharmony_ci#include "sof-pci-dev.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic char *fw_path; 2462306a36Sopenharmony_cimodule_param(fw_path, charp, 0444); 2562306a36Sopenharmony_ciMODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic char *fw_filename; 2862306a36Sopenharmony_cimodule_param(fw_filename, charp, 0444); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware."); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic char *lib_path; 3262306a36Sopenharmony_cimodule_param(lib_path, charp, 0444); 3362306a36Sopenharmony_ciMODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries."); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic char *tplg_path; 3662306a36Sopenharmony_cimodule_param(tplg_path, charp, 0444); 3762306a36Sopenharmony_ciMODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic char *tplg_filename; 4062306a36Sopenharmony_cimodule_param(tplg_filename, charp, 0444); 4162306a36Sopenharmony_ciMODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology."); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int sof_pci_debug; 4462306a36Sopenharmony_cimodule_param_named(sof_pci_debug, sof_pci_debug, int, 0444); 4562306a36Sopenharmony_ciMODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int sof_pci_ipc_type = -1; 4862306a36Sopenharmony_cimodule_param_named(ipc_type, sof_pci_ipc_type, int, 0444); 4962306a36Sopenharmony_ciMODULE_PARM_DESC(ipc_type, "SOF IPC type (0): SOF, (1) Intel CAVS"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const char *sof_dmi_override_tplg_name; 5262306a36Sopenharmony_cistatic bool sof_dmi_use_community_key; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int sof_tplg_cb(const struct dmi_system_id *id) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci sof_dmi_override_tplg_name = id->driver_data; 5962306a36Sopenharmony_ci return 1; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct dmi_system_id sof_tplg_table[] = { 6362306a36Sopenharmony_ci { 6462306a36Sopenharmony_ci .callback = sof_tplg_cb, 6562306a36Sopenharmony_ci .matches = { 6662306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"), 6762306a36Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"), 6862306a36Sopenharmony_ci }, 6962306a36Sopenharmony_ci .driver_data = "sof-tgl-rt5682-ssp0-max98373-ssp2.tplg", 7062306a36Sopenharmony_ci }, 7162306a36Sopenharmony_ci { 7262306a36Sopenharmony_ci .callback = sof_tplg_cb, 7362306a36Sopenharmony_ci .matches = { 7462306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 7562306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), 7662306a36Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"), 7762306a36Sopenharmony_ci }, 7862306a36Sopenharmony_ci .driver_data = "sof-adl-rt5682-ssp0-max98373-ssp2.tplg", 7962306a36Sopenharmony_ci }, 8062306a36Sopenharmony_ci { 8162306a36Sopenharmony_ci .callback = sof_tplg_cb, 8262306a36Sopenharmony_ci .matches = { 8362306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 8462306a36Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), 8562306a36Sopenharmony_ci }, 8662306a36Sopenharmony_ci .driver_data = "sof-adl-max98390-ssp2-rt5682-ssp0.tplg", 8762306a36Sopenharmony_ci }, 8862306a36Sopenharmony_ci { 8962306a36Sopenharmony_ci .callback = sof_tplg_cb, 9062306a36Sopenharmony_ci .matches = { 9162306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 9262306a36Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO_AMP-MAX98360_ALC5682VS_I2S_2WAY"), 9362306a36Sopenharmony_ci }, 9462306a36Sopenharmony_ci .driver_data = "sof-adl-max98360a-rt5682-2way.tplg", 9562306a36Sopenharmony_ci }, 9662306a36Sopenharmony_ci { 9762306a36Sopenharmony_ci .callback = sof_tplg_cb, 9862306a36Sopenharmony_ci .matches = { 9962306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 10062306a36Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO-AUDIO_MAX98357_ALC5682I_I2S_2WAY"), 10162306a36Sopenharmony_ci }, 10262306a36Sopenharmony_ci .driver_data = "sof-adl-max98357a-rt5682-2way.tplg", 10362306a36Sopenharmony_ci }, 10462306a36Sopenharmony_ci { 10562306a36Sopenharmony_ci .callback = sof_tplg_cb, 10662306a36Sopenharmony_ci .matches = { 10762306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), 10862306a36Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"), 10962306a36Sopenharmony_ci }, 11062306a36Sopenharmony_ci .driver_data = "sof-adl-max98357a-rt5682.tplg", 11162306a36Sopenharmony_ci }, 11262306a36Sopenharmony_ci {} 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* all Up boards use the community key */ 11662306a36Sopenharmony_cistatic int up_use_community_key(const struct dmi_system_id *id) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci sof_dmi_use_community_key = true; 11962306a36Sopenharmony_ci return 1; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * For ApolloLake Chromebooks we want to force the use of the Intel production key. 12462306a36Sopenharmony_ci * All newer platforms use the community key 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic int chromebook_use_community_key(const struct dmi_system_id *id) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci if (!soc_intel_is_apl()) 12962306a36Sopenharmony_ci sof_dmi_use_community_key = true; 13062306a36Sopenharmony_ci return 1; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const struct dmi_system_id community_key_platforms[] = { 13462306a36Sopenharmony_ci { 13562306a36Sopenharmony_ci .ident = "Up boards", 13662306a36Sopenharmony_ci .callback = up_use_community_key, 13762306a36Sopenharmony_ci .matches = { 13862306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci .ident = "Google Chromebooks", 14362306a36Sopenharmony_ci .callback = chromebook_use_community_key, 14462306a36Sopenharmony_ci .matches = { 14562306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google"), 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci { 14962306a36Sopenharmony_ci .ident = "Google firmware", 15062306a36Sopenharmony_ci .callback = chromebook_use_community_key, 15162306a36Sopenharmony_ci .matches = { 15262306a36Sopenharmony_ci DMI_MATCH(DMI_BIOS_VERSION, "Google"), 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci }, 15562306a36Sopenharmony_ci {}, 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ciconst struct dev_pm_ops sof_pci_pm = { 15962306a36Sopenharmony_ci .prepare = snd_sof_prepare, 16062306a36Sopenharmony_ci .complete = snd_sof_complete, 16162306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 16262306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 16362306a36Sopenharmony_ci snd_sof_runtime_idle) 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ciEXPORT_SYMBOL_NS(sof_pci_pm, SND_SOC_SOF_PCI_DEV); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void sof_pci_probe_complete(struct device *dev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci dev_dbg(dev, "Completing SOF PCI probe"); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME) 17262306a36Sopenharmony_ci return; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* allow runtime_pm */ 17562306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 17662306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * runtime pm for pci device is "forbidden" by default. 18062306a36Sopenharmony_ci * so call pm_runtime_allow() to enable it. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci pm_runtime_allow(dev); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* mark last_busy for pm_runtime to make sure not suspend immediately */ 18562306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* follow recommendation in pci-driver.c to decrement usage counter */ 18862306a36Sopenharmony_ci pm_runtime_put_noidle(dev); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciint sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct device *dev = &pci->dev; 19462306a36Sopenharmony_ci const struct sof_dev_desc *desc = 19562306a36Sopenharmony_ci (const struct sof_dev_desc *)pci_id->driver_data; 19662306a36Sopenharmony_ci struct snd_sof_pdata *sof_pdata; 19762306a36Sopenharmony_ci int ret; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci dev_dbg(&pci->dev, "PCI DSP detected"); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (!desc) { 20262306a36Sopenharmony_ci dev_err(dev, "error: no matching PCI descriptor\n"); 20362306a36Sopenharmony_ci return -ENODEV; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (!desc->ops) { 20762306a36Sopenharmony_ci dev_err(dev, "error: no matching PCI descriptor ops\n"); 20862306a36Sopenharmony_ci return -ENODEV; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 21262306a36Sopenharmony_ci if (!sof_pdata) 21362306a36Sopenharmony_ci return -ENOMEM; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci ret = pcim_enable_device(pci); 21662306a36Sopenharmony_ci if (ret < 0) 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ret = pci_request_regions(pci, "Audio DSP"); 22062306a36Sopenharmony_ci if (ret < 0) 22162306a36Sopenharmony_ci return ret; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci sof_pdata->name = pci_name(pci); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* PCI defines a vendor ID of 0xFFFF as invalid. */ 22662306a36Sopenharmony_ci if (pci->subsystem_vendor != 0xFFFF) { 22762306a36Sopenharmony_ci sof_pdata->subsystem_vendor = pci->subsystem_vendor; 22862306a36Sopenharmony_ci sof_pdata->subsystem_device = pci->subsystem_device; 22962306a36Sopenharmony_ci sof_pdata->subsystem_id_set = true; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci sof_pdata->desc = desc; 23362306a36Sopenharmony_ci sof_pdata->dev = dev; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci sof_pdata->ipc_type = desc->ipc_default; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (sof_pci_ipc_type < 0) { 23862306a36Sopenharmony_ci sof_pdata->ipc_type = desc->ipc_default; 23962306a36Sopenharmony_ci } else { 24062306a36Sopenharmony_ci dev_info(dev, "overriding default IPC %d to requested %d\n", 24162306a36Sopenharmony_ci desc->ipc_default, sof_pci_ipc_type); 24262306a36Sopenharmony_ci if (sof_pci_ipc_type >= SOF_IPC_TYPE_COUNT) { 24362306a36Sopenharmony_ci dev_err(dev, "invalid request value %d\n", sof_pci_ipc_type); 24462306a36Sopenharmony_ci ret = -EINVAL; 24562306a36Sopenharmony_ci goto out; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci if (!(BIT(sof_pci_ipc_type) & desc->ipc_supported_mask)) { 24862306a36Sopenharmony_ci dev_err(dev, "invalid request value %d, supported mask is %#x\n", 24962306a36Sopenharmony_ci sof_pci_ipc_type, desc->ipc_supported_mask); 25062306a36Sopenharmony_ci ret = -EINVAL; 25162306a36Sopenharmony_ci goto out; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci sof_pdata->ipc_type = sof_pci_ipc_type; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (fw_filename) { 25762306a36Sopenharmony_ci sof_pdata->fw_filename = fw_filename; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci dev_dbg(dev, "Module parameter used, changed fw filename to %s\n", 26062306a36Sopenharmony_ci sof_pdata->fw_filename); 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci sof_pdata->fw_filename = desc->default_fw_filename[sof_pdata->ipc_type]; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * for platforms using the SOF community key, change the 26762306a36Sopenharmony_ci * default path automatically to pick the right files from the 26862306a36Sopenharmony_ci * linux-firmware tree. This can be overridden with the 26962306a36Sopenharmony_ci * fw_path kernel parameter, e.g. for developers. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* alternate fw and tplg filenames ? */ 27362306a36Sopenharmony_ci if (fw_path) { 27462306a36Sopenharmony_ci sof_pdata->fw_filename_prefix = fw_path; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci dev_dbg(dev, 27762306a36Sopenharmony_ci "Module parameter used, changed fw path to %s\n", 27862306a36Sopenharmony_ci sof_pdata->fw_filename_prefix); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci } else if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) { 28162306a36Sopenharmony_ci sof_pdata->fw_filename_prefix = 28262306a36Sopenharmony_ci devm_kasprintf(dev, GFP_KERNEL, "%s/%s", 28362306a36Sopenharmony_ci sof_pdata->desc->default_fw_path[sof_pdata->ipc_type], 28462306a36Sopenharmony_ci "community"); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci dev_dbg(dev, 28762306a36Sopenharmony_ci "Platform uses community key, changed fw path to %s\n", 28862306a36Sopenharmony_ci sof_pdata->fw_filename_prefix); 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci sof_pdata->fw_filename_prefix = 29162306a36Sopenharmony_ci sof_pdata->desc->default_fw_path[sof_pdata->ipc_type]; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (lib_path) { 29562306a36Sopenharmony_ci sof_pdata->fw_lib_prefix = lib_path; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n", 29862306a36Sopenharmony_ci sof_pdata->fw_lib_prefix); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) { 30162306a36Sopenharmony_ci if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) { 30262306a36Sopenharmony_ci sof_pdata->fw_lib_prefix = 30362306a36Sopenharmony_ci devm_kasprintf(dev, GFP_KERNEL, "%s/%s", 30462306a36Sopenharmony_ci sof_pdata->desc->default_lib_path[sof_pdata->ipc_type], 30562306a36Sopenharmony_ci "community"); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci dev_dbg(dev, 30862306a36Sopenharmony_ci "Platform uses community key, changed fw_lib path to %s\n", 30962306a36Sopenharmony_ci sof_pdata->fw_lib_prefix); 31062306a36Sopenharmony_ci } else { 31162306a36Sopenharmony_ci sof_pdata->fw_lib_prefix = 31262306a36Sopenharmony_ci sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (tplg_path) 31762306a36Sopenharmony_ci sof_pdata->tplg_filename_prefix = tplg_path; 31862306a36Sopenharmony_ci else 31962306a36Sopenharmony_ci sof_pdata->tplg_filename_prefix = 32062306a36Sopenharmony_ci sof_pdata->desc->default_tplg_path[sof_pdata->ipc_type]; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * the topology filename will be provided in the machine descriptor, unless 32462306a36Sopenharmony_ci * it is overridden by a module parameter or DMI quirk. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci if (tplg_filename) { 32762306a36Sopenharmony_ci sof_pdata->tplg_filename = tplg_filename; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci dev_dbg(dev, "Module parameter used, changed tplg filename to %s\n", 33062306a36Sopenharmony_ci sof_pdata->tplg_filename); 33162306a36Sopenharmony_ci } else { 33262306a36Sopenharmony_ci dmi_check_system(sof_tplg_table); 33362306a36Sopenharmony_ci if (sof_dmi_override_tplg_name) 33462306a36Sopenharmony_ci sof_pdata->tplg_filename = sof_dmi_override_tplg_name; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* set callback to be called on successful device probe to enable runtime_pm */ 33862306a36Sopenharmony_ci sof_pdata->sof_probe_complete = sof_pci_probe_complete; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* call sof helper for DSP hardware probe */ 34162306a36Sopenharmony_ci ret = snd_sof_device_probe(dev, sof_pdata); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciout: 34462306a36Sopenharmony_ci if (ret) 34562306a36Sopenharmony_ci pci_release_regions(pci); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ciEXPORT_SYMBOL_NS(sof_pci_probe, SND_SOC_SOF_PCI_DEV); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_civoid sof_pci_remove(struct pci_dev *pci) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci /* call sof helper for DSP hardware remove */ 35462306a36Sopenharmony_ci snd_sof_device_remove(&pci->dev); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* follow recommendation in pci-driver.c to increment usage counter */ 35762306a36Sopenharmony_ci if (snd_sof_device_probe_completed(&pci->dev) && 35862306a36Sopenharmony_ci !(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)) 35962306a36Sopenharmony_ci pm_runtime_get_noresume(&pci->dev); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* release pci regions and disable device */ 36262306a36Sopenharmony_ci pci_release_regions(pci); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ciEXPORT_SYMBOL_NS(sof_pci_remove, SND_SOC_SOF_PCI_DEV); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_civoid sof_pci_shutdown(struct pci_dev *pci) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci snd_sof_device_shutdown(&pci->dev); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ciEXPORT_SYMBOL_NS(sof_pci_shutdown, SND_SOC_SOF_PCI_DEV); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 373