rk3368: clk: clk_add_recalc_ddr_freq.
[firefly-linux-kernel-4.4.55.git] / drivers / clk / rockchip / clk-ops.c
index c303239c3f1c78993c636f59003ccb4e28e81bb1..f2cb1c6572160f45fbc9348a41b8d5665a2f9784 100644 (file)
@@ -438,7 +438,7 @@ static long clk_ddr_determine_rate(struct clk_hw *hw, unsigned long rate,
 }
 
 static long clk_ddr_round_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long *prate)
+                unsigned long *prate)
 {
        return clk_ddr_determine_rate(hw, rate, prate, NULL);
 }
@@ -836,6 +836,66 @@ const struct clk_ops clkops_rate_3368_dclk_lcdc = {
        .recalc_rate    = clk_divider_recalc_rate,
 };
 
+static unsigned long clk_rk3368_ddr_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       if (!ddr_recalc_rate)
+               return (clk_core_recalc_rate(hw, parent_rate)/2);
+       else
+               return ddr_recalc_rate();
+}
+
+static long clk_ddr_determine_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *best_parent_rate,
+                       struct clk **best_parent_p)
+{
+       long best = 0;
+
+       if (!ddr_round_rate) {
+               /* Do nothing before ddr init */
+               best = rate;
+       } else {
+               /* Func provided by ddr driver */
+               best = ddr_round_rate(rate/MHZ) * MHZ;
+       }
+       clk_debug("%s: from %lu to %lu\n", __func__, rate, best);
+       return best;
+}
+static long clk_ddr_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       return clk_ddr_determine_rate(hw, rate, prate, NULL);
+}
+static int clk_ddr_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk *parent = __clk_get_parent(hw->clk);
+       struct clk *grand_p = __clk_get_parent(parent);
+
+       /* Do nothing before ddr init */
+       if (!ddr_change_freq)
+               return 0;
+       if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
+               clk_err("fail to get parent or grand_parent!\n");
+               return -EINVAL;
+       }
+       clk_debug("%s: will set rate = %lu\n", __func__, rate);
+       /* Func provided by ddr driver */
+       ddr_change_freq(rate/MHZ);
+       parent->rate = parent->ops->recalc_rate(parent->hw,
+       __clk_get_rate(grand_p));
+       return 0;
+}
+
+const struct clk_ops clkops_rate_rk3368_ddr = {
+       .recalc_rate    = clk_rk3368_ddr_recalc_rate,
+       .round_rate     = clk_ddr_round_rate,
+       .set_rate       = clk_ddr_set_rate,
+       .determine_rate = clk_ddr_determine_rate,
+};
+
+
+
 struct clk_ops_table rk_clkops_rate_table[] = {
        {.index = CLKOPS_RATE_MUX_DIV,          .clk_ops = &clkops_rate_auto_parent},
        {.index = CLKOPS_RATE_EVENDIV,          .clk_ops = &clkops_rate_evendiv},
@@ -853,6 +913,7 @@ struct clk_ops_table rk_clkops_rate_table[] = {
        {.index = CLKOPS_RATE_DDR_DIV4,         .clk_ops = NULL},
        {.index = CLKOPS_RATE_RK3368_MUX_DIV_NPLL,   .clk_ops = &clkops_rate_3368_auto_parent},
        {.index = CLKOPS_RATE_RK3368_DCLK_LCDC, .clk_ops = &clkops_rate_3368_dclk_lcdc},
+       {.index = CLKOPS_RATE_RK3368_DDR,   .clk_ops = &clkops_rate_rk3368_ddr},
        {.index = CLKOPS_RATE_I2S,              .clk_ops = NULL},
        {.index = CLKOPS_RATE_CIFOUT,           .clk_ops = NULL},
        {.index = CLKOPS_RATE_UART,             .clk_ops = NULL},