xref: /linux/drivers/clk/qcom/lcc-ipq806x.c (revision 2ba9268dd603d23e17643437b2246acb6844953b)
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 		.of_match_table = lcc_ipq806x_match_table,
466 	},
467 };
468 module_platform_driver(lcc_ipq806x_driver);
469 
470 MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
471 MODULE_LICENSE("GPL v2");
472 MODULE_ALIAS("platform:lcc-ipq806x");
473