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 
194 static struct clk_branch lpass_core_cc_core_clk = {
195 	.halt_reg = 0x1f000,
196 	.halt_check = BRANCH_HALT_VOTED,
197 	.hwcg_reg = 0x1f000,
198 	.hwcg_bit = 1,
199 	.clkr = {
200 		.enable_reg = 0x1f000,
201 		.enable_mask = BIT(0),
202 		.hw.init = &(const struct clk_init_data){
203 			.name = "lpass_core_cc_core_clk",
204 			.parent_hws = (const struct clk_hw*[]){
205 				&lpass_core_cc_core_clk_src.clkr.hw,
206 			},
207 			.num_parents = 1,
208 			.flags = CLK_SET_RATE_PARENT,
209 			.ops = &clk_branch2_aon_ops,
210 		},
211 	},
212 };
213 
214 static struct clk_branch lpass_core_cc_ext_if0_ibit_clk = {
215 	.halt_reg = 0x10018,
216 	.halt_check = BRANCH_HALT,
217 	.clkr = {
218 		.enable_reg = 0x10018,
219 		.enable_mask = BIT(0),
220 		.hw.init = &(const struct clk_init_data){
221 			.name = "lpass_core_cc_ext_if0_ibit_clk",
222 			.parent_hws = (const struct clk_hw*[]){
223 				&lpass_core_cc_ext_if0_clk_src.clkr.hw,
224 			},
225 			.num_parents = 1,
226 			.flags = CLK_SET_RATE_PARENT,
227 			.ops = &clk_branch2_ops,
228 		},
229 	},
230 };
231 
232 static struct clk_branch lpass_core_cc_ext_if1_ibit_clk = {
233 	.halt_reg = 0x11018,
234 	.halt_check = BRANCH_HALT,
235 	.clkr = {
236 		.enable_reg = 0x11018,
237 		.enable_mask = BIT(0),
238 		.hw.init = &(const struct clk_init_data){
239 			.name = "lpass_core_cc_ext_if1_ibit_clk",
240 			.parent_hws = (const struct clk_hw*[]){
241 				&lpass_core_cc_ext_if1_clk_src.clkr.hw,
242 			},
243 			.num_parents = 1,
244 			.flags = CLK_SET_RATE_PARENT,
245 			.ops = &clk_branch2_ops,
246 		},
247 	},
248 };
249 
250 static struct clk_branch lpass_core_cc_lpm_core_clk = {
251 	.halt_reg = 0x1e000,
252 	.halt_check = BRANCH_HALT,
253 	.clkr = {
254 		.enable_reg = 0x1e000,
255 		.enable_mask = BIT(0),
256 		.hw.init = &(const struct clk_init_data){
257 			.name = "lpass_core_cc_lpm_core_clk",
258 			.parent_hws = (const struct clk_hw*[]){
259 				&lpass_core_cc_core_clk_src.clkr.hw,
260 			},
261 			.num_parents = 1,
262 			.flags = CLK_SET_RATE_PARENT,
263 			.ops = &clk_branch2_ops,
264 		},
265 	},
266 };
267 
268 static struct clk_branch lpass_core_cc_lpm_mem0_core_clk = {
269 	.halt_reg = 0x1e004,
270 	.halt_check = BRANCH_HALT,
271 	.clkr = {
272 		.enable_reg = 0x1e004,
273 		.enable_mask = BIT(0),
274 		.hw.init = &(const struct clk_init_data){
275 			.name = "lpass_core_cc_lpm_mem0_core_clk",
276 			.parent_hws = (const struct clk_hw*[]){
277 				&lpass_core_cc_core_clk_src.clkr.hw,
278 			},
279 			.num_parents = 1,
280 			.flags = CLK_SET_RATE_PARENT,
281 			.ops = &clk_branch2_ops,
282 		},
283 	},
284 };
285 
286 static struct clk_branch lpass_core_cc_sysnoc_mport_core_clk = {
287 	.halt_reg = 0x23000,
288 	.halt_check = BRANCH_HALT_VOTED,
289 	.hwcg_reg = 0x23000,
290 	.hwcg_bit = 1,
291 	.clkr = {
292 		.enable_reg = 0x23000,
293 		.enable_mask = BIT(0),
294 		.hw.init = &(const struct clk_init_data){
295 			.name = "lpass_core_cc_sysnoc_mport_core_clk",
296 			.parent_hws = (const struct clk_hw*[]){
297 				&lpass_core_cc_core_clk_src.clkr.hw,
298 			},
299 			.num_parents = 1,
300 			.flags = CLK_SET_RATE_PARENT,
301 			.ops = &clk_branch2_ops,
302 		},
303 	},
304 };
305 
306 static struct gdsc lpass_core_cc_lpass_core_hm_gdsc = {
307 	.gdscr = 0x0,
308 	.pd = {
309 		.name = "lpass_core_cc_lpass_core_hm_gdsc",
310 	},
311 	.pwrsts = PWRSTS_OFF_ON,
312 	.flags = RETAIN_FF_ENABLE,
313 };
314 
315 static struct clk_regmap *lpass_core_cc_sc7280_clocks[] = {
316 	[LPASS_CORE_CC_CORE_CLK] = &lpass_core_cc_core_clk.clkr,
317 	[LPASS_CORE_CC_CORE_CLK_SRC] = &lpass_core_cc_core_clk_src.clkr,
318 	[LPASS_CORE_CC_DIG_PLL] = &lpass_core_cc_dig_pll.clkr,
319 	[LPASS_CORE_CC_DIG_PLL_OUT_MAIN_DIV_CLK_SRC] =
320 		&lpass_core_cc_dig_pll_out_main_div_clk_src.clkr,
321 	[LPASS_CORE_CC_DIG_PLL_OUT_ODD] = &lpass_core_cc_dig_pll_out_odd.clkr,
322 	[LPASS_CORE_CC_EXT_IF0_CLK_SRC] = &lpass_core_cc_ext_if0_clk_src.clkr,
323 	[LPASS_CORE_CC_EXT_IF0_IBIT_CLK] = &lpass_core_cc_ext_if0_ibit_clk.clkr,
324 	[LPASS_CORE_CC_EXT_IF1_CLK_SRC] = &lpass_core_cc_ext_if1_clk_src.clkr,
325 	[LPASS_CORE_CC_EXT_IF1_IBIT_CLK] = &lpass_core_cc_ext_if1_ibit_clk.clkr,
326 	[LPASS_CORE_CC_LPM_CORE_CLK] = &lpass_core_cc_lpm_core_clk.clkr,
327 	[LPASS_CORE_CC_LPM_MEM0_CORE_CLK] = &lpass_core_cc_lpm_mem0_core_clk.clkr,
328 	[LPASS_CORE_CC_SYSNOC_MPORT_CORE_CLK] = &lpass_core_cc_sysnoc_mport_core_clk.clkr,
329 };
330 
331 static struct regmap_config lpass_core_cc_sc7280_regmap_config = {
332 	.reg_bits = 32,
333 	.reg_stride = 4,
334 	.val_bits = 32,
335 	.fast_io = true,
336 };
337 
338 static const struct qcom_cc_desc lpass_core_cc_sc7280_desc = {
339 	.config = &lpass_core_cc_sc7280_regmap_config,
340 	.clks = lpass_core_cc_sc7280_clocks,
341 	.num_clks = ARRAY_SIZE(lpass_core_cc_sc7280_clocks),
342 };
343 
344 static const struct of_device_id lpass_core_cc_sc7280_match_table[] = {
345 	{ .compatible = "qcom,sc7280-lpasscorecc" },
346 	{ }
347 };
348 MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7280_match_table);
349 
350 static struct gdsc *lpass_core_hm_sc7280_gdscs[] = {
351 	[LPASS_CORE_CC_LPASS_CORE_HM_GDSC] = &lpass_core_cc_lpass_core_hm_gdsc,
352 };
353 
354 static const struct qcom_cc_desc lpass_core_hm_sc7280_desc = {
355 	.config = &lpass_core_cc_sc7280_regmap_config,
356 	.gdscs = lpass_core_hm_sc7280_gdscs,
357 	.num_gdscs = ARRAY_SIZE(lpass_core_hm_sc7280_gdscs),
358 };
359 
360 static int lpass_core_cc_sc7280_probe(struct platform_device *pdev)
361 {
362 	const struct qcom_cc_desc *desc;
363 	struct regmap *regmap;
364 
365 	lpass_core_cc_sc7280_regmap_config.name = "lpass_core_cc";
366 	lpass_core_cc_sc7280_regmap_config.max_register = 0x4f004;
367 	desc = &lpass_core_cc_sc7280_desc;
368 
369 	regmap = qcom_cc_map(pdev, desc);
370 	if (IS_ERR(regmap))
371 		return PTR_ERR(regmap);
372 
373 	clk_lucid_pll_configure(&lpass_core_cc_dig_pll, regmap, &lpass_core_cc_dig_pll_config);
374 
375 	return qcom_cc_really_probe(pdev, &lpass_core_cc_sc7280_desc, regmap);
376 }
377 
378 static struct platform_driver lpass_core_cc_sc7280_driver = {
379 	.probe = lpass_core_cc_sc7280_probe,
380 	.driver = {
381 		.name = "lpass_core_cc-sc7280",
382 		.of_match_table = lpass_core_cc_sc7280_match_table,
383 	},
384 };
385 
386 static int lpass_hm_core_probe(struct platform_device *pdev)
387 {
388 	const struct qcom_cc_desc *desc;
389 
390 	lpass_core_cc_sc7280_regmap_config.name = "lpass_hm_core";
391 	lpass_core_cc_sc7280_regmap_config.max_register = 0x24;
392 	desc = &lpass_core_hm_sc7280_desc;
393 
394 	return qcom_cc_probe_by_index(pdev, 0, desc);
395 }
396 
397 static const struct of_device_id lpass_hm_sc7280_match_table[] = {
398 	{ .compatible = "qcom,sc7280-lpasshm" },
399 	{ }
400 };
401 MODULE_DEVICE_TABLE(of, lpass_hm_sc7280_match_table);
402 
403 static struct platform_driver lpass_hm_sc7280_driver = {
404 	.probe = lpass_hm_core_probe,
405 	.driver = {
406 		.name = "lpass_hm-sc7280",
407 		.of_match_table = lpass_hm_sc7280_match_table,
408 	},
409 };
410 
411 static int __init lpass_core_cc_sc7280_init(void)
412 {
413 	int ret;
414 
415 	ret = platform_driver_register(&lpass_hm_sc7280_driver);
416 	if (ret)
417 		return ret;
418 
419 	return platform_driver_register(&lpass_core_cc_sc7280_driver);
420 }
421 subsys_initcall(lpass_core_cc_sc7280_init);
422 
423 static void __exit lpass_core_cc_sc7280_exit(void)
424 {
425 	platform_driver_unregister(&lpass_core_cc_sc7280_driver);
426 	platform_driver_unregister(&lpass_hm_sc7280_driver);
427 }
428 module_exit(lpass_core_cc_sc7280_exit);
429 
430 MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7280 Driver");
431 MODULE_LICENSE("GPL v2");
432