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

Commit 8c1ebe97 authored by Marek Vasut's avatar Marek Vasut Committed by Stephen Boyd
Browse files

clk: vc5: Add support for the input frequency doubler



The VersaClock 6 has an input frequency doubler between the input
clock mux and the predivider. Add new capability flag and support
for this frequency doubler block into the driver.

Signed-off-by: default avatarMarek Vasut <marek.vasut+renesas@gmail.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Alexey Firago <alexey_firago@mentor.com>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: linux-renesas-soc@vger.kernel.org
Tested-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
on Salvator-XS with the display LVDS output.
Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
parent 55997db5
Loading
Loading
Loading
Loading
+77 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
#define VC5_PRIM_SRC_SHDN			0x10
#define VC5_PRIM_SRC_SHDN_EN_XTAL		BIT(7)
#define VC5_PRIM_SRC_SHDN_EN_CLKIN		BIT(6)
#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ	BIT(3)
#define VC5_PRIM_SRC_SHDN_SP			BIT(1)
#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN		BIT(0)

@@ -122,6 +123,8 @@
/* flags to describe chip features */
/* chip has built-in oscilator */
#define VC5_HAS_INTERNAL_XTAL	BIT(0)
/* chip has PFD requency doubler */
#define VC5_HAS_PFD_FREQ_DBL	BIT(1)

/* Supported IDT VC5 models. */
enum vc5_model {
@@ -157,6 +160,7 @@ struct vc5_driver_data {
	struct clk		*pin_clkin;
	unsigned char		clk_mux_ins;
	struct clk_hw		clk_mux;
	struct clk_hw		clk_mul;
	struct clk_hw		clk_pfd;
	struct vc5_hw_data	clk_pll;
	struct vc5_hw_data	clk_fod[VC5_MAX_FOD_NUM];
@@ -167,6 +171,10 @@ static const char * const vc5_mux_names[] = {
	"mux"
};

static const char * const vc5_dbl_names[] = {
	"dbl"
};

static const char * const vc5_pfd_names[] = {
	"pfd"
};
@@ -264,6 +272,54 @@ static const struct clk_ops vc5_mux_ops = {
	.get_parent	= vc5_mux_get_parent,
};

static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
					 unsigned long parent_rate)
{
	struct vc5_driver_data *vc5 =
		container_of(hw, struct vc5_driver_data, clk_mul);
	unsigned int premul;

	regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
	if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
		parent_rate *= 2;

	return parent_rate;
}

static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
			       unsigned long *parent_rate)
{
	if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
		return rate;
	else
		return -EINVAL;
}

static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
			    unsigned long parent_rate)
{
	struct vc5_driver_data *vc5 =
		container_of(hw, struct vc5_driver_data, clk_mul);
	u32 mask;

	if ((parent_rate * 2) == rate)
		mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ;
	else
		mask = 0;

	regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
			   VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
			   mask);

	return 0;
}

static const struct clk_ops vc5_dbl_ops = {
	.recalc_rate	= vc5_dbl_recalc_rate,
	.round_rate	= vc5_dbl_round_rate,
	.set_rate	= vc5_dbl_set_rate,
};

static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
					 unsigned long parent_rate)
{
@@ -706,11 +762,31 @@ static int vc5_probe(struct i2c_client *client,
		goto err_clk;
	}

	if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
		/* Register frequency doubler */
		memset(&init, 0, sizeof(init));
		init.name = vc5_dbl_names[0];
		init.ops = &vc5_dbl_ops;
		init.flags = CLK_SET_RATE_PARENT;
		init.parent_names = vc5_mux_names;
		init.num_parents = 1;
		vc5->clk_mul.init = &init;
		ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
		if (ret) {
			dev_err(&client->dev, "unable to register %s\n",
				init.name);
			goto err_clk;
		}
	}

	/* Register PFD */
	memset(&init, 0, sizeof(init));
	init.name = vc5_pfd_names[0];
	init.ops = &vc5_pfd_ops;
	init.flags = CLK_SET_RATE_PARENT;
	if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
		init.parent_names = vc5_dbl_names;
	else
		init.parent_names = vc5_mux_names;
	init.num_parents = 1;
	vc5->clk_pfd.init = &init;