From 9530c87bec5365aeca290e95ecaddaa61c90d09b Mon Sep 17 00:00:00 2001 From: Vivek Aknurwar Date: Fri, 24 Apr 2020 17:57:11 -0700 Subject: [PATCH] clk: qcom: Add support to proxy vote until clk controllers sync states Clock consumers gets deferred due to their dependencies during device boot/probes, and can not put essential vdd vote before clock late init clk_disable_unused() un-votes them. This behavior breaks functionality of keeping clocks/feature continuously enabled from boot to HLOS. Putting proxy vdd votes will ensure that votes are hold till consumer sync states and it gives chance to consumers act on necessary votes when it's ready. Also clock controller can not rely on consumers to vote vdd votes during boot/probe sequence in all paths of clk provided consumed APIs. Putting proxy votes makes sure that clk driver can access it's provided register access. Change-Id: I79301ff354b3ab53cc7c05db5e1dc75223228de6 Signed-off-by: Vivek Aknurwar --- drivers/clk/qcom/common.c | 6 ++++++ drivers/clk/qcom/vdd-class.c | 38 ++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/vdd-class.h | 2 ++ 3 files changed, 46 insertions(+) diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 0f17e4189986..19da2567eca6 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -272,6 +272,10 @@ int qcom_cc_really_probe(struct platform_device *pdev, if (ret) return ret; + ret = clk_vdd_proxy_vote(&pdev->dev, desc); + if (ret) + return ret; + if (desc->num_resets) { ret = devm_reset_controller_register(dev, &reset->rcdev); if (ret) @@ -363,6 +367,8 @@ void qcom_cc_sync_state(struct device *dev, const struct qcom_cc_desc *desc) { dev_info(dev, "sync-state\n"); clk_sync_state(dev); + + clk_vdd_proxy_unvote(dev, desc); } EXPORT_SYMBOL(qcom_cc_sync_state); diff --git a/drivers/clk/qcom/vdd-class.c b/drivers/clk/qcom/vdd-class.c index a8e0cd18eb99..602715b05ad7 100644 --- a/drivers/clk/qcom/vdd-class.c +++ b/drivers/clk/qcom/vdd-class.c @@ -200,3 +200,41 @@ int clk_regulator_init(struct device *dev, const struct qcom_cc_desc *desc) return 0; } +int clk_vdd_proxy_vote(struct device *dev, const struct qcom_cc_desc *desc) +{ + struct clk_vdd_class_data vdd_data; + struct clk_vdd_class *vdd_class; + u32 i; + int ret = 0; + + for (i = 0; i < desc->num_clk_regulators; i++) { + vdd_data.vdd_class = vdd_class = desc->clk_regulators[i]; + + ret = clk_vote_vdd_level(&vdd_data, + vdd_class->num_levels - 1); + if (ret) + WARN(ret, "%s failed, ret=%d\n", __func__, ret); + } + + return ret; +} + +int clk_vdd_proxy_unvote(struct device *dev, const struct qcom_cc_desc *desc) +{ + struct clk_vdd_class_data vdd_data; + struct clk_vdd_class *vdd_class; + u32 i; + int ret = 0; + + for (i = 0; i < desc->num_clk_regulators; i++) { + vdd_data.vdd_class = vdd_class = desc->clk_regulators[i]; + + ret = clk_unvote_vdd_level(&vdd_data, + vdd_class->num_levels - 1); + if (ret) + WARN(ret, "clk_unvote_vdd_level failed ret=%d\n", ret); + } + + return ret; +} + diff --git a/drivers/clk/qcom/vdd-class.h b/drivers/clk/qcom/vdd-class.h index 126aae47f728..f50ebe0a0e9d 100644 --- a/drivers/clk/qcom/vdd-class.h +++ b/drivers/clk/qcom/vdd-class.h @@ -71,4 +71,6 @@ int clk_find_vdd_level(struct clk_hw *hw, struct clk_vdd_class_data *vdd_data, int clk_vote_vdd_level(struct clk_vdd_class_data *vdd_class, int level); int clk_unvote_vdd_level(struct clk_vdd_class_data *vdd_class, int level); int clk_regulator_init(struct device *dev, const struct qcom_cc_desc *desc); +int clk_vdd_proxy_vote(struct device *dev, const struct qcom_cc_desc *desc); +int clk_vdd_proxy_unvote(struct device *dev, const struct qcom_cc_desc *desc); #endif