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: Marek 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: Laurent Pinchart <laurent.pinchart@ideasonboard.com> on Salvator-XS with the display LVDS output. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
parent
55997db52e
commit
8c1ebe9762
|
@ -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,12 +762,32 @@ 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;
|
||||
init.parent_names = vc5_mux_names;
|
||||
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;
|
||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
|
||||
|
|
Loading…
Reference in New Issue