1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // Copyright(c) 2021 Mediatek Corporation. All rights reserved. 4 // 5 // Author: YC Hung <yc.hung@mediatek.com> 6 // 7 // Hardware interface for mt8195 DSP clock 8 9 #include <linux/clk.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/io.h> 12 #include "mt8195.h" 13 #include "mt8195-clk.h" 14 #include "../adsp_helper.h" 15 #include "../../sof-audio.h" 16 17 static const char *adsp_clks[ADSP_CLK_MAX] = { 18 [CLK_TOP_ADSP] = "adsp_sel", 19 [CLK_TOP_CLK26M] = "clk26m_ck", 20 [CLK_TOP_AUDIO_LOCAL_BUS] = "audio_local_bus", 21 [CLK_TOP_MAINPLL_D7_D2] = "mainpll_d7_d2", 22 [CLK_SCP_ADSP_AUDIODSP] = "scp_adsp_audiodsp", 23 [CLK_TOP_AUDIO_H] = "audio_h", 24 }; 25 26 int mt8195_adsp_init_clock(struct snd_sof_dev *sdev) 27 { 28 struct device *dev = sdev->dev; 29 struct adsp_priv *priv = sdev->pdata->hw_pdata; 30 int i; 31 32 priv->clk = devm_kcalloc(dev, ADSP_CLK_MAX, sizeof(*priv->clk), GFP_KERNEL); 33 34 if (!priv->clk) 35 return -ENOMEM; 36 37 for (i = 0; i < ADSP_CLK_MAX; i++) { 38 priv->clk[i] = devm_clk_get(dev, adsp_clks[i]); 39 if (IS_ERR(priv->clk[i])) 40 return PTR_ERR(priv->clk[i]); 41 } 42 43 return 0; 44 } 45 46 static int adsp_enable_all_clock(struct snd_sof_dev *sdev) 47 { 48 struct device *dev = sdev->dev; 49 struct adsp_priv *priv = sdev->pdata->hw_pdata; 50 int ret; 51 52 ret = clk_prepare_enable(priv->clk[CLK_TOP_MAINPLL_D7_D2]); 53 if (ret) { 54 dev_err(dev, "%s clk_prepare_enable(mainpll_d7_d2) fail %d\n", 55 __func__, ret); 56 return ret; 57 } 58 59 ret = clk_prepare_enable(priv->clk[CLK_TOP_ADSP]); 60 if (ret) { 61 dev_err(dev, "%s clk_prepare_enable(adsp_sel) fail %d\n", 62 __func__, ret); 63 goto disable_mainpll_d7_d2_clk; 64 } 65 66 ret = clk_prepare_enable(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); 67 if (ret) { 68 dev_err(dev, "%s clk_prepare_enable(audio_local_bus) fail %d\n", 69 __func__, ret); 70 goto disable_dsp_sel_clk; 71 } 72 73 ret = clk_prepare_enable(priv->clk[CLK_SCP_ADSP_AUDIODSP]); 74 if (ret) { 75 dev_err(dev, "%s clk_prepare_enable(scp_adsp_audiodsp) fail %d\n", 76 __func__, ret); 77 goto disable_audio_local_bus_clk; 78 } 79 80 ret = clk_prepare_enable(priv->clk[CLK_TOP_AUDIO_H]); 81 if (ret) { 82 dev_err(dev, "%s clk_prepare_enable(audio_h) fail %d\n", 83 __func__, ret); 84 goto disable_scp_adsp_audiodsp_clk; 85 } 86 87 return 0; 88 89 disable_scp_adsp_audiodsp_clk: 90 clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]); 91 disable_audio_local_bus_clk: 92 clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); 93 disable_dsp_sel_clk: 94 clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]); 95 disable_mainpll_d7_d2_clk: 96 clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]); 97 98 return ret; 99 } 100 101 static void adsp_disable_all_clock(struct snd_sof_dev *sdev) 102 { 103 struct adsp_priv *priv = sdev->pdata->hw_pdata; 104 105 clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_H]); 106 clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]); 107 clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); 108 clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]); 109 clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]); 110 } 111 112 static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable) 113 { 114 struct device *dev = sdev->dev; 115 struct adsp_priv *priv = sdev->pdata->hw_pdata; 116 int ret; 117 118 dev_dbg(dev, "%s: %s\n", __func__, enable ? "on" : "off"); 119 120 if (enable) { 121 ret = clk_set_parent(priv->clk[CLK_TOP_ADSP], 122 priv->clk[CLK_TOP_CLK26M]); 123 if (ret) { 124 dev_err(dev, "failed to set dsp_sel to clk26m: %d\n", ret); 125 return ret; 126 } 127 128 ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS], 129 priv->clk[CLK_TOP_MAINPLL_D7_D2]); 130 if (ret) { 131 dev_err(dev, "set audio_local_bus failed %d\n", ret); 132 return ret; 133 } 134 135 ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_H], 136 priv->clk[CLK_TOP_CLK26M]); 137 if (ret) { 138 dev_err(dev, "set audio_h_sel failed %d\n", ret); 139 return ret; 140 } 141 142 ret = adsp_enable_all_clock(sdev); 143 if (ret) { 144 dev_err(dev, "failed to adsp_enable_clock: %d\n", ret); 145 return ret; 146 } 147 } else { 148 adsp_disable_all_clock(sdev); 149 } 150 151 return 0; 152 } 153 154 int adsp_clock_on(struct snd_sof_dev *sdev) 155 { 156 /* Open ADSP clock */ 157 return adsp_default_clk_init(sdev, 1); 158 } 159 160 int adsp_clock_off(struct snd_sof_dev *sdev) 161 { 162 /* Close ADSP clock */ 163 return adsp_default_clk_init(sdev, 0); 164 } 165 166