[PATCH 09/13] clk: qcom: common: Add support to register and control clocks using CRM

Jagadeesh Kona
2026-04-20T16:30:42Z

Add support for helper macros to maintain the list of CRM clocks in a
clock controller. Add support for qcom_cc_register_cesta_clks() which takes
this list of CRM clocks and update the ops of these clocks to CRM clock ops
only if CRM is enabled.

Co-developed-by: Taniya Das <taniya.das@oss.qualcomm.com>
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
Signed-off-by: Jagadeesh Kona <jagadeesh.kona@oss.qualcomm.com>
---
drivers/clk/qcom/common.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/qcom/common.h | 19 +++++++++++++++++
2 files changed, 73 insertions(+)

diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index 968e19997daf5eebec65315974cd0c41e08e55ec..14dfae80e567852d09a5972858ae14c62e5074ee 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -10,10 +10,13 @@
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/interconnect-clk.h>
+#include <linux/mfd/syscon.h>
#include <linux/pm_runtime.h>
#include <linux/reset-controller.h>
#include <linux/of.h>

+#include <soc/qcom/crm.h>
+
#include "common.h"
#include "clk-alpha-pll.h"
#include "clk-branch.h"
@@ -266,6 +269,47 @@ int qcom_cc_register_sleep_clk(struct device *dev)
}
EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);

+static void qcom_register_crm_clk(const struct crm_clk_data *data)
+{
+ struct clk_init_data *init = data->init;
+
+ switch (data->flags) {
+ case CRM_PLL:
+ init->ops = &clk_alpha_pll_crm_ops;
+ break;
+ case CRM_RCG_CRMB:
+ init->ops = &clk_rcg2_crmb_ops;
+ break;
+ default:
+ pr_err("Invalid CRM flag for %s\n", init->name);
+ break;
+ }
+}
+
+static int qcom_cc_register_crm_clks(struct device *dev, struct clk_crm *crm,
+ const struct crm_clk_data *clks, size_t len)
+{
+ int i;
+
+ crm->crm_dev = crm_get(dev);
+ if (IS_ERR(crm->crm_dev))
+ return PTR_ERR(crm->crm_dev);
+
+ if (crm->crm_dev && crm->max_perf_ol) {
+ crm->regmap_crmc = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "qcom,crmc-regmap");
+ if (IS_ERR(crm->regmap_crmc))
+ return PTR_ERR(crm->regmap_crmc);
+
+ for (i = 0; i < len; i++)
+ qcom_register_crm_clk(&clks[i]);
+
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
/* Drop 'protected-clocks' from the list of clocks to register */
static void qcom_cc_drop_protected(struct device *dev, struct qcom_cc *cc)
{
@@ -439,6 +483,16 @@ int qcom_cc_really_probe(struct device *dev,
goto put_rpm;
}

+ if (desc->driver_data &&
+ desc->driver_data->crm) {
+ ret = qcom_cc_register_crm_clks(dev, desc->driver_data->crm,
+ desc->driver_data->crm_clks,
+ desc->driver_data->num_crm_clks);
+ if (ret)
+ dev_err_probe(dev, ret,
+ "Failed to register clocks with CRM, ret: %d\n", ret);
+ }
+
cc->rclks = rclks;
cc->num_rclks = num_clks;

diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 9987cec84324a258f3405c7b9093237f52a41b45..d00376f058ce1de7aa82ff760f92826282b1606f 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -35,6 +35,9 @@ struct qcom_cc_driver_data {
size_t num_clk_cbcrs;
const struct clk_rcg_dfs_data *dfs_rcgs;
size_t num_dfs_rcgs;
+ struct clk_crm *crm;
+ const struct crm_clk_data *crm_clks;
+ size_t num_crm_clks;
void (*clk_regs_configure)(struct device *dev, struct regmap *regmap);
};

@@ -97,6 +100,22 @@ struct clk_crm {
u8 client_idx;
};

+struct crm_clk_data {
+ struct clk_init_data *init;
+#define CRM_PLL BIT(0)
+#define CRM_RCG_CRMB BIT(1)
+ u8 flags;
+};
+
+#define CRM_CLK(clk, flag) \
+{ \
+ .init = &clk##_init, \
+ .flags = flag, \
+}
+
+#define CRM_CLK_PLL(clk) CRM_CLK(clk, CRM_PLL)
+#define CRM_CLK_RCG_CRMB(clk) CRM_CLK(clk, CRM_RCG_CRMB)
+
extern int qcom_find_crm_freq_index(const struct freq_tbl *f, unsigned long rate);
extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
unsigned long rate);

--
2.34.1