diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 9d2bbacf10fa..030d20079ab8 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -171,6 +171,7 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; extern const struct clk_ops clk_dp_ops; +extern const struct clk_ops clk_rcg2_dependent_ops; struct clk_rcg_dfs_data { struct clk_rcg2 *rcg; diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 7240039e4413..7230719324e4 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1411,3 +1411,102 @@ int qcom_cc_register_rcg_dfs(struct regmap *regmap, return 0; } EXPORT_SYMBOL_GPL(qcom_cc_register_rcg_dfs); + +static int clk_rcg2_dependent_enable(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int ret; + + ret = clk_rcg2_enable(hw); + if (ret < 0) + return ret; + + return clk_enable(rcg->clkr.dependent_hw->clk); +} + +static void clk_rcg2_dependent_disable(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + clk_rcg2_disable(hw); + clk_disable(rcg->clkr.dependent_hw->clk); +} + +static int clk_rcg2_dependent_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct clk_hw *p_hw; + int ret; + + ret = clk_rcg2_set_parent(hw, index); + if (ret < 0) + return ret; + + p_hw = clk_hw_get_parent_by_index(rcg->clkr.dependent_hw, index); + return clk_set_parent(rcg->clkr.dependent_hw->clk, p_hw->clk); +} + +static int clk_rcg2_dependent_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + __clk_determine_rate(rcg->clkr.dependent_hw, req); + + return clk_rcg2_determine_rate(hw, req); +} + +static int clk_rcg2_dependent_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + int ret; + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + ret = clk_rcg2_set_rate(hw, rate, parent_rate); + if (ret < 0) + return ret; + + return clk_set_rate(rcg->clkr.dependent_hw->clk, rate); +} + +static int clk_rcg2_dependent_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int ret; + + ret = clk_rcg2_set_rate_and_parent(hw, rate, parent_rate, index); + if (ret < 0) + return ret; + + return clk_set_rate(rcg->clkr.dependent_hw->clk, rate); +} + +static int clk_rcg2_dependent_prepare(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + return clk_prepare(rcg->clkr.dependent_hw->clk); +} + +static void clk_rcg2_dependent_unprepare(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + clk_unprepare(rcg->clkr.dependent_hw->clk); +} + +const struct clk_ops clk_rcg2_dependent_ops = { + .is_enabled = clk_rcg2_is_enabled, + .prepare = clk_rcg2_dependent_prepare, + .unprepare = clk_rcg2_dependent_unprepare, + .enable = clk_rcg2_dependent_enable, + .disable = clk_rcg2_dependent_disable, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_dependent_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .determine_rate = clk_rcg2_dependent_determine_rate, + .set_rate = clk_rcg2_dependent_set_rate, + .set_rate_and_parent = clk_rcg2_dependent_set_rate_and_parent, +}; +EXPORT_SYMBOL(clk_rcg2_dependent_ops); diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 6cfc1bccb255..790145847684 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2014, 2016-2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_REGMAP_H__ #define __QCOM_CLK_REGMAP_H__ @@ -11,6 +11,7 @@ struct regmap; /** * struct clk_regmap - regmap supporting clock * @hw: handle between common and hardware-specific interfaces + * @dependent_hw: dependent clocks clock hw * @regmap: regmap to use for regmap helpers and/or by providers * @enable_reg: register when using regmap enable/disable ops * @enable_mask: mask when using regmap enable/disable ops @@ -19,6 +20,7 @@ struct regmap; */ struct clk_regmap { struct clk_hw hw; + struct clk_hw *dependent_hw; struct regmap *regmap; unsigned int enable_reg; unsigned int enable_mask;