1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
6 #include <linux/clk-provider.h>
7 #include <linux/module.h>
8 #include <linux/mod_devicetable.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/regmap.h>
14 #include <dt-bindings/clock/qcom,sa8775p-videocc.h>
16 #include "clk-alpha-pll.h"
17 #include "clk-branch.h"
20 #include "clk-regmap.h"
21 #include "clk-regmap-divider.h"
22 #include "clk-regmap-mux.h"
38 P_VIDEO_PLL0_OUT_MAIN
,
39 P_VIDEO_PLL1_OUT_MAIN
,
42 static const struct pll_vco lucid_evo_vco
[] = {
43 { 249600000, 2020000000, 0 },
46 static const struct alpha_pll_config video_pll0_config
= {
49 .config_ctl_val
= 0x20485699,
50 .config_ctl_hi_val
= 0x00182261,
51 .config_ctl_hi1_val
= 0x32aa299c,
52 .user_ctl_val
= 0x00000000,
53 .user_ctl_hi_val
= 0x00400805,
56 static struct clk_alpha_pll video_pll0
= {
58 .vco_table
= lucid_evo_vco
,
59 .num_vco
= ARRAY_SIZE(lucid_evo_vco
),
60 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID_EVO
],
62 .hw
.init
= &(const struct clk_init_data
) {
64 .parent_data
= &(const struct clk_parent_data
) {
68 .ops
= &clk_alpha_pll_lucid_evo_ops
,
73 static const struct alpha_pll_config video_pll1_config
= {
76 .config_ctl_val
= 0x20485699,
77 .config_ctl_hi_val
= 0x00182261,
78 .config_ctl_hi1_val
= 0x32aa299c,
79 .user_ctl_val
= 0x00000000,
80 .user_ctl_hi_val
= 0x00400805,
83 static struct clk_alpha_pll video_pll1
= {
85 .vco_table
= lucid_evo_vco
,
86 .num_vco
= ARRAY_SIZE(lucid_evo_vco
),
87 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID_EVO
],
89 .hw
.init
= &(const struct clk_init_data
) {
91 .parent_data
= &(const struct clk_parent_data
) {
95 .ops
= &clk_alpha_pll_lucid_evo_ops
,
100 static const struct parent_map video_cc_parent_map_0_ao
[] = {
104 static const struct clk_parent_data video_cc_parent_data_0_ao
[] = {
105 { .index
= DT_BI_TCXO_AO
},
108 static const struct parent_map video_cc_parent_map_1
[] = {
110 { P_VIDEO_PLL0_OUT_MAIN
, 1 },
113 static const struct clk_parent_data video_cc_parent_data_1
[] = {
114 { .index
= DT_BI_TCXO
},
115 { .hw
= &video_pll0
.clkr
.hw
},
118 static const struct parent_map video_cc_parent_map_2
[] = {
120 { P_VIDEO_PLL1_OUT_MAIN
, 1 },
123 static const struct clk_parent_data video_cc_parent_data_2
[] = {
124 { .index
= DT_BI_TCXO
},
125 { .hw
= &video_pll1
.clkr
.hw
},
128 static const struct parent_map video_cc_parent_map_3
[] = {
132 static const struct clk_parent_data video_cc_parent_data_3
[] = {
133 { .index
= DT_SLEEP_CLK
},
136 static const struct freq_tbl ftbl_video_cc_ahb_clk_src
[] = {
137 F(19200000, P_BI_TCXO_AO
, 1, 0, 0),
141 static struct clk_rcg2 video_cc_ahb_clk_src
= {
145 .parent_map
= video_cc_parent_map_0_ao
,
146 .freq_tbl
= ftbl_video_cc_ahb_clk_src
,
147 .clkr
.hw
.init
= &(const struct clk_init_data
) {
148 .name
= "video_cc_ahb_clk_src",
149 .parent_data
= video_cc_parent_data_0_ao
,
150 .num_parents
= ARRAY_SIZE(video_cc_parent_data_0_ao
),
151 .flags
= CLK_SET_RATE_PARENT
,
152 .ops
= &clk_rcg2_shared_ops
,
156 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src
[] = {
157 F(1098000000, P_VIDEO_PLL0_OUT_MAIN
, 1, 0, 0),
158 F(1332000000, P_VIDEO_PLL0_OUT_MAIN
, 1, 0, 0),
159 F(1599000000, P_VIDEO_PLL0_OUT_MAIN
, 1, 0, 0),
160 F(1680000000, P_VIDEO_PLL0_OUT_MAIN
, 1, 0, 0),
164 static struct clk_rcg2 video_cc_mvs0_clk_src
= {
168 .parent_map
= video_cc_parent_map_1
,
169 .freq_tbl
= ftbl_video_cc_mvs0_clk_src
,
170 .clkr
.hw
.init
= &(const struct clk_init_data
) {
171 .name
= "video_cc_mvs0_clk_src",
172 .parent_data
= video_cc_parent_data_1
,
173 .num_parents
= ARRAY_SIZE(video_cc_parent_data_1
),
174 .flags
= CLK_SET_RATE_PARENT
,
175 .ops
= &clk_rcg2_shared_ops
,
179 static const struct freq_tbl ftbl_video_cc_mvs1_clk_src
[] = {
180 F(1098000000, P_VIDEO_PLL1_OUT_MAIN
, 1, 0, 0),
181 F(1332000000, P_VIDEO_PLL1_OUT_MAIN
, 1, 0, 0),
182 F(1600000000, P_VIDEO_PLL1_OUT_MAIN
, 1, 0, 0),
183 F(1800000000, P_VIDEO_PLL1_OUT_MAIN
, 1, 0, 0),
187 static struct clk_rcg2 video_cc_mvs1_clk_src
= {
191 .parent_map
= video_cc_parent_map_2
,
192 .freq_tbl
= ftbl_video_cc_mvs1_clk_src
,
193 .clkr
.hw
.init
= &(const struct clk_init_data
) {
194 .name
= "video_cc_mvs1_clk_src",
195 .parent_data
= video_cc_parent_data_2
,
196 .num_parents
= ARRAY_SIZE(video_cc_parent_data_2
),
197 .flags
= CLK_SET_RATE_PARENT
,
198 .ops
= &clk_rcg2_shared_ops
,
202 static const struct freq_tbl ftbl_video_cc_sleep_clk_src
[] = {
203 F(32000, P_SLEEP_CLK
, 1, 0, 0),
207 static struct clk_rcg2 video_cc_sleep_clk_src
= {
211 .parent_map
= video_cc_parent_map_3
,
212 .freq_tbl
= ftbl_video_cc_sleep_clk_src
,
213 .clkr
.hw
.init
= &(const struct clk_init_data
) {
214 .name
= "video_cc_sleep_clk_src",
215 .parent_data
= video_cc_parent_data_3
,
216 .num_parents
= ARRAY_SIZE(video_cc_parent_data_3
),
217 .flags
= CLK_SET_RATE_PARENT
,
218 .ops
= &clk_rcg2_shared_ops
,
222 static struct clk_rcg2 video_cc_xo_clk_src
= {
226 .parent_map
= video_cc_parent_map_0_ao
,
227 .freq_tbl
= ftbl_video_cc_ahb_clk_src
,
228 .clkr
.hw
.init
= &(const struct clk_init_data
) {
229 .name
= "video_cc_xo_clk_src",
230 .parent_data
= video_cc_parent_data_0_ao
,
231 .num_parents
= ARRAY_SIZE(video_cc_parent_data_0_ao
),
232 .flags
= CLK_SET_RATE_PARENT
,
233 .ops
= &clk_rcg2_shared_ops
,
237 static struct clk_regmap_div video_cc_mvs0_div_clk_src
= {
241 .clkr
.hw
.init
= &(const struct clk_init_data
) {
242 .name
= "video_cc_mvs0_div_clk_src",
243 .parent_hws
= (const struct clk_hw
*[]) {
244 &video_cc_mvs0_clk_src
.clkr
.hw
,
247 .flags
= CLK_SET_RATE_PARENT
,
248 .ops
= &clk_regmap_div_ro_ops
,
252 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src
= {
256 .clkr
.hw
.init
= &(const struct clk_init_data
) {
257 .name
= "video_cc_mvs0c_div2_div_clk_src",
258 .parent_hws
= (const struct clk_hw
*[]) {
259 &video_cc_mvs0_clk_src
.clkr
.hw
,
262 .flags
= CLK_SET_RATE_PARENT
,
263 .ops
= &clk_regmap_div_ro_ops
,
267 static struct clk_regmap_div video_cc_mvs1_div_clk_src
= {
271 .clkr
.hw
.init
= &(const struct clk_init_data
) {
272 .name
= "video_cc_mvs1_div_clk_src",
273 .parent_hws
= (const struct clk_hw
*[]) {
274 &video_cc_mvs1_clk_src
.clkr
.hw
,
277 .flags
= CLK_SET_RATE_PARENT
,
278 .ops
= &clk_regmap_div_ro_ops
,
282 static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src
= {
286 .clkr
.hw
.init
= &(const struct clk_init_data
) {
287 .name
= "video_cc_mvs1c_div2_div_clk_src",
288 .parent_hws
= (const struct clk_hw
*[]) {
289 &video_cc_mvs1_clk_src
.clkr
.hw
,
292 .flags
= CLK_SET_RATE_PARENT
,
293 .ops
= &clk_regmap_div_ro_ops
,
297 static struct clk_regmap_div video_cc_sm_div_clk_src
= {
301 .clkr
.hw
.init
= &(const struct clk_init_data
) {
302 .name
= "video_cc_sm_div_clk_src",
303 .ops
= &clk_regmap_div_ro_ops
,
307 static struct clk_branch video_cc_mvs0_clk
= {
309 .halt_check
= BRANCH_HALT_VOTED
,
313 .enable_reg
= 0x80b0,
314 .enable_mask
= BIT(0),
315 .hw
.init
= &(const struct clk_init_data
) {
316 .name
= "video_cc_mvs0_clk",
317 .parent_hws
= (const struct clk_hw
*[]) {
318 &video_cc_mvs0_div_clk_src
.clkr
.hw
,
321 .flags
= CLK_SET_RATE_PARENT
,
322 .ops
= &clk_branch2_ops
,
327 static struct clk_branch video_cc_mvs0c_clk
= {
329 .halt_check
= BRANCH_HALT
,
331 .enable_reg
= 0x8064,
332 .enable_mask
= BIT(0),
333 .hw
.init
= &(const struct clk_init_data
) {
334 .name
= "video_cc_mvs0c_clk",
335 .parent_hws
= (const struct clk_hw
*[]) {
336 &video_cc_mvs0c_div2_div_clk_src
.clkr
.hw
,
339 .flags
= CLK_SET_RATE_PARENT
,
340 .ops
= &clk_branch2_ops
,
345 static struct clk_branch video_cc_mvs1_clk
= {
347 .halt_check
= BRANCH_HALT_VOTED
,
351 .enable_reg
= 0x80d4,
352 .enable_mask
= BIT(0),
353 .hw
.init
= &(const struct clk_init_data
) {
354 .name
= "video_cc_mvs1_clk",
355 .parent_hws
= (const struct clk_hw
*[]) {
356 &video_cc_mvs1_div_clk_src
.clkr
.hw
,
359 .flags
= CLK_SET_RATE_PARENT
,
360 .ops
= &clk_branch2_ops
,
365 static struct clk_branch video_cc_mvs1c_clk
= {
367 .halt_check
= BRANCH_HALT
,
369 .enable_reg
= 0x808c,
370 .enable_mask
= BIT(0),
371 .hw
.init
= &(const struct clk_init_data
) {
372 .name
= "video_cc_mvs1c_clk",
373 .parent_hws
= (const struct clk_hw
*[]) {
374 &video_cc_mvs1c_div2_div_clk_src
.clkr
.hw
,
377 .flags
= CLK_SET_RATE_PARENT
,
378 .ops
= &clk_branch2_ops
,
383 static struct clk_branch video_cc_pll_lock_monitor_clk
= {
385 .halt_check
= BRANCH_HALT
,
387 .enable_reg
= 0x9000,
388 .enable_mask
= BIT(0),
389 .hw
.init
= &(const struct clk_init_data
) {
390 .name
= "video_cc_pll_lock_monitor_clk",
391 .parent_hws
= (const struct clk_hw
*[]) {
392 &video_cc_xo_clk_src
.clkr
.hw
,
395 .flags
= CLK_SET_RATE_PARENT
,
396 .ops
= &clk_branch2_ops
,
401 static struct clk_branch video_cc_sm_obs_clk
= {
403 .halt_check
= BRANCH_HALT_SKIP
,
405 .enable_reg
= 0x810c,
406 .enable_mask
= BIT(0),
407 .hw
.init
= &(const struct clk_init_data
) {
408 .name
= "video_cc_sm_obs_clk",
409 .parent_hws
= (const struct clk_hw
*[]) {
410 &video_cc_sm_div_clk_src
.clkr
.hw
,
413 .flags
= CLK_SET_RATE_PARENT
,
414 .ops
= &clk_branch2_ops
,
419 static struct gdsc video_cc_mvs0c_gdsc
= {
421 .en_rest_wait_val
= 0x2,
422 .en_few_wait_val
= 0x2,
423 .clk_dis_wait_val
= 0x6,
425 .name
= "video_cc_mvs0c_gdsc",
427 .pwrsts
= PWRSTS_OFF_ON
,
428 .flags
= RETAIN_FF_ENABLE
| POLL_CFG_GDSCR
,
431 static struct gdsc video_cc_mvs0_gdsc
= {
433 .en_rest_wait_val
= 0x2,
434 .en_few_wait_val
= 0x2,
435 .clk_dis_wait_val
= 0x6,
437 .name
= "video_cc_mvs0_gdsc",
439 .pwrsts
= PWRSTS_OFF_ON
,
440 .parent
= &video_cc_mvs0c_gdsc
.pd
,
441 .flags
= RETAIN_FF_ENABLE
| POLL_CFG_GDSCR
| HW_CTRL_TRIGGER
,
444 static struct gdsc video_cc_mvs1c_gdsc
= {
446 .en_rest_wait_val
= 0x2,
447 .en_few_wait_val
= 0x2,
448 .clk_dis_wait_val
= 0x6,
450 .name
= "video_cc_mvs1c_gdsc",
452 .pwrsts
= PWRSTS_OFF_ON
,
453 .flags
= RETAIN_FF_ENABLE
| POLL_CFG_GDSCR
,
456 static struct gdsc video_cc_mvs1_gdsc
= {
458 .en_rest_wait_val
= 0x2,
459 .en_few_wait_val
= 0x2,
460 .clk_dis_wait_val
= 0x6,
462 .name
= "video_cc_mvs1_gdsc",
464 .pwrsts
= PWRSTS_OFF_ON
,
465 .parent
= &video_cc_mvs1c_gdsc
.pd
,
466 .flags
= RETAIN_FF_ENABLE
| POLL_CFG_GDSCR
| HW_CTRL_TRIGGER
,
469 static struct clk_regmap
*video_cc_sa8775p_clocks
[] = {
470 [VIDEO_CC_AHB_CLK_SRC
] = &video_cc_ahb_clk_src
.clkr
,
471 [VIDEO_CC_MVS0_CLK
] = &video_cc_mvs0_clk
.clkr
,
472 [VIDEO_CC_MVS0_CLK_SRC
] = &video_cc_mvs0_clk_src
.clkr
,
473 [VIDEO_CC_MVS0_DIV_CLK_SRC
] = &video_cc_mvs0_div_clk_src
.clkr
,
474 [VIDEO_CC_MVS0C_CLK
] = &video_cc_mvs0c_clk
.clkr
,
475 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC
] = &video_cc_mvs0c_div2_div_clk_src
.clkr
,
476 [VIDEO_CC_MVS1_CLK
] = &video_cc_mvs1_clk
.clkr
,
477 [VIDEO_CC_MVS1_CLK_SRC
] = &video_cc_mvs1_clk_src
.clkr
,
478 [VIDEO_CC_MVS1_DIV_CLK_SRC
] = &video_cc_mvs1_div_clk_src
.clkr
,
479 [VIDEO_CC_MVS1C_CLK
] = &video_cc_mvs1c_clk
.clkr
,
480 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC
] = &video_cc_mvs1c_div2_div_clk_src
.clkr
,
481 [VIDEO_CC_PLL_LOCK_MONITOR_CLK
] = &video_cc_pll_lock_monitor_clk
.clkr
,
482 [VIDEO_CC_SLEEP_CLK_SRC
] = &video_cc_sleep_clk_src
.clkr
,
483 [VIDEO_CC_SM_DIV_CLK_SRC
] = &video_cc_sm_div_clk_src
.clkr
,
484 [VIDEO_CC_SM_OBS_CLK
] = &video_cc_sm_obs_clk
.clkr
,
485 [VIDEO_CC_XO_CLK_SRC
] = &video_cc_xo_clk_src
.clkr
,
486 [VIDEO_PLL0
] = &video_pll0
.clkr
,
487 [VIDEO_PLL1
] = &video_pll1
.clkr
,
490 static struct gdsc
*video_cc_sa8775p_gdscs
[] = {
491 [VIDEO_CC_MVS0_GDSC
] = &video_cc_mvs0_gdsc
,
492 [VIDEO_CC_MVS0C_GDSC
] = &video_cc_mvs0c_gdsc
,
493 [VIDEO_CC_MVS1_GDSC
] = &video_cc_mvs1_gdsc
,
494 [VIDEO_CC_MVS1C_GDSC
] = &video_cc_mvs1c_gdsc
,
497 static const struct qcom_reset_map video_cc_sa8775p_resets
[] = {
498 [VIDEO_CC_INTERFACE_BCR
] = { 0x80e8 },
499 [VIDEO_CC_MVS0_BCR
] = { 0x8098 },
500 [VIDEO_CC_MVS0C_CLK_ARES
] = { 0x8064, 2 },
501 [VIDEO_CC_MVS0C_BCR
] = { 0x8048 },
502 [VIDEO_CC_MVS1_BCR
] = { 0x80bc },
503 [VIDEO_CC_MVS1C_CLK_ARES
] = { 0x808c, 2 },
504 [VIDEO_CC_MVS1C_BCR
] = { 0x8070 },
507 static const struct regmap_config video_cc_sa8775p_regmap_config
= {
511 .max_register
= 0xb000,
515 static struct qcom_cc_desc video_cc_sa8775p_desc
= {
516 .config
= &video_cc_sa8775p_regmap_config
,
517 .clks
= video_cc_sa8775p_clocks
,
518 .num_clks
= ARRAY_SIZE(video_cc_sa8775p_clocks
),
519 .resets
= video_cc_sa8775p_resets
,
520 .num_resets
= ARRAY_SIZE(video_cc_sa8775p_resets
),
521 .gdscs
= video_cc_sa8775p_gdscs
,
522 .num_gdscs
= ARRAY_SIZE(video_cc_sa8775p_gdscs
),
525 static const struct of_device_id video_cc_sa8775p_match_table
[] = {
526 { .compatible
= "qcom,sa8775p-videocc" },
529 MODULE_DEVICE_TABLE(of
, video_cc_sa8775p_match_table
);
531 static int video_cc_sa8775p_probe(struct platform_device
*pdev
)
533 struct regmap
*regmap
;
536 ret
= devm_pm_runtime_enable(&pdev
->dev
);
540 ret
= pm_runtime_resume_and_get(&pdev
->dev
);
544 regmap
= qcom_cc_map(pdev
, &video_cc_sa8775p_desc
);
545 if (IS_ERR(regmap
)) {
546 pm_runtime_put(&pdev
->dev
);
547 return PTR_ERR(regmap
);
550 clk_lucid_evo_pll_configure(&video_pll0
, regmap
, &video_pll0_config
);
551 clk_lucid_evo_pll_configure(&video_pll1
, regmap
, &video_pll1_config
);
553 /* Keep some clocks always enabled */
554 qcom_branch_set_clk_en(regmap
, 0x80ec); /* VIDEO_CC_AHB_CLK */
555 qcom_branch_set_clk_en(regmap
, 0x8144); /* VIDEO_CC_SLEEP_CLK */
556 qcom_branch_set_clk_en(regmap
, 0x8128); /* VIDEO_CC_XO_CLK */
558 ret
= qcom_cc_really_probe(&pdev
->dev
, &video_cc_sa8775p_desc
, regmap
);
560 pm_runtime_put(&pdev
->dev
);
565 static struct platform_driver video_cc_sa8775p_driver
= {
566 .probe
= video_cc_sa8775p_probe
,
568 .name
= "videocc-sa8775p",
569 .of_match_table
= video_cc_sa8775p_match_table
,
573 module_platform_driver(video_cc_sa8775p_driver
);
575 MODULE_DESCRIPTION("QTI VIDEOCC SA8775P Driver");
576 MODULE_LICENSE("GPL");