0001
0002
0003
0004
0005
0006 #include <linux/clk-provider.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/pm_clock.h>
0009 #include <linux/pm_runtime.h>
0010 #include <linux/module.h>
0011 #include <linux/of_address.h>
0012 #include <linux/regmap.h>
0013
0014 #include <dt-bindings/clock/qcom,lpass-sc7280.h>
0015
0016 #include "clk-regmap.h"
0017 #include "clk-branch.h"
0018 #include "common.h"
0019
0020 static struct clk_branch lpass_q6ss_ahbm_clk = {
0021 .halt_reg = 0x1c,
0022 .halt_check = BRANCH_HALT,
0023 .clkr = {
0024 .enable_reg = 0x1c,
0025 .enable_mask = BIT(0),
0026 .hw.init = &(struct clk_init_data){
0027 .name = "lpass_q6ss_ahbm_clk",
0028 .ops = &clk_branch2_ops,
0029 },
0030 },
0031 };
0032
0033 static struct clk_branch lpass_q6ss_ahbs_clk = {
0034 .halt_reg = 0x20,
0035 .halt_check = BRANCH_HALT_VOTED,
0036 .clkr = {
0037 .enable_reg = 0x20,
0038 .enable_mask = BIT(0),
0039 .hw.init = &(struct clk_init_data){
0040 .name = "lpass_q6ss_ahbs_clk",
0041 .ops = &clk_branch2_ops,
0042 },
0043 },
0044 };
0045
0046 static struct clk_branch lpass_top_cc_lpi_q6_axim_hs_clk = {
0047 .halt_reg = 0x0,
0048 .halt_check = BRANCH_HALT,
0049 .clkr = {
0050 .enable_reg = 0x0,
0051 .enable_mask = BIT(0),
0052 .hw.init = &(struct clk_init_data){
0053 .name = "lpass_top_cc_lpi_q6_axim_hs_clk",
0054 .ops = &clk_branch2_ops,
0055 },
0056 },
0057 };
0058
0059 static struct clk_branch lpass_qdsp6ss_core_clk = {
0060 .halt_reg = 0x20,
0061
0062 .halt_check = BRANCH_HALT_SKIP,
0063 .clkr = {
0064 .enable_reg = 0x20,
0065 .enable_mask = BIT(0),
0066 .hw.init = &(struct clk_init_data){
0067 .name = "lpass_qdsp6ss_core_clk",
0068 .ops = &clk_branch2_ops,
0069 },
0070 },
0071 };
0072
0073 static struct clk_branch lpass_qdsp6ss_xo_clk = {
0074 .halt_reg = 0x38,
0075
0076 .halt_check = BRANCH_HALT_SKIP,
0077 .clkr = {
0078 .enable_reg = 0x38,
0079 .enable_mask = BIT(0),
0080 .hw.init = &(struct clk_init_data){
0081 .name = "lpass_qdsp6ss_xo_clk",
0082 .ops = &clk_branch2_ops,
0083 },
0084 },
0085 };
0086
0087 static struct clk_branch lpass_qdsp6ss_sleep_clk = {
0088 .halt_reg = 0x3c,
0089
0090 .halt_check = BRANCH_HALT_SKIP,
0091 .clkr = {
0092 .enable_reg = 0x3c,
0093 .enable_mask = BIT(0),
0094 .hw.init = &(struct clk_init_data){
0095 .name = "lpass_qdsp6ss_sleep_clk",
0096 .ops = &clk_branch2_ops,
0097 },
0098 },
0099 };
0100
0101 static struct regmap_config lpass_regmap_config = {
0102 .reg_bits = 32,
0103 .reg_stride = 4,
0104 .val_bits = 32,
0105 .fast_io = true,
0106 };
0107
0108 static struct clk_regmap *lpass_cc_sc7280_clocks[] = {
0109 [LPASS_Q6SS_AHBM_CLK] = &lpass_q6ss_ahbm_clk.clkr,
0110 [LPASS_Q6SS_AHBS_CLK] = &lpass_q6ss_ahbs_clk.clkr,
0111 };
0112
0113 static const struct qcom_cc_desc lpass_cc_sc7280_desc = {
0114 .config = &lpass_regmap_config,
0115 .clks = lpass_cc_sc7280_clocks,
0116 .num_clks = ARRAY_SIZE(lpass_cc_sc7280_clocks),
0117 };
0118
0119 static struct clk_regmap *lpass_cc_top_sc7280_clocks[] = {
0120 [LPASS_TOP_CC_LPI_Q6_AXIM_HS_CLK] =
0121 &lpass_top_cc_lpi_q6_axim_hs_clk.clkr,
0122 };
0123
0124 static const struct qcom_cc_desc lpass_cc_top_sc7280_desc = {
0125 .config = &lpass_regmap_config,
0126 .clks = lpass_cc_top_sc7280_clocks,
0127 .num_clks = ARRAY_SIZE(lpass_cc_top_sc7280_clocks),
0128 };
0129
0130 static struct clk_regmap *lpass_qdsp6ss_sc7280_clocks[] = {
0131 [LPASS_QDSP6SS_XO_CLK] = &lpass_qdsp6ss_xo_clk.clkr,
0132 [LPASS_QDSP6SS_SLEEP_CLK] = &lpass_qdsp6ss_sleep_clk.clkr,
0133 [LPASS_QDSP6SS_CORE_CLK] = &lpass_qdsp6ss_core_clk.clkr,
0134 };
0135
0136 static const struct qcom_cc_desc lpass_qdsp6ss_sc7280_desc = {
0137 .config = &lpass_regmap_config,
0138 .clks = lpass_qdsp6ss_sc7280_clocks,
0139 .num_clks = ARRAY_SIZE(lpass_qdsp6ss_sc7280_clocks),
0140 };
0141
0142 static int lpass_cc_sc7280_probe(struct platform_device *pdev)
0143 {
0144 const struct qcom_cc_desc *desc;
0145 int ret;
0146
0147 pm_runtime_enable(&pdev->dev);
0148 ret = pm_clk_create(&pdev->dev);
0149 if (ret)
0150 goto disable_pm_runtime;
0151
0152 ret = pm_clk_add(&pdev->dev, "iface");
0153 if (ret < 0) {
0154 dev_err(&pdev->dev, "failed to acquire iface clock\n");
0155 goto destroy_pm_clk;
0156 }
0157
0158 lpass_regmap_config.name = "qdsp6ss";
0159 desc = &lpass_qdsp6ss_sc7280_desc;
0160
0161 ret = qcom_cc_probe_by_index(pdev, 0, desc);
0162 if (ret)
0163 goto destroy_pm_clk;
0164
0165 lpass_regmap_config.name = "top_cc";
0166 desc = &lpass_cc_top_sc7280_desc;
0167
0168 ret = qcom_cc_probe_by_index(pdev, 1, desc);
0169 if (ret)
0170 goto destroy_pm_clk;
0171
0172 lpass_regmap_config.name = "cc";
0173 desc = &lpass_cc_sc7280_desc;
0174
0175 ret = qcom_cc_probe_by_index(pdev, 2, desc);
0176 if (ret)
0177 goto destroy_pm_clk;
0178
0179 return 0;
0180
0181 destroy_pm_clk:
0182 pm_clk_destroy(&pdev->dev);
0183
0184 disable_pm_runtime:
0185 pm_runtime_disable(&pdev->dev);
0186
0187 return ret;
0188 }
0189
0190 static const struct of_device_id lpass_cc_sc7280_match_table[] = {
0191 { .compatible = "qcom,sc7280-lpasscc" },
0192 { }
0193 };
0194 MODULE_DEVICE_TABLE(of, lpass_cc_sc7280_match_table);
0195
0196 static struct platform_driver lpass_cc_sc7280_driver = {
0197 .probe = lpass_cc_sc7280_probe,
0198 .driver = {
0199 .name = "sc7280-lpasscc",
0200 .of_match_table = lpass_cc_sc7280_match_table,
0201 },
0202 };
0203
0204 static int __init lpass_cc_sc7280_init(void)
0205 {
0206 return platform_driver_register(&lpass_cc_sc7280_driver);
0207 }
0208 subsys_initcall(lpass_cc_sc7280_init);
0209
0210 static void __exit lpass_cc_sc7280_exit(void)
0211 {
0212 platform_driver_unregister(&lpass_cc_sc7280_driver);
0213 }
0214 module_exit(lpass_cc_sc7280_exit);
0215
0216 MODULE_DESCRIPTION("QTI LPASS_CC SC7280 Driver");
0217 MODULE_LICENSE("GPL v2");