kernel: update 3.14 to 3.14.18
[openwrt.git] / target / linux / ipq806x / patches / 0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch
1 From fd06a2cc719296f65a280cb1533b125f63cfcb34 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Mon, 28 Apr 2014 15:58:11 -0700
4 Subject: [PATCH 127/182] clk: qcom: Add support for setting rates on PLLs
5
6 Some PLLs may require changing their rate at runtime. Add support
7 for these PLLs.
8
9 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
10 ---
11  drivers/clk/qcom/clk-pll.c |   68 +++++++++++++++++++++++++++++++++++++++++++-
12  drivers/clk/qcom/clk-pll.h |   20 +++++++++++++
13  2 files changed, 87 insertions(+), 1 deletion(-)
14
15 --- a/drivers/clk/qcom/clk-pll.c
16 +++ b/drivers/clk/qcom/clk-pll.c
17 @@ -97,7 +97,7 @@ static unsigned long
18  clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
19  {
20         struct clk_pll *pll = to_clk_pll(hw);
21 -       u32 l, m, n;
22 +       u32 l, m, n, config;
23         unsigned long rate;
24         u64 tmp;
25  
26 @@ -116,13 +116,79 @@ clk_pll_recalc_rate(struct clk_hw *hw, u
27                 do_div(tmp, n);
28                 rate += tmp;
29         }
30 +       if (pll->post_div_width) {
31 +               regmap_read(pll->clkr.regmap, pll->config_reg, &config);
32 +               config >>= pll->post_div_shift;
33 +               config &= BIT(pll->post_div_width) - 1;
34 +               rate /= config + 1;
35 +       }
36 +
37         return rate;
38  }
39  
40 +static const
41 +struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
42 +{
43 +       if (!f)
44 +               return NULL;
45 +
46 +       for (; f->freq; f++)
47 +               if (rate <= f->freq)
48 +                       return f;
49 +
50 +       return NULL;
51 +}
52 +
53 +static long
54 +clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
55 +                      unsigned long *p_rate, struct clk **p)
56 +{
57 +       struct clk_pll *pll = to_clk_pll(hw);
58 +       const struct pll_freq_tbl *f;
59 +
60 +       f = find_freq(pll->freq_tbl, rate);
61 +       if (!f)
62 +               return clk_pll_recalc_rate(hw, *p_rate);
63 +
64 +       return f->freq;
65 +}
66 +
67 +static int
68 +clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
69 +{
70 +       struct clk_pll *pll = to_clk_pll(hw);
71 +       const struct pll_freq_tbl *f;
72 +       bool enabled;
73 +       u32 mode;
74 +       u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
75 +
76 +       f = find_freq(pll->freq_tbl, rate);
77 +       if (!f)
78 +               return -EINVAL;
79 +
80 +       regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
81 +       enabled = (mode & enable_mask) == enable_mask;
82 +
83 +       if (enabled)
84 +               clk_pll_disable(hw);
85 +
86 +       regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
87 +       regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
88 +       regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
89 +       regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
90 +
91 +       if (enabled)
92 +               clk_pll_enable(hw);
93 +
94 +       return 0;
95 +}
96 +
97  const struct clk_ops clk_pll_ops = {
98         .enable = clk_pll_enable,
99         .disable = clk_pll_disable,
100         .recalc_rate = clk_pll_recalc_rate,
101 +       .determine_rate = clk_pll_determine_rate,
102 +       .set_rate = clk_pll_set_rate,
103  };
104  EXPORT_SYMBOL_GPL(clk_pll_ops);
105  
106 --- a/drivers/clk/qcom/clk-pll.h
107 +++ b/drivers/clk/qcom/clk-pll.h
108 @@ -18,6 +18,21 @@
109  #include "clk-regmap.h"
110  
111  /**
112 + * struct pll_freq_tbl - PLL frequency table
113 + * @l: L value
114 + * @m: M value
115 + * @n: N value
116 + * @ibits: internal values
117 + */
118 +struct pll_freq_tbl {
119 +       unsigned long freq;
120 +       u16 l;
121 +       u16 m;
122 +       u16 n;
123 +       u32 ibits;
124 +};
125 +
126 +/**
127   * struct clk_pll - phase locked loop (PLL)
128   * @l_reg: L register
129   * @m_reg: M register
130 @@ -26,6 +41,7 @@
131   * @mode_reg: mode register
132   * @status_reg: status register
133   * @status_bit: ANDed with @status_reg to determine if PLL is enabled
134 + * @freq_tbl: PLL frequency table
135   * @hw: handle between common and hardware-specific interfaces
136   */
137  struct clk_pll {
138 @@ -36,6 +52,10 @@ struct clk_pll {
139         u32     mode_reg;
140         u32     status_reg;
141         u8      status_bit;
142 +       u8      post_div_width;
143 +       u8      post_div_shift;
144 +
145 +       const struct pll_freq_tbl *freq_tbl;
146  
147         struct clk_regmap clkr;
148  };