18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright 2019 NXP 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Author: Daniel Baluta <daniel.baluta@nxp.com> 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/firmware.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 118c2ecf20Sopenharmony_ci#include <sound/sof.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "ops.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciextern struct snd_sof_dsp_ops sof_imx8_ops; 168c2ecf20Sopenharmony_ciextern struct snd_sof_dsp_ops sof_imx8x_ops; 178c2ecf20Sopenharmony_ciextern struct snd_sof_dsp_ops sof_imx8m_ops; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* platform specific devices */ 208c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) 218c2ecf20Sopenharmony_cistatic struct sof_dev_desc sof_of_imx8qxp_desc = { 228c2ecf20Sopenharmony_ci .default_fw_path = "imx/sof", 238c2ecf20Sopenharmony_ci .default_tplg_path = "imx/sof-tplg", 248c2ecf20Sopenharmony_ci .default_fw_filename = "sof-imx8x.ri", 258c2ecf20Sopenharmony_ci .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", 268c2ecf20Sopenharmony_ci .ops = &sof_imx8x_ops, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct sof_dev_desc sof_of_imx8qm_desc = { 308c2ecf20Sopenharmony_ci .default_fw_path = "imx/sof", 318c2ecf20Sopenharmony_ci .default_tplg_path = "imx/sof-tplg", 328c2ecf20Sopenharmony_ci .default_fw_filename = "sof-imx8.ri", 338c2ecf20Sopenharmony_ci .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", 348c2ecf20Sopenharmony_ci .ops = &sof_imx8_ops, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M) 398c2ecf20Sopenharmony_cistatic struct sof_dev_desc sof_of_imx8mp_desc = { 408c2ecf20Sopenharmony_ci .default_fw_path = "imx/sof", 418c2ecf20Sopenharmony_ci .default_tplg_path = "imx/sof-tplg", 428c2ecf20Sopenharmony_ci .default_fw_filename = "sof-imx8m.ri", 438c2ecf20Sopenharmony_ci .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", 448c2ecf20Sopenharmony_ci .ops = &sof_imx8m_ops, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sof_of_pm = { 498c2ecf20Sopenharmony_ci .prepare = snd_sof_prepare, 508c2ecf20Sopenharmony_ci .complete = snd_sof_complete, 518c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 528c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 538c2ecf20Sopenharmony_ci NULL) 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void sof_of_probe_complete(struct device *dev) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci /* allow runtime_pm */ 598c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 608c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 618c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 628c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 658c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int sof_of_probe(struct platform_device *pdev) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 718c2ecf20Sopenharmony_ci const struct sof_dev_desc *desc; 728c2ecf20Sopenharmony_ci struct snd_sof_pdata *sof_pdata; 738c2ecf20Sopenharmony_ci const struct snd_sof_dsp_ops *ops; 748c2ecf20Sopenharmony_ci int ret; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "DT DSP detected"); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 798c2ecf20Sopenharmony_ci if (!sof_pdata) 808c2ecf20Sopenharmony_ci return -ENOMEM; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci desc = device_get_match_data(dev); 838c2ecf20Sopenharmony_ci if (!desc) 848c2ecf20Sopenharmony_ci return -ENODEV; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* get ops for platform */ 878c2ecf20Sopenharmony_ci ops = desc->ops; 888c2ecf20Sopenharmony_ci if (!ops) { 898c2ecf20Sopenharmony_ci dev_err(dev, "error: no matching DT descriptor ops\n"); 908c2ecf20Sopenharmony_ci return -ENODEV; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci sof_pdata->desc = desc; 948c2ecf20Sopenharmony_ci sof_pdata->dev = &pdev->dev; 958c2ecf20Sopenharmony_ci sof_pdata->fw_filename = desc->default_fw_filename; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* TODO: read alternate fw and tplg filenames from DT */ 988c2ecf20Sopenharmony_ci sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; 998c2ecf20Sopenharmony_ci sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 1028c2ecf20Sopenharmony_ci /* set callback to enable runtime_pm */ 1038c2ecf20Sopenharmony_ci sof_pdata->sof_probe_complete = sof_of_probe_complete; 1048c2ecf20Sopenharmony_ci#endif 1058c2ecf20Sopenharmony_ci /* call sof helper for DSP hardware probe */ 1068c2ecf20Sopenharmony_ci ret = snd_sof_device_probe(dev, sof_pdata); 1078c2ecf20Sopenharmony_ci if (ret) { 1088c2ecf20Sopenharmony_ci dev_err(dev, "error: failed to probe DSP hardware\n"); 1098c2ecf20Sopenharmony_ci return ret; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 1138c2ecf20Sopenharmony_ci sof_of_probe_complete(dev); 1148c2ecf20Sopenharmony_ci#endif 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return ret; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int sof_of_remove(struct platform_device *pdev) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* call sof helper for DSP hardware remove */ 1248c2ecf20Sopenharmony_ci snd_sof_device_remove(&pdev->dev); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic const struct of_device_id sof_of_ids[] = { 1308c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) 1318c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, 1328c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc}, 1338c2ecf20Sopenharmony_ci#endif 1348c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M) 1358c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc}, 1368c2ecf20Sopenharmony_ci#endif 1378c2ecf20Sopenharmony_ci { } 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sof_of_ids); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* DT driver definition */ 1428c2ecf20Sopenharmony_cistatic struct platform_driver snd_sof_of_driver = { 1438c2ecf20Sopenharmony_ci .probe = sof_of_probe, 1448c2ecf20Sopenharmony_ci .remove = sof_of_remove, 1458c2ecf20Sopenharmony_ci .driver = { 1468c2ecf20Sopenharmony_ci .name = "sof-audio-of", 1478c2ecf20Sopenharmony_ci .pm = &sof_of_pm, 1488c2ecf20Sopenharmony_ci .of_match_table = sof_of_ids, 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_cimodule_platform_driver(snd_sof_of_driver); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 154