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/module.h>
9 #include <linux/of_device.h>
10 #include <linux/pm_clock.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/regmap.h>
13 
14 #include <dt-bindings/clock/qcom,lpasscorecc-sc7280.h>
15 
16 #include "clk-alpha-pll.h"
17 #include "clk-branch.h"
18 #include "clk-rcg.h"
19 #include "clk-regmap.h"
20 #include "clk-regmap-divider.h"
21 #include "common.h"
22 #include "gdsc.h"
23 
24 enum {
25 	P_BI_TCXO,
26 	P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN,
27 	P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN_DIV_CLK_SRC,
28 	P_LPASS_CORE_CC_DIG_PLL_OUT_ODD,
29 };
30 
31 static const struct pll_vco lucid_vco[] = {
32 	{ 249600000, 2000000000, 0 },
33 };
34 
35 /* 614.4MHz configuration */
36 static const struct alpha_pll_config lpass_core_cc_dig_pll_config = {
37 	.l = 0x20,
38 	.alpha = 0x0,
39 	.config_ctl_val = 0x20485699,
40 	.config_ctl_hi_val = 0x00002261,
41 	.config_ctl_hi1_val = 0xB2923BBC,
42 	.user_ctl_val = 0x00005100,
43 	.user_ctl_hi_val = 0x00050805,
44 	.user_ctl_hi1_val = 0x00000000,
45 };
46 
47 static struct clk_alpha_pll lpass_core_cc_dig_pll = {
48 	.offset = 0x1000,
49 	.vco_table = lucid_vco,
50 	.num_vco = ARRAY_SIZE(lucid_vco),
51 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
52 	.clkr = {
53 		.hw.init = &(struct clk_init_data){
54 			.name = "lpass_core_cc_dig_pll",
55 			.parent_data = &(const struct clk_parent_data){
56 				.index = 0,
57 			},
58 			.num_parents = 1,
59 			.ops = &clk_alpha_pll_lucid_ops,
60 		},
61 	},
62 };
63 
64 static const struct clk_div_table post_div_table_lpass_core_cc_dig_pll_out_odd[] = {
65 	{ 0x5, 5 },
66 	{ }
67 };
68 
69 static struct clk_alpha_pll_postdiv lpass_core_cc_dig_pll_out_odd = {
70 	.offset = 0x1000,
71 	.post_div_shift = 12,
72 	.post_div_table = post_div_table_lpass_core_cc_dig_pll_out_odd,
73 	.num_post_div = ARRAY_SIZE(post_div_table_lpass_core_cc_dig_pll_out_odd),
74 	.width = 4,
75 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
76 	.clkr.hw.init = &(struct clk_init_data){
77 		.name = "lpass_core_cc_dig_pll_out_odd",
78 		.parent_hws = (const struct clk_hw*[]){
79 			&lpass_core_cc_dig_pll.clkr.hw,
80 		},
81 		.num_parents = 1,
82 		.flags = CLK_SET_RATE_PARENT,
83 		.ops = &clk_alpha_pll_postdiv_lucid_ops,
84 	},
85 };
86 
87 static struct clk_regmap_div lpass_core_cc_dig_pll_out_main_div_clk_src = {
88 	.reg = 0x1054,
89 	.shift = 0,
90 	.width = 4,
91 	.clkr.hw.init = &(struct clk_init_data) {
92 		.name = "lpass_core_cc_dig_pll_out_main_div_clk_src",
93 		.parent_hws = (const struct clk_hw*[]){
94 			&lpass_core_cc_dig_pll.clkr.hw,
95 		},
96 		.num_parents = 1,
97 		.flags = CLK_SET_RATE_PARENT,
98 		.ops = &clk_regmap_div_ro_ops,
99 	},
100 };
101 
102 
103 static const struct parent_map lpass_core_cc_parent_map_0[] = {
104 	{ P_BI_TCXO, 0 },
105 	{ P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 5 },
106 };
107 
108 static const struct clk_parent_data lpass_core_cc_parent_data_0[] = {
109 	{ .index = 0 },
110 	{ .hw = &lpass_core_cc_dig_pll_out_odd.clkr.hw },
111 };
112 
113 static const struct parent_map lpass_core_cc_parent_map_2[] = {
114 	{ P_BI_TCXO, 0 },
115 	{ P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN, 1 },
116 	{ P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN_DIV_CLK_SRC, 2 },
117 };
118 
119 static const struct clk_parent_data lpass_core_cc_parent_data_ao_2[] = {
120 	{ .index = 1 },
121 	{ .hw = &lpass_core_cc_dig_pll.clkr.hw },
122 	{ .hw = &lpass_core_cc_dig_pll_out_main_div_clk_src.clkr.hw },
123 };
124 
125 static const struct freq_tbl ftbl_lpass_core_cc_core_clk_src[] = {
126 	F(19200000, P_BI_TCXO, 1, 0, 0),
127 	F(51200000, P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN_DIV_CLK_SRC, 6, 0, 0),
128 	F(102400000, P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN_DIV_CLK_SRC, 3, 0, 0),
129 	F(204800000, P_LPASS_CORE_CC_DIG_PLL_OUT_MAIN, 3, 0, 0),
130 	{ }
131 };
132 
133 static struct clk_rcg2 lpass_core_cc_core_clk_src = {
134 	.cmd_rcgr = 0x1d000,
135 	.mnd_width = 8,
136 	.hid_width = 5,
137 	.parent_map = lpass_core_cc_parent_map_2,
138 	.freq_tbl = ftbl_lpass_core_cc_core_clk_src,
139 	.clkr.hw.init = &(const struct clk_init_data){
140 		.name = "lpass_core_cc_core_clk_src",
141 		.parent_data = lpass_core_cc_parent_data_ao_2,
142 		.num_parents = ARRAY_SIZE(lpass_core_cc_parent_data_ao_2),
143 		.ops = &clk_rcg2_shared_ops,
144 	},
145 };
146 
147 static const struct freq_tbl ftbl_lpass_core_cc_ext_if0_clk_src[] = {
148 	F(256000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 15, 1, 32),
149 	F(512000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 15, 1, 16),
150 	F(768000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 10, 1, 16),
151 	F(1024000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 15, 1, 8),
152 	F(1536000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 10, 1, 8),
153 	F(2048000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 15, 1, 4),
154 	F(3072000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 10, 1, 4),
155 	F(4096000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 15, 1, 2),
156 	F(6144000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 10, 1, 2),
157 	F(8192000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 15, 0, 0),
158 	F(9600000, P_BI_TCXO, 2, 0, 0),
159 	F(12288000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 10, 0, 0),
160 	F(19200000, P_BI_TCXO, 1, 0, 0),
161 	F(24576000, P_LPASS_CORE_CC_DIG_PLL_OUT_ODD, 5, 0, 0),
162 	{ }
163 };
164 
165 static struct clk_rcg2 lpass_core_cc_ext_if0_clk_src = {
166 	.cmd_rcgr = 0x10000,
167 	.mnd_width = 16,
168 	.hid_width = 5,
169 	.parent_map = lpass_core_cc_parent_map_0,
170 	.freq_tbl = ftbl_lpass_core_cc_ext_if0_clk_src,
171 	.clkr.hw.init = &(const struct clk_init_data){
172 		.name = "lpass_core_cc_ext_if0_clk_src",
173 		.parent_data = lpass_core_cc_parent_data_0,
174 		.num_parents = ARRAY_SIZE(lpass_core_cc_parent_data_0),
175 		.ops = &clk_rcg2_ops,
176 	},
177 };
178 
179 static struct clk_rcg2 lpass_core_cc_ext_if1_clk_src = {
180 	.cmd_rcgr = 0x11000,
181 	.mnd_width = 16,
182 	.hid_width = 5,
183 	.parent_map = lpass_core_cc_parent_map_0,
184 	.freq_tbl = ftbl_lpass_core_cc_ext_if0_clk_src,
185 	.clkr.hw.init = &(const struct clk_init_data){
186 		.name = "lpass_core_cc_ext_if1_clk_src",
187 		.parent_data = lpass_core_cc_parent_data_0,
188 		.num_parents = ARRAY_SIZE(lpass_core_cc_parent_data_0),
189 		.ops = &clk_rcg2_ops,
190 	},
191 };
192 
193 static struct clk_rcg2 lpass_core_cc_ext_mclk0_clk_src = {
194 	.cmd_rcgr = 0x20000,
195 	.mnd_width = 8,
196 	.hid_width = 5,
197 	.parent_map = lpass_core_cc_parent_map_0,
198 	.freq_tbl = ftbl_lpass_core_cc_ext_if0_clk_src,
199 	.clkr.hw.init = &(const struct clk_init_data){
200 		.name = "lpass_core_cc_ext_mclk0_clk_src",
201 		.parent_data = lpass_core_cc_parent_data_0,
202 		.num_parents = ARRAY_SIZE(lpass_core_cc_parent_data_0),
203 		.ops = &clk_rcg2_ops,
204 	},
205 };
206 
207 static struct clk_branch lpass_core_cc_core_clk = {
208 	.halt_reg = 0x1f000,
209 	.halt_check = BRANCH_HALT_VOTED,
210 	.hwcg_reg = 0x1f000,
211 	.hwcg_bit = 1,
212 	.clkr = {
213 		.enable_reg = 0x1f000,
214 		.enable_mask = BIT(0),
215 		.hw.init = &(const struct clk_init_data){
216 			.name = "lpass_core_cc_core_clk",
217 			.parent_hws = (const struct clk_hw*[]){
218 				&lpass_core_cc_core_clk_src.clkr.hw,
219 			},
220 			.num_parents = 1,
221 			.flags = CLK_SET_RATE_PARENT,
222 			.ops = &clk_branch2_aon_ops,
223 		},
224 	},
225 };
226 
227 static struct clk_branch lpass_core_cc_ext_if0_ibit_clk = {
228 	.halt_reg = 0x10018,
229 	.halt_check = BRANCH_HALT,
230 	.clkr = {
231 		.enable_reg = 0x10018,
232 		.enable_mask = BIT(0),
233 		.hw.init = &(const struct clk_init_data){
234 			.name = "lpass_core_cc_ext_if0_ibit_clk",
235 			.parent_hws = (const struct clk_hw*[]){
236 				&lpass_core_cc_ext_if0_clk_src.clkr.hw,
237 			},
238 			.num_parents = 1,
239 			.flags = CLK_SET_RATE_PARENT,
240 			.ops = &clk_branch2_ops,
241 		},
242 	},
243 };
244 
245 static struct clk_branch lpass_core_cc_ext_if1_ibit_clk = {
246 	.halt_reg = 0x11018,
247 	.halt_check = BRANCH_HALT,
248 	.clkr = {
249 		.enable_reg = 0x11018,
250 		.enable_mask = BIT(0),
251 		.hw.init = &(const struct clk_init_data){
252 			.name = "lpass_core_cc_ext_if1_ibit_clk",
253 			.parent_hws = (const struct clk_hw*[]){
254 				&lpass_core_cc_ext_if1_clk_src.clkr.hw,
255 			},
256 			.num_parents = 1,
257 			.flags = CLK_SET_RATE_PARENT,
258 			.ops = &clk_branch2_ops,
259 		},
260 	},
261 };
262 
263 static struct clk_branch lpass_core_cc_lpm_core_clk = {
264 	.halt_reg = 0x1e000,
265 	.halt_check = BRANCH_HALT,
266 	.clkr = {
267 		.enable_reg = 0x1e000,
268 		.enable_mask = BIT(0),
269 		.hw.init = &(const struct clk_init_data){
270 			.name = "lpass_core_cc_lpm_core_clk",
271 			.parent_hws = (const struct clk_hw*[]){
272 				&lpass_core_cc_core_clk_src.clkr.hw,
273 			},
274 			.num_parents = 1,
275 			.flags = CLK_SET_RATE_PARENT,
276 			.ops = &clk_branch2_ops,
277 		},
278 	},
279 };
280 
281 static struct clk_branch lpass_core_cc_lpm_mem0_core_clk = {
282 	.halt_reg = 0x1e004,
283 	.halt_check = BRANCH_HALT,
284 	.clkr = {
285 		.enable_reg = 0x1e004,
286 		.enable_mask = BIT(0),
287 		.hw.init = &(const struct clk_init_data){
288 			.name = "lpass_core_cc_lpm_mem0_core_clk",
289 			.parent_hws = (const struct clk_hw*[]){
290 				&lpass_core_cc_core_clk_src.clkr.hw,
291 			},
292 			.num_parents = 1,
293 			.flags = CLK_SET_RATE_PARENT,
294 			.ops = &clk_branch2_ops,
295 		},
296 	},
297 };
298 
299 static struct clk_branch lpass_core_cc_ext_mclk0_clk = {
300 	.halt_reg = 0x20014,
301 	.halt_check = BRANCH_HALT,
302 	.clkr = {
303 		.enable_reg = 0x20014,
304 		.enable_mask = BIT(0),
305 		.hw.init = &(const struct clk_init_data){
306 			.name = "lpass_core_cc_ext_mclk0_clk",
307 			.parent_hws = (const struct clk_hw*[]){
308 				&lpass_core_cc_ext_mclk0_clk_src.clkr.hw,
309 			},
310 			.num_parents = 1,
311 			.flags = CLK_SET_RATE_PARENT,
312 			.ops = &clk_branch2_ops,
313 		},
314 	},
315 };
316 
317 static struct clk_branch lpass_core_cc_sysnoc_mport_core_clk = {
318 	.halt_reg = 0x23000,
319 	.halt_check = BRANCH_HALT_VOTED,
320 	.hwcg_reg = 0x23000,
321 	.hwcg_bit = 1,
322 	.clkr = {
323 		.enable_reg = 0x23000,
324 		.enable_mask = BIT(0),
325 		.hw.init = &(const struct clk_init_data){
326 			.name = "lpass_core_cc_sysnoc_mport_core_clk",
327 			.parent_hws = (const struct clk_hw*[]){
328 				&lpass_core_cc_core_clk_src.clkr.hw,
329 			},
330 			.num_parents = 1,
331 			.flags = CLK_SET_RATE_PARENT,
332 			.ops = &clk_branch2_ops,
333 		},
334 	},
335 };
336 
337 static struct gdsc lpass_core_cc_lpass_core_hm_gdsc = {
338 	.gdscr = 0x0,
339 	.pd = {
340 		.name = "lpass_core_cc_lpass_core_hm_gdsc",
341 	},
342 	.pwrsts = PWRSTS_OFF_ON,
343 	.flags = RETAIN_FF_ENABLE,
344 };
345 
346 static struct clk_regmap *lpass_core_cc_sc7280_clocks[] = {
347 	[LPASS_CORE_CC_CORE_CLK] = &lpass_core_cc_core_clk.clkr,
348 	[LPASS_CORE_CC_CORE_CLK_SRC] = &lpass_core_cc_core_clk_src.clkr,
349 	[LPASS_CORE_CC_DIG_PLL] = &lpass_core_cc_dig_pll.clkr,
350 	[LPASS_CORE_CC_DIG_PLL_OUT_MAIN_DIV_CLK_SRC] =
351 		&lpass_core_cc_dig_pll_out_main_div_clk_src.clkr,
352 	[LPASS_CORE_CC_DIG_PLL_OUT_ODD] = &lpass_core_cc_dig_pll_out_odd.clkr,
353 	[LPASS_CORE_CC_EXT_IF0_CLK_SRC] = &lpass_core_cc_ext_if0_clk_src.clkr,
354 	[LPASS_CORE_CC_EXT_IF0_IBIT_CLK] = &lpass_core_cc_ext_if0_ibit_clk.clkr,
355 	[LPASS_CORE_CC_EXT_IF1_CLK_SRC] = &lpass_core_cc_ext_if1_clk_src.clkr,
356 	[LPASS_CORE_CC_EXT_IF1_IBIT_CLK] = &lpass_core_cc_ext_if1_ibit_clk.clkr,
357 	[LPASS_CORE_CC_LPM_CORE_CLK] = &lpass_core_cc_lpm_core_clk.clkr,
358 	[LPASS_CORE_CC_LPM_MEM0_CORE_CLK] = &lpass_core_cc_lpm_mem0_core_clk.clkr,
359 	[LPASS_CORE_CC_SYSNOC_MPORT_CORE_CLK] = &lpass_core_cc_sysnoc_mport_core_clk.clkr,
360 	[LPASS_CORE_CC_EXT_MCLK0_CLK] = &lpass_core_cc_ext_mclk0_clk.clkr,
361 	[LPASS_CORE_CC_EXT_MCLK0_CLK_SRC] = &lpass_core_cc_ext_mclk0_clk_src.clkr,
362 };
363 
364 static struct regmap_config lpass_core_cc_sc7280_regmap_config = {
365 	.reg_bits = 32,
366 	.reg_stride = 4,
367 	.val_bits = 32,
368 	.fast_io = true,
369 };
370 
371 static const struct qcom_cc_desc lpass_core_cc_sc7280_desc = {
372 	.config = &lpass_core_cc_sc7280_regmap_config,
373 	.clks = lpass_core_cc_sc7280_clocks,
374 	.num_clks = ARRAY_SIZE(lpass_core_cc_sc7280_clocks),
375 };
376 
377 static const struct of_device_id lpass_core_cc_sc7280_match_table[] = {
378 	{ .compatible = "qcom,sc7280-lpasscorecc" },
379 	{ }
380 };
381 MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7280_match_table);
382 
383 static struct gdsc *lpass_core_hm_sc7280_gdscs[] = {
384 	[LPASS_CORE_CC_LPASS_CORE_HM_GDSC] = &lpass_core_cc_lpass_core_hm_gdsc,
385 };
386 
387 static const struct qcom_cc_desc lpass_core_hm_sc7280_desc = {
388 	.config = &lpass_core_cc_sc7280_regmap_config,
389 	.gdscs = lpass_core_hm_sc7280_gdscs,
390 	.num_gdscs = ARRAY_SIZE(lpass_core_hm_sc7280_gdscs),
391 };
392 
393 static int lpass_core_cc_sc7280_probe(struct platform_device *pdev)
394 {
395 	const struct qcom_cc_desc *desc;
396 	struct regmap *regmap;
397 
398 	lpass_core_cc_sc7280_regmap_config.name = "lpass_core_cc";
399 	lpass_core_cc_sc7280_regmap_config.max_register = 0x4f004;
400 	desc = &lpass_core_cc_sc7280_desc;
401 
402 	regmap = qcom_cc_map(pdev, desc);
403 	if (IS_ERR(regmap))
404 		return PTR_ERR(regmap);
405 
406 	clk_lucid_pll_configure(&lpass_core_cc_dig_pll, regmap, &lpass_core_cc_dig_pll_config);
407 
408 	return qcom_cc_really_probe(pdev, &lpass_core_cc_sc7280_desc, regmap);
409 }
410 
411 static struct platform_driver lpass_core_cc_sc7280_driver = {
412 	.probe = lpass_core_cc_sc7280_probe,
413 	.driver = {
414 		.name = "lpass_core_cc-sc7280",
415 		.of_match_table = lpass_core_cc_sc7280_match_table,
416 	},
417 };
418 
419 static int lpass_hm_core_probe(struct platform_device *pdev)
420 {
421 	const struct qcom_cc_desc *desc;
422 
423 	lpass_core_cc_sc7280_regmap_config.name = "lpass_hm_core";
424 	lpass_core_cc_sc7280_regmap_config.max_register = 0x24;
425 	desc = &lpass_core_hm_sc7280_desc;
426 
427 	return qcom_cc_probe_by_index(pdev, 0, desc);
428 }
429 
430 static const struct of_device_id lpass_hm_sc7280_match_table[] = {
431 	{ .compatible = "qcom,sc7280-lpasshm" },
432 	{ }
433 };
434 MODULE_DEVICE_TABLE(of, lpass_hm_sc7280_match_table);
435 
436 static struct platform_driver lpass_hm_sc7280_driver = {
437 	.probe = lpass_hm_core_probe,
438 	.driver = {
439 		.name = "lpass_hm-sc7280",
440 		.of_match_table = lpass_hm_sc7280_match_table,
441 	},
442 };
443 
444 static int __init lpass_core_cc_sc7280_init(void)
445 {
446 	int ret;
447 
448 	ret = platform_driver_register(&lpass_hm_sc7280_driver);
449 	if (ret)
450 		return ret;
451 
452 	return platform_driver_register(&lpass_core_cc_sc7280_driver);
453 }
454 subsys_initcall(lpass_core_cc_sc7280_init);
455 
456 static void __exit lpass_core_cc_sc7280_exit(void)
457 {
458 	platform_driver_unregister(&lpass_core_cc_sc7280_driver);
459 	platform_driver_unregister(&lpass_hm_sc7280_driver);
460 }
461 module_exit(lpass_core_cc_sc7280_exit);
462 
463 MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7280 Driver");
464 MODULE_LICENSE("GPL v2");
465