1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 // 3 // Copyright 2019 NXP 4 // 5 // Author: Daniel Baluta <daniel.baluta@nxp.com> 6 // 7 8 #include <linux/firmware.h> 9 #include <linux/module.h> 10 #include <linux/pm_runtime.h> 11 #include <sound/sof.h> 12 13 #include "ops.h" 14 15 extern struct snd_sof_dsp_ops sof_imx8_ops; 16 17 /* platform specific devices */ 18 #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) 19 static struct sof_dev_desc sof_of_imx8qxp_desc = { 20 .default_fw_path = "imx/sof", 21 .default_tplg_path = "imx/sof-tplg", 22 .default_fw_filename = "sof-imx8.ri", 23 .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", 24 .ops = &sof_imx8_ops, 25 }; 26 #endif 27 28 static const struct dev_pm_ops sof_of_pm = { 29 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 30 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 31 NULL) 32 }; 33 34 static void sof_of_probe_complete(struct device *dev) 35 { 36 /* allow runtime_pm */ 37 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 38 pm_runtime_use_autosuspend(dev); 39 pm_runtime_enable(dev); 40 } 41 42 static int sof_of_probe(struct platform_device *pdev) 43 { 44 struct device *dev = &pdev->dev; 45 const struct sof_dev_desc *desc; 46 struct snd_sof_pdata *sof_pdata; 47 const struct snd_sof_dsp_ops *ops; 48 int ret; 49 50 dev_info(&pdev->dev, "DT DSP detected"); 51 52 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 53 if (!sof_pdata) 54 return -ENOMEM; 55 56 desc = device_get_match_data(dev); 57 if (!desc) 58 return -ENODEV; 59 60 /* get ops for platform */ 61 ops = desc->ops; 62 if (!ops) { 63 dev_err(dev, "error: no matching DT descriptor ops\n"); 64 return -ENODEV; 65 } 66 67 sof_pdata->desc = desc; 68 sof_pdata->dev = &pdev->dev; 69 sof_pdata->fw_filename = desc->default_fw_filename; 70 71 /* TODO: read alternate fw and tplg filenames from DT */ 72 sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; 73 sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; 74 75 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 76 /* set callback to enable runtime_pm */ 77 sof_pdata->sof_probe_complete = sof_of_probe_complete; 78 #endif 79 /* call sof helper for DSP hardware probe */ 80 ret = snd_sof_device_probe(dev, sof_pdata); 81 if (ret) { 82 dev_err(dev, "error: failed to probe DSP hardware\n"); 83 return ret; 84 } 85 86 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 87 sof_of_probe_complete(dev); 88 #endif 89 90 return ret; 91 } 92 93 static int sof_of_remove(struct platform_device *pdev) 94 { 95 pm_runtime_disable(&pdev->dev); 96 97 /* call sof helper for DSP hardware remove */ 98 snd_sof_device_remove(&pdev->dev); 99 100 return 0; 101 } 102 103 static const struct of_device_id sof_of_ids[] = { 104 #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) 105 { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, 106 #endif 107 { } 108 }; 109 MODULE_DEVICE_TABLE(of, sof_of_ids); 110 111 /* DT driver definition */ 112 static struct platform_driver snd_sof_of_driver = { 113 .probe = sof_of_probe, 114 .remove = sof_of_remove, 115 .driver = { 116 .name = "sof-audio-of", 117 .pm = &sof_of_pm, 118 .of_match_table = sof_of_ids, 119 }, 120 }; 121 module_platform_driver(snd_sof_of_driver); 122 123 MODULE_LICENSE("Dual BSD/GPL"); 124