1 /*
2  * mt6797-afe-clk.c  --  Mediatek 6797 afe clock ctrl
3  *
4  * Copyright (c) 2018 MediaTek Inc.
5  * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 and
9  * only version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #include <linux/clk.h>
18 
19 #include "mt6797-afe-common.h"
20 #include "mt6797-afe-clk.h"
21 
22 enum {
23 	CLK_INFRA_SYS_AUD,
24 	CLK_INFRA_SYS_AUD_26M,
25 	CLK_TOP_MUX_AUD,
26 	CLK_TOP_MUX_AUD_BUS,
27 	CLK_TOP_SYSPLL3_D4,
28 	CLK_TOP_SYSPLL1_D4,
29 	CLK_CLK26M,
30 	CLK_NUM
31 };
32 
33 static const char *aud_clks[CLK_NUM] = {
34 	[CLK_INFRA_SYS_AUD] = "infra_sys_audio_clk",
35 	[CLK_INFRA_SYS_AUD_26M] = "infra_sys_audio_26m",
36 	[CLK_TOP_MUX_AUD] = "top_mux_audio",
37 	[CLK_TOP_MUX_AUD_BUS] = "top_mux_aud_intbus",
38 	[CLK_TOP_SYSPLL3_D4] = "top_sys_pll3_d4",
39 	[CLK_TOP_SYSPLL1_D4] = "top_sys_pll1_d4",
40 	[CLK_CLK26M] = "top_clk26m_clk",
41 };
42 
43 int mt6797_init_clock(struct mtk_base_afe *afe)
44 {
45 	struct mt6797_afe_private *afe_priv = afe->platform_priv;
46 	int i;
47 
48 	afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
49 				     GFP_KERNEL);
50 	if (!afe_priv->clk)
51 		return -ENOMEM;
52 
53 	for (i = 0; i < CLK_NUM; i++) {
54 		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
55 		if (IS_ERR(afe_priv->clk[i])) {
56 			dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
57 				__func__, aud_clks[i],
58 				PTR_ERR(afe_priv->clk[i]));
59 			return PTR_ERR(afe_priv->clk[i]);
60 		}
61 	}
62 
63 	return 0;
64 }
65 
66 int mt6797_afe_enable_clock(struct mtk_base_afe *afe)
67 {
68 	struct mt6797_afe_private *afe_priv = afe->platform_priv;
69 	int ret;
70 
71 	ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD]);
72 	if (ret) {
73 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
74 			__func__, aud_clks[CLK_INFRA_SYS_AUD], ret);
75 		goto CLK_INFRA_SYS_AUDIO_ERR;
76 	}
77 
78 	ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
79 	if (ret) {
80 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
81 			__func__, aud_clks[CLK_INFRA_SYS_AUD_26M], ret);
82 		goto CLK_INFRA_SYS_AUD_26M_ERR;
83 	}
84 
85 	ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD]);
86 	if (ret) {
87 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
88 			__func__, aud_clks[CLK_TOP_MUX_AUD], ret);
89 		goto CLK_MUX_AUDIO_ERR;
90 	}
91 
92 	ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD],
93 			     afe_priv->clk[CLK_CLK26M]);
94 	if (ret) {
95 		dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
96 			__func__, aud_clks[CLK_TOP_MUX_AUD],
97 			aud_clks[CLK_CLK26M], ret);
98 		goto CLK_MUX_AUDIO_ERR;
99 	}
100 
101 	ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
102 	if (ret) {
103 		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
104 			__func__, aud_clks[CLK_TOP_MUX_AUD_BUS], ret);
105 		goto CLK_MUX_AUDIO_INTBUS_ERR;
106 	}
107 
108 	return ret;
109 
110 CLK_MUX_AUDIO_INTBUS_ERR:
111 	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
112 CLK_MUX_AUDIO_ERR:
113 	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
114 CLK_INFRA_SYS_AUD_26M_ERR:
115 	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
116 CLK_INFRA_SYS_AUDIO_ERR:
117 	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
118 
119 	return 0;
120 }
121 
122 int mt6797_afe_disable_clock(struct mtk_base_afe *afe)
123 {
124 	struct mt6797_afe_private *afe_priv = afe->platform_priv;
125 
126 	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_BUS]);
127 	clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD]);
128 	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD_26M]);
129 	clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUD]);
130 
131 	return 0;
132 }
133