Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/err.h>
0008 #include <linux/module.h>
0009 #include <linux/of_device.h>
0010 #include <linux/pm_clock.h>
0011 #include <linux/pm_runtime.h>
0012 #include <linux/of.h>
0013 #include <linux/regmap.h>
0014 
0015 #include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
0016 
0017 #include "clk-alpha-pll.h"
0018 #include "clk-branch.h"
0019 #include "clk-rcg.h"
0020 #include "clk-regmap.h"
0021 #include "common.h"
0022 #include "gdsc.h"
0023 
0024 enum {
0025     P_BI_TCXO,
0026     P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD,
0027     P_SLEEP_CLK,
0028 };
0029 
0030 static struct pll_vco fabia_vco[] = {
0031     { 249600000, 2000000000, 0 },
0032 };
0033 
0034 static const struct alpha_pll_config lpass_lpaaudio_dig_pll_config = {
0035     .l = 0x20,
0036     .alpha = 0x0,
0037     .config_ctl_val = 0x20485699,
0038     .config_ctl_hi_val = 0x00002067,
0039     .test_ctl_val = 0x40000000,
0040     .test_ctl_hi_val = 0x00000000,
0041     .user_ctl_val = 0x00005105,
0042     .user_ctl_hi_val = 0x00004805,
0043 };
0044 
0045 static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = {
0046     [CLK_ALPHA_PLL_TYPE_FABIA] =  {
0047         [PLL_OFF_L_VAL] = 0x04,
0048         [PLL_OFF_CAL_L_VAL] = 0x8,
0049         [PLL_OFF_USER_CTL] = 0x0c,
0050         [PLL_OFF_USER_CTL_U] = 0x10,
0051         [PLL_OFF_USER_CTL_U1] = 0x14,
0052         [PLL_OFF_CONFIG_CTL] = 0x18,
0053         [PLL_OFF_CONFIG_CTL_U] = 0x1C,
0054         [PLL_OFF_CONFIG_CTL_U1] = 0x20,
0055         [PLL_OFF_TEST_CTL] = 0x24,
0056         [PLL_OFF_TEST_CTL_U] = 0x28,
0057         [PLL_OFF_STATUS] = 0x30,
0058         [PLL_OFF_OPMODE] = 0x38,
0059         [PLL_OFF_FRAC] = 0x40,
0060     },
0061 };
0062 
0063 static struct clk_alpha_pll lpass_lpaaudio_dig_pll = {
0064     .offset = 0x1000,
0065     .vco_table = fabia_vco,
0066     .num_vco = ARRAY_SIZE(fabia_vco),
0067     .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_FABIA],
0068     .clkr = {
0069         .hw.init = &(struct clk_init_data){
0070             .name = "lpass_lpaaudio_dig_pll",
0071             .parent_data = &(const struct clk_parent_data){
0072                 .fw_name = "bi_tcxo",
0073             },
0074             .num_parents = 1,
0075             .ops = &clk_alpha_pll_fabia_ops,
0076         },
0077     },
0078 };
0079 
0080 static const struct clk_div_table
0081             post_div_table_lpass_lpaaudio_dig_pll_out_odd[] = {
0082     { 0x5, 5 },
0083     { }
0084 };
0085 
0086 static struct clk_alpha_pll_postdiv lpass_lpaaudio_dig_pll_out_odd = {
0087     .offset = 0x1000,
0088     .post_div_shift = 12,
0089     .post_div_table = post_div_table_lpass_lpaaudio_dig_pll_out_odd,
0090     .num_post_div =
0091         ARRAY_SIZE(post_div_table_lpass_lpaaudio_dig_pll_out_odd),
0092     .width = 4,
0093     .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
0094     .clkr.hw.init = &(struct clk_init_data){
0095         .name = "lpass_lpaaudio_dig_pll_out_odd",
0096         .parent_data = &(const struct clk_parent_data){
0097             .hw = &lpass_lpaaudio_dig_pll.clkr.hw,
0098         },
0099         .num_parents = 1,
0100         .flags = CLK_SET_RATE_PARENT,
0101         .ops = &clk_alpha_pll_postdiv_fabia_ops,
0102     },
0103 };
0104 
0105 static const struct parent_map lpass_core_cc_parent_map_0[] = {
0106     { P_BI_TCXO, 0 },
0107     { P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5 },
0108 };
0109 
0110 static const struct clk_parent_data lpass_core_cc_parent_data_0[] = {
0111     { .fw_name = "bi_tcxo" },
0112     { .hw = &lpass_lpaaudio_dig_pll_out_odd.clkr.hw },
0113 };
0114 
0115 static const struct parent_map lpass_core_cc_parent_map_2[] = {
0116     { P_BI_TCXO, 0 },
0117 };
0118 
0119 static struct clk_rcg2 core_clk_src = {
0120     .cmd_rcgr = 0x1d000,
0121     .mnd_width = 8,
0122     .hid_width = 5,
0123     .parent_map = lpass_core_cc_parent_map_2,
0124     .clkr.hw.init = &(struct clk_init_data){
0125         .name = "core_clk_src",
0126         .parent_data = &(const struct clk_parent_data){
0127             .fw_name = "bi_tcxo",
0128         },
0129         .num_parents = 1,
0130         .ops = &clk_rcg2_ops,
0131     },
0132 };
0133 
0134 static const struct freq_tbl ftbl_ext_mclk0_clk_src[] = {
0135     F(9600000, P_BI_TCXO, 2, 0, 0),
0136     F(19200000, P_BI_TCXO, 1, 0, 0),
0137     { }
0138 };
0139 
0140 static const struct freq_tbl ftbl_ext_lpaif_clk_src[] = {
0141     F(256000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 32),
0142     F(512000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 16),
0143     F(768000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 16),
0144     F(1024000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 8),
0145     F(1536000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 8),
0146     F(2048000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 4),
0147     F(3072000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 4),
0148     F(4096000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 2),
0149     F(6144000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 2),
0150     F(8192000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 0, 0),
0151     F(9600000, P_BI_TCXO, 2, 0, 0),
0152     F(12288000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 0, 0),
0153     F(19200000, P_BI_TCXO, 1, 0, 0),
0154     F(24576000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5, 0, 0),
0155     { }
0156 };
0157 
0158 static struct clk_rcg2 ext_mclk0_clk_src = {
0159     .cmd_rcgr = 0x20000,
0160     .mnd_width = 8,
0161     .hid_width = 5,
0162     .parent_map = lpass_core_cc_parent_map_0,
0163     .freq_tbl = ftbl_ext_mclk0_clk_src,
0164     .clkr.hw.init = &(struct clk_init_data){
0165         .name = "ext_mclk0_clk_src",
0166         .parent_data = lpass_core_cc_parent_data_0,
0167         .num_parents = 2,
0168         .flags = CLK_SET_RATE_PARENT,
0169         .ops = &clk_rcg2_ops,
0170     },
0171 };
0172 
0173 static struct clk_rcg2 lpaif_pri_clk_src = {
0174     .cmd_rcgr = 0x10000,
0175     .mnd_width = 16,
0176     .hid_width = 5,
0177     .parent_map = lpass_core_cc_parent_map_0,
0178     .freq_tbl = ftbl_ext_lpaif_clk_src,
0179     .clkr.hw.init = &(struct clk_init_data){
0180         .name = "lpaif_pri_clk_src",
0181         .parent_data = lpass_core_cc_parent_data_0,
0182         .num_parents = 2,
0183         .flags = CLK_SET_RATE_PARENT,
0184         .ops = &clk_rcg2_ops,
0185     },
0186 };
0187 
0188 static struct clk_rcg2 lpaif_sec_clk_src = {
0189     .cmd_rcgr = 0x11000,
0190     .mnd_width = 16,
0191     .hid_width = 5,
0192     .parent_map = lpass_core_cc_parent_map_0,
0193     .freq_tbl = ftbl_ext_lpaif_clk_src,
0194     .clkr.hw.init = &(struct clk_init_data){
0195         .name = "lpaif_sec_clk_src",
0196         .parent_data = lpass_core_cc_parent_data_0,
0197         .num_parents = 2,
0198         .flags = CLK_SET_RATE_PARENT,
0199         .ops = &clk_rcg2_ops,
0200     },
0201 };
0202 
0203 static struct clk_branch lpass_audio_core_ext_mclk0_clk = {
0204     .halt_reg = 0x20014,
0205     .halt_check = BRANCH_HALT,
0206     .hwcg_reg = 0x20014,
0207     .hwcg_bit = 1,
0208     .clkr = {
0209         .enable_reg = 0x20014,
0210         .enable_mask = BIT(0),
0211         .hw.init = &(struct clk_init_data){
0212             .name = "lpass_audio_core_ext_mclk0_clk",
0213             .parent_data = &(const struct clk_parent_data){
0214                 .hw = &ext_mclk0_clk_src.clkr.hw,
0215             },
0216             .num_parents = 1,
0217             .flags = CLK_SET_RATE_PARENT,
0218             .ops = &clk_branch2_ops,
0219         },
0220     },
0221 };
0222 
0223 static struct clk_branch lpass_audio_core_lpaif_pri_ibit_clk = {
0224     .halt_reg = 0x10018,
0225     .halt_check = BRANCH_HALT,
0226     .hwcg_reg = 0x10018,
0227     .hwcg_bit = 1,
0228     .clkr = {
0229         .enable_reg = 0x10018,
0230         .enable_mask = BIT(0),
0231         .hw.init = &(struct clk_init_data){
0232             .name = "lpass_audio_core_lpaif_pri_ibit_clk",
0233             .parent_data = &(const struct clk_parent_data){
0234                 .hw = &lpaif_pri_clk_src.clkr.hw,
0235             },
0236             .num_parents = 1,
0237             .flags = CLK_SET_RATE_PARENT,
0238             .ops = &clk_branch2_ops,
0239         },
0240     },
0241 };
0242 
0243 static struct clk_branch lpass_audio_core_lpaif_sec_ibit_clk = {
0244     .halt_reg = 0x11018,
0245     .halt_check = BRANCH_HALT,
0246     .hwcg_reg = 0x11018,
0247     .hwcg_bit = 1,
0248     .clkr = {
0249         .enable_reg = 0x11018,
0250         .enable_mask = BIT(0),
0251         .hw.init = &(struct clk_init_data){
0252             .name = "lpass_audio_core_lpaif_sec_ibit_clk",
0253             .parent_data = &(const struct clk_parent_data){
0254                 .hw = &lpaif_sec_clk_src.clkr.hw,
0255             },
0256             .num_parents = 1,
0257             .flags = CLK_SET_RATE_PARENT,
0258             .ops = &clk_branch2_ops,
0259         },
0260     },
0261 };
0262 
0263 static struct clk_branch lpass_audio_core_sysnoc_mport_core_clk = {
0264     .halt_reg = 0x23000,
0265     .halt_check = BRANCH_HALT,
0266     .hwcg_reg = 0x23000,
0267     .hwcg_bit = 1,
0268     .clkr = {
0269         .enable_reg = 0x23000,
0270         .enable_mask = BIT(0),
0271         .hw.init = &(struct clk_init_data){
0272             .name = "lpass_audio_core_sysnoc_mport_core_clk",
0273             .parent_data = &(const struct clk_parent_data){
0274                 .hw = &core_clk_src.clkr.hw,
0275             },
0276             .num_parents = 1,
0277             .flags = CLK_SET_RATE_PARENT,
0278             .ops = &clk_branch2_ops,
0279         },
0280     },
0281 };
0282 
0283 static struct clk_regmap *lpass_core_cc_sc7180_clocks[] = {
0284     [EXT_MCLK0_CLK_SRC] = &ext_mclk0_clk_src.clkr,
0285     [LPAIF_PRI_CLK_SRC] = &lpaif_pri_clk_src.clkr,
0286     [LPAIF_SEC_CLK_SRC] = &lpaif_sec_clk_src.clkr,
0287     [CORE_CLK_SRC] = &core_clk_src.clkr,
0288     [LPASS_AUDIO_CORE_EXT_MCLK0_CLK] = &lpass_audio_core_ext_mclk0_clk.clkr,
0289     [LPASS_AUDIO_CORE_LPAIF_PRI_IBIT_CLK] =
0290         &lpass_audio_core_lpaif_pri_ibit_clk.clkr,
0291     [LPASS_AUDIO_CORE_LPAIF_SEC_IBIT_CLK] =
0292         &lpass_audio_core_lpaif_sec_ibit_clk.clkr,
0293     [LPASS_AUDIO_CORE_SYSNOC_MPORT_CORE_CLK] =
0294         &lpass_audio_core_sysnoc_mport_core_clk.clkr,
0295     [LPASS_LPAAUDIO_DIG_PLL] = &lpass_lpaaudio_dig_pll.clkr,
0296     [LPASS_LPAAUDIO_DIG_PLL_OUT_ODD] = &lpass_lpaaudio_dig_pll_out_odd.clkr,
0297 };
0298 
0299 static struct gdsc lpass_pdc_hm_gdsc = {
0300     .gdscr = 0x3090,
0301     .pd = {
0302         .name = "lpass_pdc_hm_gdsc",
0303     },
0304     .pwrsts = PWRSTS_OFF_ON,
0305     .flags = VOTABLE,
0306 };
0307 
0308 static struct gdsc lpass_audio_hm_gdsc = {
0309     .gdscr = 0x9090,
0310     .pd = {
0311         .name = "lpass_audio_hm_gdsc",
0312     },
0313     .pwrsts = PWRSTS_OFF_ON,
0314 };
0315 
0316 static struct gdsc lpass_core_hm_gdsc = {
0317     .gdscr = 0x0,
0318     .pd = {
0319         .name = "lpass_core_hm_gdsc",
0320     },
0321     .pwrsts = PWRSTS_OFF_ON,
0322     .flags = RETAIN_FF_ENABLE,
0323 };
0324 
0325 static struct gdsc *lpass_core_hm_sc7180_gdscs[] = {
0326     [LPASS_CORE_HM_GDSCR] = &lpass_core_hm_gdsc,
0327 };
0328 
0329 static struct gdsc *lpass_audio_hm_sc7180_gdscs[] = {
0330     [LPASS_PDC_HM_GDSCR] = &lpass_pdc_hm_gdsc,
0331     [LPASS_AUDIO_HM_GDSCR] = &lpass_audio_hm_gdsc,
0332 };
0333 
0334 static struct regmap_config lpass_core_cc_sc7180_regmap_config = {
0335     .reg_bits = 32,
0336     .reg_stride = 4,
0337     .val_bits = 32,
0338     .fast_io = true,
0339 };
0340 
0341 static const struct qcom_cc_desc lpass_core_hm_sc7180_desc = {
0342     .config = &lpass_core_cc_sc7180_regmap_config,
0343     .gdscs = lpass_core_hm_sc7180_gdscs,
0344     .num_gdscs = ARRAY_SIZE(lpass_core_hm_sc7180_gdscs),
0345 };
0346 
0347 static const struct qcom_cc_desc lpass_core_cc_sc7180_desc = {
0348     .config = &lpass_core_cc_sc7180_regmap_config,
0349     .clks = lpass_core_cc_sc7180_clocks,
0350     .num_clks = ARRAY_SIZE(lpass_core_cc_sc7180_clocks),
0351 };
0352 
0353 static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = {
0354     .config = &lpass_core_cc_sc7180_regmap_config,
0355     .gdscs = lpass_audio_hm_sc7180_gdscs,
0356     .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs),
0357 };
0358 
0359 static int lpass_create_pm_clks(struct platform_device *pdev)
0360 {
0361     int ret;
0362 
0363     pm_runtime_use_autosuspend(&pdev->dev);
0364     pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
0365 
0366     ret = devm_pm_runtime_enable(&pdev->dev);
0367     if (ret)
0368         return ret;
0369 
0370     ret = devm_pm_clk_create(&pdev->dev);
0371     if (ret)
0372         return ret;
0373 
0374     ret = pm_clk_add(&pdev->dev, "iface");
0375     if (ret < 0)
0376         dev_err(&pdev->dev, "failed to acquire iface clock\n");
0377 
0378     return ret;
0379 }
0380 
0381 static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
0382 {
0383     const struct qcom_cc_desc *desc;
0384     struct regmap *regmap;
0385     int ret;
0386 
0387     ret = lpass_create_pm_clks(pdev);
0388     if (ret)
0389         return ret;
0390 
0391     lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc";
0392     desc = &lpass_audio_hm_sc7180_desc;
0393     ret = qcom_cc_probe_by_index(pdev, 1, desc);
0394     if (ret)
0395         return ret;
0396 
0397     lpass_core_cc_sc7180_regmap_config.name = "lpass_core_cc";
0398     regmap = qcom_cc_map(pdev, &lpass_core_cc_sc7180_desc);
0399     if (IS_ERR(regmap))
0400         return PTR_ERR(regmap);
0401 
0402     /*
0403      * Keep the CLK always-ON
0404      * LPASS_AUDIO_CORE_SYSNOC_SWAY_CORE_CLK
0405      */
0406     regmap_update_bits(regmap, 0x24000, BIT(0), BIT(0));
0407 
0408     /* PLL settings */
0409     regmap_write(regmap, 0x1008, 0x20);
0410     regmap_update_bits(regmap, 0x1014, BIT(0), BIT(0));
0411 
0412     clk_fabia_pll_configure(&lpass_lpaaudio_dig_pll, regmap,
0413                 &lpass_lpaaudio_dig_pll_config);
0414 
0415     ret = qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
0416 
0417     pm_runtime_mark_last_busy(&pdev->dev);
0418     pm_runtime_put_autosuspend(&pdev->dev);
0419 
0420     return ret;
0421 }
0422 
0423 static int lpass_hm_core_probe(struct platform_device *pdev)
0424 {
0425     const struct qcom_cc_desc *desc;
0426     int ret;
0427 
0428     ret = lpass_create_pm_clks(pdev);
0429     if (ret)
0430         return ret;
0431 
0432     lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core";
0433     desc = &lpass_core_hm_sc7180_desc;
0434 
0435     return qcom_cc_probe_by_index(pdev, 0, desc);
0436 }
0437 
0438 static const struct of_device_id lpass_hm_sc7180_match_table[] = {
0439     {
0440         .compatible = "qcom,sc7180-lpasshm",
0441     },
0442     { }
0443 };
0444 MODULE_DEVICE_TABLE(of, lpass_hm_sc7180_match_table);
0445 
0446 static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
0447     {
0448         .compatible = "qcom,sc7180-lpasscorecc",
0449     },
0450     { }
0451 };
0452 MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table);
0453 
0454 static const struct dev_pm_ops lpass_core_cc_pm_ops = {
0455     SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
0456 };
0457 
0458 static struct platform_driver lpass_core_cc_sc7180_driver = {
0459     .probe = lpass_core_cc_sc7180_probe,
0460     .driver = {
0461         .name = "lpass_core_cc-sc7180",
0462         .of_match_table = lpass_core_cc_sc7180_match_table,
0463         .pm = &lpass_core_cc_pm_ops,
0464     },
0465 };
0466 
0467 static const struct dev_pm_ops lpass_hm_pm_ops = {
0468     SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
0469 };
0470 
0471 static struct platform_driver lpass_hm_sc7180_driver = {
0472     .probe = lpass_hm_core_probe,
0473     .driver = {
0474         .name = "lpass_hm-sc7180",
0475         .of_match_table = lpass_hm_sc7180_match_table,
0476         .pm = &lpass_hm_pm_ops,
0477     },
0478 };
0479 
0480 static int __init lpass_sc7180_init(void)
0481 {
0482     int ret;
0483 
0484     ret = platform_driver_register(&lpass_core_cc_sc7180_driver);
0485     if (ret)
0486         return ret;
0487 
0488     ret = platform_driver_register(&lpass_hm_sc7180_driver);
0489     if (ret) {
0490         platform_driver_unregister(&lpass_core_cc_sc7180_driver);
0491         return ret;
0492     }
0493 
0494     return 0;
0495 }
0496 subsys_initcall(lpass_sc7180_init);
0497 
0498 static void __exit lpass_sc7180_exit(void)
0499 {
0500     platform_driver_unregister(&lpass_hm_sc7180_driver);
0501     platform_driver_unregister(&lpass_core_cc_sc7180_driver);
0502 }
0503 module_exit(lpass_sc7180_exit);
0504 
0505 MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver");
0506 MODULE_LICENSE("GPL v2");