diff options
-rw-r--r-- | drivers/clk/qcom/Kconfig | 9 | ||||
-rw-r--r-- | drivers/clk/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-ipq806x.c | 12 | ||||
-rw-r--r-- | drivers/clk/qcom/lcc-ipq806x.c | 473 |
4 files changed, 495 insertions, 0 deletions
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 1107351ed346..07bce5f35eee 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig | |||
@@ -29,6 +29,15 @@ config IPQ_GCC_806X | |||
29 | Say Y if you want to use peripheral devices such as UART, SPI, | 29 | Say Y if you want to use peripheral devices such as UART, SPI, |
30 | i2c, USB, SD/eMMC, etc. | 30 | i2c, USB, SD/eMMC, etc. |
31 | 31 | ||
32 | config IPQ_LCC_806X | ||
33 | tristate "IPQ806x LPASS Clock Controller" | ||
34 | select IPQ_GCC_806X | ||
35 | depends on COMMON_CLK_QCOM | ||
36 | help | ||
37 | Support for the LPASS clock controller on ipq806x devices. | ||
38 | Say Y if you want to use audio devices such as i2s, pcm, | ||
39 | S/PDIF, etc. | ||
40 | |||
32 | config MSM_GCC_8660 | 41 | config MSM_GCC_8660 |
33 | tristate "MSM8660 Global Clock Controller" | 42 | tristate "MSM8660 Global Clock Controller" |
34 | depends on COMMON_CLK_QCOM | 43 | depends on COMMON_CLK_QCOM |
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index f5e5607f3965..13c03a8808ec 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile | |||
@@ -13,6 +13,7 @@ clk-qcom-y += reset.o | |||
13 | obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o | 13 | obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o |
14 | obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o | 14 | obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o |
15 | obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o | 15 | obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o |
16 | obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o | ||
16 | obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o | 17 | obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o |
17 | obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o | 18 | obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o |
18 | obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o | 19 | obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o |
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index afed5eb0691e..cbdc31dea7f4 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c | |||
@@ -75,6 +75,17 @@ static struct clk_pll pll3 = { | |||
75 | }, | 75 | }, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | static struct clk_regmap pll4_vote = { | ||
79 | .enable_reg = 0x34c0, | ||
80 | .enable_mask = BIT(4), | ||
81 | .hw.init = &(struct clk_init_data){ | ||
82 | .name = "pll4_vote", | ||
83 | .parent_names = (const char *[]){ "pll4" }, | ||
84 | .num_parents = 1, | ||
85 | .ops = &clk_pll_vote_ops, | ||
86 | }, | ||
87 | }; | ||
88 | |||
78 | static struct clk_pll pll8 = { | 89 | static struct clk_pll pll8 = { |
79 | .l_reg = 0x3144, | 90 | .l_reg = 0x3144, |
80 | .m_reg = 0x3148, | 91 | .m_reg = 0x3148, |
@@ -2163,6 +2174,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { | |||
2163 | [PLL0] = &pll0.clkr, | 2174 | [PLL0] = &pll0.clkr, |
2164 | [PLL0_VOTE] = &pll0_vote, | 2175 | [PLL0_VOTE] = &pll0_vote, |
2165 | [PLL3] = &pll3.clkr, | 2176 | [PLL3] = &pll3.clkr, |
2177 | [PLL4_VOTE] = &pll4_vote, | ||
2166 | [PLL8] = &pll8.clkr, | 2178 | [PLL8] = &pll8.clkr, |
2167 | [PLL8_VOTE] = &pll8_vote, | 2179 | [PLL8_VOTE] = &pll8_vote, |
2168 | [PLL14] = &pll14.clkr, | 2180 | [PLL14] = &pll14.clkr, |
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c new file mode 100644 index 000000000000..121ffde25dc3 --- /dev/null +++ b/drivers/clk/qcom/lcc-ipq806x.c | |||
@@ -0,0 +1,473 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/bitops.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/clk-provider.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | #include <dt-bindings/clock/qcom,lcc-ipq806x.h> | ||
25 | |||
26 | #include "common.h" | ||
27 | #include "clk-regmap.h" | ||
28 | #include "clk-pll.h" | ||
29 | #include "clk-rcg.h" | ||
30 | #include "clk-branch.h" | ||
31 | #include "clk-regmap-divider.h" | ||
32 | #include "clk-regmap-mux.h" | ||
33 | |||
34 | static struct clk_pll pll4 = { | ||
35 | .l_reg = 0x4, | ||
36 | .m_reg = 0x8, | ||
37 | .n_reg = 0xc, | ||
38 | .config_reg = 0x14, | ||
39 | .mode_reg = 0x0, | ||
40 | .status_reg = 0x18, | ||
41 | .status_bit = 16, | ||
42 | .clkr.hw.init = &(struct clk_init_data){ | ||
43 | .name = "pll4", | ||
44 | .parent_names = (const char *[]){ "pxo" }, | ||
45 | .num_parents = 1, | ||
46 | .ops = &clk_pll_ops, | ||
47 | }, | ||
48 | }; | ||
49 | |||
50 | static const struct pll_config pll4_config = { | ||
51 | .l = 0xf, | ||
52 | .m = 0x91, | ||
53 | .n = 0xc7, | ||
54 | .vco_val = 0x0, | ||
55 | .vco_mask = BIT(17) | BIT(16), | ||
56 | .pre_div_val = 0x0, | ||
57 | .pre_div_mask = BIT(19), | ||
58 | .post_div_val = 0x0, | ||
59 | .post_div_mask = BIT(21) | BIT(20), | ||
60 | .mn_ena_mask = BIT(22), | ||
61 | .main_output_mask = BIT(23), | ||
62 | }; | ||
63 | |||
64 | #define P_PXO 0 | ||
65 | #define P_PLL4 1 | ||
66 | |||
67 | static const u8 lcc_pxo_pll4_map[] = { | ||
68 | [P_PXO] = 0, | ||
69 | [P_PLL4] = 2, | ||
70 | }; | ||
71 | |||
72 | static const char *lcc_pxo_pll4[] = { | ||
73 | "pxo", | ||
74 | "pll4_vote", | ||
75 | }; | ||
76 | |||
77 | static struct freq_tbl clk_tbl_aif_mi2s[] = { | ||
78 | { 1024000, P_PLL4, 4, 1, 96 }, | ||
79 | { 1411200, P_PLL4, 4, 2, 139 }, | ||
80 | { 1536000, P_PLL4, 4, 1, 64 }, | ||
81 | { 2048000, P_PLL4, 4, 1, 48 }, | ||
82 | { 2116800, P_PLL4, 4, 2, 93 }, | ||
83 | { 2304000, P_PLL4, 4, 2, 85 }, | ||
84 | { 2822400, P_PLL4, 4, 6, 209 }, | ||
85 | { 3072000, P_PLL4, 4, 1, 32 }, | ||
86 | { 3175200, P_PLL4, 4, 1, 31 }, | ||
87 | { 4096000, P_PLL4, 4, 1, 24 }, | ||
88 | { 4233600, P_PLL4, 4, 9, 209 }, | ||
89 | { 4608000, P_PLL4, 4, 3, 64 }, | ||
90 | { 5644800, P_PLL4, 4, 12, 209 }, | ||
91 | { 6144000, P_PLL4, 4, 1, 16 }, | ||
92 | { 6350400, P_PLL4, 4, 2, 31 }, | ||
93 | { 8192000, P_PLL4, 4, 1, 12 }, | ||
94 | { 8467200, P_PLL4, 4, 18, 209 }, | ||
95 | { 9216000, P_PLL4, 4, 3, 32 }, | ||
96 | { 11289600, P_PLL4, 4, 24, 209 }, | ||
97 | { 12288000, P_PLL4, 4, 1, 8 }, | ||
98 | { 12700800, P_PLL4, 4, 27, 209 }, | ||
99 | { 13824000, P_PLL4, 4, 9, 64 }, | ||
100 | { 16384000, P_PLL4, 4, 1, 6 }, | ||
101 | { 16934400, P_PLL4, 4, 41, 238 }, | ||
102 | { 18432000, P_PLL4, 4, 3, 16 }, | ||
103 | { 22579200, P_PLL4, 2, 24, 209 }, | ||
104 | { 24576000, P_PLL4, 4, 1, 4 }, | ||
105 | { 27648000, P_PLL4, 4, 9, 32 }, | ||
106 | { 33868800, P_PLL4, 4, 41, 119 }, | ||
107 | { 36864000, P_PLL4, 4, 3, 8 }, | ||
108 | { 45158400, P_PLL4, 1, 24, 209 }, | ||
109 | { 49152000, P_PLL4, 4, 1, 2 }, | ||
110 | { 50803200, P_PLL4, 1, 27, 209 }, | ||
111 | { } | ||
112 | }; | ||
113 | |||
114 | static struct clk_rcg mi2s_osr_src = { | ||
115 | .ns_reg = 0x48, | ||
116 | .md_reg = 0x4c, | ||
117 | .mn = { | ||
118 | .mnctr_en_bit = 8, | ||
119 | .mnctr_reset_bit = 7, | ||
120 | .mnctr_mode_shift = 5, | ||
121 | .n_val_shift = 24, | ||
122 | .m_val_shift = 8, | ||
123 | .width = 8, | ||
124 | }, | ||
125 | .p = { | ||
126 | .pre_div_shift = 3, | ||
127 | .pre_div_width = 2, | ||
128 | }, | ||
129 | .s = { | ||
130 | .src_sel_shift = 0, | ||
131 | .parent_map = lcc_pxo_pll4_map, | ||
132 | }, | ||
133 | .freq_tbl = clk_tbl_aif_mi2s, | ||
134 | .clkr = { | ||
135 | .enable_reg = 0x48, | ||
136 | .enable_mask = BIT(9), | ||
137 | .hw.init = &(struct clk_init_data){ | ||
138 | .name = "mi2s_osr_src", | ||
139 | .parent_names = lcc_pxo_pll4, | ||
140 | .num_parents = 2, | ||
141 | .ops = &clk_rcg_ops, | ||
142 | .flags = CLK_SET_RATE_GATE, | ||
143 | }, | ||
144 | }, | ||
145 | }; | ||
146 | |||
147 | static const char *lcc_mi2s_parents[] = { | ||
148 | "mi2s_osr_src", | ||
149 | }; | ||
150 | |||
151 | static struct clk_branch mi2s_osr_clk = { | ||
152 | .halt_reg = 0x50, | ||
153 | .halt_bit = 1, | ||
154 | .halt_check = BRANCH_HALT_ENABLE, | ||
155 | .clkr = { | ||
156 | .enable_reg = 0x48, | ||
157 | .enable_mask = BIT(17), | ||
158 | .hw.init = &(struct clk_init_data){ | ||
159 | .name = "mi2s_osr_clk", | ||
160 | .parent_names = lcc_mi2s_parents, | ||
161 | .num_parents = 1, | ||
162 | .ops = &clk_branch_ops, | ||
163 | .flags = CLK_SET_RATE_PARENT, | ||
164 | }, | ||
165 | }, | ||
166 | }; | ||
167 | |||
168 | static struct clk_regmap_div mi2s_div_clk = { | ||
169 | .reg = 0x48, | ||
170 | .shift = 10, | ||
171 | .width = 4, | ||
172 | .clkr = { | ||
173 | .hw.init = &(struct clk_init_data){ | ||
174 | .name = "mi2s_div_clk", | ||
175 | .parent_names = lcc_mi2s_parents, | ||
176 | .num_parents = 1, | ||
177 | .ops = &clk_regmap_div_ops, | ||
178 | }, | ||
179 | }, | ||
180 | }; | ||
181 | |||
182 | static struct clk_branch mi2s_bit_div_clk = { | ||
183 | .halt_reg = 0x50, | ||
184 | .halt_bit = 0, | ||
185 | .halt_check = BRANCH_HALT_ENABLE, | ||
186 | .clkr = { | ||
187 | .enable_reg = 0x48, | ||
188 | .enable_mask = BIT(15), | ||
189 | .hw.init = &(struct clk_init_data){ | ||
190 | .name = "mi2s_bit_div_clk", | ||
191 | .parent_names = (const char *[]){ "mi2s_div_clk" }, | ||
192 | .num_parents = 1, | ||
193 | .ops = &clk_branch_ops, | ||
194 | .flags = CLK_SET_RATE_PARENT, | ||
195 | }, | ||
196 | }, | ||
197 | }; | ||
198 | |||
199 | |||
200 | static struct clk_regmap_mux mi2s_bit_clk = { | ||
201 | .reg = 0x48, | ||
202 | .shift = 14, | ||
203 | .width = 1, | ||
204 | .clkr = { | ||
205 | .hw.init = &(struct clk_init_data){ | ||
206 | .name = "mi2s_bit_clk", | ||
207 | .parent_names = (const char *[]){ | ||
208 | "mi2s_bit_div_clk", | ||
209 | "mi2s_codec_clk", | ||
210 | }, | ||
211 | .num_parents = 2, | ||
212 | .ops = &clk_regmap_mux_closest_ops, | ||
213 | .flags = CLK_SET_RATE_PARENT, | ||
214 | }, | ||
215 | }, | ||
216 | }; | ||
217 | |||
218 | static struct freq_tbl clk_tbl_pcm[] = { | ||
219 | { 64000, P_PLL4, 4, 1, 1536 }, | ||
220 | { 128000, P_PLL4, 4, 1, 768 }, | ||
221 | { 256000, P_PLL4, 4, 1, 384 }, | ||
222 | { 512000, P_PLL4, 4, 1, 192 }, | ||
223 | { 1024000, P_PLL4, 4, 1, 96 }, | ||
224 | { 2048000, P_PLL4, 4, 1, 48 }, | ||
225 | { }, | ||
226 | }; | ||
227 | |||
228 | static struct clk_rcg pcm_src = { | ||
229 | .ns_reg = 0x54, | ||
230 | .md_reg = 0x58, | ||
231 | .mn = { | ||
232 | .mnctr_en_bit = 8, | ||
233 | .mnctr_reset_bit = 7, | ||
234 | .mnctr_mode_shift = 5, | ||
235 | .n_val_shift = 16, | ||
236 | .m_val_shift = 16, | ||
237 | .width = 16, | ||
238 | }, | ||
239 | .p = { | ||
240 | .pre_div_shift = 3, | ||
241 | .pre_div_width = 2, | ||
242 | }, | ||
243 | .s = { | ||
244 | .src_sel_shift = 0, | ||
245 | .parent_map = lcc_pxo_pll4_map, | ||
246 | }, | ||
247 | .freq_tbl = clk_tbl_pcm, | ||
248 | .clkr = { | ||
249 | .enable_reg = 0x54, | ||
250 | .enable_mask = BIT(9), | ||
251 | .hw.init = &(struct clk_init_data){ | ||
252 | .name = "pcm_src", | ||
253 | .parent_names = lcc_pxo_pll4, | ||
254 | .num_parents = 2, | ||
255 | .ops = &clk_rcg_ops, | ||
256 | .flags = CLK_SET_RATE_GATE, | ||
257 | }, | ||
258 | }, | ||
259 | }; | ||
260 | |||
261 | static struct clk_branch pcm_clk_out = { | ||
262 | .halt_reg = 0x5c, | ||
263 | .halt_bit = 0, | ||
264 | .halt_check = BRANCH_HALT_ENABLE, | ||
265 | .clkr = { | ||
266 | .enable_reg = 0x54, | ||
267 | .enable_mask = BIT(11), | ||
268 | .hw.init = &(struct clk_init_data){ | ||
269 | .name = "pcm_clk_out", | ||
270 | .parent_names = (const char *[]){ "pcm_src" }, | ||
271 | .num_parents = 1, | ||
272 | .ops = &clk_branch_ops, | ||
273 | .flags = CLK_SET_RATE_PARENT, | ||
274 | }, | ||
275 | }, | ||
276 | }; | ||
277 | |||
278 | static struct clk_regmap_mux pcm_clk = { | ||
279 | .reg = 0x54, | ||
280 | .shift = 10, | ||
281 | .width = 1, | ||
282 | .clkr = { | ||
283 | .hw.init = &(struct clk_init_data){ | ||
284 | .name = "pcm_clk", | ||
285 | .parent_names = (const char *[]){ | ||
286 | "pcm_clk_out", | ||
287 | "pcm_codec_clk", | ||
288 | }, | ||
289 | .num_parents = 2, | ||
290 | .ops = &clk_regmap_mux_closest_ops, | ||
291 | .flags = CLK_SET_RATE_PARENT, | ||
292 | }, | ||
293 | }, | ||
294 | }; | ||
295 | |||
296 | static struct freq_tbl clk_tbl_aif_osr[] = { | ||
297 | { 22050, P_PLL4, 1, 147, 20480 }, | ||
298 | { 32000, P_PLL4, 1, 1, 96 }, | ||
299 | { 44100, P_PLL4, 1, 147, 10240 }, | ||
300 | { 48000, P_PLL4, 1, 1, 64 }, | ||
301 | { 88200, P_PLL4, 1, 147, 5120 }, | ||
302 | { 96000, P_PLL4, 1, 1, 32 }, | ||
303 | { 176400, P_PLL4, 1, 147, 2560 }, | ||
304 | { 192000, P_PLL4, 1, 1, 16 }, | ||
305 | { }, | ||
306 | }; | ||
307 | |||
308 | static struct clk_rcg spdif_src = { | ||
309 | .ns_reg = 0xcc, | ||
310 | .md_reg = 0xd0, | ||
311 | .mn = { | ||
312 | .mnctr_en_bit = 8, | ||
313 | .mnctr_reset_bit = 7, | ||
314 | .mnctr_mode_shift = 5, | ||
315 | .n_val_shift = 16, | ||
316 | .m_val_shift = 16, | ||
317 | .width = 8, | ||
318 | }, | ||
319 | .p = { | ||
320 | .pre_div_shift = 3, | ||
321 | .pre_div_width = 2, | ||
322 | }, | ||
323 | .s = { | ||
324 | .src_sel_shift = 0, | ||
325 | .parent_map = lcc_pxo_pll4_map, | ||
326 | }, | ||
327 | .freq_tbl = clk_tbl_aif_osr, | ||
328 | .clkr = { | ||
329 | .enable_reg = 0xcc, | ||
330 | .enable_mask = BIT(9), | ||
331 | .hw.init = &(struct clk_init_data){ | ||
332 | .name = "spdif_src", | ||
333 | .parent_names = lcc_pxo_pll4, | ||
334 | .num_parents = 2, | ||
335 | .ops = &clk_rcg_ops, | ||
336 | .flags = CLK_SET_RATE_GATE, | ||
337 | }, | ||
338 | }, | ||
339 | }; | ||
340 | |||
341 | static const char *lcc_spdif_parents[] = { | ||
342 | "spdif_src", | ||
343 | }; | ||
344 | |||
345 | static struct clk_branch spdif_clk = { | ||
346 | .halt_reg = 0xd4, | ||
347 | .halt_bit = 1, | ||
348 | .halt_check = BRANCH_HALT_ENABLE, | ||
349 | .clkr = { | ||
350 | .enable_reg = 0xcc, | ||
351 | .enable_mask = BIT(12), | ||
352 | .hw.init = &(struct clk_init_data){ | ||
353 | .name = "spdif_clk", | ||
354 | .parent_names = lcc_spdif_parents, | ||
355 | .num_parents = 1, | ||
356 | .ops = &clk_branch_ops, | ||
357 | .flags = CLK_SET_RATE_PARENT, | ||
358 | }, | ||
359 | }, | ||
360 | }; | ||
361 | |||
362 | static struct freq_tbl clk_tbl_ahbix[] = { | ||
363 | { 131072, P_PLL4, 1, 1, 3 }, | ||
364 | { }, | ||
365 | }; | ||
366 | |||
367 | static struct clk_rcg ahbix_clk = { | ||
368 | .ns_reg = 0x38, | ||
369 | .md_reg = 0x3c, | ||
370 | .mn = { | ||
371 | .mnctr_en_bit = 8, | ||
372 | .mnctr_reset_bit = 7, | ||
373 | .mnctr_mode_shift = 5, | ||
374 | .n_val_shift = 24, | ||
375 | .m_val_shift = 8, | ||
376 | .width = 8, | ||
377 | }, | ||
378 | .p = { | ||
379 | .pre_div_shift = 3, | ||
380 | .pre_div_width = 2, | ||
381 | }, | ||
382 | .s = { | ||
383 | .src_sel_shift = 0, | ||
384 | .parent_map = lcc_pxo_pll4_map, | ||
385 | }, | ||
386 | .freq_tbl = clk_tbl_ahbix, | ||
387 | .clkr = { | ||
388 | .enable_reg = 0x38, | ||
389 | .enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */ | ||
390 | .hw.init = &(struct clk_init_data){ | ||
391 | .name = "ahbix", | ||
392 | .parent_names = lcc_pxo_pll4, | ||
393 | .num_parents = 2, | ||
394 | .ops = &clk_rcg_ops, | ||
395 | .flags = CLK_SET_RATE_GATE, | ||
396 | }, | ||
397 | }, | ||
398 | }; | ||
399 | |||
400 | static struct clk_regmap *lcc_ipq806x_clks[] = { | ||
401 | [PLL4] = &pll4.clkr, | ||
402 | [MI2S_OSR_SRC] = &mi2s_osr_src.clkr, | ||
403 | [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr, | ||
404 | [MI2S_DIV_CLK] = &mi2s_div_clk.clkr, | ||
405 | [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr, | ||
406 | [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr, | ||
407 | [PCM_SRC] = &pcm_src.clkr, | ||
408 | [PCM_CLK_OUT] = &pcm_clk_out.clkr, | ||
409 | [PCM_CLK] = &pcm_clk.clkr, | ||
410 | [SPDIF_SRC] = &spdif_src.clkr, | ||
411 | [SPDIF_CLK] = &spdif_clk.clkr, | ||
412 | [AHBIX_CLK] = &ahbix_clk.clkr, | ||
413 | }; | ||
414 | |||
415 | static const struct regmap_config lcc_ipq806x_regmap_config = { | ||
416 | .reg_bits = 32, | ||
417 | .reg_stride = 4, | ||
418 | .val_bits = 32, | ||
419 | .max_register = 0xfc, | ||
420 | .fast_io = true, | ||
421 | }; | ||
422 | |||
423 | static const struct qcom_cc_desc lcc_ipq806x_desc = { | ||
424 | .config = &lcc_ipq806x_regmap_config, | ||
425 | .clks = lcc_ipq806x_clks, | ||
426 | .num_clks = ARRAY_SIZE(lcc_ipq806x_clks), | ||
427 | }; | ||
428 | |||
429 | static const struct of_device_id lcc_ipq806x_match_table[] = { | ||
430 | { .compatible = "qcom,lcc-ipq8064" }, | ||
431 | { } | ||
432 | }; | ||
433 | MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table); | ||
434 | |||
435 | static int lcc_ipq806x_probe(struct platform_device *pdev) | ||
436 | { | ||
437 | u32 val; | ||
438 | struct regmap *regmap; | ||
439 | |||
440 | regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc); | ||
441 | if (IS_ERR(regmap)) | ||
442 | return PTR_ERR(regmap); | ||
443 | |||
444 | /* Configure the rate of PLL4 if the bootloader hasn't already */ | ||
445 | val = regmap_read(regmap, 0x0, &val); | ||
446 | if (!val) | ||
447 | clk_pll_configure_sr(&pll4, regmap, &pll4_config, true); | ||
448 | /* Enable PLL4 source on the LPASS Primary PLL Mux */ | ||
449 | regmap_write(regmap, 0xc4, 0x1); | ||
450 | |||
451 | return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap); | ||
452 | } | ||
453 | |||
454 | static int lcc_ipq806x_remove(struct platform_device *pdev) | ||
455 | { | ||
456 | qcom_cc_remove(pdev); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static struct platform_driver lcc_ipq806x_driver = { | ||
461 | .probe = lcc_ipq806x_probe, | ||
462 | .remove = lcc_ipq806x_remove, | ||
463 | .driver = { | ||
464 | .name = "lcc-ipq806x", | ||
465 | .owner = THIS_MODULE, | ||
466 | .of_match_table = lcc_ipq806x_match_table, | ||
467 | }, | ||
468 | }; | ||
469 | module_platform_driver(lcc_ipq806x_driver); | ||
470 | |||
471 | MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver"); | ||
472 | MODULE_LICENSE("GPL v2"); | ||
473 | MODULE_ALIAS("platform:lcc-ipq806x"); | ||