These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / qcom / clk-rcg.c
index 7b3d626..bfbb28f 100644 (file)
@@ -45,7 +45,7 @@ static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns)
 static u8 clk_rcg_get_parent(struct clk_hw *hw)
 {
        struct clk_rcg *rcg = to_clk_rcg(hw);
-       int num_parents = __clk_get_num_parents(hw->clk);
+       int num_parents = clk_hw_get_num_parents(hw);
        u32 ns;
        int i, ret;
 
@@ -59,7 +59,7 @@ static u8 clk_rcg_get_parent(struct clk_hw *hw)
 
 err:
        pr_debug("%s: Clock %s has invalid parent, using default.\n",
-                __func__, __clk_get_name(hw->clk));
+                __func__, clk_hw_get_name(hw));
        return 0;
 }
 
@@ -72,7 +72,7 @@ static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank)
 static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
 {
        struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
-       int num_parents = __clk_get_num_parents(hw->clk);
+       int num_parents = clk_hw_get_num_parents(hw);
        u32 ns, reg;
        int bank;
        int i, ret;
@@ -95,7 +95,7 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw)
 
 err:
        pr_debug("%s: Clock %s has invalid parent, using default.\n",
-                __func__, __clk_get_name(hw->clk));
+                __func__, clk_hw_get_name(hw));
        return 0;
 }
 
@@ -404,14 +404,12 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
        return calc_rate(parent_rate, m, n, mode, pre_div);
 }
 
-static long _freq_tbl_determine_rate(struct clk_hw *hw,
-               const struct freq_tbl *f, unsigned long rate,
-               unsigned long min_rate, unsigned long max_rate,
-               unsigned long *p_rate, struct clk_hw **p_hw,
+static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
+               struct clk_rate_request *req,
                const struct parent_map *parent_map)
 {
-       unsigned long clk_flags;
-       struct clk *p;
+       unsigned long clk_flags, rate = req->rate;
+       struct clk_hw *p;
        int index;
 
        f = qcom_find_freq(f, rate);
@@ -422,8 +420,8 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
        if (index < 0)
                return index;
 
-       clk_flags = __clk_get_flags(hw->clk);
-       p = clk_get_parent_by_index(hw->clk, index);
+       clk_flags = clk_hw_get_flags(hw);
+       p = clk_hw_get_parent_by_index(hw, index);
        if (clk_flags & CLK_SET_RATE_PARENT) {
                rate = rate * f->pre_div;
                if (f->n) {
@@ -433,27 +431,26 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
                        rate = tmp;
                }
        } else {
-               rate =  __clk_get_rate(p);
+               rate =  clk_hw_get_rate(p);
        }
-       *p_hw = __clk_get_hw(p);
-       *p_rate = rate;
+       req->best_parent_hw = p;
+       req->best_parent_rate = rate;
+       req->rate = f->freq;
 
-       return f->freq;
+       return 0;
 }
 
-static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long min_rate, unsigned long max_rate,
-               unsigned long *p_rate, struct clk_hw **p)
+static int clk_rcg_determine_rate(struct clk_hw *hw,
+                                 struct clk_rate_request *req)
 {
        struct clk_rcg *rcg = to_clk_rcg(hw);
 
-       return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
-                       max_rate, p_rate, p, rcg->s.parent_map);
+       return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req,
+                                       rcg->s.parent_map);
 }
 
-static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long min_rate, unsigned long max_rate,
-               unsigned long *p_rate, struct clk_hw **p)
+static int clk_dyn_rcg_determine_rate(struct clk_hw *hw,
+                                     struct clk_rate_request *req)
 {
        struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
        u32 reg;
@@ -464,24 +461,22 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
        bank = reg_to_bank(rcg, reg);
        s = &rcg->s[bank];
 
-       return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
-                       max_rate, p_rate, p, s->parent_map);
+       return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map);
 }
 
-static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long min_rate, unsigned long max_rate,
-               unsigned long *p_rate, struct clk_hw **p_hw)
+static int clk_rcg_bypass_determine_rate(struct clk_hw *hw,
+                                        struct clk_rate_request *req)
 {
        struct clk_rcg *rcg = to_clk_rcg(hw);
        const struct freq_tbl *f = rcg->freq_tbl;
-       struct clk *p;
+       struct clk_hw *p;
        int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src);
 
