File Index
Files and directories
Sign in
FILE

mt8195-clk.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/sof/mediatek/mt8195/mt8195-clk.c 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 clock
  8
  9#include <linux/clk.h>
 10#include <linux/io.h>
 11#include <linux/string_choices.h>
 12#include "mt8195.h"
 13#include "mt8195-clk.h"
 14#include "../adsp_helper.h"
 15#include "../../sof-audio.h"
 16
 17static 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
 26int 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
 46static 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
 89disable_scp_adsp_audiodsp_clk:
 90	clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]);
 91disable_audio_local_bus_clk:
 92	clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]);
 93disable_dsp_sel_clk:
 94	clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]);
 95disable_mainpll_d7_d2_clk:
 96	clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]);
 97
 98	return ret;
 99}
100
101static 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
112static 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__, str_on_off(enable));
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
154int adsp_clock_on(struct snd_sof_dev *sdev)
155{
156	/* Open ADSP clock */
157	return adsp_default_clk_init(sdev, 1);
158}
159
160int adsp_clock_off(struct snd_sof_dev *sdev)
161{
162	/* Close ADSP clock */
163	return adsp_default_clk_init(sdev, 0);
164}
165
~/ Read-only file preview.