GNU Linux-libre 6.1.24-gnu
[releases.git] / drivers / clk / qcom / lcc-ipq806x.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/bitops.h>
8 #include <linux/err.h>
9 #include <linux/platform_device.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <linux/clk-provider.h>
14 #include <linux/regmap.h>
15
16 #include <dt-bindings/clock/qcom,lcc-ipq806x.h>
17
18 #include "common.h"
19 #include "clk-regmap.h"
20 #include "clk-pll.h"
21 #include "clk-rcg.h"
22 #include "clk-branch.h"
23 #include "clk-regmap-divider.h"
24 #include "clk-regmap-mux.h"
25 #include "reset.h"
26
27 static struct clk_pll pll4 = {
28         .l_reg = 0x4,
29         .m_reg = 0x8,
30         .n_reg = 0xc,
31         .config_reg = 0x14,
32         .mode_reg = 0x0,
33         .status_reg = 0x18,
34         .status_bit = 16,
35         .clkr.hw.init = &(struct clk_init_data){
36                 .name = "pll4",
37                 .parent_data = &(const struct clk_parent_data) {
38                         .fw_name = "pxo", .name = "pxo_board",
39                 },
40                 .num_parents = 1,
41                 .ops = &clk_pll_ops,
42         },
43 };
44
45 static const struct pll_config pll4_config = {
46         .l = 0xf,
47         .m = 0x91,
48         .n = 0xc7,
49         .vco_val = 0x0,
50         .vco_mask = BIT(17) | BIT(16),
51         .pre_div_val = 0x0,
52         .pre_div_mask = BIT(19),
53         .post_div_val = 0x0,
54         .post_div_mask = BIT(21) | BIT(20),
55         .mn_ena_mask = BIT(22),
56         .main_output_mask = BIT(23),
57 };
58
59 enum {
60         P_PXO,
61         P_PLL4,
62 };
63
64 static const struct parent_map lcc_pxo_pll4_map[] = {
65         { P_PXO, 0 },
66         { P_PLL4, 2 }
67 };
68
69 static const struct clk_parent_data lcc_pxo_pll4[] = {
70         { .fw_name = "pxo", .name = "pxo_board" },
71         { .fw_name = "pll4_vote", .name = "pll4_vote" },
72 };
73
74 static struct freq_tbl clk_tbl_aif_mi2s[] = {
75         {  1024000, P_PLL4, 4,  1,  96 },
76         {  1411200, P_PLL4, 4,  2, 139 },
77         {  1536000, P_PLL4, 4,  1,  64 },
78         {  2048000, P_PLL4, 4,  1,  48 },
79         {  2116800, P_PLL4, 4,  2,  93 },
80         {  2304000, P_PLL4, 4,  2,  85 },
81         {  2822400, P_PLL4, 4,  6, 209 },
82         {  3072000, P_PLL4, 4,  1,  32 },
83         {  3175200, P_PLL4, 4,  1,  31 },
84         {  4096000, P_PLL4, 4,  1,  24 },
85         {  4233600, P_PLL4, 4,  9, 209 },
86         {  4608000, P_PLL4, 4,  3,  64 },
87         {  5644800, P_PLL4, 4, 12, 209 },
88         {  6144000, P_PLL4, 4,  1,  16 },
89         {  6350400, P_PLL4, 4,  2,  31 },
90         {  8192000, P_PLL4, 4,  1,  12 },
91         {  8467200, P_PLL4, 4, 18, 209 },
92         {  9216000, P_PLL4, 4,  3,  32 },
93         { 11289600, P_PLL4, 4, 24, 209 },
94         { 12288000, P_PLL4, 4,  1,   8 },
95         { 12700800, P_PLL4, 4, 27, 209 },
96         { 13824000, P_PLL4, 4,  9,  64 },
97         { 16384000, P_PLL4, 4,  1,   6 },
98         { 16934400, P_PLL4, 4, 41, 238 },
99         { 18432000, P_PLL4, 4,  3,  16 },
100         { 22579200, P_PLL4, 2, 24, 209 },
101         { 24576000, P_PLL4, 4,  1,   4 },
102         { 27648000, P_PLL4, 4,  9,  32 },
103         { 33868800, P_PLL4, 4, 41, 119 },
104         { 36864000, P_PLL4, 4,  3,   8 },
105         { 45158400, P_PLL4, 1, 24, 209 },
106         { 49152000, P_PLL4, 4,  1,   2 },
107         { 50803200, P_PLL4, 1, 27, 209 },
108         { }
109 };
110
111 static struct clk_rcg mi2s_osr_src = {
112         .ns_reg = 0x48,
113         .md_reg = 0x4c,
114         .mn = {
115                 .mnctr_en_bit = 8,
116                 .mnctr_reset_bit = 7,
117                 .mnctr_mode_shift = 5,
118                 .n_val_shift = 24,
119                 .m_val_shift = 8,
120                 .width = 8,
121         },
122         .p = {
123                 .pre_div_shift = 3,
124                 .pre_div_width = 2,
125         },
126         .s = {
127                 .src_sel_shift = 0,
128                 .parent_map = lcc_pxo_pll4_map,
129         },
130         .freq_tbl = clk_tbl_aif_mi2s,
131         .clkr = {
132                 .enable_reg = 0x48,
133                 .enable_mask = BIT(9),
134                 .hw.init = &(struct clk_init_data){
135                         .name = "mi2s_osr_src",
136                         .parent_data = lcc_pxo_pll4,
137                         .num_parents = ARRAY_SIZE(lcc_pxo_pll4),
138                         .ops = &clk_rcg_ops,
139                         .flags = CLK_SET_RATE_GATE,
140                 },
141         },
142 };
143
144 static struct clk_branch mi2s_osr_clk = {
145         .halt_reg = 0x50,
146         .halt_bit = 1,
147         .halt_check = BRANCH_HALT_ENABLE,
148         .clkr = {
149                 .enable_reg = 0x48,
150                 .enable_mask = BIT(17),
151                 .hw.init = &(struct clk_init_data){
152                         .name = "mi2s_osr_clk",
153                         .parent_hws = (const struct clk_hw*[]) {
154                                 &mi2s_osr_src.clkr.hw,
155                         },
156                         .num_parents = 1,
157                         .ops = &clk_branch_ops,
158                         .flags = CLK_SET_RATE_PARENT,
159                 },
160         },
161 };
162
163 static struct clk_regmap_div mi2s_div_clk = {
164         .reg = 0x48,
165         .shift = 10,
166         .width = 4,
167         .clkr = {
168                 .hw.init = &(struct clk_init_data){
169                         .name = "mi2s_div_clk",
170                         .parent_hws = (const struct clk_hw*[]) {
171                                 &mi2s_osr_src.clkr.hw,
172                         },
173                         .num_parents = 1,
174                         .ops = &clk_regmap_div_ops,
175                 },
176         },
177 };
178
179 static struct clk_branch mi2s_bit_div_clk = {
180         .halt_reg = 0x50,
181         .halt_bit = 0,
182         .halt_check = BRANCH_HALT_ENABLE,
183         .clkr = {
184                 .enable_reg = 0x48,
185                 .enable_mask = BIT(15),
186                 .hw.init = &(struct clk_init_data){
187                         .name = "mi2s_bit_div_clk",
188                         .parent_hws = (const struct clk_hw*[]) {
189                                 &mi2s_div_clk.clkr.hw,
190                         },
191                         .num_parents = 1,
192                         .ops = &clk_branch_ops,
193                         .flags = CLK_SET_RATE_PARENT,
194                 },
195         },
196 };
197
198 static const struct clk_parent_data lcc_mi2s_bit_div_codec_clk[] = {
199         { .hw = &mi2s_bit_div_clk.clkr.hw, },
200         { .fw_name = "mi2s_codec", .name = "mi2s_codec_clk" },
201 };
202
203 static struct clk_regmap_mux mi2s_bit_clk = {
204         .reg = 0x48,
205         .shift = 14,
206         .width = 1,
207         .clkr = {
208                 .hw.init = &(struct clk_init_data){
209                         .name = "mi2s_bit_clk",
210                         .parent_data = lcc_mi2s_bit_div_codec_clk,
211                         .num_parents = ARRAY_SIZE(lcc_mi2s_bit_div_codec_clk),
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_data = lcc_pxo_pll4,
254                         .num_parents = ARRAY_SIZE(lcc_pxo_pll4),
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_hws = (const struct clk_hw*[]) {
271                                 &pcm_src.clkr.hw,
272                         },
273                         .num_parents = 1,
274                         .ops = &clk_branch_ops,
275                         .flags = CLK_SET_RATE_PARENT,
276                 },
277         },
278 };
279
280 static const struct clk_parent_data lcc_pcm_clk_out_codec_clk[] = {
281         { .hw = &pcm_clk_out.clkr.hw, },
282         { .fw_name = "pcm_codec_clk", .name = "pcm_codec_clk" },
283 };
284
285 static struct clk_regmap_mux pcm_clk = {
286         .reg = 0x54,
287         .shift = 10,
288         .width = 1,
289         .clkr = {
290                 .hw.init = &(struct clk_init_data){
291                         .name = "pcm_clk",
292                         .parent_data = lcc_pcm_clk_out_codec_clk,
293                         .num_parents = ARRAY_SIZE(lcc_pcm_clk_out_codec_clk),
294                         .ops = &clk_regmap_mux_closest_ops,
295                         .flags = CLK_SET_RATE_PARENT,
296                 },
297         },
298 };
299
300 static struct freq_tbl clk_tbl_aif_osr[] = {
301         {  2822400, P_PLL4, 1, 147, 20480 },
302         {  4096000, P_PLL4, 1,   1,    96 },
303         {  5644800, P_PLL4, 1, 147, 10240 },
304         {  6144000, P_PLL4, 1,   1,    64 },
305         { 11289600, P_PLL4, 1, 147,  5120 },
306         { 12288000, P_PLL4, 1,   1,    32 },
307         { 22579200, P_PLL4, 1, 147,  2560 },
308         { 24576000, P_PLL4, 1,   1,    16 },
309         { },
310 };
311
312 static struct clk_rcg spdif_src = {
313         .ns_reg = 0xcc,
314         .md_reg = 0xd0,
315         .mn = {
316                 .mnctr_en_bit = 8,
317                 .mnctr_reset_bit = 7,
318                 .mnctr_mode_shift = 5,
319                 .n_val_shift = 16,
320                 .m_val_shift = 16,
321                 .width = 8,
322         },
323         .p = {
324                 .pre_div_shift = 3,
325                 .pre_div_width = 2,
326         },
327         .s = {
328                 .src_sel_shift = 0,
329                 .parent_map = lcc_pxo_pll4_map,
330         },
331         .freq_tbl = clk_tbl_aif_osr,
332         .clkr = {
333                 .enable_reg = 0xcc,
334                 .enable_mask = BIT(9),
335                 .hw.init = &(struct clk_init_data){
336                         .name = "spdif_src",
337                         .parent_data = lcc_pxo_pll4,
338                         .num_parents = ARRAY_SIZE(lcc_pxo_pll4),
339                         .ops = &clk_rcg_ops,
340                         .flags = CLK_SET_RATE_GATE,
341                 },
342         },
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_hws = (const struct clk_hw*[]) {
355                                 &spdif_src.clkr.hw,
356                         },
357                         .num_parents = 1,
358                         .ops = &clk_branch_ops,
359                         .flags = CLK_SET_RATE_PARENT,
360                 },
361         },
362 };
363
364 static struct freq_tbl clk_tbl_ahbix[] = {
365         { 131072000, P_PLL4, 1, 1, 3 },
366         { },
367 };
368
369 static struct clk_rcg ahbix_clk = {
370         .ns_reg = 0x38,
371         .md_reg = 0x3c,
372         .mn = {
373                 .mnctr_en_bit = 8,
374                 .mnctr_reset_bit = 7,
375                 .mnctr_mode_shift = 5,
376                 .n_val_shift = 24,
377                 .m_val_shift = 8,
378                 .width = 8,
379         },
380         .p = {
381                 .pre_div_shift = 3,
382                 .pre_div_width = 2,
383         },
384         .s = {
385                 .src_sel_shift = 0,
386                 .parent_map = lcc_pxo_pll4_map,
387         },
388         .freq_tbl = clk_tbl_ahbix,
389         .clkr = {
390                 .enable_reg = 0x38,
391                 .enable_mask = BIT(11),
392                 .hw.init = &(struct clk_init_data){
393                         .name = "ahbix",
394                         .parent_data = lcc_pxo_pll4,
395                         .num_parents = ARRAY_SIZE(lcc_pxo_pll4),
396                         .ops = &clk_rcg_lcc_ops,
397                 },
398         },
399 };
400
401 static struct clk_regmap *lcc_ipq806x_clks[] = {
402         [PLL4] = &pll4.clkr,
403         [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
404         [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
405         [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
406         [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
407         [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
408         [PCM_SRC] = &pcm_src.clkr,
409         [PCM_CLK_OUT] = &pcm_clk_out.clkr,
410         [PCM_CLK] = &pcm_clk.clkr,
411         [SPDIF_SRC] = &spdif_src.clkr,
412         [SPDIF_CLK] = &spdif_clk.clkr,
413         [AHBIX_CLK] = &ahbix_clk.clkr,
414 };
415
416 static const struct qcom_reset_map lcc_ipq806x_resets[] = {
417         [LCC_PCM_RESET] = { 0x54, 13 },
418 };
419
420 static const struct regmap_config lcc_ipq806x_regmap_config = {
421         .reg_bits       = 32,
422         .reg_stride     = 4,
423         .val_bits       = 32,
424         .max_register   = 0xfc,
425         .fast_io        = true,
426 };
427
428 static const struct qcom_cc_desc lcc_ipq806x_desc = {
429         .config = &lcc_ipq806x_regmap_config,
430         .clks = lcc_ipq806x_clks,
431         .num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
432         .resets = lcc_ipq806x_resets,
433         .num_resets = ARRAY_SIZE(lcc_ipq806x_resets),
434 };
435
436 static const struct of_device_id lcc_ipq806x_match_table[] = {
437         { .compatible = "qcom,lcc-ipq8064" },
438         { }
439 };
440 MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
441
442 static int lcc_ipq806x_probe(struct platform_device *pdev)
443 {
444         u32 val;
445         struct regmap *regmap;
446
447         regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
448         if (IS_ERR(regmap))
449                 return PTR_ERR(regmap);
450
451         /* Configure the rate of PLL4 if the bootloader hasn't already */
452         regmap_read(regmap, 0x0, &val);
453         if (!val)
454                 clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
455         /* Enable PLL4 source on the LPASS Primary PLL Mux */
456         regmap_write(regmap, 0xc4, 0x1);
457
458         return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
459 }
460
461 static struct platform_driver lcc_ipq806x_driver = {
462         .probe          = lcc_ipq806x_probe,
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");