Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d0a5805 authored by Deepak Katragadda's avatar Deepak Katragadda
Browse files

clk: qcom: clk-rcg2: Add support to force enable an RCG



In certain cases, it is desirable for an RCG to be turned on
explicitly instead of just relying on the enable signal from
its branch clock(s). Add support for this.

Change-Id: I2b0b81bddfe7cc7543c313e4ed13a332fb1a0fcb
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent ca4ec317
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ extern const struct clk_ops clk_dyn_rcg_ops;
 * @current_freq: last cached frequency when using branches with shared RCGs
 * @enable_safe_config: When set, the RCG is parked at CXO when it's disabled
 * @clkr: regmap clock handle
 *
 * @flags: additional flag parameters for the RCG
 */
struct clk_rcg2 {
	u32			cmd_rcgr;
@@ -170,6 +170,8 @@ struct clk_rcg2 {
	unsigned long		current_freq;
	bool			enable_safe_config;
	struct clk_regmap	clkr;
	u8			flags;
#define FORCE_ENABLE_RCG	BIT(0)
};

#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
+84 −2
Original line number Diff line number Diff line
@@ -167,6 +167,47 @@ static void clk_rcg2_clear_force_enable(struct clk_hw *hw)
					CMD_ROOT_EN, 0);
}

static int prepare_enable_rcg_srcs(struct clk *curr, struct clk *new)
{
	int rc = 0;

	rc = clk_prepare(curr);
	if (rc)
		return rc;

	rc = clk_prepare(new);
	if (rc)
		goto err_new_src_prepare;

	rc = clk_enable(curr);
	if (rc)
		goto err_curr_src_enable;

	rc = clk_enable(new);
	if (rc)
		goto err_new_src_enable;

	return rc;

err_new_src_enable:
	clk_disable(curr);
err_curr_src_enable:
	clk_unprepare(new);
err_new_src_prepare:
	clk_unprepare(curr);

	return rc;
}

static void disable_unprepare_rcg_srcs(struct clk *curr, struct clk *new)
{
	clk_disable(new);
	clk_disable(curr);

	clk_unprepare(new);
	clk_unprepare(curr);
}

/*
 * Calculate m/n:d rate
 *
@@ -337,8 +378,9 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
			       enum freq_policy policy)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	const struct freq_tbl *f;
	int ret;
	const struct freq_tbl *f, *f_curr;
	int ret, curr_src_index, new_src_index;
	struct clk_hw *curr_src = NULL, *new_src = NULL;

	switch (policy) {
	case FLOOR:
@@ -362,10 +404,40 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
		return 0;
	}

	if (rcg->flags & FORCE_ENABLE_RCG) {
		rcg->current_freq = clk_get_rate(hw->clk);
		if (rcg->current_freq == cxo_f.freq)
			curr_src_index = 0;
		else {
			f_curr = qcom_find_freq(rcg->freq_tbl,
							rcg->current_freq);
			if (!f_curr)
				return -EINVAL;

			curr_src_index = qcom_find_src_index(hw,
						rcg->parent_map, f_curr->src);
		}

		new_src_index = qcom_find_src_index(hw, rcg->parent_map,
							f->src);

		curr_src = clk_hw_get_parent_by_index(hw, curr_src_index);
		new_src = clk_hw_get_parent_by_index(hw, new_src_index);

		/* The RCG could currently be disabled. Enable its parents. */
		ret = prepare_enable_rcg_srcs(curr_src->clk, new_src->clk);
		clk_rcg2_set_force_enable(hw);
	}

	ret = clk_rcg2_configure(rcg, f);
	if (ret)
		return ret;

	if (rcg->flags & FORCE_ENABLE_RCG) {
		clk_rcg2_clear_force_enable(hw);
		disable_unprepare_rcg_srcs(curr_src->clk, new_src->clk);
	}

	/* Update current frequency with the requested frequency. */
	rcg->current_freq = rate;
	return ret;
@@ -401,6 +473,11 @@ static int clk_rcg2_enable(struct clk_hw *hw)
	unsigned long rate;
	const struct freq_tbl *f;

	if (rcg->flags & FORCE_ENABLE_RCG) {
		clk_rcg2_set_force_enable(hw);
		return 0;
	}

	if (!rcg->enable_safe_config)
		return 0;

@@ -437,6 +514,11 @@ static void clk_rcg2_disable(struct clk_hw *hw)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);

	if (rcg->flags & FORCE_ENABLE_RCG) {
		clk_rcg2_clear_force_enable(hw);
		return;
	}

	if (!rcg->enable_safe_config)
		return;
	/*