ipq806x: Add support for IPQ806x chip family
[openwrt/staging/wigyori.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 diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
16 index 0f927c5..80c7a76 100644
17 --- a/drivers/clk/qcom/clk-pll.c
18 +++ b/drivers/clk/qcom/clk-pll.c
19 @@ -97,7 +97,7 @@ static unsigned long
20 clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
21 {
22 struct clk_pll *pll = to_clk_pll(hw);
23 - u32 l, m, n;
24 + u32 l, m, n, config;
25 unsigned long rate;
26 u64 tmp;
27
28 @@ -116,13 +116,79 @@ clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
29 do_div(tmp, n);
30 rate += tmp;
31 }
32 + if (pll->post_div_width) {
33 + regmap_read(pll->clkr.regmap, pll->config_reg, &config);
34 + config >>= pll->post_div_shift;
35 + config &= BIT(pll->post_div_width) - 1;
36 + rate /= config + 1;
37 + }
38 +
39 return rate;
40 }
41
42 +static const
43 +struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
44 +{
45 + if (!f)
46 + return NULL;
47 +
48 + for (; f->freq; f++)
49 + if (rate <= f->freq)
50 + return f;
51 +
52 + return NULL;
53 +}
54 +
55 +static long
56 +clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
57 + unsigned long *p_rate, struct clk **p)
58 +{
59 + struct clk_pll *pll = to_clk_pll(hw);
60 + const struct pll_freq_tbl *f;
61 +
62 + f = find_freq(pll->freq_tbl, rate);
63 + if (!f)
64 + return clk_pll_recalc_rate(hw, *p_rate);
65 +
66 + return f->freq;
67 +}
68 +
69 +static int
70 +clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
71 +{
72 + struct clk_pll *pll = to_clk_pll(hw);
73 + const struct pll_freq_tbl *f;
74 + bool enabled;
75 + u32 mode;
76 + u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
77 +
78 + f = find_freq(pll->freq_tbl, rate);
79 + if (!f)
80 + return -EINVAL;
81 +
82 + regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
83 + enabled = (mode & enable_mask) == enable_mask;
84 +
85 + if (enabled)
86 + clk_pll_disable(hw);
87 +
88 + regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
89 + regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
90 + regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
91 + regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
92 +
93 + if (enabled)
94 + clk_pll_enable(hw);
95 +
96 + return 0;
97 +}
98 +
99 const struct clk_ops clk_pll_ops = {
100 .enable = clk_pll_enable,
101 .disable = clk_pll_disable,
102 .recalc_rate = clk_pll_recalc_rate,
103 + .determine_rate = clk_pll_determine_rate,
104 + .set_rate = clk_pll_set_rate,
105 };
106 EXPORT_SYMBOL_GPL(clk_pll_ops);
107
108 diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h
109 index 0775a99..5f9928b 100644
110 --- a/drivers/clk/qcom/clk-pll.h
111 +++ b/drivers/clk/qcom/clk-pll.h
112 @@ -18,6 +18,21 @@
113 #include "clk-regmap.h"
114
115 /**
116 + * struct pll_freq_tbl - PLL frequency table
117 + * @l: L value
118 + * @m: M value
119 + * @n: N value
120 + * @ibits: internal values
121 + */
122 +struct pll_freq_tbl {
123 + unsigned long freq;
124 + u16 l;
125 + u16 m;
126 + u16 n;
127 + u32 ibits;
128 +};
129 +
130 +/**
131 * struct clk_pll - phase locked loop (PLL)
132 * @l_reg: L register
133 * @m_reg: M register
134 @@ -26,6 +41,7 @@
135 * @mode_reg: mode register
136 * @status_reg: status register
137 * @status_bit: ANDed with @status_reg to determine if PLL is enabled
138 + * @freq_tbl: PLL frequency table
139 * @hw: handle between common and hardware-specific interfaces
140 */
141 struct clk_pll {
142 @@ -36,6 +52,10 @@ struct clk_pll {
143 u32 mode_reg;
144 u32 status_reg;
145 u8 status_bit;
146 + u8 post_div_width;
147 + u8 post_div_shift;
148 +
149 + const struct pll_freq_tbl *freq_tbl;
150
151 struct clk_regmap clkr;
152 };
153 --
154 1.7.10.4
155