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