1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2021, The Linux Foundation. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/err.h> |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/pm_clock.h> |
13 | #include <linux/pm_runtime.h> |
14 | #include <linux/regmap.h> |
15 | |
16 | #include <dt-bindings/clock/qcom,lpass-sc7280.h> |
17 | #include <dt-bindings/clock/qcom,lpassaudiocc-sc7280.h> |
18 | |
19 | #include "clk-alpha-pll.h" |
20 | #include "clk-branch.h" |
21 | #include "clk-rcg.h" |
22 | #include "clk-regmap.h" |
23 | #include "clk-regmap-divider.h" |
24 | #include "clk-regmap-mux.h" |
25 | #include "common.h" |
26 | #include "gdsc.h" |
27 | #include "reset.h" |
28 | |
29 | enum { |
30 | P_BI_TCXO, |
31 | P_LPASS_AON_CC_PLL_OUT_EVEN, |
32 | P_LPASS_AON_CC_PLL_OUT_MAIN, |
33 | P_LPASS_AON_CC_PLL_OUT_MAIN_CDIV_DIV_CLK_SRC, |
34 | P_LPASS_AON_CC_PLL_OUT_ODD, |
35 | P_LPASS_AUDIO_CC_PLL_OUT_AUX, |
36 | P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, |
37 | P_LPASS_AUDIO_CC_PLL_MAIN_DIV_CLK, |
38 | }; |
39 | |
40 | static const struct pll_vco zonda_vco[] = { |
41 | { 595200000UL, 3600000000UL, 0 }, |
42 | }; |
43 | |
44 | static struct clk_branch lpass_q6ss_ahbm_clk = { |
45 | .halt_reg = 0x901c, |
46 | .halt_check = BRANCH_HALT, |
47 | .clkr = { |
48 | .enable_reg = 0x901c, |
49 | .enable_mask = BIT(0), |
50 | .hw.init = &(struct clk_init_data){ |
51 | .name = "lpass_q6ss_ahbm_clk" , |
52 | .ops = &clk_branch2_ops, |
53 | }, |
54 | }, |
55 | }; |
56 | |
57 | static struct clk_branch lpass_q6ss_ahbs_clk = { |
58 | .halt_reg = 0x9020, |
59 | .halt_check = BRANCH_HALT_VOTED, |
60 | .clkr = { |
61 | .enable_reg = 0x9020, |
62 | .enable_mask = BIT(0), |
63 | .hw.init = &(struct clk_init_data){ |
64 | .name = "lpass_q6ss_ahbs_clk" , |
65 | .ops = &clk_branch2_ops, |
66 | }, |
67 | }, |
68 | }; |
69 | |
70 | /* 1128.96MHz configuration */ |
71 | static const struct alpha_pll_config lpass_audio_cc_pll_config = { |
72 | .l = 0x3a, |
73 | .alpha = 0xcccc, |
74 | .config_ctl_val = 0x08200920, |
75 | .config_ctl_hi_val = 0x05002001, |
76 | .config_ctl_hi1_val = 0x00000000, |
77 | .user_ctl_val = 0x03000101, |
78 | }; |
79 | |
80 | static struct clk_alpha_pll lpass_audio_cc_pll = { |
81 | .offset = 0x0, |
82 | .vco_table = zonda_vco, |
83 | .num_vco = ARRAY_SIZE(zonda_vco), |
84 | .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA], |
85 | .clkr = { |
86 | .hw.init = &(const struct clk_init_data){ |
87 | .name = "lpass_audio_cc_pll" , |
88 | .parent_data = &(const struct clk_parent_data){ |
89 | .index = 0, |
90 | }, |
91 | .num_parents = 1, |
92 | .ops = &clk_alpha_pll_zonda_ops, |
93 | }, |
94 | }, |
95 | }; |
96 | |
97 | static const struct clk_div_table post_div_table_lpass_audio_cc_pll_out_aux2[] = { |
98 | { 0x1, 2 }, |
99 | { } |
100 | }; |
101 | |
102 | static struct clk_alpha_pll_postdiv lpass_audio_cc_pll_out_aux2 = { |
103 | .offset = 0x0, |
104 | .post_div_shift = 8, |
105 | .post_div_table = post_div_table_lpass_audio_cc_pll_out_aux2, |
106 | .num_post_div = ARRAY_SIZE(post_div_table_lpass_audio_cc_pll_out_aux2), |
107 | .width = 2, |
108 | .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA], |
109 | .clkr.hw.init = &(const struct clk_init_data){ |
110 | .name = "lpass_audio_cc_pll_out_aux2" , |
111 | .parent_hws = (const struct clk_hw*[]){ |
112 | &lpass_audio_cc_pll.clkr.hw, |
113 | }, |
114 | .num_parents = 1, |
115 | .ops = &clk_alpha_pll_postdiv_zonda_ops, |
116 | }, |
117 | }; |
118 | |
119 | static const struct pll_vco lucid_vco[] = { |
120 | { 249600000, 2000000000, 0 }, |
121 | }; |
122 | |
123 | /* 614.4 MHz configuration */ |
124 | static const struct alpha_pll_config lpass_aon_cc_pll_config = { |
125 | .l = 0x20, |
126 | .alpha = 0x0, |
127 | .config_ctl_val = 0x20485699, |
128 | .config_ctl_hi_val = 0x00002261, |
129 | .config_ctl_hi1_val = 0x329A299C, |
130 | .user_ctl_val = 0x00005100, |
131 | .user_ctl_hi_val = 0x00000805, |
132 | .user_ctl_hi1_val = 0x00000000, |
133 | }; |
134 | |
135 | static struct clk_alpha_pll lpass_aon_cc_pll = { |
136 | .offset = 0x0, |
137 | .vco_table = lucid_vco, |
138 | .num_vco = ARRAY_SIZE(lucid_vco), |
139 | .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], |
140 | .clkr = { |
141 | .hw.init = &(const struct clk_init_data){ |
142 | .name = "lpass_aon_cc_pll" , |
143 | .parent_data = &(const struct clk_parent_data){ |
144 | .index = 0, |
145 | }, |
146 | .num_parents = 1, |
147 | .ops = &clk_alpha_pll_lucid_ops, |
148 | }, |
149 | }, |
150 | }; |
151 | |
152 | static const struct clk_div_table post_div_table_lpass_aon_cc_pll_out_even[] = { |
153 | { 0x1, 2 }, |
154 | { } |
155 | }; |
156 | |
157 | static struct clk_alpha_pll_postdiv lpass_aon_cc_pll_out_even = { |
158 | .offset = 0x0, |
159 | .post_div_shift = 8, |
160 | .post_div_table = post_div_table_lpass_aon_cc_pll_out_even, |
161 | .num_post_div = ARRAY_SIZE(post_div_table_lpass_aon_cc_pll_out_even), |
162 | .width = 4, |
163 | .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], |
164 | .clkr.hw.init = &(const struct clk_init_data){ |
165 | .name = "lpass_aon_cc_pll_out_even" , |
166 | .parent_hws = (const struct clk_hw*[]){ |
167 | &lpass_aon_cc_pll.clkr.hw, |
168 | }, |
169 | .num_parents = 1, |
170 | .ops = &clk_alpha_pll_postdiv_lucid_ops, |
171 | }, |
172 | }; |
173 | |
174 | static const struct clk_div_table post_div_table_lpass_aon_cc_pll_out_odd[] = { |
175 | { .val: 0x5, .div: 5 }, |
176 | { } |
177 | }; |
178 | |
179 | static struct clk_alpha_pll_postdiv lpass_aon_cc_pll_out_odd = { |
180 | .offset = 0x0, |
181 | .post_div_shift = 12, |
182 | .post_div_table = post_div_table_lpass_aon_cc_pll_out_odd, |
183 | .num_post_div = ARRAY_SIZE(post_div_table_lpass_aon_cc_pll_out_odd), |
184 | .width = 4, |
185 | .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], |
186 | .clkr.hw.init = &(const struct clk_init_data){ |
187 | .name = "lpass_aon_cc_pll_out_odd" , |
188 | .parent_hws = (const struct clk_hw*[]){ |
189 | &lpass_aon_cc_pll.clkr.hw, |
190 | }, |
191 | .num_parents = 1, |
192 | .ops = &clk_alpha_pll_postdiv_lucid_ops, |
193 | }, |
194 | }; |
195 | |
196 | static const struct parent_map lpass_audio_cc_parent_map_0[] = { |
197 | { P_BI_TCXO, 0 }, |
198 | { P_LPASS_AUDIO_CC_PLL_OUT_AUX, 3 }, |
199 | { P_LPASS_AON_CC_PLL_OUT_ODD, 5 }, |
200 | { P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 6 }, |
201 | }; |
202 | |
203 | static struct clk_regmap_div lpass_audio_cc_pll_out_aux2_div_clk_src; |
204 | static struct clk_regmap_div lpass_audio_cc_pll_out_main_div_clk_src; |
205 | |
206 | static const struct clk_parent_data lpass_audio_cc_parent_data_0[] = { |
207 | { .index = 0 }, |
208 | { .hw = &lpass_audio_cc_pll.clkr.hw }, |
209 | { .hw = &lpass_aon_cc_pll_out_odd.clkr.hw }, |
210 | { .hw = &lpass_audio_cc_pll_out_aux2_div_clk_src.clkr.hw }, |
211 | }; |
212 | |
213 | static const struct parent_map lpass_aon_cc_parent_map_0[] = { |
214 | { P_BI_TCXO, 0 }, |
215 | { P_LPASS_AON_CC_PLL_OUT_EVEN, 4 }, |
216 | }; |
217 | |
218 | static const struct clk_parent_data lpass_aon_cc_parent_data_0[] = { |
219 | { .index = 0 }, |
220 | { .hw = &lpass_aon_cc_pll_out_even.clkr.hw }, |
221 | }; |
222 | |
223 | static const struct parent_map lpass_aon_cc_parent_map_1[] = { |
224 | { P_BI_TCXO, 0 }, |
225 | { P_LPASS_AON_CC_PLL_OUT_ODD, 1 }, |
226 | { P_LPASS_AUDIO_CC_PLL_MAIN_DIV_CLK, 6 }, |
227 | }; |
228 | |
229 | static const struct clk_parent_data lpass_aon_cc_parent_data_1[] = { |
230 | { .index = 0 }, |
231 | { .hw = &lpass_aon_cc_pll_out_odd.clkr.hw }, |
232 | { .hw = &lpass_audio_cc_pll_out_main_div_clk_src.clkr.hw }, |
233 | }; |
234 | |
235 | static const struct freq_tbl ftbl_lpass_aon_cc_main_rcg_clk_src[] = { |
236 | F(38400000, P_LPASS_AON_CC_PLL_OUT_EVEN, 8, 0, 0), |
237 | F(76800000, P_LPASS_AON_CC_PLL_OUT_EVEN, 4, 0, 0), |
238 | F(153600000, P_LPASS_AON_CC_PLL_OUT_EVEN, 2, 0, 0), |
239 | { } |
240 | }; |
241 | |
242 | static struct clk_rcg2 lpass_aon_cc_main_rcg_clk_src = { |
243 | .cmd_rcgr = 0x1000, |
244 | .mnd_width = 0, |
245 | .hid_width = 5, |
246 | .parent_map = lpass_aon_cc_parent_map_0, |
247 | .freq_tbl = ftbl_lpass_aon_cc_main_rcg_clk_src, |
248 | .clkr.hw.init = &(const struct clk_init_data){ |
249 | .name = "lpass_aon_cc_main_rcg_clk_src" , |
250 | .parent_data = lpass_aon_cc_parent_data_0, |
251 | .num_parents = ARRAY_SIZE(lpass_aon_cc_parent_data_0), |
252 | .flags = CLK_OPS_PARENT_ENABLE, |
253 | .ops = &clk_rcg2_shared_ops, |
254 | }, |
255 | }; |
256 | |
257 | static const struct freq_tbl ftbl_lpass_aon_cc_tx_mclk_rcg_clk_src[] = { |
258 | F(19200000, P_BI_TCXO, 1, 0, 0), |
259 | F(24576000, P_LPASS_AON_CC_PLL_OUT_ODD, 5, 0, 0), |
260 | { } |
261 | }; |
262 | |
263 | static struct clk_rcg2 lpass_aon_cc_tx_mclk_rcg_clk_src = { |
264 | .cmd_rcgr = 0x13004, |
265 | .mnd_width = 0, |
266 | .hid_width = 5, |
267 | .parent_map = lpass_aon_cc_parent_map_1, |
268 | .freq_tbl = ftbl_lpass_aon_cc_tx_mclk_rcg_clk_src, |
269 | .clkr.hw.init = &(const struct clk_init_data){ |
270 | .name = "lpass_aon_cc_tx_mclk_rcg_clk_src" , |
271 | .parent_data = lpass_aon_cc_parent_data_1, |
272 | .num_parents = ARRAY_SIZE(lpass_aon_cc_parent_data_1), |
273 | .ops = &clk_rcg2_ops, |
274 | }, |
275 | }; |
276 | |
277 | static struct clk_regmap_div lpass_audio_cc_pll_out_aux2_div_clk_src = { |
278 | .reg = 0x48, |
279 | .shift = 0, |
280 | .width = 4, |
281 | .clkr.hw.init = &(const struct clk_init_data) { |
282 | .name = "lpass_audio_cc_pll_out_aux2_div_clk_src" , |
283 | .parent_hws = (const struct clk_hw*[]){ |
284 | &lpass_audio_cc_pll_out_aux2.clkr.hw, |
285 | }, |
286 | .num_parents = 1, |
287 | .flags = CLK_SET_RATE_PARENT, |
288 | .ops = &clk_regmap_div_ro_ops, |
289 | }, |
290 | }; |
291 | |
292 | static struct clk_regmap_div lpass_audio_cc_pll_out_main_div_clk_src = { |
293 | .reg = 0x3c, |
294 | .shift = 0, |
295 | .width = 4, |
296 | .clkr.hw.init = &(const struct clk_init_data) { |
297 | .name = "lpass_audio_cc_pll_out_main_div_clk_src" , |
298 | .parent_hws = (const struct clk_hw*[]){ |
299 | &lpass_audio_cc_pll.clkr.hw, |
300 | }, |
301 | .num_parents = 1, |
302 | .flags = CLK_SET_RATE_PARENT, |
303 | .ops = &clk_regmap_div_ro_ops, |
304 | }, |
305 | }; |
306 | |
307 | static struct clk_regmap_div lpass_aon_cc_cdiv_tx_mclk_div_clk_src = { |
308 | .reg = 0x13010, |
309 | .shift = 0, |
310 | .width = 4, |
311 | .clkr.hw.init = &(const struct clk_init_data) { |
312 | .name = "lpass_aon_cc_cdiv_tx_mclk_div_clk_src" , |
313 | .parent_hws = (const struct clk_hw*[]){ |
314 | &lpass_aon_cc_tx_mclk_rcg_clk_src.clkr.hw, |
315 | }, |
316 | .num_parents = 1, |
317 | .flags = CLK_SET_RATE_PARENT, |
318 | .ops = &clk_regmap_div_ro_ops, |
319 | }, |
320 | }; |
321 | |
322 | static struct clk_regmap_div lpass_aon_cc_pll_out_main_cdiv_div_clk_src = { |
323 | .reg = 0x80, |
324 | .shift = 0, |
325 | .width = 4, |
326 | .clkr.hw.init = &(const struct clk_init_data) { |
327 | .name = "lpass_aon_cc_pll_out_main_cdiv_div_clk_src" , |
328 | .parent_hws = (const struct clk_hw*[]){ |
329 | &lpass_aon_cc_pll.clkr.hw, |
330 | }, |
331 | .num_parents = 1, |
332 | .flags = CLK_SET_RATE_PARENT, |
333 | .ops = &clk_regmap_div_ro_ops, |
334 | }, |
335 | }; |
336 | |
337 | static const struct freq_tbl ftbl_lpass_audio_cc_ext_mclk0_clk_src[] = { |
338 | F(256000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 32), |
339 | F(352800, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 32), |
340 | F(512000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 16), |
341 | F(705600, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 16), |
342 | F(768000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 16), |
343 | F(1024000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 8), |
344 | F(1411200, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 8), |
345 | F(1536000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 8), |
346 | F(2048000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 4), |
347 | F(2822400, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 4), |
348 | F(3072000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 4), |
349 | F(4096000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 1, 2), |
350 | F(5644800, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 1, 2), |
351 | F(6144000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 1, 2), |
352 | F(8192000, P_LPASS_AON_CC_PLL_OUT_ODD, 15, 0, 0), |
353 | F(9600000, P_BI_TCXO, 2, 0, 0), |
354 | F(11289600, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 10, 0, 0), |
355 | F(12288000, P_LPASS_AON_CC_PLL_OUT_ODD, 10, 0, 0), |
356 | F(19200000, P_BI_TCXO, 1, 0, 0), |
357 | F(22579200, P_LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC, 5, 0, 0), |
358 | F(24576000, P_LPASS_AON_CC_PLL_OUT_ODD, 5, 0, 0), |
359 | { } |
360 | }; |
361 | |
362 | static struct clk_rcg2 lpass_audio_cc_ext_mclk0_clk_src = { |
363 | .cmd_rcgr = 0x20004, |
364 | .mnd_width = 8, |
365 | .hid_width = 5, |
366 | .parent_map = lpass_audio_cc_parent_map_0, |
367 | .freq_tbl = ftbl_lpass_audio_cc_ext_mclk0_clk_src, |
368 | .clkr.hw.init = &(const struct clk_init_data){ |
369 | .name = "lpass_audio_cc_ext_mclk0_clk_src" , |
370 | .parent_data = lpass_audio_cc_parent_data_0, |
371 | .num_parents = ARRAY_SIZE(lpass_audio_cc_parent_data_0), |
372 | .ops = &clk_rcg2_ops, |
373 | }, |
374 | }; |
375 | |
376 | static struct clk_rcg2 lpass_audio_cc_ext_mclk1_clk_src = { |
377 | .cmd_rcgr = 0x21004, |
378 | .mnd_width = 8, |
379 | .hid_width = 5, |
380 | .parent_map = lpass_audio_cc_parent_map_0, |
381 | .freq_tbl = ftbl_lpass_audio_cc_ext_mclk0_clk_src, |
382 | .clkr.hw.init = &(const struct clk_init_data){ |
383 | .name = "lpass_audio_cc_ext_mclk1_clk_src" , |
384 | .parent_data = lpass_audio_cc_parent_data_0, |
385 | .num_parents = ARRAY_SIZE(lpass_audio_cc_parent_data_0), |
386 | .ops = &clk_rcg2_ops, |
387 | }, |
388 | }; |
389 | |
390 | static struct clk_rcg2 lpass_audio_cc_rx_mclk_clk_src = { |
391 | .cmd_rcgr = 0x24004, |
392 | .mnd_width = 8, |
393 | .hid_width = 5, |
394 | .parent_map = lpass_audio_cc_parent_map_0, |
395 | .freq_tbl = ftbl_lpass_audio_cc_ext_mclk0_clk_src, |
396 | .clkr.hw.init = &(const struct clk_init_data){ |
397 | .name = "lpass_audio_cc_rx_mclk_clk_src" , |
398 | .parent_data = lpass_audio_cc_parent_data_0, |
399 | .num_parents = ARRAY_SIZE(lpass_audio_cc_parent_data_0), |
400 | .ops = &clk_rcg2_ops, |
401 | }, |
402 | }; |
403 | |
404 | static struct clk_regmap_div lpass_audio_cc_cdiv_rx_mclk_div_clk_src = { |
405 | .reg = 0x240d0, |
406 | .shift = 0, |
407 | .width = 4, |
408 | .clkr.hw.init = &(const struct clk_init_data) { |
409 | .name = "lpass_audio_cc_cdiv_rx_mclk_div_clk_src" , |
410 | .parent_hws = (const struct clk_hw*[]){ |
411 | &lpass_audio_cc_rx_mclk_clk_src.clkr.hw, |
412 | }, |
413 | .num_parents = 1, |
414 | .flags = CLK_SET_RATE_PARENT, |
415 | .ops = &clk_regmap_div_ro_ops, |
416 | }, |
417 | }; |
418 | |
419 | static struct clk_branch lpass_aon_cc_audio_hm_h_clk; |
420 | |
421 | static struct clk_branch lpass_audio_cc_codec_mem0_clk = { |
422 | .halt_reg = 0x1e004, |
423 | .halt_check = BRANCH_HALT, |
424 | .clkr = { |
425 | .enable_reg = 0x1e004, |
426 | .enable_mask = BIT(0), |
427 | .hw.init = &(const struct clk_init_data){ |
428 | .name = "lpass_audio_cc_codec_mem0_clk" , |
429 | .parent_hws = (const struct clk_hw*[]){ |
430 | &lpass_aon_cc_audio_hm_h_clk.clkr.hw, |
431 | }, |
432 | .num_parents = 1, |
433 | .flags = CLK_SET_RATE_PARENT, |
434 | .ops = &clk_branch2_ops, |
435 | }, |
436 | }, |
437 | }; |
438 | |
439 | static struct clk_branch lpass_audio_cc_codec_mem1_clk = { |
440 | .halt_reg = 0x1e008, |
441 | .halt_check = BRANCH_HALT, |
442 | .clkr = { |
443 | .enable_reg = 0x1e008, |
444 | .enable_mask = BIT(0), |
445 | .hw.init = &(const struct clk_init_data){ |
446 | .name = "lpass_audio_cc_codec_mem1_clk" , |
447 | .parent_hws = (const struct clk_hw*[]){ |
448 | &lpass_aon_cc_audio_hm_h_clk.clkr.hw, |
449 | }, |
450 | .num_parents = 1, |
451 | .flags = CLK_SET_RATE_PARENT, |
452 | .ops = &clk_branch2_ops, |
453 | }, |
454 | }, |
455 | }; |
456 | |
457 | static struct clk_branch lpass_audio_cc_codec_mem2_clk = { |
458 | .halt_reg = 0x1e00c, |
459 | .halt_check = BRANCH_HALT, |
460 | .clkr = { |
461 | .enable_reg = 0x1e00c, |
462 | .enable_mask = BIT(0), |
463 | .hw.init = &(const struct clk_init_data){ |
464 | .name = "lpass_audio_cc_codec_mem2_clk" , |
465 | .parent_hws = (const struct clk_hw*[]){ |
466 | &lpass_aon_cc_audio_hm_h_clk.clkr.hw, |
467 | }, |
468 | .num_parents = 1, |
469 | .flags = CLK_SET_RATE_PARENT, |
470 | .ops = &clk_branch2_ops, |
471 | }, |
472 | }, |
473 | }; |
474 | |
475 | static struct clk_branch lpass_audio_cc_codec_mem_clk = { |
476 | .halt_reg = 0x1e000, |
477 | .halt_check = BRANCH_HALT, |
478 | .clkr = { |
479 | .enable_reg = 0x1e000, |
480 | .enable_mask = BIT(0), |
481 | .hw.init = &(const struct clk_init_data){ |
482 | .name = "lpass_audio_cc_codec_mem_clk" , |
483 | .parent_hws = (const struct clk_hw*[]){ |
484 | &lpass_aon_cc_audio_hm_h_clk.clkr.hw, |
485 | }, |
486 | .num_parents = 1, |
487 | .flags = CLK_SET_RATE_PARENT, |
488 | .ops = &clk_branch2_ops, |
489 | }, |
490 | }, |
491 | }; |
492 | |
493 | static struct clk_branch lpass_audio_cc_ext_mclk0_clk = { |
494 | .halt_reg = 0x20018, |
495 | .halt_check = BRANCH_HALT, |
496 | .clkr = { |
497 | .enable_reg = 0x20018, |
498 | .enable_mask = BIT(0), |
499 | .hw.init = &(const struct clk_init_data){ |
500 | .name = "lpass_audio_cc_ext_mclk0_clk" , |
501 | .parent_hws = (const struct clk_hw*[]){ |
502 | &lpass_audio_cc_ext_mclk0_clk_src.clkr.hw, |
503 | }, |
504 | .num_parents = 1, |
505 | .flags = CLK_SET_RATE_PARENT, |
506 | .ops = &clk_branch2_ops, |
507 | }, |
508 | }, |
509 | }; |
510 | |
511 | static struct clk_branch lpass_audio_cc_ext_mclk1_clk = { |
512 | .halt_reg = 0x21018, |
513 | .halt_check = BRANCH_HALT, |
514 | .clkr = { |
515 | .enable_reg = 0x21018, |
516 | .enable_mask = BIT(0), |
517 | .hw.init = &(const struct clk_init_data){ |
518 | .name = "lpass_audio_cc_ext_mclk1_clk" , |
519 | .parent_hws = (const struct clk_hw*[]){ |
520 | &lpass_audio_cc_ext_mclk1_clk_src.clkr.hw, |
521 | }, |
522 | .num_parents = 1, |
523 | .flags = CLK_SET_RATE_PARENT, |
524 | .ops = &clk_branch2_ops, |
525 | }, |
526 | }, |
527 | }; |
528 | |
529 | static struct clk_branch lpass_audio_cc_rx_mclk_2x_clk = { |
530 | .halt_reg = 0x240cc, |
531 | .halt_check = BRANCH_HALT, |
532 | .clkr = { |
533 | .enable_reg = 0x240cc, |
534 | .enable_mask = BIT(0), |
535 | .hw.init = &(const struct clk_init_data){ |
536 | .name = "lpass_audio_cc_rx_mclk_2x_clk" , |
537 | .parent_hws = (const struct clk_hw*[]){ |
538 | &lpass_audio_cc_rx_mclk_clk_src.clkr.hw, |
539 | }, |
540 | .num_parents = 1, |
541 | .flags = CLK_SET_RATE_PARENT, |
542 | .ops = &clk_branch2_ops, |
543 | }, |
544 | }, |
545 | }; |
546 | |
547 | static struct clk_branch lpass_audio_cc_rx_mclk_clk = { |
548 | .halt_reg = 0x240d4, |
549 | .halt_check = BRANCH_HALT, |
550 | .clkr = { |
551 | .enable_reg = 0x240d4, |
552 | .enable_mask = BIT(0), |
553 | .hw.init = &(const struct clk_init_data){ |
554 | .name = "lpass_audio_cc_rx_mclk_clk" , |
555 | .parent_hws = (const struct clk_hw*[]){ |
556 | &lpass_audio_cc_cdiv_rx_mclk_div_clk_src.clkr.hw, |
557 | }, |
558 | .num_parents = 1, |
559 | .flags = CLK_SET_RATE_PARENT, |
560 | .ops = &clk_branch2_ops, |
561 | }, |
562 | }, |
563 | }; |
564 | |
565 | static struct clk_branch lpass_aon_cc_audio_hm_h_clk = { |
566 | .halt_reg = 0x9014, |
567 | .halt_check = BRANCH_HALT, |
568 | .clkr = { |
569 | .enable_reg = 0x9014, |
570 | .enable_mask = BIT(0), |
571 | .hw.init = &(const struct clk_init_data){ |
572 | .name = "lpass_aon_cc_audio_hm_h_clk" , |
573 | .parent_hws = (const struct clk_hw*[]){ |
574 | &lpass_aon_cc_main_rcg_clk_src.clkr.hw, |
575 | }, |
576 | .num_parents = 1, |
577 | .flags = CLK_SET_RATE_PARENT, |
578 | .ops = &clk_branch2_aon_ops, |
579 | }, |
580 | }, |
581 | }; |
582 | |
583 | static struct clk_branch lpass_aon_cc_va_mem0_clk = { |
584 | .halt_reg = 0x9028, |
585 | .halt_check = BRANCH_HALT, |
586 | .clkr = { |
587 | .enable_reg = 0x9028, |
588 | .enable_mask = BIT(0), |
589 | .hw.init = &(const struct clk_init_data){ |
590 | .name = "lpass_aon_cc_va_mem0_clk" , |
591 | .parent_hws = (const struct clk_hw*[]){ |
592 | &lpass_aon_cc_main_rcg_clk_src.clkr.hw, |
593 | }, |
594 | .num_parents = 1, |
595 | .flags = CLK_SET_RATE_PARENT, |
596 | .ops = &clk_branch2_ops, |
597 | }, |
598 | }, |
599 | }; |
600 | |
601 | static struct clk_branch lpass_aon_cc_tx_mclk_2x_clk = { |
602 | .halt_reg = 0x1300c, |
603 | .halt_check = BRANCH_HALT, |
604 | .clkr = { |
605 | .enable_reg = 0x1300c, |
606 | .enable_mask = BIT(0), |
607 | .hw.init = &(const struct clk_init_data){ |
608 | .name = "lpass_aon_cc_tx_mclk_2x_clk" , |
609 | .parent_hws = (const struct clk_hw*[]){ |
610 | &lpass_aon_cc_tx_mclk_rcg_clk_src.clkr.hw, |
611 | }, |
612 | .num_parents = 1, |
613 | .flags = CLK_SET_RATE_PARENT, |
614 | .ops = &clk_branch2_ops, |
615 | }, |
616 | }, |
617 | }; |
618 | |
619 | static struct clk_branch lpass_aon_cc_tx_mclk_clk = { |
620 | .halt_reg = 0x13014, |
621 | .halt_check = BRANCH_HALT, |
622 | .clkr = { |
623 | .enable_reg = 0x13014, |
624 | .enable_mask = BIT(0), |
625 | .hw.init = &(const struct clk_init_data){ |
626 | .name = "lpass_aon_cc_tx_mclk_clk" , |
627 | .parent_hws = (const struct clk_hw*[]){ |
628 | &lpass_aon_cc_cdiv_tx_mclk_div_clk_src.clkr.hw, |
629 | }, |
630 | .num_parents = 1, |
631 | .flags = CLK_SET_RATE_PARENT, |
632 | .ops = &clk_branch2_ops, |
633 | }, |
634 | }, |
635 | }; |
636 | |
637 | static struct gdsc lpass_aon_cc_lpass_audio_hm_gdsc = { |
638 | .gdscr = 0x9090, |
639 | .pd = { |
640 | .name = "lpass_aon_cc_lpass_audio_hm_gdsc" , |
641 | }, |
642 | .pwrsts = PWRSTS_OFF_ON, |
643 | .flags = RETAIN_FF_ENABLE, |
644 | }; |
645 | |
646 | static struct clk_regmap *lpass_cc_sc7280_clocks[] = { |
647 | [LPASS_Q6SS_AHBM_CLK] = &lpass_q6ss_ahbm_clk.clkr, |
648 | [LPASS_Q6SS_AHBS_CLK] = &lpass_q6ss_ahbs_clk.clkr, |
649 | }; |
650 | |
651 | static struct clk_regmap *lpass_aon_cc_sc7280_clocks[] = { |
652 | [LPASS_AON_CC_AUDIO_HM_H_CLK] = &lpass_aon_cc_audio_hm_h_clk.clkr, |
653 | [LPASS_AON_CC_VA_MEM0_CLK] = &lpass_aon_cc_va_mem0_clk.clkr, |
654 | [LPASS_AON_CC_CDIV_TX_MCLK_DIV_CLK_SRC] = &lpass_aon_cc_cdiv_tx_mclk_div_clk_src.clkr, |
655 | [LPASS_AON_CC_MAIN_RCG_CLK_SRC] = &lpass_aon_cc_main_rcg_clk_src.clkr, |
656 | [LPASS_AON_CC_PLL] = &lpass_aon_cc_pll.clkr, |
657 | [LPASS_AON_CC_PLL_OUT_EVEN] = &lpass_aon_cc_pll_out_even.clkr, |
658 | [LPASS_AON_CC_PLL_OUT_MAIN_CDIV_DIV_CLK_SRC] = |
659 | &lpass_aon_cc_pll_out_main_cdiv_div_clk_src.clkr, |
660 | [LPASS_AON_CC_PLL_OUT_ODD] = &lpass_aon_cc_pll_out_odd.clkr, |
661 | [LPASS_AON_CC_TX_MCLK_2X_CLK] = &lpass_aon_cc_tx_mclk_2x_clk.clkr, |
662 | [LPASS_AON_CC_TX_MCLK_CLK] = &lpass_aon_cc_tx_mclk_clk.clkr, |
663 | [LPASS_AON_CC_TX_MCLK_RCG_CLK_SRC] = &lpass_aon_cc_tx_mclk_rcg_clk_src.clkr, |
664 | }; |
665 | |
666 | static struct gdsc *lpass_aon_cc_sc7280_gdscs[] = { |
667 | [LPASS_AON_CC_LPASS_AUDIO_HM_GDSC] = &lpass_aon_cc_lpass_audio_hm_gdsc, |
668 | }; |
669 | |
670 | static struct clk_regmap *lpass_audio_cc_sc7280_clocks[] = { |
671 | [LPASS_AUDIO_CC_CDIV_RX_MCLK_DIV_CLK_SRC] = &lpass_audio_cc_cdiv_rx_mclk_div_clk_src.clkr, |
672 | [LPASS_AUDIO_CC_CODEC_MEM0_CLK] = &lpass_audio_cc_codec_mem0_clk.clkr, |
673 | [LPASS_AUDIO_CC_CODEC_MEM1_CLK] = &lpass_audio_cc_codec_mem1_clk.clkr, |
674 | [LPASS_AUDIO_CC_CODEC_MEM2_CLK] = &lpass_audio_cc_codec_mem2_clk.clkr, |
675 | [LPASS_AUDIO_CC_CODEC_MEM_CLK] = &lpass_audio_cc_codec_mem_clk.clkr, |
676 | [LPASS_AUDIO_CC_EXT_MCLK0_CLK] = &lpass_audio_cc_ext_mclk0_clk.clkr, |
677 | [LPASS_AUDIO_CC_EXT_MCLK0_CLK_SRC] = &lpass_audio_cc_ext_mclk0_clk_src.clkr, |
678 | [LPASS_AUDIO_CC_EXT_MCLK1_CLK] = &lpass_audio_cc_ext_mclk1_clk.clkr, |
679 | [LPASS_AUDIO_CC_EXT_MCLK1_CLK_SRC] = &lpass_audio_cc_ext_mclk1_clk_src.clkr, |
680 | [LPASS_AUDIO_CC_PLL] = &lpass_audio_cc_pll.clkr, |
681 | [LPASS_AUDIO_CC_PLL_OUT_AUX2] = &lpass_audio_cc_pll_out_aux2.clkr, |
682 | [LPASS_AUDIO_CC_PLL_OUT_AUX2_DIV_CLK_SRC] = &lpass_audio_cc_pll_out_aux2_div_clk_src.clkr, |
683 | [LPASS_AUDIO_CC_PLL_OUT_MAIN_DIV_CLK_SRC] = &lpass_audio_cc_pll_out_main_div_clk_src.clkr, |
684 | [LPASS_AUDIO_CC_RX_MCLK_2X_CLK] = &lpass_audio_cc_rx_mclk_2x_clk.clkr, |
685 | [LPASS_AUDIO_CC_RX_MCLK_CLK] = &lpass_audio_cc_rx_mclk_clk.clkr, |
686 | [LPASS_AUDIO_CC_RX_MCLK_CLK_SRC] = &lpass_audio_cc_rx_mclk_clk_src.clkr, |
687 | }; |
688 | |
689 | static struct regmap_config lpass_audio_cc_sc7280_regmap_config = { |
690 | .reg_bits = 32, |
691 | .reg_stride = 4, |
692 | .val_bits = 32, |
693 | .fast_io = true, |
694 | }; |
695 | |
696 | static const struct qcom_cc_desc lpass_cc_sc7280_desc = { |
697 | .config = &lpass_audio_cc_sc7280_regmap_config, |
698 | .clks = lpass_cc_sc7280_clocks, |
699 | .num_clks = ARRAY_SIZE(lpass_cc_sc7280_clocks), |
700 | .gdscs = lpass_aon_cc_sc7280_gdscs, |
701 | .num_gdscs = ARRAY_SIZE(lpass_aon_cc_sc7280_gdscs), |
702 | }; |
703 | |
704 | static const struct qcom_cc_desc lpass_audio_cc_sc7280_desc = { |
705 | .config = &lpass_audio_cc_sc7280_regmap_config, |
706 | .clks = lpass_audio_cc_sc7280_clocks, |
707 | .num_clks = ARRAY_SIZE(lpass_audio_cc_sc7280_clocks), |
708 | }; |
709 | |
710 | static const struct qcom_reset_map lpass_audio_cc_sc7280_resets[] = { |
711 | [LPASS_AUDIO_SWR_RX_CGCR] = { 0xa0, 1 }, |
712 | [LPASS_AUDIO_SWR_TX_CGCR] = { 0xa8, 1 }, |
713 | [LPASS_AUDIO_SWR_WSA_CGCR] = { 0xb0, 1 }, |
714 | }; |
715 | |
716 | static const struct qcom_cc_desc lpass_audio_cc_reset_sc7280_desc = { |
717 | .config = &lpass_audio_cc_sc7280_regmap_config, |
718 | .resets = lpass_audio_cc_sc7280_resets, |
719 | .num_resets = ARRAY_SIZE(lpass_audio_cc_sc7280_resets), |
720 | }; |
721 | |
722 | static const struct of_device_id lpass_audio_cc_sc7280_match_table[] = { |
723 | { .compatible = "qcom,sc7280-lpassaudiocc" }, |
724 | { } |
725 | }; |
726 | MODULE_DEVICE_TABLE(of, lpass_audio_cc_sc7280_match_table); |
727 | |
728 | static int lpass_audio_setup_runtime_pm(struct platform_device *pdev) |
729 | { |
730 | int ret; |
731 | |
732 | pm_runtime_use_autosuspend(dev: &pdev->dev); |
733 | pm_runtime_set_autosuspend_delay(dev: &pdev->dev, delay: 50); |
734 | ret = devm_pm_runtime_enable(dev: &pdev->dev); |
735 | if (ret) |
736 | return ret; |
737 | |
738 | ret = devm_pm_clk_create(dev: &pdev->dev); |
739 | if (ret) |
740 | return ret; |
741 | |
742 | ret = pm_clk_add(dev: &pdev->dev, con_id: "iface" ); |
743 | if (ret < 0) |
744 | dev_err(&pdev->dev, "failed to acquire iface clock\n" ); |
745 | |
746 | return pm_runtime_resume_and_get(dev: &pdev->dev); |
747 | } |
748 | |
749 | static int lpass_audio_cc_sc7280_probe(struct platform_device *pdev) |
750 | { |
751 | const struct qcom_cc_desc *desc; |
752 | struct regmap *regmap; |
753 | int ret; |
754 | |
755 | ret = lpass_audio_setup_runtime_pm(pdev); |
756 | if (ret) |
757 | return ret; |
758 | |
759 | lpass_audio_cc_sc7280_regmap_config.name = "lpassaudio_cc" ; |
760 | lpass_audio_cc_sc7280_regmap_config.max_register = 0x2f000; |
761 | desc = &lpass_audio_cc_sc7280_desc; |
762 | |
763 | regmap = qcom_cc_map(pdev, desc); |
764 | if (IS_ERR(ptr: regmap)) { |
765 | ret = PTR_ERR(ptr: regmap); |
766 | goto exit; |
767 | } |
768 | |
769 | clk_zonda_pll_configure(pll: &lpass_audio_cc_pll, regmap, config: &lpass_audio_cc_pll_config); |
770 | |
771 | /* PLL settings */ |
772 | regmap_write(map: regmap, reg: 0x4, val: 0x3b); |
773 | regmap_write(map: regmap, reg: 0x8, val: 0xff05); |
774 | |
775 | ret = qcom_cc_really_probe(pdev, desc: &lpass_audio_cc_sc7280_desc, regmap); |
776 | if (ret) { |
777 | dev_err(&pdev->dev, "Failed to register LPASS AUDIO CC clocks\n" ); |
778 | goto exit; |
779 | } |
780 | |
781 | ret = qcom_cc_probe_by_index(pdev, index: 1, desc: &lpass_audio_cc_reset_sc7280_desc); |
782 | if (ret) { |
783 | dev_err(&pdev->dev, "Failed to register LPASS AUDIO CC Resets\n" ); |
784 | goto exit; |
785 | } |
786 | |
787 | pm_runtime_mark_last_busy(dev: &pdev->dev); |
788 | exit: |
789 | pm_runtime_put_autosuspend(dev: &pdev->dev); |
790 | |
791 | return ret; |
792 | } |
793 | |
794 | static const struct dev_pm_ops lpass_audio_cc_pm_ops = { |
795 | SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) |
796 | }; |
797 | |
798 | static struct platform_driver lpass_audio_cc_sc7280_driver = { |
799 | .probe = lpass_audio_cc_sc7280_probe, |
800 | .driver = { |
801 | .name = "lpass_audio_cc-sc7280" , |
802 | .of_match_table = lpass_audio_cc_sc7280_match_table, |
803 | .pm = &lpass_audio_cc_pm_ops, |
804 | }, |
805 | }; |
806 | |
807 | static const struct qcom_cc_desc lpass_aon_cc_sc7280_desc = { |
808 | .config = &lpass_audio_cc_sc7280_regmap_config, |
809 | .clks = lpass_aon_cc_sc7280_clocks, |
810 | .num_clks = ARRAY_SIZE(lpass_aon_cc_sc7280_clocks), |
811 | .gdscs = lpass_aon_cc_sc7280_gdscs, |
812 | .num_gdscs = ARRAY_SIZE(lpass_aon_cc_sc7280_gdscs), |
813 | }; |
814 | |
815 | static const struct of_device_id lpass_aon_cc_sc7280_match_table[] = { |
816 | { .compatible = "qcom,sc7280-lpassaoncc" }, |
817 | { } |
818 | }; |
819 | MODULE_DEVICE_TABLE(of, lpass_aon_cc_sc7280_match_table); |
820 | |
821 | static int lpass_aon_cc_sc7280_probe(struct platform_device *pdev) |
822 | { |
823 | const struct qcom_cc_desc *desc; |
824 | struct regmap *regmap; |
825 | int ret; |
826 | |
827 | ret = lpass_audio_setup_runtime_pm(pdev); |
828 | if (ret) |
829 | return ret; |
830 | |
831 | if (of_property_read_bool(np: pdev->dev.of_node, propname: "qcom,adsp-pil-mode" )) { |
832 | lpass_audio_cc_sc7280_regmap_config.name = "cc" ; |
833 | desc = &lpass_cc_sc7280_desc; |
834 | ret = qcom_cc_probe(pdev, desc); |
835 | goto exit; |
836 | } |
837 | |
838 | lpass_audio_cc_sc7280_regmap_config.name = "lpasscc_aon" ; |
839 | lpass_audio_cc_sc7280_regmap_config.max_register = 0xa0008; |
840 | desc = &lpass_aon_cc_sc7280_desc; |
841 | |
842 | regmap = qcom_cc_map(pdev, desc); |
843 | if (IS_ERR(ptr: regmap)) { |
844 | ret = PTR_ERR(ptr: regmap); |
845 | goto exit; |
846 | } |
847 | |
848 | clk_lucid_pll_configure(&lpass_aon_cc_pll, regmap, &lpass_aon_cc_pll_config); |
849 | |
850 | ret = qcom_cc_really_probe(pdev, desc: &lpass_aon_cc_sc7280_desc, regmap); |
851 | if (ret) { |
852 | dev_err(&pdev->dev, "Failed to register LPASS AON CC clocks\n" ); |
853 | goto exit; |
854 | } |
855 | |
856 | pm_runtime_mark_last_busy(dev: &pdev->dev); |
857 | exit: |
858 | pm_runtime_put_autosuspend(dev: &pdev->dev); |
859 | |
860 | return ret; |
861 | } |
862 | |
863 | static struct platform_driver lpass_aon_cc_sc7280_driver = { |
864 | .probe = lpass_aon_cc_sc7280_probe, |
865 | .driver = { |
866 | .name = "lpass_aon_cc-sc7280" , |
867 | .of_match_table = lpass_aon_cc_sc7280_match_table, |
868 | .pm = &lpass_audio_cc_pm_ops, |
869 | }, |
870 | }; |
871 | |
872 | static int __init lpass_audio_cc_sc7280_init(void) |
873 | { |
874 | int ret; |
875 | |
876 | ret = platform_driver_register(&lpass_aon_cc_sc7280_driver); |
877 | if (ret) |
878 | return ret; |
879 | |
880 | return platform_driver_register(&lpass_audio_cc_sc7280_driver); |
881 | } |
882 | subsys_initcall(lpass_audio_cc_sc7280_init); |
883 | |
884 | static void __exit lpass_audio_cc_sc7280_exit(void) |
885 | { |
886 | platform_driver_unregister(&lpass_audio_cc_sc7280_driver); |
887 | platform_driver_unregister(&lpass_aon_cc_sc7280_driver); |
888 | } |
889 | module_exit(lpass_audio_cc_sc7280_exit); |
890 | |
891 | MODULE_DESCRIPTION("QTI LPASS_AUDIO_CC SC7280 Driver" ); |
892 | MODULE_LICENSE("GPL v2" ); |
893 | |