-       p = clk_get_parent_by_index(hw->clk, index);
-       *p_hw = __clk_get_hw(p);
-       *p_rate = __clk_round_rate(p, rate);
+       req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
+       req->best_parent_rate = clk_hw_round_rate(p, req->rate);
+       req->rate = req->best_parent_rate;
 
-       return *p_rate;
+       return 0;
 }
 
 static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
@@ -547,6 +542,200 @@ static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate,
        return __clk_rcg_set_rate(rcg, rcg->freq_tbl);
 }
 
+static int clk_rcg_bypass2_determine_rate(struct clk_hw *hw,
+                               struct clk_rate_request *req)
+{
+       struct clk_hw *p;
+
+       p = req->best_parent_hw;
+       req->best_parent_rate = clk_hw_round_rate(p, req->rate);
+       req->rate = req->best_parent_rate;
+
+       return 0;
+}
+
+static int clk_rcg_bypass2_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate)
+{
+       struct clk_rcg *rcg = to_clk_rcg(hw);
+       struct freq_tbl f = { 0 };
+       u32 ns, src;
+       int i, ret, num_parents = clk_hw_get_num_parents(hw);
+
+       ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
+       if (ret)
+               return ret;
+
+       src = ns_to_src(&rcg->s, ns);
+       f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1;
+
+       for (i = 0; i < num_parents; i++) {
+               if (src == rcg->s.parent_map[i].cfg) {
+                       f.src = rcg->s.parent_map[i].src;
+                       return __clk_rcg_set_rate(rcg, &f);
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int clk_rcg_bypass2_set_rate_and_parent(struct clk_hw *hw,
+               unsigned long rate, unsigned long parent_rate, u8 index)
+{
+       /* Read the hardware to determine parent during set_rate */
+       return clk_rcg_bypass2_set_rate(hw, rate, parent_rate);
+}
+
+struct frac_entry {
+       int num;
+       int den;
+};
+
+static const struct frac_entry pixel_table[] = {
+       { 1, 2 },
+       { 1, 3 },
+       { 3, 16 },
+       { }
+};
+
+static int clk_rcg_pixel_determine_rate(struct clk_hw *hw,
+               struct clk_rate_request *req)
+{
+       int delta = 100000;
+       const struct frac_entry *frac = pixel_table;
+       unsigned long request, src_rate;
+
+       for (; frac->num; frac++) {
+               request = (req->rate * frac->den) / frac->num;
+
+               src_rate = clk_hw_round_rate(req->best_parent_hw, request);
+
+               if ((src_rate < (request - delta)) ||
+                       (src_rate > (request + delta)))
+                       continue;
+
+               req->best_parent_rate = src_rate;
+               req->rate = (src_rate * frac->num) / frac->den;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate)
+{
+       struct clk_rcg *rcg = to_clk_rcg(hw);
+       int delta = 100000;
+       const struct frac_entry *frac = pixel_table;
+       unsigned long request;
+       struct freq_tbl f = { 0 };
+       u32 ns, src;
+       int i, ret, num_parents = clk_hw_get_num_parents(hw);
+
+       ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
+       if (ret)
+               return ret;
+
+       src = ns_to_src(&rcg->s, ns);
+       f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1;
+
+       for (i = 0; i < num_parents; i++) {
+               if (src == rcg->s.parent_map[i].cfg) {
+                       f.src = rcg->s.parent_map[i].src;
+                       break;
+               }
+       }
+
+       /* let us find appropriate m/n values for this */
+       for (; frac->num; frac++) {
+               request = (rate * frac->den) / frac->num;
+
+               if ((parent_rate < (request - delta)) ||
+                       (parent_rate > (request + delta)))
+                       continue;
+
+               f.m = frac->num;
+               f.n = frac->den;
+
+               return __clk_rcg_set_rate(rcg, &f);
+       }
+
+       return -EINVAL;
+}
+
+static int clk_rcg_pixel_set_rate_and_parent(struct clk_hw *hw,
+               unsigned long rate, unsigned long parent_rate, u8 index)
+{
+       return clk_rcg_pixel_set_rate(hw, rate, parent_rate);
+}
+
+static int clk_rcg_esc_determine_rate(struct clk_hw *hw,
+               struct clk_rate_request *req)
+{
+       struct clk_rcg *rcg = to_clk_rcg(hw);
+       int pre_div_max = BIT(rcg->p.pre_div_width);
+       int div;
+       unsigned long src_rate;
+
+       if (req->rate == 0)
+               return -EINVAL;
+
+       src_rate = clk_hw_get_rate(req->best_parent_hw);
+
+       div = src_rate / req->rate;
+
+       if (div >= 1 && div <= pre_div_max) {
+               req->best_parent_rate = src_rate;
+               req->rate = src_rate / div;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int clk_rcg_esc_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate)
+{
+       struct clk_rcg *rcg = to_clk_rcg(hw);
+       struct freq_tbl f = { 0 };
+       int pre_div_max = BIT(rcg->p.pre_div_width);
+       int div;
+       u32 ns;
+       int i, ret, num_parents = clk_hw_get_num_parents(hw);
+
+       if (rate == 0)
+               return -EINVAL;
+
+       ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
+       if (ret)
+               return ret;
+
+       ns = ns_to_src(&rcg->s, ns);
+
+       for (i = 0; i < num_parents; i++) {
+               if (ns == rcg->s.parent_map[i].cfg) {
+                       f.src = rcg->s.parent_map[i].src;
+                       break;
+               }
+       }
+
+       div = parent_rate / rate;
+
+       if (div >= 1 && div <= pre_div_max) {
+               f.pre_div = div;
+               return __clk_rcg_set_rate(rcg, &f);
+       }
+
+       return -EINVAL;
+}
+
+static int clk_rcg_esc_set_rate_and_parent(struct clk_hw *hw,
+               unsigned long rate, unsigned long parent_rate, u8 index)
+{
+       return clk_rcg_esc_set_rate(hw, rate, parent_rate);
+}
+
 /*
  * This type of clock has a glitch-free mux that switches between the output of
  * the M/N counter and an always on clock source (XO). When clk_set_rate() is
@@ -644,6 +833,42 @@ const struct clk_ops clk_rcg_bypass_ops = {
 };
 EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops);
 
+const struct clk_ops clk_rcg_bypass2_ops = {
+       .enable = clk_enable_regmap,
+       .disable = clk_disable_regmap,
+       .get_parent = clk_rcg_get_parent,
+       .set_parent = clk_rcg_set_parent,
+       .recalc_rate = clk_rcg_recalc_rate,
+       .determine_rate = clk_rcg_bypass2_determine_rate,
+       .set_rate = clk_rcg_bypass2_set_rate,
+       .set_rate_and_parent = clk_rcg_bypass2_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_rcg_bypass2_ops);
+
+const struct clk_ops clk_rcg_pixel_ops = {
+       .enable = clk_enable_regmap,
+       .disable = clk_disable_regmap,
+       .get_parent = clk_rcg_get_parent,
+       .set_parent = clk_rcg_set_parent,
+       .recalc_rate = clk_rcg_recalc_rate,
+       .determine_rate = clk_rcg_pixel_determine_rate,
+       .set_rate = clk_rcg_pixel_set_rate,
+       .set_rate_and_parent = clk_rcg_pixel_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_rcg_pixel_ops);
+
+const struct clk_ops clk_rcg_esc_ops = {
+       .enable = clk_enable_regmap,
+       .disable = clk_disable_regmap,
+       .get_parent = clk_rcg_get_parent,
+       .set_parent = clk_rcg_set_parent,
+       .recalc_rate = clk_rcg_recalc_rate,
+       .determine_rate = clk_rcg_esc_determine_rate,
+       .set_rate = clk_rcg_esc_set_rate,
+       .set_rate_and_parent = clk_rcg_esc_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_rcg_esc_ops);
+
 const struct clk_ops clk_rcg_lcc_ops = {
        .enable = clk_rcg_lcc_enable,
        .disable = clk_rcg_lcc_disable,