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

Commit 51b1e61b authored by Rajendra Nayak's avatar Rajendra Nayak Committed by Kyle Yan
Browse files

clk: qcom: alpha-pll: Add support for hwfsm ops



Add support to enable/disable the alpha pll using hwfsm
Also add support for initial configuration (needs to be split)

Change-Id: Ifc2fe0539b943e850681143da76da27274203ed2
Signed-off-by: default avatarRajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
parent b090808a
Loading
Loading
Loading
Loading
+121 −12
Original line number Diff line number Diff line
@@ -62,9 +62,10 @@
#define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \
					   struct clk_alpha_pll_postdiv, clkr)

static int wait_for_pll(struct clk_alpha_pll *pll)
static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
			const char *action)
{
	u32 val, mask, off;
	u32 val, off;
	int count;
	int ret;
	const char *name = clk_hw_get_name(&pll->clkr.hw);
@@ -74,26 +75,125 @@ static int wait_for_pll(struct clk_alpha_pll *pll)
	if (ret)
		return ret;

	if (val & PLL_VOTE_FSM_ENA)
		mask = PLL_ACTIVE_FLAG;
	else
		mask = PLL_LOCK_DET;

	/* Wait for pll to enable. */
	for (count = 100; count > 0; count--) {
		ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
		if (ret)
			return ret;
		if ((val & mask) == mask)
		if (inverse && (val & mask))
			return 0;
		else if ((val & mask) == mask)
			return 0;

		udelay(1);
	}

	WARN(1, "%s didn't enable after voting for it!\n", name);
	WARN(1, "%s failed to %s!\n", name, action);
	return -ETIMEDOUT;
}

static int wait_for_pll_enable(struct clk_alpha_pll *pll, u32 mask)
{
	return wait_for_pll(pll, mask, 0, "enable");
}

static int wait_for_pll_disable(struct clk_alpha_pll *pll, u32 mask)
{
	return wait_for_pll(pll, mask, 1, "disable");
}

static int wait_for_pll_offline(struct clk_alpha_pll *pll, u32 mask)
{
	return wait_for_pll(pll, mask, 0, "offline");
}


/* alpha pll with hwfsm support */

#define PLL_OFFLINE_REQ		BIT(7)
#define PLL_FSM_ENA		BIT(20)
#define PLL_OFFLINE_ACK		BIT(28)
#define PLL_ACTIVE_FLAG		BIT(30)

void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
			     const struct pll_config *config)
{
	u32 val, mask;

	regmap_write(regmap, pll->offset + PLL_CONFIG_CTL,
			   config->config_ctl_val);

	val = config->main_output_mask;
	val |= config->aux_output_mask;
	val |= config->aux2_output_mask;
	val |= config->early_output_mask;
	val |= config->post_div_val;

	mask = config->main_output_mask;
	mask |= config->aux_output_mask;
	mask |= config->aux2_output_mask;
	mask |= config->early_output_mask;
	mask |= config->post_div_mask;

	regmap_update_bits(regmap, pll->offset + PLL_USER_CTL, mask, val);

	return;
}

static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
{
	int ret;
	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
	u32 val, off;

	off = pll->offset;
	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
	if (ret)
		return ret;
	/* Enable HW FSM mode, clear OFFLINE request */
	val |= PLL_FSM_ENA;
	val &= ~PLL_OFFLINE_REQ;
	ret = regmap_write(pll->clkr.regmap, off + PLL_MODE, val);
	if (ret)
		return ret;

	/* Make sure enable request goes through before waiting for update */
	mb();

	ret = wait_for_pll_enable(pll, PLL_ACTIVE_FLAG);
	if (ret)
		return ret;

	return 0;
}

static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw)
{
	int ret;
	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
	u32 val, off;

	off = pll->offset;
	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
	if (ret)
		return;
	/* Request PLL_OFFLINE and wait for ack */
	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
				 PLL_OFFLINE_REQ, PLL_OFFLINE_REQ);
	if (ret)
		return;
	ret = wait_for_pll_offline(pll, PLL_OFFLINE_ACK);
	if (ret)
		return;

	/* Disable hwfsm */
	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
				 PLL_FSM_ENA, 0);
	if (ret)
		return;
	wait_for_pll_disable(pll, PLL_ACTIVE_FLAG);
	return;
}

static int clk_alpha_pll_enable(struct clk_hw *hw)
{
	int ret;
@@ -112,7 +212,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)
		ret = clk_enable_regmap(hw);
		if (ret)
			return ret;
		return wait_for_pll(pll);
		return wait_for_pll_enable(pll, PLL_ACTIVE_FLAG);
	}

	/* Skip if already enabled */
@@ -136,7 +236,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw)
	if (ret)
		return ret;

	ret = wait_for_pll(pll);
	ret = wait_for_pll_enable(pll, PLL_LOCK_DET);
	if (ret)
		return ret;

@@ -300,6 +400,15 @@ const struct clk_ops clk_alpha_pll_ops = {
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);

const struct clk_ops clk_alpha_pll_hwfsm_ops = {
	.enable = clk_alpha_pll_hwfsm_enable,
	.disable = clk_alpha_pll_hwfsm_disable,
	.recalc_rate = clk_alpha_pll_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.set_rate = clk_alpha_pll_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);

static unsigned long
clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
+11 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <linux/clk-provider.h>
#include "clk-regmap.h"
#include "clk-pll.h"

struct pll_vco {
	unsigned long min_freq;
@@ -36,6 +37,12 @@ struct clk_alpha_pll {
	size_t num_vco;

	struct clk_regmap clkr;
	u32 config_ctl_val;
#define PLLOUT_MAIN	BIT(0)
#define PLLOUT_AUX	BIT(1)
#define PLLOUT_AUX2	BIT(2)
#define PLLOUT_EARLY	BIT(3)
	u32 pllout_flags;
};

/**
@@ -52,6 +59,10 @@ struct clk_alpha_pll_postdiv {
};

extern const struct clk_ops clk_alpha_pll_ops;
extern const struct clk_ops clk_alpha_pll_hwfsm_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ops;

void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
		const struct pll_config *config);

#endif
+3 −0
Original line number Diff line number Diff line
@@ -79,6 +79,9 @@ struct pll_config {
	u32 mn_ena_mask;
	u32 main_output_mask;
	u32 aux_output_mask;
	u32 aux2_output_mask;
	u32 early_output_mask;
	u32 config_ctl_val;
};

void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,