Merge branch 'stable/fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad...
[sfrench/cifs-2.6.git] / arch / arm / plat-s5p / include / plat / pll.h
1 /* arch/arm/plat-s5p/include/plat/pll.h
2  *
3  * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5P PLL code
7  *
8  * Based on arch/arm/plat-s3c64xx/include/plat/pll.h
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13 */
14
15 #define PLL45XX_MDIV_MASK       (0x3FF)
16 #define PLL45XX_PDIV_MASK       (0x3F)
17 #define PLL45XX_SDIV_MASK       (0x7)
18 #define PLL45XX_MDIV_SHIFT      (16)
19 #define PLL45XX_PDIV_SHIFT      (8)
20 #define PLL45XX_SDIV_SHIFT      (0)
21
22 #include <asm/div64.h>
23
24 enum pll45xx_type_t {
25         pll_4500,
26         pll_4502,
27         pll_4508
28 };
29
30 static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
31                                             enum pll45xx_type_t pll_type)
32 {
33         u32 mdiv, pdiv, sdiv;
34         u64 fvco = baseclk;
35
36         mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
37         pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
38         sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
39
40         if (pll_type == pll_4508)
41                 sdiv = sdiv - 1;
42
43         fvco *= mdiv;
44         do_div(fvco, (pdiv << sdiv));
45
46         return (unsigned long)fvco;
47 }
48
49 #define PLL46XX_KDIV_MASK       (0xFFFF)
50 #define PLL46XX_MDIV_MASK       (0x1FF)
51 #define PLL46XX_PDIV_MASK       (0x3F)
52 #define PLL46XX_SDIV_MASK       (0x7)
53 #define PLL46XX_MDIV_SHIFT      (16)
54 #define PLL46XX_PDIV_SHIFT      (8)
55 #define PLL46XX_SDIV_SHIFT      (0)
56
57 enum pll46xx_type_t {
58         pll_4600,
59         pll_4650,
60 };
61
62 static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
63                                             u32 pll_con0, u32 pll_con1,
64                                             enum pll46xx_type_t pll_type)
65 {
66         unsigned long result;
67         u32 mdiv, pdiv, sdiv, kdiv;
68         u64 tmp;
69
70         mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
71         pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
72         sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
73         kdiv = pll_con1 & PLL46XX_KDIV_MASK;
74
75         tmp = baseclk;
76
77         if (pll_type == pll_4600) {
78                 tmp *= (mdiv << 16) + kdiv;
79                 do_div(tmp, (pdiv << sdiv));
80                 result = tmp >> 16;
81         } else {
82                 tmp *= (mdiv << 10) + kdiv;
83                 do_div(tmp, (pdiv << sdiv));
84                 result = tmp >> 10;
85         }
86
87         return result;
88 }
89
90 #define PLL90XX_MDIV_MASK       (0xFF)
91 #define PLL90XX_PDIV_MASK       (0x3F)
92 #define PLL90XX_SDIV_MASK       (0x7)
93 #define PLL90XX_KDIV_MASK       (0xffff)
94 #define PLL90XX_MDIV_SHIFT      (16)
95 #define PLL90XX_PDIV_SHIFT      (8)
96 #define PLL90XX_SDIV_SHIFT      (0)
97 #define PLL90XX_KDIV_SHIFT      (0)
98
99 static inline unsigned long s5p_get_pll90xx(unsigned long baseclk,
100                                             u32 pll_con, u32 pll_conk)
101 {
102         unsigned long result;
103         u32 mdiv, pdiv, sdiv, kdiv;
104         u64 tmp;
105
106         mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
107         pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
108         sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
109         kdiv = pll_conk & PLL90XX_KDIV_MASK;
110
111         /* We need to multiple baseclk by mdiv (the integer part) and kdiv
112          * which is in 2^16ths, so shift mdiv up (does not overflow) and
113          * add kdiv before multiplying. The use of tmp is to avoid any
114          * overflows before shifting bac down into result when multipling
115          * by the mdiv and kdiv pair.
116          */
117
118         tmp = baseclk;
119         tmp *= (mdiv << 16) + kdiv;
120         do_div(tmp, (pdiv << sdiv));
121         result = tmp >> 16;
122
123         return result;
124 }
125
126 #define PLL65XX_MDIV_MASK       (0x3FF)
127 #define PLL65XX_PDIV_MASK       (0x3F)
128 #define PLL65XX_SDIV_MASK       (0x7)
129 #define PLL65XX_MDIV_SHIFT      (16)
130 #define PLL65XX_PDIV_SHIFT      (8)
131 #define PLL65XX_SDIV_SHIFT      (0)
132
133 static inline unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con)
134 {
135         u32 mdiv, pdiv, sdiv;
136         u64 fvco = baseclk;
137
138         mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK;
139         pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK;
140         sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK;
141
142         fvco *= mdiv;
143         do_div(fvco, (pdiv << sdiv));
144
145         return (unsigned long)fvco;
146 }