rk_clk: add clk-pll.c support
[firefly-linux-kernel-4.4.55.git] / drivers / clk / rockchip / clk-pll.c
1 #include <linux/slab.h>
2 #include <asm/io.h>
3
4 #include "clk-ops.h"
5 #include "clk-pll.h"
6
7
8 //static unsigned long lpj_gpll;
9
10 //fixme
11 extern void __iomem *reg_start;
12 #define RK30_CRU_BASE   (reg_start)
13
14 #define cru_readl(offset)       readl(RK30_CRU_BASE + offset)
15 #define cru_writel(v, offset)   do {writel(v, RK30_CRU_BASE + offset); dsb();} \
16         while (0)
17
18 #define PLLS_IN_NORM(pll_id) (((cru_readl(CRU_MODE_CON)&PLL_MODE_MSK(pll_id))\
19                         ==(PLL_MODE_NORM(pll_id)&PLL_MODE_MSK(pll_id)))\
20                 &&!(cru_readl(PLL_CONS(pll_id,3))&PLL_BYPASS))
21
22
23
24 static const struct apll_clk_set apll_table[] = {
25 };
26
27 static const struct pll_clk_set pll_com_table[] = {
28         _PLL_SET_CLKS(1200000,  1,      50,     1),
29         _PLL_SET_CLKS(1188000,  2,      99,     1),
30         _PLL_SET_CLKS(891000,   8,      594,    2),
31         _PLL_SET_CLKS(768000,   1,      64,     2),
32         _PLL_SET_CLKS(594000,   2,      198,    4),
33         _PLL_SET_CLKS(408000,   1,      68,     4),
34         _PLL_SET_CLKS(384000,   2,      128,    4),
35         _PLL_SET_CLKS(360000,   1,      60,     4),
36         _PLL_SET_CLKS(300000,   1,      50,     4),
37         _PLL_SET_CLKS(297000,   2,      198,    8),
38         _PLL_SET_CLKS(148500,   2,      99,     8),
39         _PLL_SET_CLKS(0,        0,      0,      0),
40 };
41
42 /*recalc_rate*/
43 static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
44                 unsigned long parent_rate)
45 {
46         struct clk_pll *pll = to_clk_pll(hw);
47         u8 pll_id = pll->id;
48         unsigned long rate;
49
50         if (PLLS_IN_NORM(pll_id)) {
51                 u32 pll_con0 = cru_readl(PLL_CONS(pll_id, 0));
52                 u32 pll_con1 = cru_readl(PLL_CONS(pll_id, 1));
53
54                 u64 rate64 = (u64)parent_rate * PLL_NF(pll_con1);
55
56                 do_div(rate64, PLL_NR(pll_con0));
57                 do_div(rate64, PLL_NO(pll_con0));
58
59                 rate = rate64;
60         } else {
61                 rate = parent_rate;
62                 clk_debug("pll id=%d  by pass mode\n", pll_id);
63         }
64
65         clk_debug("pll id=%d, recalc rate =%lu\n", pll->id, rate);
66
67         return rate;
68 }
69
70 /*round_rate*/
71 /*get rate that is most close to target*/
72 static const struct pll_clk_set *pll_clk_get_best_set(unsigned long rate,
73                 const struct pll_clk_set *table)
74 {
75         const struct pll_clk_set *ps, *pt;
76
77         ps = pt = table;
78         while (pt->rate) {
79                 if (pt->rate == rate) {
80                         ps = pt;
81                         break;
82                 }
83
84                 if ((pt->rate > rate || (rate - pt->rate < ps->rate - rate)))
85                         ps = pt;
86                 if (pt->rate < rate)
87                         break;
88                 pt++;
89         }
90
91         return ps;
92 }
93
94 static long clk_apll_round_rate(struct clk_hw *hw, unsigned long rate,
95                 unsigned long *prate)
96 {
97         return rate;
98 }
99
100 static long clk_pll_com_round_rate(struct clk_hw *hw, unsigned long rate,
101                 unsigned long *prate)
102 {
103         return (pll_clk_get_best_set(rate, pll_com_table)->rate);
104 }
105
106 static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
107                 unsigned long *prate)
108 {
109         struct clk_pll *pll = to_clk_pll(hw);
110         long rate_out = 0;
111
112         switch (pll->id){
113                 case APLL_ID: {
114                                       rate_out = clk_apll_round_rate(hw, rate, prate);
115                                       break;
116                               }
117                 default: {
118                                  rate_out = clk_pll_com_round_rate(hw, rate, prate);
119                                  break;
120                          }
121         }
122
123         return rate_out;
124 }
125
126 /*set_rate*/
127 static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
128                 unsigned long parent_rate)
129 {
130         return 0;
131 }
132
133 static int clk_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
134                 unsigned long parent_rate)
135 {
136         return 0;
137 }
138
139 static int clk_gpll_set_rate(struct clk_hw *hw, unsigned long rate,
140                 unsigned long parent_rate)
141 {
142         return 0;
143 }
144
145 static int clk_pll_com_set_rate(struct clk_hw *hw, unsigned long rate,
146                 unsigned long parent_rate)
147 {
148         return 0;
149 }
150
151 static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
152                 unsigned long parent_rate)
153 {
154         struct clk_pll *pll = to_clk_pll(hw);
155         int ret = 0;
156
157         switch (pll->id){
158                 case APLL_ID: {
159                                       ret = clk_apll_set_rate(hw, rate, parent_rate);
160                                       break;
161                               }
162                 case DPLL_ID: {
163                                       ret = clk_dpll_set_rate(hw, rate, parent_rate);
164                                       break;
165                               }
166                 case GPLL_ID: {
167                                       ret = clk_gpll_set_rate(hw, rate, parent_rate);
168                                       break;
169                               }
170                 default: {
171                                  ret = clk_pll_com_set_rate(hw, rate, parent_rate);
172                                  break;
173                          }
174         }
175
176         return ret;
177 }
178
179 const struct clk_ops clk_pll_ops = {
180         .recalc_rate = clk_pll_recalc_rate,
181         .round_rate = clk_pll_round_rate,
182         .set_rate = clk_pll_set_rate,
183 };
184
185 EXPORT_SYMBOL_GPL(clk_pll_ops);
186
187
188 struct clk *rk_clk_register_pll(struct device *dev, const char *name,
189                 const char *parent_name, unsigned long flags, void __iomem *reg,
190                 u32 width, u8 id, spinlock_t *lock)
191 {
192         struct clk_pll *pll;
193         struct clk *clk;
194         struct clk_init_data init;
195
196
197         clk_debug("%s: pll name = %s, id = %d, register start!\n",__func__,name,id);
198
199 #if 0
200         if(id >= END_PLL_ID){
201                 clk_err("%s: PLL id = %d >= END_PLL_ID = %d\n", __func__,
202                                 id, END_PLL_ID);
203                 return ERR_PTR(-EINVAL);
204         }
205 #endif
206
207         /* allocate the pll */
208         pll = kzalloc(sizeof(struct clk_pll), GFP_KERNEL);
209         if (!pll) {
210                 clk_err("%s: could not allocate pll clk\n", __func__);
211                 return ERR_PTR(-ENOMEM);
212         }
213
214         init.name = name;
215         init.flags = flags;
216         init.parent_names = (parent_name ? &parent_name: NULL);
217         init.num_parents = (parent_name ? 1 : 0);
218         init.ops = &clk_pll_ops;
219
220         /* struct clk_pll assignments */
221         pll->reg = reg;
222         pll->width = width;
223         pll->id = id;
224         pll->lock = lock;
225         pll->hw.init = &init;
226
227         /* register the clock */
228         clk = clk_register(dev, &pll->hw);
229
230         if (IS_ERR(clk))
231                 kfree(pll);
232
233         clk_debug("%s: pll name = %s, id = %d, register finish!\n",__func__,name,id);
234
235         return clk;
236 }
237