1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2018, The Linux Foundation. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/platform_device.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of_address.h> |
10 | #include <linux/regmap.h> |
11 | |
12 | #include <dt-bindings/clock/qcom,lpass-sdm845.h> |
13 | |
14 | #include "clk-regmap.h" |
15 | #include "clk-branch.h" |
16 | #include "common.h" |
17 | |
18 | static struct clk_branch lpass_q6ss_ahbm_aon_clk = { |
19 | .halt_reg = 0x12000, |
20 | .halt_check = BRANCH_VOTED, |
21 | .clkr = { |
22 | .enable_reg = 0x12000, |
23 | .enable_mask = BIT(0), |
24 | .hw.init = &(struct clk_init_data){ |
25 | .name = "lpass_q6ss_ahbm_aon_clk" , |
26 | .ops = &clk_branch2_ops, |
27 | }, |
28 | }, |
29 | }; |
30 | |
31 | static struct clk_branch lpass_q6ss_ahbs_aon_clk = { |
32 | .halt_reg = 0x1f000, |
33 | .halt_check = BRANCH_VOTED, |
34 | .clkr = { |
35 | .enable_reg = 0x1f000, |
36 | .enable_mask = BIT(0), |
37 | .hw.init = &(struct clk_init_data){ |
38 | .name = "lpass_q6ss_ahbs_aon_clk" , |
39 | .ops = &clk_branch2_ops, |
40 | }, |
41 | }, |
42 | }; |
43 | |
44 | static struct clk_branch lpass_qdsp6ss_core_clk = { |
45 | .halt_reg = 0x20, |
46 | /* CLK_OFF would not toggle until LPASS is out of reset */ |
47 | .halt_check = BRANCH_HALT_SKIP, |
48 | .clkr = { |
49 | .enable_reg = 0x20, |
50 | .enable_mask = BIT(0), |
51 | .hw.init = &(struct clk_init_data){ |
52 | .name = "lpass_qdsp6ss_core_clk" , |
53 | .ops = &clk_branch2_ops, |
54 | }, |
55 | }, |
56 | }; |
57 | |
58 | static struct clk_branch lpass_qdsp6ss_xo_clk = { |
59 | .halt_reg = 0x38, |
60 | /* CLK_OFF would not toggle until LPASS is out of reset */ |
61 | .halt_check = BRANCH_HALT_SKIP, |
62 | .clkr = { |
63 | .enable_reg = 0x38, |
64 | .enable_mask = BIT(0), |
65 | .hw.init = &(struct clk_init_data){ |
66 | .name = "lpass_qdsp6ss_xo_clk" , |
67 | .ops = &clk_branch2_ops, |
68 | }, |
69 | }, |
70 | }; |
71 | |
72 | static struct clk_branch lpass_qdsp6ss_sleep_clk = { |
73 | .halt_reg = 0x3c, |
74 | /* CLK_OFF would not toggle until LPASS is out of reset */ |
75 | .halt_check = BRANCH_HALT_SKIP, |
76 | .clkr = { |
77 | .enable_reg = 0x3c, |
78 | .enable_mask = BIT(0), |
79 | .hw.init = &(struct clk_init_data){ |
80 | .name = "lpass_qdsp6ss_sleep_clk" , |
81 | .ops = &clk_branch2_ops, |
82 | }, |
83 | }, |
84 | }; |
85 | |
86 | static struct regmap_config lpass_regmap_config = { |
87 | .reg_bits = 32, |
88 | .reg_stride = 4, |
89 | .val_bits = 32, |
90 | .fast_io = true, |
91 | }; |
92 | |
93 | static struct clk_regmap *lpass_cc_sdm845_clocks[] = { |
94 | [LPASS_Q6SS_AHBM_AON_CLK] = &lpass_q6ss_ahbm_aon_clk.clkr, |
95 | [LPASS_Q6SS_AHBS_AON_CLK] = &lpass_q6ss_ahbs_aon_clk.clkr, |
96 | }; |
97 | |
98 | static const struct qcom_cc_desc lpass_cc_sdm845_desc = { |
99 | .config = &lpass_regmap_config, |
100 | .clks = lpass_cc_sdm845_clocks, |
101 | .num_clks = ARRAY_SIZE(lpass_cc_sdm845_clocks), |
102 | }; |
103 | |
104 | static struct clk_regmap *lpass_qdsp6ss_sdm845_clocks[] = { |
105 | [LPASS_QDSP6SS_XO_CLK] = &lpass_qdsp6ss_xo_clk.clkr, |
106 | [LPASS_QDSP6SS_SLEEP_CLK] = &lpass_qdsp6ss_sleep_clk.clkr, |
107 | [LPASS_QDSP6SS_CORE_CLK] = &lpass_qdsp6ss_core_clk.clkr, |
108 | }; |
109 | |
110 | static const struct qcom_cc_desc lpass_qdsp6ss_sdm845_desc = { |
111 | .config = &lpass_regmap_config, |
112 | .clks = lpass_qdsp6ss_sdm845_clocks, |
113 | .num_clks = ARRAY_SIZE(lpass_qdsp6ss_sdm845_clocks), |
114 | }; |
115 | |
116 | static int lpass_cc_sdm845_probe(struct platform_device *pdev) |
117 | { |
118 | const struct qcom_cc_desc *desc; |
119 | int ret; |
120 | |
121 | lpass_regmap_config.name = "cc" ; |
122 | desc = &lpass_cc_sdm845_desc; |
123 | |
124 | ret = qcom_cc_probe_by_index(pdev, index: 0, desc); |
125 | if (ret) |
126 | return ret; |
127 | |
128 | lpass_regmap_config.name = "qdsp6ss" ; |
129 | desc = &lpass_qdsp6ss_sdm845_desc; |
130 | |
131 | return qcom_cc_probe_by_index(pdev, index: 1, desc); |
132 | } |
133 | |
134 | static const struct of_device_id lpass_cc_sdm845_match_table[] = { |
135 | { .compatible = "qcom,sdm845-lpasscc" }, |
136 | { } |
137 | }; |
138 | MODULE_DEVICE_TABLE(of, lpass_cc_sdm845_match_table); |
139 | |
140 | static struct platform_driver lpass_cc_sdm845_driver = { |
141 | .probe = lpass_cc_sdm845_probe, |
142 | .driver = { |
143 | .name = "sdm845-lpasscc" , |
144 | .of_match_table = lpass_cc_sdm845_match_table, |
145 | }, |
146 | }; |
147 | |
148 | static int __init lpass_cc_sdm845_init(void) |
149 | { |
150 | return platform_driver_register(&lpass_cc_sdm845_driver); |
151 | } |
152 | subsys_initcall(lpass_cc_sdm845_init); |
153 | |
154 | static void __exit lpass_cc_sdm845_exit(void) |
155 | { |
156 | platform_driver_unregister(&lpass_cc_sdm845_driver); |
157 | } |
158 | module_exit(lpass_cc_sdm845_exit); |
159 | |
160 | MODULE_DESCRIPTION("QTI LPASS_CC SDM845 Driver" ); |
161 | MODULE_LICENSE("GPL v2" ); |
162 | |