OSDN Git Service

clk: vc5: Split clock input mux and predivider
authorMarek Vasut <marek.vasut@gmail.com>
Sun, 9 Jul 2017 13:28:11 +0000 (15:28 +0200)
committerStephen Boyd <sboyd@codeaurora.org>
Mon, 17 Jul 2017 18:50:59 +0000 (11:50 -0700)
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: 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>
drivers/clk/clk-versaclock5.c

index 29df110..cae0726 100644 (file)
@@ -157,6 +157,7 @@ struct vc5_driver_data {
        struct clk              *pin_clkin;
        unsigned char           clk_mux_ins;
        struct clk_hw           clk_mux;
+       struct clk_hw           clk_pfd;
        struct vc5_hw_data      clk_pll;
        struct vc5_hw_data      clk_fod[VC5_MAX_FOD_NUM];
        struct vc5_hw_data      clk_out[VC5_MAX_CLK_OUT_NUM];
@@ -166,6 +167,10 @@ static const char * const vc5_mux_names[] = {
        "mux"
 };
 
+static const char * const vc5_pfd_names[] = {
+       "pfd"
+};
+
 static const char * const vc5_pll_names[] = {
        "pll"
 };
@@ -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);
 }
 
-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)
 {
        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;
 
        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,
                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 idiv;
@@ -296,11 +306,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
        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)
 {
        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;
        u8 div;
 
@@ -328,12 +338,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
-static const struct clk_ops vc5_mux_ops = {
-       .set_parent     = vc5_mux_set_parent,
-       .get_parent     = vc5_mux_get_parent,
-       .recalc_rate    = vc5_mux_recalc_rate,
-       .round_rate     = vc5_mux_round_rate,
-       .set_rate       = vc5_mux_set_rate,
+static const struct clk_ops vc5_pfd_ops = {
+       .recalc_rate    = vc5_pfd_recalc_rate,
+       .round_rate     = vc5_pfd_round_rate,
+       .set_rate       = vc5_pfd_set_rate,
 };
 
 /*
@@ -698,12 +706,26 @@ static int vc5_probe(struct i2c_client *client,
                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 */
        memset(&init, 0, sizeof(init));
        init.name = vc5_pll_names[0];
        init.ops = &vc5_pll_ops;
        init.flags = CLK_SET_RATE_PARENT;
-       init.parent_names = vc5_mux_names;
+       init.parent_names = vc5_pfd_names;
        init.num_parents = 1;
        vc5->clk_pll.num = 0;
        vc5->clk_pll.vc5 = vc5;