@@ -74,4 +74,48 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
}
EXPORT_SYMBOL(imx8_dump);
+int imx8_parse_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks)
+{
+ int ret;
+
+ ret = devm_clk_bulk_get(sdev->dev, clks->num_dsp_clks, clks->dsp_clks);
+ if (ret) {
+ dev_err(sdev->dev, "Failed to request DSP clocks\n");
+ return ret;
+ }
+
+ ret = devm_clk_bulk_get_optional(sdev->dev, clks->num_dai_clks, clks->dai_clks);
+ if (ret) {
+ dev_err(sdev->dev, "Failed to request DAI clks\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(imx8_parse_clocks);
+
+int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks)
+{
+ int ret;
+
+ ret = clk_bulk_prepare_enable(clks->num_dsp_clks, clks->dsp_clks);
+ if (ret)
+ return ret;
+ ret = clk_bulk_prepare_enable(clks->num_dai_clks, clks->dai_clks);
+ if (ret) {
+ clk_bulk_disable_unprepare(clks->num_dsp_clks, clks->dsp_clks);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(imx8_enable_clocks);
+
+void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks)
+{
+ clk_bulk_disable_unprepare(clks->num_dsp_clks, clks->dsp_clks);
+ clk_bulk_disable_unprepare(clks->num_dai_clks, clks->dai_clks);
+}
+EXPORT_SYMBOL(imx8_disable_clocks);
+
MODULE_LICENSE("Dual BSD/GPL");
@@ -3,6 +3,8 @@
#ifndef __IMX_COMMON_H__
#define __IMX_COMMON_H__
+#include <linux/clk.h>
+
#define EXCEPT_MAX_HDR_SIZE 0x400
#define IMX8_STACK_DUMP_SIZE 32
@@ -13,4 +15,15 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
void imx8_dump(struct snd_sof_dev *sdev, u32 flags);
+struct imx_clocks {
+ struct clk_bulk_data *dsp_clks;
+ int num_dsp_clks;
+ struct clk_bulk_data *dai_clks;
+ int num_dai_clks;
+};
+
+int imx8_parse_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks);
+int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks);
+void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks);
+
#endif
@@ -41,6 +41,25 @@
#define MBOX_OFFSET 0x800000
#define MBOX_SIZE 0x1000
+/* DSP clocks */
+struct clk_bulk_data imx8_dsp_clks[] = {
+ { .id = "ipg" },
+ { .id = "ocram" },
+ { .id = "core" },
+};
+
+/* DAI clocks */
+struct clk_bulk_data imx8_dai_clks[] = {
+ { .id = "esai0_core" },
+ { .id = "esai0_extal" },
+ { .id = "esai0_spba" },
+ { .id = "sai1_bus" },
+ { .id = "sai1_mclk0" },
+ { .id = "sai1_mclk1" },
+ { .id = "sai1_mclk2" },
+ { .id = "sai1_mclk3" },
+};
+
struct imx8_priv {
struct device *dev;
struct snd_sof_dev *sdev;
@@ -57,6 +76,7 @@ struct imx8_priv {
struct device **pd_dev;
struct device_link **link;
+ struct imx_clocks *clks;
};
static void imx8_get_reply(struct snd_sof_dev *sdev)
@@ -223,6 +243,10 @@ static int imx8_probe(struct snd_sof_dev *sdev)
if (!priv)
return -ENOMEM;
+ priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL);
+ if (!priv->clks)
+ return -ENOMEM;
+
sdev->num_cores = 1;
sdev->pdata->hw_pdata = priv;
priv->dev = sdev->dev;
@@ -336,6 +360,18 @@ static int imx8_probe(struct snd_sof_dev *sdev)
/* set default mailbox offset for FW ready message */
sdev->dsp_box.offset = MBOX_OFFSET;
+ /* init clocks info */
+ priv->clks->dsp_clks = imx8_dsp_clks;
+ priv->clks->num_dsp_clks = ARRAY_SIZE(imx8_dsp_clks);
+ priv->clks->dai_clks = imx8_dai_clks;
+ priv->clks->num_dai_clks = ARRAY_SIZE(imx8_dai_clks);
+
+ ret = imx8_parse_clocks(sdev, priv->clks);
+ if (ret < 0)
+ goto exit_pdev_unregister;
+
+ imx8_enable_clocks(sdev, priv->clks);
+
return 0;
exit_pdev_unregister:
@@ -354,6 +390,7 @@ static int imx8_remove(struct snd_sof_dev *sdev)
struct imx8_priv *priv = sdev->pdata->hw_pdata;
int i;
+ imx8_disable_clocks(sdev, priv->clks);
platform_device_unregister(priv->ipc_dev);
for (i = 0; i < priv->num_domains; i++) {
@@ -23,6 +23,21 @@
#define MBOX_OFFSET 0x800000
#define MBOX_SIZE 0x1000
+struct clk_bulk_data imx8m_dsp_clks[] = {
+ { .id = "ipg" },
+ { .id = "ocram" },
+ { .id = "core" },
+};
+
+struct clk_bulk_data imx8m_dai_clks[] = {
+ { .id = "sai3_bus" },
+ { .id = "sai3_mclk0" },
+ { .id = "sai3_mclk1" },
+ { .id = "sai3_mclk2" },
+ { .id = "sai3_mclk3" },
+ { .id = "sdma3_root" },
+};
+
struct imx8m_priv {
struct device *dev;
struct snd_sof_dev *sdev;
@@ -30,6 +45,8 @@ struct imx8m_priv {
/* DSP IPC handler */
struct imx_dsp_ipc *dsp_ipc;
struct platform_device *ipc_dev;
+
+ struct imx_clocks *clks;
};
static void imx8m_get_reply(struct snd_sof_dev *sdev)
@@ -143,6 +160,10 @@ static int imx8m_probe(struct snd_sof_dev *sdev)
if (!priv)
return -ENOMEM;
+ priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL);
+ if (!priv->clks)
+ return -ENOMEM;
+
sdev->num_cores = 1;
sdev->pdata->hw_pdata = priv;
priv->dev = sdev->dev;
@@ -211,6 +232,18 @@ static int imx8m_probe(struct snd_sof_dev *sdev)
/* set default mailbox offset for FW ready message */
sdev->dsp_box.offset = MBOX_OFFSET;
+ /* init clocks info */
+ priv->clks->dsp_clks = imx8m_dsp_clks;
+ priv->clks->num_dsp_clks = ARRAY_SIZE(imx8m_dsp_clks);
+ priv->clks->dai_clks = imx8m_dai_clks;
+ priv->clks->num_dai_clks = ARRAY_SIZE(imx8m_dai_clks);
+
+ ret = imx8_parse_clocks(sdev, priv->clks);
+ if (ret < 0)
+ goto exit_pdev_unregister;
+
+ imx8_enable_clocks(sdev, priv->clks);
+
return 0;
exit_pdev_unregister:
@@ -222,6 +255,7 @@ static int imx8m_remove(struct snd_sof_dev *sdev)
{
struct imx8m_priv *priv = sdev->pdata->hw_pdata;
+ imx8_disable_clocks(sdev, priv->clks);
platform_device_unregister(priv->ipc_dev);
return 0;