1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020, Linaro Limited
3 
4 #include <linux/err.h>
5 #include <linux/init.h>
6 #include <linux/clk-provider.h>
7 #include <linux/module.h>
8 #include <linux/device.h>
9 #include <linux/platform_device.h>
10 #include <linux/of.h>
11 #include <linux/slab.h>
12 #include "q6afe.h"
13 
14 #define Q6AFE_CLK(id) {					\
15 		.clk_id	= id,				\
16 		.afe_clk_id	= Q6AFE_##id,		\
17 		.name = #id,				\
18 		.rate = 19200000,			\
19 	}
20 
21 #define Q6AFE_VOTE_CLK(id, blkid, n) {			\
22 		.clk_id	= id,				\
23 		.afe_clk_id = blkid,			\
24 		.name = n,				\
25 	}
26 
27 struct q6afe_clk_init {
28 	int clk_id;
29 	int afe_clk_id;
30 	char *name;
31 	int rate;
32 };
33 
34 struct q6afe_clk {
35 	struct device *dev;
36 	int afe_clk_id;
37 	int attributes;
38 	int rate;
39 	uint32_t handle;
40 	struct clk_hw hw;
41 };
42 
43 #define to_q6afe_clk(_hw) container_of(_hw, struct q6afe_clk, hw)
44 
45 struct q6afe_cc {
46 	struct device *dev;
47 	struct q6afe_clk *clks[Q6AFE_MAX_CLK_ID];
48 };
49 
50 static int clk_q6afe_prepare(struct clk_hw *hw)
51 {
52 	struct q6afe_clk *clk = to_q6afe_clk(hw);
53 
54 	return q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes,
55 				     Q6AFE_LPASS_CLK_ROOT_DEFAULT, clk->rate);
56 }
57 
58 static void clk_q6afe_unprepare(struct clk_hw *hw)
59 {
60 	struct q6afe_clk *clk = to_q6afe_clk(hw);
61 
62 	q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes,
63 			      Q6AFE_LPASS_CLK_ROOT_DEFAULT, 0);
64 }
65 
66 static int clk_q6afe_set_rate(struct clk_hw *hw, unsigned long rate,
67 			      unsigned long parent_rate)
68 {
69 	struct q6afe_clk *clk = to_q6afe_clk(hw);
70 
71 	clk->rate = rate;
72 
73 	return 0;
74 }
75 
76 static unsigned long clk_q6afe_recalc_rate(struct clk_hw *hw,
77 					   unsigned long parent_rate)
78 {
79 	struct q6afe_clk *clk = to_q6afe_clk(hw);
80 
81 	return clk->rate;
82 }
83 
84 static long clk_q6afe_round_rate(struct clk_hw *hw, unsigned long rate,
85 				 unsigned long *parent_rate)
86 {
87 	return rate;
88 }
89 
90 static const struct clk_ops clk_q6afe_ops = {
91 	.prepare	= clk_q6afe_prepare,
92 	.unprepare	= clk_q6afe_unprepare,
93 	.set_rate	= clk_q6afe_set_rate,
94 	.round_rate	= clk_q6afe_round_rate,
95 	.recalc_rate	= clk_q6afe_recalc_rate,
96 };
97 
98 static int clk_vote_q6afe_block(struct clk_hw *hw)
99 {
100 	struct q6afe_clk *clk = to_q6afe_clk(hw);
101 
102 	return q6afe_vote_lpass_core_hw(clk->dev, clk->afe_clk_id,
103 					clk_hw_get_name(&clk->hw), &clk->handle);
104 }
105 
106 static void clk_unvote_q6afe_block(struct clk_hw *hw)
107 {
108 	struct q6afe_clk *clk = to_q6afe_clk(hw);
109 
110 	q6afe_unvote_lpass_core_hw(clk->dev, clk->afe_clk_id, clk->handle);
111 }
112 
113 static const struct clk_ops clk_vote_q6afe_ops = {
114 	.prepare	= clk_vote_q6afe_block,
115 	.unprepare	= clk_unvote_q6afe_block,
116 };
117 
118 static const struct q6afe_clk_init q6afe_clks[] = {
119 	Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT),
120 	Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT),
121 	Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT),
122 	Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_EBIT),
123 	Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_IBIT),
124 	Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_EBIT),
125 	Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_IBIT),
126 	Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_EBIT),
127 	Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_IBIT),
128 	Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_EBIT),
129 	Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_OSR),
130 	Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_IBIT),
131 	Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_EBIT),
132 	Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_IBIT),
133 	Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_EBIT),
134 	Q6AFE_CLK(LPASS_CLK_ID_INT0_MI2S_IBIT),
135 	Q6AFE_CLK(LPASS_CLK_ID_INT1_MI2S_IBIT),
136 	Q6AFE_CLK(LPASS_CLK_ID_INT2_MI2S_IBIT),
137 	Q6AFE_CLK(LPASS_CLK_ID_INT3_MI2S_IBIT),
138 	Q6AFE_CLK(LPASS_CLK_ID_INT4_MI2S_IBIT),
139 	Q6AFE_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT),
140 	Q6AFE_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT),
141 	Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_OSR),
142 	Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_IBIT),
143 	Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_EBIT),
144 	Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_IBIT),
145 	Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_EBIT),
146 	Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_IBIT),
147 	Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_EBIT),
148 	Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_IBIT),
149 	Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_EBIT),
150 	Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_IBIT),
151 	Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_EBIT),
152 	Q6AFE_CLK(LPASS_CLK_ID_QUI_PCM_OSR),
153 	Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_IBIT),
154 	Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_EBIT),
155 	Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_IBIT),
156 	Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_EBIT),
157 	Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_IBIT),
158 	Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_EBIT),
159 	Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_IBIT),
160 	Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_EBIT),
161 	Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_IBIT),
162 	Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_EBIT),
163 	Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_OSR),
164 	Q6AFE_CLK(LPASS_CLK_ID_MCLK_1),
165 	Q6AFE_CLK(LPASS_CLK_ID_MCLK_2),
166 	Q6AFE_CLK(LPASS_CLK_ID_MCLK_3),
167 	Q6AFE_CLK(LPASS_CLK_ID_MCLK_4),
168 	Q6AFE_CLK(LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE),
169 	Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_0),
170 	Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_1),
171 	Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_MCLK),
172 	Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK),
173 	Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_MCLK),
174 	Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_MCLK),
175 	Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_NPL_MCLK),
176 	Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_MCLK),
177 	Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK),
178 	Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK),
179 	Q6AFE_VOTE_CLK(LPASS_HW_AVTIMER_VOTE,
180 		       Q6AFE_LPASS_CORE_AVTIMER_BLOCK,
181 		       "LPASS_AVTIMER_MACRO"),
182 	Q6AFE_VOTE_CLK(LPASS_HW_MACRO_VOTE,
183 		       Q6AFE_LPASS_CORE_HW_MACRO_BLOCK,
184 		       "LPASS_HW_MACRO"),
185 	Q6AFE_VOTE_CLK(LPASS_HW_DCODEC_VOTE,
186 		       Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK,
187 		       "LPASS_HW_DCODEC"),
188 };
189 
190 static struct clk_hw *q6afe_of_clk_hw_get(struct of_phandle_args *clkspec,
191 					  void *data)
192 {
193 	struct q6afe_cc *cc = data;
194 	unsigned int idx = clkspec->args[0];
195 	unsigned int attr = clkspec->args[1];
196 
197 	if (idx >= Q6AFE_MAX_CLK_ID || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) {
198 		dev_err(cc->dev, "Invalid clk specifier (%d, %d)\n", idx, attr);
199 		return ERR_PTR(-EINVAL);
200 	}
201 
202 	if (cc->clks[idx]) {
203 		cc->clks[idx]->attributes = attr;
204 		return &cc->clks[idx]->hw;
205 	}
206 
207 	return ERR_PTR(-ENOENT);
208 }
209 
210 static int q6afe_clock_dev_probe(struct platform_device *pdev)
211 {
212 	struct q6afe_cc *cc;
213 	struct device *dev = &pdev->dev;
214 	int i, ret;
215 
216 	cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
217 	if (!cc)
218 		return -ENOMEM;
219 
220 	cc->dev = dev;
221 	for (i = 0; i < ARRAY_SIZE(q6afe_clks); i++) {
222 		unsigned int id = q6afe_clks[i].clk_id;
223 		struct clk_init_data init = {
224 			.name =  q6afe_clks[i].name,
225 		};
226 		struct q6afe_clk *clk;
227 
228 		clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
229 		if (!clk)
230 			return -ENOMEM;
231 
232 		clk->dev = dev;
233 		clk->afe_clk_id = q6afe_clks[i].afe_clk_id;
234 		clk->rate = q6afe_clks[i].rate;
235 		clk->hw.init = &init;
236 
237 		if (clk->rate)
238 			init.ops = &clk_q6afe_ops;
239 		else
240 			init.ops = &clk_vote_q6afe_ops;
241 
242 		cc->clks[id] = clk;
243 
244 		ret = devm_clk_hw_register(dev, &clk->hw);
245 		if (ret)
246 			return ret;
247 	}
248 
249 	ret = devm_of_clk_add_hw_provider(dev, q6afe_of_clk_hw_get, cc);
250 	if (ret)
251 		return ret;
252 
253 	dev_set_drvdata(dev, cc);
254 
255 	return 0;
256 }
257 
258 #ifdef CONFIG_OF
259 static const struct of_device_id q6afe_clock_device_id[] = {
260 	{ .compatible = "qcom,q6afe-clocks" },
261 	{},
262 };
263 MODULE_DEVICE_TABLE(of, q6afe_clock_device_id);
264 #endif
265 
266 static struct platform_driver q6afe_clock_platform_driver = {
267 	.driver = {
268 		.name = "q6afe-clock",
269 		.of_match_table = of_match_ptr(q6afe_clock_device_id),
270 	},
271 	.probe = q6afe_clock_dev_probe,
272 };
273 module_platform_driver(q6afe_clock_platform_driver);
274 
275 MODULE_DESCRIPTION("Q6 Audio Frontend clock driver");
276 MODULE_LICENSE("GPL v2");
277