tools headers UAPI: Sync kvm.h headers with the kernel sources
[linux-2.6-microblaze.git] / drivers / clk / qcom / lpasscorecc-sc7180.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4  */
5
6 #include <linux/clk-provider.h>
7 #include <linux/err.h>
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/pm_clock.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/of.h>
13 #include <linux/regmap.h>
14
15 #include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
16
17 #include "clk-alpha-pll.h"
18 #include "clk-branch.h"
19 #include "clk-rcg.h"
20 #include "clk-regmap.h"
21 #include "common.h"
22 #include "gdsc.h"
23
24 enum {
25         P_BI_TCXO,
26         P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD,
27         P_SLEEP_CLK,
28 };
29
30 static struct pll_vco fabia_vco[] = {
31         { 249600000, 2000000000, 0 },
32 };
33
34 static const struct alpha_pll_config lpass_lpaaudio_dig_pll_config = {
35         .l = 0x20,
36         .alpha = 0x0,
37         .config_ctl_val = 0x20485699,
38         .config_ctl_hi_val = 0x00002067,
39         .test_ctl_val = 0x40000000,
40         .test_ctl_hi_val = 0x00000000,
41         .user_ctl_val = 0x00005105,
42         .user_ctl_hi_val = 0x00004805,
43 };
44
45 static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = {
46         [CLK_ALPHA_PLL_TYPE_FABIA] =  {
47                 [PLL_OFF_L_VAL] = 0x04,
48                 [PLL_OFF_CAL_L_VAL] = 0x8,
49                 [PLL_OFF_USER_CTL] = 0x0c,
50                 [PLL_OFF_USER_CTL_U] = 0x10,
51                 [PLL_OFF_USER_CTL_U1] = 0x14,
52                 [PLL_OFF_CONFIG_CTL] = 0x18,
53                 [PLL_OFF_CONFIG_CTL_U] = 0x1C,
54                 [PLL_OFF_CONFIG_CTL_U1] = 0x20,
55                 [PLL_OFF_TEST_CTL] = 0x24,
56                 [PLL_OFF_TEST_CTL_U] = 0x28,
57                 [PLL_OFF_STATUS] = 0x30,
58                 [PLL_OFF_OPMODE] = 0x38,
59                 [PLL_OFF_FRAC] = 0x40,
60         },
61 };
62
63 static struct clk_alpha_pll lpass_lpaaudio_dig_pll = {
64         .offset = 0x1000,
65         .vco_table = fabia_vco,
66         .num_vco = ARRAY_SIZE(fabia_vco),
67         .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_FABIA],
68         .clkr = {
69                 .hw.init = &(struct clk_init_data){
70                         .name = "lpass_lpaaudio_dig_pll",
71                         .parent_data = &(const struct clk_parent_data){
72                                 .fw_name = "bi_tcxo",
73                         },
74                         .num_parents = 1,
75                         .ops = &clk_alpha_pll_fabia_ops,
76                 },
77         },
78 };
79
80 static const struct clk_div_table
81                         post_div_table_lpass_lpaaudio_dig_pll_out_odd[] = {
82         { 0x5, 5 },
83         { }
84 };
85
86 static struct clk_alpha_pll_postdiv lpass_lpaaudio_dig_pll_out_odd = {
87         .offset = 0x1000,
88         .post_div_shift = 12,
89         .post_div_table = post_div_table_lpass_lpaaudio_dig_pll_out_odd,
90         .num_post_div =
91                 ARRAY_SIZE(post_div_table_lpass_lpaaudio_dig_pll_out_odd),
92         .width = 4,
93         .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
94         .clkr.hw.init = &(struct clk_init_data){
95                 .name = "lpass_lpaaudio_dig_pll_out_odd",
96                 .parent_data = &(const struct clk_parent_data){
97                         .hw = &lpass_lpaaudio_dig_pll.clkr.hw,
98                 },
99                 .num_parents = 1,
100                 .flags = CLK_SET_RATE_PARENT,
101                 .ops = &clk_alpha_pll_postdiv_fabia_ops,
102         },
103 };
104
105 static const struct parent_map lpass_core_cc_parent_map_0[] = {
106         { P_BI_TCXO, 0 },
107         { P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5 },
108 };
109
110 static const struct clk_parent_data lpass_core_cc_parent_data_0[] = {
111         { .fw_name = "bi_tcxo" },
112         { .hw = &lpass_lpaaudio_dig_pll_out_odd.clkr.hw },
113 };
114
115 static const struct parent_map lpass_core_cc_parent_map_2[] = {
116         { P_BI_TCXO, 0 },
117 };
118
119 static struct clk_rcg2 core_clk_src = {
120         .cmd_rcgr = 0x1d000,
121         .mnd_width = 8,
122         .hid_width = 5,
123         .parent_map = lpass_core_cc_parent_map_2,
124         .clkr.hw.init = &(struct clk_init_data){
125                 .name = "core_clk_src",
126                 .parent_data = &(const struct clk_parent_data){
127                         .fw_name = "bi_tcxo",
128                 },
129                 .num_parents = 1,
130                 .ops = &clk_rcg2_ops,
131         },
132 };
133
134 static const struct freq_tbl ftbl_ext_mclk0_clk_src[] = {
135         F(9600000, P_BI_TCXO, 2, 0, 0),
136         F(19200000, P_BI_TCXO, 1, 0, 0),
137         { }
138 };
139
140 static const struct freq_tbl ftbl_ext_lpaif_clk_src[] = {
141         F(256000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 32),
142         F(512000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 16),
143         F(768000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 16),
144         F(1024000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 8),
145         F(1536000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 8),
146         F(2048000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 4),
147         F(3072000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 4),
148         F(4096000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 2),
149         F(6144000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 2),
150         F(8192000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 0, 0),
151         F(9600000, P_BI_TCXO, 2, 0, 0),
152         F(12288000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 0, 0),
153         F(19200000, P_BI_TCXO, 1, 0, 0),
154         F(24576000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5, 0, 0),
155         { }
156 };
157
158 static struct clk_rcg2 ext_mclk0_clk_src = {
159         .cmd_rcgr = 0x20000,
160         .mnd_width = 8,
161         .hid_width = 5,
162         .parent_map = lpass_core_cc_parent_map_0,
163         .freq_tbl = ftbl_ext_mclk0_clk_src,
164         .clkr.hw.init = &(struct clk_init_data){
165                 .name = "ext_mclk0_clk_src",
166                 .parent_data = lpass_core_cc_parent_data_0,
167                 .num_parents = 2,
168                 .flags = CLK_SET_RATE_PARENT,
169                 .ops = &clk_rcg2_ops,
170         },
171 };
172
173 static struct clk_rcg2 lpaif_pri_clk_src = {
174         .cmd_rcgr = 0x10000,
175         .mnd_width = 16,
176         .hid_width = 5,
177         .parent_map = lpass_core_cc_parent_map_0,
178         .freq_tbl = ftbl_ext_lpaif_clk_src,
179         .clkr.hw.init = &(struct clk_init_data){
180                 .name = "lpaif_pri_clk_src",
181                 .parent_data = lpass_core_cc_parent_data_0,
182                 .num_parents = 2,
183                 .flags = CLK_SET_RATE_PARENT,
184                 .ops = &clk_rcg2_ops,
185         },
186 };
187
188 static struct clk_rcg2 lpaif_sec_clk_src = {
189         .cmd_rcgr = 0x11000,
190         .mnd_width = 16,
191         .hid_width = 5,
192         .parent_map = lpass_core_cc_parent_map_0,
193         .freq_tbl = ftbl_ext_lpaif_clk_src,
194         .clkr.hw.init = &(struct clk_init_data){
195                 .name = "lpaif_sec_clk_src",
196                 .parent_data = lpass_core_cc_parent_data_0,
197                 .num_parents = 2,
198                 .flags = CLK_SET_RATE_PARENT,
199                 .ops = &clk_rcg2_ops,
200         },
201 };
202
203 static struct clk_branch lpass_audio_core_ext_mclk0_clk = {
204         .halt_reg = 0x20014,
205         .halt_check = BRANCH_HALT,
206         .hwcg_reg = 0x20014,
207         .hwcg_bit = 1,
208         .clkr = {
209                 .enable_reg = 0x20014,
210                 .enable_mask = BIT(0),
211                 .hw.init = &(struct clk_init_data){
212                         .name = "lpass_audio_core_ext_mclk0_clk",
213                         .parent_data = &(const struct clk_parent_data){
214                                 .hw = &ext_mclk0_clk_src.clkr.hw,
215                         },
216                         .num_parents = 1,
217                         .flags = CLK_SET_RATE_PARENT,
218                         .ops = &clk_branch2_ops,
219                 },
220         },
221 };
222
223 static struct clk_branch lpass_audio_core_lpaif_pri_ibit_clk = {
224         .halt_reg = 0x10018,
225         .halt_check = BRANCH_HALT,
226         .hwcg_reg = 0x10018,
227         .hwcg_bit = 1,
228         .clkr = {
229                 .enable_reg = 0x10018,
230                 .enable_mask = BIT(0),
231                 .hw.init = &(struct clk_init_data){
232                         .name = "lpass_audio_core_lpaif_pri_ibit_clk",
233                         .parent_data = &(const struct clk_parent_data){
234                                 .hw = &lpaif_pri_clk_src.clkr.hw,
235                         },
236                         .num_parents = 1,
237                         .flags = CLK_SET_RATE_PARENT,
238                         .ops = &clk_branch2_ops,
239                 },
240         },
241 };
242
243 static struct clk_branch lpass_audio_core_lpaif_sec_ibit_clk = {
244         .halt_reg = 0x11018,
245         .halt_check = BRANCH_HALT,
246         .hwcg_reg = 0x11018,
247         .hwcg_bit = 1,
248         .clkr = {
249                 .enable_reg = 0x11018,
250                 .enable_mask = BIT(0),
251                 .hw.init = &(struct clk_init_data){
252                         .name = "lpass_audio_core_lpaif_sec_ibit_clk",
253                         .parent_data = &(const struct clk_parent_data){
254                                 .hw = &lpaif_sec_clk_src.clkr.hw,
255                         },
256                         .num_parents = 1,
257                         .flags = CLK_SET_RATE_PARENT,
258                         .ops = &clk_branch2_ops,
259                 },
260         },
261 };
262
263 static struct clk_branch lpass_audio_core_sysnoc_mport_core_clk = {
264         .halt_reg = 0x23000,
265         .halt_check = BRANCH_HALT,
266         .hwcg_reg = 0x23000,
267         .hwcg_bit = 1,
268         .clkr = {
269                 .enable_reg = 0x23000,
270                 .enable_mask = BIT(0),
271                 .hw.init = &(struct clk_init_data){
272                         .name = "lpass_audio_core_sysnoc_mport_core_clk",
273                         .parent_data = &(const struct clk_parent_data){
274                                 .hw = &core_clk_src.clkr.hw,
275                         },
276                         .num_parents = 1,
277                         .flags = CLK_SET_RATE_PARENT,
278                         .ops = &clk_branch2_ops,
279                 },
280         },
281 };
282
283 static struct clk_regmap *lpass_core_cc_sc7180_clocks[] = {
284         [EXT_MCLK0_CLK_SRC] = &ext_mclk0_clk_src.clkr,
285         [LPAIF_PRI_CLK_SRC] = &lpaif_pri_clk_src.clkr,
286         [LPAIF_SEC_CLK_SRC] = &lpaif_sec_clk_src.clkr,
287         [CORE_CLK_SRC] = &core_clk_src.clkr,
288         [LPASS_AUDIO_CORE_EXT_MCLK0_CLK] = &lpass_audio_core_ext_mclk0_clk.clkr,
289         [LPASS_AUDIO_CORE_LPAIF_PRI_IBIT_CLK] =
290                 &lpass_audio_core_lpaif_pri_ibit_clk.clkr,
291         [LPASS_AUDIO_CORE_LPAIF_SEC_IBIT_CLK] =
292                 &lpass_audio_core_lpaif_sec_ibit_clk.clkr,
293         [LPASS_AUDIO_CORE_SYSNOC_MPORT_CORE_CLK] =
294                 &lpass_audio_core_sysnoc_mport_core_clk.clkr,
295         [LPASS_LPAAUDIO_DIG_PLL] = &lpass_lpaaudio_dig_pll.clkr,
296         [LPASS_LPAAUDIO_DIG_PLL_OUT_ODD] = &lpass_lpaaudio_dig_pll_out_odd.clkr,
297 };
298
299 static struct gdsc lpass_pdc_hm_gdsc = {
300         .gdscr = 0x3090,
301         .pd = {
302                 .name = "lpass_pdc_hm_gdsc",
303         },
304         .pwrsts = PWRSTS_OFF_ON,
305         .flags = VOTABLE,
306 };
307
308 static struct gdsc lpass_audio_hm_gdsc = {
309         .gdscr = 0x9090,
310         .pd = {
311                 .name = "lpass_audio_hm_gdsc",
312         },
313         .pwrsts = PWRSTS_OFF_ON,
314 };
315
316 static struct gdsc lpass_core_hm_gdsc = {
317         .gdscr = 0x0,
318         .pd = {
319                 .name = "lpass_core_hm_gdsc",
320         },
321         .pwrsts = PWRSTS_OFF_ON,
322         .flags = RETAIN_FF_ENABLE,
323 };
324
325 static struct gdsc *lpass_core_hm_sc7180_gdscs[] = {
326         [LPASS_CORE_HM_GDSCR] = &lpass_core_hm_gdsc,
327 };
328
329 static struct gdsc *lpass_audio_hm_sc7180_gdscs[] = {
330         [LPASS_PDC_HM_GDSCR] = &lpass_pdc_hm_gdsc,
331         [LPASS_AUDIO_HM_GDSCR] = &lpass_audio_hm_gdsc,
332 };
333
334 static struct regmap_config lpass_core_cc_sc7180_regmap_config = {
335         .reg_bits = 32,
336         .reg_stride = 4,
337         .val_bits = 32,
338         .fast_io = true,
339 };
340
341 static const struct qcom_cc_desc lpass_core_hm_sc7180_desc = {
342         .config = &lpass_core_cc_sc7180_regmap_config,
343         .gdscs = lpass_core_hm_sc7180_gdscs,
344         .num_gdscs = ARRAY_SIZE(lpass_core_hm_sc7180_gdscs),
345 };
346
347 static const struct qcom_cc_desc lpass_core_cc_sc7180_desc = {
348         .config = &lpass_core_cc_sc7180_regmap_config,
349         .clks = lpass_core_cc_sc7180_clocks,
350         .num_clks = ARRAY_SIZE(lpass_core_cc_sc7180_clocks),
351 };
352
353 static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = {
354         .config = &lpass_core_cc_sc7180_regmap_config,
355         .gdscs = lpass_audio_hm_sc7180_gdscs,
356         .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs),
357 };
358
359 static void lpass_pm_runtime_disable(void *data)
360 {
361         pm_runtime_disable(data);
362 }
363
364 static void lpass_pm_clk_destroy(void *data)
365 {
366         pm_clk_destroy(data);
367 }
368
369 static int lpass_create_pm_clks(struct platform_device *pdev)
370 {
371         int ret;
372
373         pm_runtime_use_autosuspend(&pdev->dev);
374         pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
375         pm_runtime_enable(&pdev->dev);
376
377         ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev);
378         if (ret)
379                 return ret;
380
381         ret = pm_clk_create(&pdev->dev);
382         if (ret)
383                 return ret;
384         ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_clk_destroy, &pdev->dev);
385         if (ret)
386                 return ret;
387
388         ret = pm_clk_add(&pdev->dev, "iface");
389         if (ret < 0)
390                 dev_err(&pdev->dev, "failed to acquire iface clock\n");
391
392         return ret;
393 }
394
395 static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
396 {
397         const struct qcom_cc_desc *desc;
398         struct regmap *regmap;
399         int ret;
400
401         ret = lpass_create_pm_clks(pdev);
402         if (ret)
403                 return ret;
404
405         lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc";
406         desc = &lpass_audio_hm_sc7180_desc;
407         ret = qcom_cc_probe_by_index(pdev, 1, desc);
408         if (ret)
409                 return ret;
410
411         lpass_core_cc_sc7180_regmap_config.name = "lpass_core_cc";
412         regmap = qcom_cc_map(pdev, &lpass_core_cc_sc7180_desc);
413         if (IS_ERR(regmap))
414                 return PTR_ERR(regmap);
415
416         /*
417          * Keep the CLK always-ON
418          * LPASS_AUDIO_CORE_SYSNOC_SWAY_CORE_CLK
419          */
420         regmap_update_bits(regmap, 0x24000, BIT(0), BIT(0));
421
422         /* PLL settings */
423         regmap_write(regmap, 0x1008, 0x20);
424         regmap_update_bits(regmap, 0x1014, BIT(0), BIT(0));
425
426         clk_fabia_pll_configure(&lpass_lpaaudio_dig_pll, regmap,
427                                 &lpass_lpaaudio_dig_pll_config);
428
429         ret = qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
430
431         pm_runtime_mark_last_busy(&pdev->dev);
432         pm_runtime_put_autosuspend(&pdev->dev);
433
434         return ret;
435 }
436
437 static int lpass_hm_core_probe(struct platform_device *pdev)
438 {
439         const struct qcom_cc_desc *desc;
440         int ret;
441
442         ret = lpass_create_pm_clks(pdev);
443         if (ret)
444                 return ret;
445
446         lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core";
447         desc = &lpass_core_hm_sc7180_desc;
448
449         return qcom_cc_probe_by_index(pdev, 0, desc);
450 }
451
452 static const struct of_device_id lpass_hm_sc7180_match_table[] = {
453         {
454                 .compatible = "qcom,sc7180-lpasshm",
455         },
456         { }
457 };
458 MODULE_DEVICE_TABLE(of, lpass_hm_sc7180_match_table);
459
460 static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
461         {
462                 .compatible = "qcom,sc7180-lpasscorecc",
463         },
464         { }
465 };
466 MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table);
467
468 static const struct dev_pm_ops lpass_core_cc_pm_ops = {
469         SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
470 };
471
472 static struct platform_driver lpass_core_cc_sc7180_driver = {
473         .probe = lpass_core_cc_sc7180_probe,
474         .driver = {
475                 .name = "lpass_core_cc-sc7180",
476                 .of_match_table = lpass_core_cc_sc7180_match_table,
477                 .pm = &lpass_core_cc_pm_ops,
478         },
479 };
480
481 static const struct dev_pm_ops lpass_hm_pm_ops = {
482         SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
483 };
484
485 static struct platform_driver lpass_hm_sc7180_driver = {
486         .probe = lpass_hm_core_probe,
487         .driver = {
488                 .name = "lpass_hm-sc7180",
489                 .of_match_table = lpass_hm_sc7180_match_table,
490                 .pm = &lpass_hm_pm_ops,
491         },
492 };
493
494 static int __init lpass_sc7180_init(void)
495 {
496         int ret;
497
498         ret = platform_driver_register(&lpass_core_cc_sc7180_driver);
499         if (ret)
500                 return ret;
501
502         ret = platform_driver_register(&lpass_hm_sc7180_driver);
503         if (ret) {
504                 platform_driver_unregister(&lpass_core_cc_sc7180_driver);
505                 return ret;
506         }
507
508         return 0;
509 }
510 subsys_initcall(lpass_sc7180_init);
511
512 static void __exit lpass_sc7180_exit(void)
513 {
514         platform_driver_unregister(&lpass_hm_sc7180_driver);
515         platform_driver_unregister(&lpass_core_cc_sc7180_driver);
516 }
517 module_exit(lpass_sc7180_exit);
518
519 MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver");
520 MODULE_LICENSE("GPL v2");