0001
0002
0003
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
0404
0405
0406 regmap_update_bits(regmap, 0x24000, BIT(0), BIT(0));
0407
0408
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");