clk: rockchip: Add adaptive frequency scaling for pll_rk3066
authorFinley Xiao <finley.xiao@rock-chips.com>
Mon, 24 Apr 2017 11:42:05 +0000 (19:42 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 25 Apr 2017 06:42:16 +0000 (14:42 +0800)
Change-Id: I9c3422a45f86e8b95be0ad069ac70d5490eb5161
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/clk.h

index d61d2a170496c69e019c9bb2cfa1f95354764934..592fde7c11b675bda7d9841380b496f60d5e5995 100644 (file)
@@ -47,6 +47,8 @@ struct rockchip_clk_pll {
        u8                      flags;
        const struct rockchip_pll_rate_table *rate_table;
        unsigned int            rate_count;
+       int                     sel;
+       unsigned long           scaling;
        spinlock_t              *lock;
 
        struct rockchip_clk_provider *ctx;
@@ -84,6 +86,23 @@ static int rockchip_rk3366_pll_set_params(struct rockchip_clk_pll *pll,
 
 static struct rockchip_pll_rate_table auto_table;
 
+int rockchip_pll_clk_adaptive_scaling(struct clk *clk, int sel)
+{
+       struct clk *parent = clk_get_parent(clk);
+       struct rockchip_clk_pll *pll;
+
+       if (IS_ERR_OR_NULL(parent))
+               return -EINVAL;
+
+       pll = to_rockchip_clk_pll(__clk_get_hw(parent));
+       if (!pll)
+               return -EINVAL;
+
+       pll->sel = sel;
+
+       return 0;
+}
+
 static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void)
 {
        return &auto_table;
@@ -260,9 +279,16 @@ static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
        int i;
 
        for (i = 0; i < pll->rate_count; i++) {
-               if (rate == rate_table[i].rate)
+               if (rate == rate_table[i].rate) {
+                       if (i < pll->sel) {
+                               pll->scaling = rate;
+                               return &rate_table[pll->sel];
+                       }
+                       pll->scaling = 0;
                        return &rate_table[i];
+               }
        }
+       pll->scaling = 0;
 
        if (pll->type == pll_rk3066)
                return rockchip_rk3066_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
@@ -617,6 +643,9 @@ static unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw,
                return prate;
        }
 
+       if (pll->sel && pll->scaling)
+               return pll->scaling;
+
        rockchip_rk3066_pll_get_params(pll, &cur);
 
        rate64 *= cur.nf;
@@ -692,6 +721,7 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
        const struct rockchip_pll_rate_table *rate;
        unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate);
        struct regmap *grf = rockchip_clk_get_grf(pll->ctx);
+       int ret;
 
        if (IS_ERR(grf)) {
                pr_debug("%s: grf regmap not available, aborting rate change\n",
@@ -710,7 +740,11 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
                return -EINVAL;
        }
 
-       return rockchip_rk3066_pll_set_params(pll, rate);
+       ret = rockchip_rk3066_pll_set_params(pll, rate);
+       if (ret)
+               pll->scaling = 0;
+
+       return ret;
 }
 
 static int rockchip_rk3066_pll_enable(struct clk_hw *hw)
index c1e49b2767ec46d1343e184e4c49699442ae4b6b..a0f8ccb54b5036a8b93884510a239d012cde2e75 100644 (file)
@@ -697,6 +697,7 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
                        const struct rockchip_cpuclk_rate_table *rates,
                        int nrates);
 void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
+int rockchip_pll_clk_adaptive_scaling(struct clk *clk, int sel);
 void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
                                        unsigned int reg, void (*cb)(void));