165 lines · c
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 clock8 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 16static 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 25int 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 45static 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 88disable_scp_adsp_audiodsp_clk:89 clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]);90disable_audio_local_bus_clk:91 clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]);92disable_dsp_sel_clk:93 clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]);94disable_mainpll_d7_d2_clk:95 clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]);96 97 return ret;98}99 100static 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 111static 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 153int adsp_clock_on(struct snd_sof_dev *sdev)154{155 /* Open ADSP clock */156 return adsp_default_clk_init(sdev, 1);157}158 159int adsp_clock_off(struct snd_sof_dev *sdev)160{161 /* Close ADSP clock */162 return adsp_default_clk_init(sdev, 0);163}164 165