1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
5 // Author: Daniel Baluta <daniel.baluta@nxp.com>
8 #include <linux/firmware.h>
9 #include <linux/module.h>
10 #include <linux/pm_runtime.h>
11 #include <sound/sof.h>
15 extern struct snd_sof_dsp_ops sof_imx8_ops
;
16 extern struct snd_sof_dsp_ops sof_imx8x_ops
;
17 extern struct snd_sof_dsp_ops sof_imx8m_ops
;
19 /* platform specific devices */
20 #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
21 static struct sof_dev_desc sof_of_imx8qxp_desc
= {
22 .default_fw_path
= "imx/sof",
23 .default_tplg_path
= "imx/sof-tplg",
24 .default_fw_filename
= "sof-imx8x.ri",
25 .nocodec_tplg_filename
= "sof-imx8-nocodec.tplg",
26 .ops
= &sof_imx8x_ops
,
29 static struct sof_dev_desc sof_of_imx8qm_desc
= {
30 .default_fw_path
= "imx/sof",
31 .default_tplg_path
= "imx/sof-tplg",
32 .default_fw_filename
= "sof-imx8.ri",
33 .nocodec_tplg_filename
= "sof-imx8-nocodec.tplg",
38 #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
39 static struct sof_dev_desc sof_of_imx8mp_desc
= {
40 .default_fw_path
= "imx/sof",
41 .default_tplg_path
= "imx/sof-tplg",
42 .default_fw_filename
= "sof-imx8m.ri",
43 .nocodec_tplg_filename
= "sof-imx8-nocodec.tplg",
44 .ops
= &sof_imx8m_ops
,
48 static const struct dev_pm_ops sof_of_pm
= {
49 .prepare
= snd_sof_prepare
,
50 .complete
= snd_sof_complete
,
51 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend
, snd_sof_resume
)
52 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend
, snd_sof_runtime_resume
,
56 static void sof_of_probe_complete(struct device
*dev
)
58 /* allow runtime_pm */
59 pm_runtime_set_autosuspend_delay(dev
, SND_SOF_SUSPEND_DELAY_MS
);
60 pm_runtime_use_autosuspend(dev
);
61 pm_runtime_set_active(dev
);
62 pm_runtime_enable(dev
);
64 pm_runtime_mark_last_busy(dev
);
65 pm_runtime_put_autosuspend(dev
);
68 static int sof_of_probe(struct platform_device
*pdev
)
70 struct device
*dev
= &pdev
->dev
;
71 const struct sof_dev_desc
*desc
;
72 struct snd_sof_pdata
*sof_pdata
;
73 const struct snd_sof_dsp_ops
*ops
;
76 dev_info(&pdev
->dev
, "DT DSP detected");
78 sof_pdata
= devm_kzalloc(dev
, sizeof(*sof_pdata
), GFP_KERNEL
);
82 desc
= device_get_match_data(dev
);
86 /* get ops for platform */
89 dev_err(dev
, "error: no matching DT descriptor ops\n");
93 sof_pdata
->desc
= desc
;
94 sof_pdata
->dev
= &pdev
->dev
;
95 sof_pdata
->fw_filename
= desc
->default_fw_filename
;
97 /* TODO: read alternate fw and tplg filenames from DT */
98 sof_pdata
->fw_filename_prefix
= sof_pdata
->desc
->default_fw_path
;
99 sof_pdata
->tplg_filename_prefix
= sof_pdata
->desc
->default_tplg_path
;
101 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
102 /* set callback to enable runtime_pm */
103 sof_pdata
->sof_probe_complete
= sof_of_probe_complete
;
105 /* call sof helper for DSP hardware probe */
106 ret
= snd_sof_device_probe(dev
, sof_pdata
);
108 dev_err(dev
, "error: failed to probe DSP hardware\n");
112 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
113 sof_of_probe_complete(dev
);
119 static int sof_of_remove(struct platform_device
*pdev
)
121 pm_runtime_disable(&pdev
->dev
);
123 /* call sof helper for DSP hardware remove */
124 snd_sof_device_remove(&pdev
->dev
);
129 static const struct of_device_id sof_of_ids
[] = {
130 #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
131 { .compatible
= "fsl,imx8qxp-dsp", .data
= &sof_of_imx8qxp_desc
},
132 { .compatible
= "fsl,imx8qm-dsp", .data
= &sof_of_imx8qm_desc
},
134 #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
135 { .compatible
= "fsl,imx8mp-dsp", .data
= &sof_of_imx8mp_desc
},
139 MODULE_DEVICE_TABLE(of
, sof_of_ids
);
141 /* DT driver definition */
142 static struct platform_driver snd_sof_of_driver
= {
143 .probe
= sof_of_probe
,
144 .remove
= sof_of_remove
,
146 .name
= "sof-audio-of",
148 .of_match_table
= sof_of_ids
,
151 module_platform_driver(snd_sof_of_driver
);
153 MODULE_LICENSE("Dual BSD/GPL");