rk312x: correct clk_ddr rate
[firefly-linux-kernel-4.4.55.git] / drivers / clk / rockchip / clk-ops.c
1 #include <linux/clk.h>
2 #include <linux/clkdev.h>
3 #include <linux/io.h>
4 #include <linux/clk-provider.h>
5 #include <linux/of.h>
6 #include <linux/of_address.h>
7 #include <linux/clk-private.h>
8 #include <linux/delay.h>
9 #include <linux/rockchip/common.h>
10
11 #include "clk-ops.h"
12
13 /* mux_ops */
14 struct clk_ops_table rk_clk_mux_ops_table[] = {
15         {.index = CLKOPS_TABLE_END},
16 };
17
18
19 /* rate_ops */
20 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
21 #define div_mask(d)     ((1 << ((d)->width)) - 1)
22
23 static u32 clk_gcd(u32 numerator, u32 denominator)
24 {
25         u32 a, b;
26
27         if (!numerator || !denominator)
28                 return 0;
29         if (numerator > denominator) {
30                 a = numerator;
31                 b = denominator;
32         } else {
33                 a = denominator;
34                 b = numerator;
35         }
36         while (b != 0) {
37                 int r = b;
38                 b = a % b;
39                 a = r;
40         }
41
42         return a;
43 }
44
45 static int clk_fracdiv_get_config(unsigned long rate_out, unsigned long rate,
46                 u32 *numerator, u32 *denominator)
47 {
48         u32 gcd_val;
49         gcd_val = clk_gcd(rate, rate_out);
50         clk_debug("%s: frac_get_seting rate=%lu, parent=%lu, gcd=%d\n",
51                         __func__, rate_out, rate, gcd_val);
52
53         if (!gcd_val) {
54                 clk_err("gcd=0, frac div is not be supported\n");
55                 return -EINVAL;
56         }
57
58         *numerator = rate_out / gcd_val;
59         *denominator = rate / gcd_val;
60
61         clk_debug("%s: frac_get_seting numerator=%d, denominator=%d, times=%d\n",
62                         __func__, *numerator, *denominator,
63                         *denominator / *numerator);
64
65         if (*numerator > 0xffff || *denominator > 0xffff ||
66                         (*denominator / (*numerator)) < 20) {
67                 clk_err("can't get a available nume and deno\n");
68                 return -EINVAL;
69         }
70
71         return 0;
72
73 }
74
75 static int clk_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
76                 unsigned long parent_rate)
77 {
78         u32 numerator, denominator;
79         struct clk_divider *div = to_clk_divider(hw);
80
81
82         if(clk_fracdiv_get_config(rate, parent_rate,
83                                 &numerator, &denominator) == 0) {
84                 writel(numerator << 16 | denominator, div->reg);
85                 clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate);
86         } else {
87                 clk_err("clk_frac_div name=%s can't get rate=%lu\n",
88                                 hw->clk->name, rate);
89                 return -EINVAL;
90         }
91
92         return 0;
93 }
94
95 static unsigned long clk_fracdiv_recalc(struct clk_hw *hw,
96                 unsigned long parent_rate)
97 {
98         unsigned long rate;
99         u64 rate64;
100         struct clk_divider *div = to_clk_divider(hw);
101         u32 numerator, denominator, reg_val;
102
103         reg_val = readl(div->reg);
104         if (reg_val == 0)
105                 return parent_rate;
106
107         numerator = reg_val >> 16;
108         denominator = reg_val & 0xFFFF;
109         rate64 = (u64)parent_rate * numerator;
110         do_div(rate64, denominator);
111         rate = rate64;
112         clk_debug("%s: %s new clock rate is %lu, prate %lu (frac %u/%u)\n",
113                         __func__, hw->clk->name, rate, parent_rate,
114                         numerator, denominator);
115         return rate;
116 }
117
118 static long clk_fracdiv_round_rate(struct clk_hw *hw, unsigned long rate,
119                 unsigned long *prate)
120 {
121         struct clk *clk = hw->clk;
122         struct clk *parent = clk->parent;
123         long rate_out;
124
125         //FIXME: now just simply return rate
126         /*
127          *frac_div request a big input rate, and its parent is always a div,
128          *so we set parent->parent->rate as best_parent_rate.
129          */
130         rate_out = rate;
131         *prate = parent->parent->rate;
132
133         return rate_out;
134 }
135
136 static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
137                 unsigned long parent_rate)
138 {
139         return clk_divider_ops.recalc_rate(hw, parent_rate);
140 }
141
142 static long clk_divider_round_rate(struct clk_hw *hw,
143                 unsigned long rate, unsigned long *prate)
144 {
145         return clk_divider_ops.round_rate(hw, rate, prate);
146 }
147
148 static int clk_divider_set_rate(struct clk_hw *hw,
149                 unsigned long rate, unsigned long parent_rate)
150 {
151         return clk_divider_ops.set_rate(hw, rate, parent_rate);
152 }
153
154 static long clk_mux_with_div_determine_rate(struct clk_hw *div_hw, unsigned long rate,
155                 unsigned long *best_parent_rate,
156                 struct clk **best_parent_p)
157 {
158         struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
159         int i, num_parents;
160         unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
161
162
163         parent = __clk_get_parent(clk);
164         if(!parent){
165                 best = __clk_get_rate(clk);
166                 goto out;
167         }
168
169         /* if NO_REPARENT flag set, pass through to current parent */
170         if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
171                 best_prate = __clk_get_rate(parent);
172                 best = clk_divider_ops.round_rate(div_hw, rate, &best_prate);
173                 goto out;
174         }
175
176         /* find the parent that can provide the fastest rate <= rate */
177         num_parents = clk->num_parents;
178         for (i = 0; i < num_parents; i++) {
179                 parent = clk_get_parent_by_index(clk, i);
180                 if (!parent)
181                         continue;
182
183                 parent_rate = __clk_get_rate(parent);
184                 now = clk_divider_ops.round_rate(div_hw, rate, &parent_rate);
185
186                 if (now <= rate && now > best) {
187                         best_parent = parent;
188                         best_prate = parent_rate;
189                         best = now;
190                 }
191         }
192
193 out:
194         if(best_prate)
195                 *best_parent_rate = best_prate;
196
197         if (best_parent)
198                 *best_parent_p = best_parent;
199
200         clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
201                         "\tbest_parent name = %s, best_prate = %lu\n",
202                         clk->name, rate, best,
203                         __clk_get_name(*best_parent_p), *best_parent_rate);
204
205         return best;
206 }
207
208 const struct clk_ops clkops_rate_auto_parent = {
209         .recalc_rate    = clk_divider_recalc_rate,
210         .round_rate     = clk_divider_round_rate,
211         .set_rate       = clk_divider_set_rate,
212         .determine_rate = clk_mux_with_div_determine_rate,
213 };
214
215 static long clk_div_round_rate_even(struct clk_hw *hw, unsigned long rate,
216                 unsigned long *prate)
217 {
218         int i = 0;
219         struct clk_divider *divider =to_clk_divider(hw);
220         int max_div = 1 << divider->width;
221
222         for (i = 1; i <= max_div; i++) {
223                 if (i > 1 && (i % 2 != 0))
224                         continue;
225                 if (rate >= (*prate / i))
226                         return *prate / i;
227         }
228
229         return (*prate / max_div);
230 }
231
232 const struct clk_ops clkops_rate_evendiv = {
233         .recalc_rate    = clk_divider_recalc_rate,
234         .round_rate     = clk_div_round_rate_even,
235         .set_rate       = clk_divider_set_rate,
236 };
237
238 static long clk_mux_with_evendiv_determine_rate(struct clk_hw *div_hw, unsigned long rate,
239                 unsigned long *best_parent_rate,
240                 struct clk **best_parent_p)
241 {
242         struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
243         int i, num_parents;
244         unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
245
246
247         parent = __clk_get_parent(clk);
248         if(!parent){
249                 best = __clk_get_rate(clk);
250                 goto out;
251         }
252
253         /* if NO_REPARENT flag set, pass through to current parent */
254         if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
255                 best_prate = __clk_get_rate(parent);
256                 best = clk_div_round_rate_even(div_hw, rate, &best_prate);
257                 goto out;
258         }
259
260         /* find the parent that can provide the fastest rate <= rate */
261         num_parents = clk->num_parents;
262         for (i = 0; i < num_parents; i++) {
263                 parent = clk_get_parent_by_index(clk, i);
264                 if (!parent)
265                         continue;
266
267                 parent_rate = __clk_get_rate(parent);
268                 now = clk_div_round_rate_even(div_hw, rate, &parent_rate);
269
270                 if (now <= rate && now > best) {
271                         best_parent = parent;
272                         best_prate = parent_rate;
273                         best = now;
274                 }
275         }
276
277 out:
278         if(best_prate)
279                 *best_parent_rate = best_prate;
280
281         if (best_parent)
282                 *best_parent_p = best_parent;
283
284         clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
285                         "\tbest_parent name = %s, best_prate = %lu\n",
286                         clk->name, rate, best,
287                         __clk_get_name(*best_parent_p), *best_parent_rate);
288
289         return best;
290 }
291
292 static long clk_mux_with_evendiv_round_rate(struct clk_hw *hw, unsigned long rate,
293                 unsigned long *prate)
294 {
295         return clk_div_round_rate_even(hw, rate, prate);
296 }
297
298 const struct clk_ops clkops_rate_mux_with_evendiv = {
299         .recalc_rate    = clk_divider_recalc_rate,
300         .set_rate       = clk_divider_set_rate,
301         .round_rate     = clk_mux_with_evendiv_round_rate,
302         .determine_rate = clk_mux_with_evendiv_determine_rate,
303 };
304
305 static int clk_i2s_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
306                 unsigned long parent_rate)
307 {
308         u32 numerator, denominator;
309         struct clk_divider *div = to_clk_divider(hw);
310         int i = 10;
311
312
313         if(clk_fracdiv_get_config(rate, parent_rate,
314                                 &numerator, &denominator) == 0) {
315                 while (i--) {
316                         writel((numerator - 1) << 16 | denominator, div->reg);
317                         mdelay(1);
318                         writel(numerator << 16 | denominator, div->reg);
319                         mdelay(1);
320                 }
321                 clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate);
322         } else {
323                 clk_err("clk_frac_div name=%s can't get rate=%lu\n",
324                                 hw->clk->name, rate);
325                 return -EINVAL;
326         }
327
328         return 0;
329 }
330
331 const struct clk_ops clkops_rate_frac = {
332         .recalc_rate    = clk_fracdiv_recalc,
333         .round_rate     = clk_fracdiv_round_rate,
334         .set_rate       = clk_fracdiv_set_rate,
335 };
336
337 const struct clk_ops clkops_rate_i2s_frac = {
338         .recalc_rate    = clk_fracdiv_recalc,
339         .round_rate     = clk_fracdiv_round_rate,
340         .set_rate       = clk_i2s_fracdiv_set_rate,
341 };
342
343 static unsigned long clk_core_recalc_rate(struct clk_hw *hw,
344                 unsigned long parent_rate)
345 {
346         /* As parent rate could be changed in clk_core.set_rate
347          * ops, the passing_in parent_rate may not be the newest
348          * and we should use the parent->rate instead. As a side
349          * effect, we should NOT directly set clk_core's parent
350          * (apll) rate, otherwise we will get a wrong recalc rate
351          * with clk_core_recalc_rate.
352          */
353         struct clk *parent = __clk_get_parent(hw->clk);
354
355         return clk_divider_recalc_rate(hw, __clk_get_rate(parent));
356 }
357
358 static long clk_core_determine_rate(struct clk_hw *hw, unsigned long rate,
359                 unsigned long *best_parent_rate,
360                 struct clk **best_parent_p)
361 {
362         struct clk *parent = __clk_get_parent(hw->clk);
363
364         if (IS_ERR_OR_NULL(parent)) {
365                 clk_err("fail to get parent!\n");
366                 return 0;
367         }
368
369         return clk_round_rate(parent, rate);
370 }
371
372 static long clk_core_round_rate(struct clk_hw *hw, unsigned long rate,
373                 unsigned long *prate)
374 {
375         return clk_core_determine_rate(hw, rate, prate, NULL);
376 }
377
378 static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate,
379                 unsigned long parent_rate)
380 {
381         struct clk *parent = __clk_get_parent(hw->clk);
382         struct clk *grand_p = __clk_get_parent(parent);
383         int ret;
384
385         if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
386                 clk_err("fail to get parent or grand_parent!\n");
387                 return -EINVAL;
388         }
389
390         ret = parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
391         parent->rate = parent->ops->recalc_rate(parent->hw,
392                         __clk_get_rate(grand_p));
393
394         return ret;
395 }
396
397 const struct clk_ops clkops_rate_core = {
398         .recalc_rate    = clk_core_recalc_rate,
399         .round_rate     = clk_core_round_rate,
400         .set_rate       = clk_core_set_rate,
401         .determine_rate = clk_core_determine_rate,
402 };
403
404 /* Clk_ops for the child clk of clk_core, for example core_periph in rk3188 */
405 const struct clk_ops clkops_rate_core_peri = {
406         .recalc_rate    = clk_divider_recalc_rate,
407         .round_rate     = clk_divider_round_rate,
408         .set_rate       = NULL,
409 };
410
411 static unsigned long clk_ddr_recalc_rate(struct clk_hw *hw,
412                 unsigned long parent_rate)
413 {
414         /* Same as clk_core, we should NOT set clk_ddr's parent
415          * (dpll) rate directly as a side effect.
416          */
417         return clk_core_recalc_rate(hw, parent_rate);
418 }
419
420 static long clk_ddr_determine_rate(struct clk_hw *hw, unsigned long rate,
421                 unsigned long *best_parent_rate,
422                 struct clk **best_parent_p)
423 {
424         long best = 0;
425
426         if (!ddr_round_rate) {
427                 /* Do nothing before ddr init */
428                 best = rate;//__clk_get_rate(hw->clk);
429         } else {
430                 /* Func provided by ddr driver */
431                 best = ddr_round_rate(rate/MHZ) * MHZ;
432         }
433
434         clk_debug("%s: from %lu to %lu\n", __func__, rate, best);
435
436         return best;
437 }
438
439 static long clk_ddr_round_rate(struct clk_hw *hw, unsigned long rate,
440                 unsigned long *prate)
441 {
442         return clk_ddr_determine_rate(hw, rate, prate, NULL);
443 }
444
445 static int clk_ddr_set_rate(struct clk_hw *hw, unsigned long rate,
446                 unsigned long parent_rate)
447 {
448         struct clk *parent = __clk_get_parent(hw->clk);
449         struct clk *grand_p = __clk_get_parent(parent);
450
451
452         /* Do nothing before ddr init */
453         if (!ddr_change_freq)
454                 return 0;
455
456         if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
457                 clk_err("fail to get parent or grand_parent!\n");
458                 return -EINVAL;
459         }
460
461         clk_debug("%s: will set rate = %lu\n", __func__, rate);
462
463         /* Func provided by ddr driver */
464         ddr_change_freq(rate/MHZ);
465
466         parent->rate = parent->ops->recalc_rate(parent->hw,
467                         __clk_get_rate(grand_p));
468
469         return 0;
470 }
471
472 const struct clk_ops clkops_rate_ddr = {
473         .recalc_rate    = clk_ddr_recalc_rate,
474         .round_rate     = clk_ddr_round_rate,
475         .set_rate       = clk_ddr_set_rate,
476         .determine_rate = clk_ddr_determine_rate,
477 };
478
479 static unsigned long clk_ddr_div2_recalc_rate(struct clk_hw *hw,
480                                               unsigned long parent_rate)
481 {
482         /* Same as clk_core, we should NOT set clk_ddr's parent
483          * (dpll) rate directly as a side effect.
484          */
485         struct clk *parent = __clk_get_parent(hw->clk);
486
487         return clk_divider_recalc_rate(hw, __clk_get_rate(parent))/2;
488 }
489
490 const struct clk_ops clkops_rate_ddr_div2 = {
491         .recalc_rate    = clk_ddr_div2_recalc_rate,
492         .round_rate     = clk_ddr_round_rate,
493         .set_rate       = clk_ddr_set_rate,
494         .determine_rate = clk_ddr_determine_rate,
495 };
496
497 static unsigned long clk_3288_i2s_recalc_rate(struct clk_hw *hw,
498                 unsigned long parent_rate)
499 {
500         return parent_rate;
501 }
502
503 static long clk_3288_i2s_round_rate(struct clk_hw *hw, unsigned long rate,
504                 unsigned long *prate)
505 {
506         return rate;
507 }
508
509 static int clk_3288_i2s_set_rate(struct clk_hw *hw, unsigned long rate,
510                 unsigned long parent_rate)
511 {
512         struct clk *parent = __clk_get_parent(hw->clk);
513         struct clk *grand_p = __clk_get_parent(parent);
514
515
516         if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
517                 return 0;
518         }
519
520         if (parent->ops->set_rate) {
521                 parent->ops->set_rate(parent->hw, rate/2, __clk_get_rate(grand_p));
522                 parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
523         }
524
525         return 0;
526 }
527
528 const struct clk_ops clkops_rate_3288_i2s = {
529         .recalc_rate    = clk_3288_i2s_recalc_rate,
530         .round_rate     = clk_3288_i2s_round_rate,
531         .set_rate       = clk_3288_i2s_set_rate,
532 };
533
534 static bool usb480m_state = false;
535
536 static long clk_3288_usb480m_determine_rate(struct clk_hw *hw, unsigned long rate,
537                 unsigned long *best_parent_rate,
538                 struct clk **best_parent_p)
539 {
540         if(rate == 0)
541                 return 0;
542         else
543                 return 480*MHZ;
544 }
545
546 static long clk_3288_usb480m_round_rate(struct clk_hw *hw, unsigned long rate,
547                 unsigned long *prate)
548 {
549         return clk_3288_usb480m_determine_rate(hw, rate, prate, NULL);
550 }
551
552 static int clk_3288_usb480m_set_rate(struct clk_hw *hw, unsigned long rate,
553                 unsigned long parent_rate)
554 {
555         if(rate == 0)
556                 usb480m_state = false;
557         else
558                 usb480m_state = true;
559
560         return 0;
561 }
562
563 static unsigned long clk_3288_usb480m_recalc_rate(struct clk_hw *hw,
564                 unsigned long parent_rate)
565 {
566         if(usb480m_state)
567                 return 480*MHZ;
568         else
569                 return 0;
570 }
571
572 const struct clk_ops clkops_rate_3288_usb480m = {
573         .determine_rate = clk_3288_usb480m_determine_rate,
574         .set_rate       = clk_3288_usb480m_set_rate,
575         .round_rate     = clk_3288_usb480m_round_rate,
576         .recalc_rate    = clk_3288_usb480m_recalc_rate,
577 };
578
579 #define RK3288_LIMIT_PLL_VIO0 (410*MHZ)
580
581 static long clk_3288_dclk_lcdc0_determine_rate(struct clk_hw *hw, unsigned long rate,
582                 unsigned long *best_parent_rate,
583                 struct clk **best_parent_p)
584 {
585         struct clk *gpll = clk_get(NULL, "clk_gpll");
586         struct clk *cpll = clk_get(NULL, "clk_cpll");
587         unsigned long best, div, prate;
588
589
590         if((rate <= (297*MHZ)) && ((297*MHZ)%rate == 0)) {
591                 *best_parent_p = gpll;
592                 best = rate;
593                 *best_parent_rate = 297*MHZ;
594         } else {
595                 *best_parent_p = cpll;
596                 div = RK3288_LIMIT_PLL_VIO0/rate;
597                 prate = div * rate;
598                 *best_parent_rate = clk_round_rate(cpll, prate);
599                 best = (*best_parent_rate)/div; 
600         }
601
602         return best;
603 }
604
605 static long clk_3288_dclk_lcdc0_round_rate(struct clk_hw *hw, unsigned long rate,
606                 unsigned long *prate)
607 {
608         return clk_3288_dclk_lcdc0_determine_rate(hw, rate, prate, NULL);
609 }
610
611 static int clk_3288_dclk_lcdc0_set_rate(struct clk_hw *hw, unsigned long rate,
612                 unsigned long parent_rate)
613 {
614         struct clk* aclk_vio0 = clk_get(NULL, "aclk_vio0");
615         struct clk* hclk_vio = clk_get(NULL, "hclk_vio");
616         struct clk* parent;
617
618         clk_divider_ops.set_rate(hw, rate, parent_rate);
619
620         /* set aclk_vio */
621         if(parent_rate  == 297*MHZ)
622                 parent = clk_get(NULL, "clk_gpll");
623         else
624                 parent = clk_get(NULL, "clk_cpll");
625
626         clk_set_parent(aclk_vio0, parent);
627         clk_set_rate(aclk_vio0, __clk_get_rate(parent));
628         clk_set_rate(hclk_vio, 100*MHZ);
629
630         return 0;
631 }
632
633 const struct clk_ops clkops_rate_3288_dclk_lcdc0 = {
634         .determine_rate = clk_3288_dclk_lcdc0_determine_rate,
635         .set_rate       = clk_3288_dclk_lcdc0_set_rate,
636         .round_rate     = clk_3288_dclk_lcdc0_round_rate,
637         .recalc_rate    = clk_divider_recalc_rate,
638 };
639
640 #define RK3288_LIMIT_PLL_VIO1 (350*MHZ)
641
642 static long clk_3288_dclk_lcdc1_determine_rate(struct clk_hw *hw, unsigned long rate,
643                 unsigned long *best_parent_rate,
644                 struct clk **best_parent_p)
645 {
646         struct clk *gpll = clk_get(NULL, "clk_gpll");
647         struct clk *cpll = clk_get(NULL, "clk_cpll");
648         unsigned long best, div, prate;
649
650
651         if((rate <= (297*MHZ)) && ((297*MHZ)%rate == 0)) {
652                 *best_parent_p = gpll;
653                 best = rate;
654                 *best_parent_rate = 297*MHZ;
655         } else {
656                 *best_parent_p = cpll;
657                 div = RK3288_LIMIT_PLL_VIO1/rate;
658                 prate = div * rate;
659                 *best_parent_rate = clk_round_rate(cpll, prate);
660                 best = (*best_parent_rate)/div; 
661         }
662
663         return best;
664 }
665
666 static long clk_3288_dclk_lcdc1_round_rate(struct clk_hw *hw, unsigned long rate,
667                 unsigned long *prate)
668 {
669         return clk_3288_dclk_lcdc1_determine_rate(hw, rate, prate, NULL);
670 }
671
672 static int clk_3288_dclk_lcdc1_set_rate(struct clk_hw *hw, unsigned long rate,
673                 unsigned long parent_rate)
674 {
675         struct clk* aclk_vio1 = clk_get(NULL, "aclk_vio1");
676         struct clk* parent;
677
678         clk_divider_ops.set_rate(hw, rate, parent_rate);
679
680         /* set aclk_vio */
681         if(parent_rate  == 297*MHZ)
682                 parent = clk_get(NULL, "clk_gpll");
683         else
684                 parent = clk_get(NULL, "clk_cpll");
685
686         clk_set_parent(aclk_vio1, parent);
687         clk_set_rate(aclk_vio1, __clk_get_rate(parent));
688
689         return 0;
690 }
691
692 const struct clk_ops clkops_rate_3288_dclk_lcdc1 = {
693         .determine_rate = clk_3288_dclk_lcdc1_determine_rate,
694         .set_rate       = clk_3288_dclk_lcdc1_set_rate,
695         .round_rate     = clk_3288_dclk_lcdc1_round_rate,
696         .recalc_rate    = clk_divider_recalc_rate,
697 };
698
699
700 struct clk_ops_table rk_clkops_rate_table[] = {
701         {.index = CLKOPS_RATE_MUX_DIV,          .clk_ops = &clkops_rate_auto_parent},
702         {.index = CLKOPS_RATE_EVENDIV,          .clk_ops = &clkops_rate_evendiv},
703         {.index = CLKOPS_RATE_MUX_EVENDIV,      .clk_ops = &clkops_rate_mux_with_evendiv},
704         {.index = CLKOPS_RATE_I2S_FRAC,         .clk_ops = &clkops_rate_i2s_frac},
705         {.index = CLKOPS_RATE_FRAC,             .clk_ops = &clkops_rate_frac},
706         {.index = CLKOPS_RATE_CORE,             .clk_ops = &clkops_rate_core},
707         {.index = CLKOPS_RATE_CORE_CHILD,       .clk_ops = &clkops_rate_core_peri},
708         {.index = CLKOPS_RATE_DDR,              .clk_ops = &clkops_rate_ddr},
709         {.index = CLKOPS_RATE_RK3288_I2S,       .clk_ops = &clkops_rate_3288_i2s},
710         {.index = CLKOPS_RATE_RK3288_USB480M,   .clk_ops = &clkops_rate_3288_usb480m},
711         {.index = CLKOPS_RATE_RK3288_DCLK_LCDC0,.clk_ops = &clkops_rate_3288_dclk_lcdc0},
712         {.index = CLKOPS_RATE_RK3288_DCLK_LCDC1,.clk_ops = &clkops_rate_3288_dclk_lcdc1},
713         {.index = CLKOPS_RATE_DDR_DIV2, .clk_ops = &clkops_rate_ddr_div2},
714         {.index = CLKOPS_RATE_I2S,              .clk_ops = NULL},
715         {.index = CLKOPS_RATE_CIFOUT,           .clk_ops = NULL},
716         {.index = CLKOPS_RATE_UART,             .clk_ops = NULL},
717         {.index = CLKOPS_RATE_HSADC,            .clk_ops = NULL},
718         {.index = CLKOPS_RATE_MAC_REF,          .clk_ops = NULL},
719         {.index = CLKOPS_TABLE_END,             .clk_ops = NULL},
720 };
721
722 const struct clk_ops *rk_get_clkops(unsigned int idx)
723 {
724         int i = 0;
725         unsigned int now_idx;
726
727         while(1){
728                 now_idx = rk_clkops_rate_table[i].index;
729
730                 if ((now_idx == idx) || (now_idx == CLKOPS_TABLE_END))
731                         return rk_clkops_rate_table[i].clk_ops;
732
733                 i++;
734         }
735 }
736 EXPORT_SYMBOL_GPL(rk_get_clkops);