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

Commit e8475506 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

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

parents d2926542 38eb3761
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -142,7 +142,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;
@@ -154,6 +154,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)
+88 −2
Original line number Diff line number Diff line
@@ -160,6 +160,47 @@ static int 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
 *
@@ -339,8 +380,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:
@@ -365,10 +407,44 @@ 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);
		if (!curr_src)
			return -EINVAL;
		new_src = clk_hw_get_parent_by_index(hw, new_src_index);
		if (!new_src)
			return -EINVAL;

		/* 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;
@@ -404,6 +480,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;

@@ -440,6 +521,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;
	/*