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