提交 55997db5 编写于 作者: M Marek Vasut 提交者: Stephen Boyd

clk: vc5: Split clock input mux and predivider

Split the VC5 clock input mux and the predivider to more accurately
model the hardware and fix the previously incorrect assumption that
both the OUT_SEL_I2CB and the PLL are fed from the predivider.

It is in fact the clock input mux output which is directly feeding
the clock into the OUT_SEL_I2CB output, while the clock input mux
output first passes through the predivider before it is fed into
the PLL.
Signed-off-by: NMarek 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: NLaurent Pinchart <laurent.pinchart@ideasonboard.com>
on Salvator-XS with the display LVDS output.
Signed-off-by: NStephen Boyd <sboyd@codeaurora.org>
上级 718f4694
...@@ -157,6 +157,7 @@ struct vc5_driver_data { ...@@ -157,6 +157,7 @@ struct vc5_driver_data {
struct clk *pin_clkin; struct clk *pin_clkin;
unsigned char clk_mux_ins; unsigned char clk_mux_ins;
struct clk_hw clk_mux; struct clk_hw clk_mux;
struct clk_hw clk_pfd;
struct vc5_hw_data clk_pll; struct vc5_hw_data clk_pll;
struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM]; struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM]; struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
...@@ -166,6 +167,10 @@ static const char * const vc5_mux_names[] = { ...@@ -166,6 +167,10 @@ static const char * const vc5_mux_names[] = {
"mux" "mux"
}; };
static const char * const vc5_pfd_names[] = {
"pfd"
};
static const char * const vc5_pll_names[] = { static const char * const vc5_pll_names[] = {
"pll" "pll"
}; };
...@@ -254,11 +259,16 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index) ...@@ -254,11 +259,16 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src); return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
} }
static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw, static const struct clk_ops vc5_mux_ops = {
.set_parent = vc5_mux_set_parent,
.get_parent = vc5_mux_get_parent,
};
static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct vc5_driver_data *vc5 = struct vc5_driver_data *vc5 =
container_of(hw, struct vc5_driver_data, clk_mux); container_of(hw, struct vc5_driver_data, clk_pfd);
unsigned int prediv, div; unsigned int prediv, div;
regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv); regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
...@@ -276,7 +286,7 @@ static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw, ...@@ -276,7 +286,7 @@ static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
return parent_rate / VC5_REF_DIVIDER_REF_DIV(div); return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
} }
static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate, static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
unsigned long idiv; unsigned long idiv;
...@@ -296,11 +306,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -296,11 +306,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
return *parent_rate / idiv; return *parent_rate / idiv;
} }
static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate, static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct vc5_driver_data *vc5 = struct vc5_driver_data *vc5 =
container_of(hw, struct vc5_driver_data, clk_mux); container_of(hw, struct vc5_driver_data, clk_pfd);
unsigned long idiv; unsigned long idiv;
u8 div; u8 div;
...@@ -328,12 +338,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -328,12 +338,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
return 0; return 0;
} }
static const struct clk_ops vc5_mux_ops = { static const struct clk_ops vc5_pfd_ops = {
.set_parent = vc5_mux_set_parent, .recalc_rate = vc5_pfd_recalc_rate,
.get_parent = vc5_mux_get_parent, .round_rate = vc5_pfd_round_rate,
.recalc_rate = vc5_mux_recalc_rate, .set_rate = vc5_pfd_set_rate,
.round_rate = vc5_mux_round_rate,
.set_rate = vc5_mux_set_rate,
}; };
/* /*
...@@ -698,12 +706,26 @@ static int vc5_probe(struct i2c_client *client, ...@@ -698,12 +706,26 @@ static int vc5_probe(struct i2c_client *client,
goto err_clk; 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;
init.num_parents = 1;
vc5->clk_pfd.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
/* Register PLL */ /* Register PLL */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_pll_names[0]; init.name = vc5_pll_names[0];
init.ops = &vc5_pll_ops; init.ops = &vc5_pll_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_mux_names; init.parent_names = vc5_pfd_names;
init.num_parents = 1; init.num_parents = 1;
vc5->clk_pll.num = 0; vc5->clk_pll.num = 0;
vc5->clk_pll.vc5 = vc5; vc5->clk_pll.vc5 = vc5;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册