Merge branch 'sh-latest' of git://github.com/pmundt/linux-sh
[pandora-kernel.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 #include <asm/div64.h>
16
17 #define PLL35XX_MDIV_MASK       (0x3FF)
18 #define PLL35XX_PDIV_MASK       (0x3F)
19 #define PLL35XX_SDIV_MASK       (0x7)
20 #define PLL35XX_MDIV_SHIFT      (16)
21 #define PLL35XX_PDIV_SHIFT      (8)
22 #define PLL35XX_SDIV_SHIFT      (0)
23
24 static inline unsigned long s5p_get_pll35xx(unsigned long baseclk, u32 pll_con)
25 {
26         u32 mdiv, pdiv, sdiv;
27         u64 fvco = baseclk;
28
29         mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
30         pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
31         sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
32
33         fvco *= mdiv;
34         do_div(fvco, (pdiv << sdiv));
35
36         return (unsigned long)fvco;
37 }
38
39 #define PLL36XX_KDIV_MASK       (0xFFFF)
40 #define PLL36XX_MDIV_MASK       (0x1FF)
41 #define PLL36XX_PDIV_MASK       (0x3F)
42 #define PLL36XX_SDIV_MASK       (0x7)
43 #define PLL36XX_MDIV_SHIFT      (16)
44 #define PLL36XX_PDIV_SHIFT      (8)
45 #define PLL36XX_SDIV_SHIFT      (0)
46
47 static inline unsigned long s5p_get_pll36xx(unsigned long baseclk,
48                                             u32 pll_con0, u32 pll_con1)
49 {
50         unsigned long result;
51         u32 mdiv, pdiv, sdiv, kdiv;
52         u64 tmp;
53
54         mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
55         pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
56         sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
57         kdiv = pll_con1 & PLL36XX_KDIV_MASK;
58
59         tmp = baseclk;
60
61         tmp *= (mdiv << 16) + kdiv;
62         do_div(tmp, (pdiv << sdiv));
63         result = tmp >> 16;
64
65         return result;
66 }
67
68 #define PLL45XX_MDIV_MASK       (0x3FF)
69 #define PLL45XX_PDIV_MASK       (0x3F)
70 #define PLL45XX_SDIV_MASK       (0x7)
71 #define PLL45XX_MDIV_SHIFT      (16)
72 #define PLL45XX_PDIV_SHIFT      (8)
73 #define PLL45XX_SDIV_SHIFT      (0)
74
75 enum pll45xx_type_t {
76         pll_4500,
77         pll_4502,
78         pll_4508
79 };
80
81 static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
82                                             enum pll45xx_type_t pll_type)
83 {
84         u32 mdiv, pdiv, sdiv;
85         u64 fvco = baseclk;
86
87         mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
88         pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
89         sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
90
91         if (pll_type == pll_4508)
92                 sdiv = sdiv - 1;
93
94         fvco *= mdiv;
95         do_div(fvco, (pdiv << sdiv));
96
97         return (unsigned long)fvco;
98 }
99
100 #define PLL46XX_KDIV_MASK       (0xFFFF)
101 #define PLL4650C_KDIV_MASK      (0xFFF)
102 #define PLL46XX_MDIV_MASK       (0x1FF)
103 #define PLL46XX_PDIV_MASK       (0x3F)
104 #define PLL46XX_SDIV_MASK       (0x7)
105 #define PLL46XX_MDIV_SHIFT      (16)
106 #define PLL46XX_PDIV_SHIFT      (8)
107 #define PLL46XX_SDIV_SHIFT      (0)
108
109 enum pll46xx_type_t {
110         pll_4600,
111         pll_4650,
112         pll_4650c,
113 };
114
115 static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
116                                             u32 pll_con0, u32 pll_con1,
117                                             enum pll46xx_type_t pll_type)
118 {
119         unsigned long result;
120         u32 mdiv, pdiv, sdiv, kdiv;
121         u64 tmp;
122
123         mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
124         pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
125         sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
126
127         if (pll_type == pll_4650c)
128                 kdiv = pll_con1 & PLL4650C_KDIV_MASK;
129         else
130                 kdiv = pll_con1 & PLL46XX_KDIV_MASK;
131
132         tmp = baseclk;
133
134         if (pll_type == pll_4600) {
135                 tmp *= (mdiv << 16) + kdiv;
136                 do_div(tmp, (pdiv << sdiv));
137                 result = tmp >> 16;
138         } else {
139                 tmp *= (mdiv << 10) + kdiv;
140                 do_div(tmp, (pdiv << sdiv));
141                 result = tmp >> 10;
142         }
143
144         return result;
145 }
146
147 #define PLL90XX_MDIV_MASK       (0xFF)
148 #define PLL90XX_PDIV_MASK       (0x3F)
149 #define PLL90XX_SDIV_MASK       (0x7)
150 #define PLL90XX_KDIV_MASK       (0xffff)
151 #define PLL90XX_MDIV_SHIFT      (16)
152 #define PLL90XX_PDIV_SHIFT      (8)
153 #define PLL90XX_SDIV_SHIFT      (0)
154 #define PLL90XX_KDIV_SHIFT      (0)
155
156 static inline unsigned long s5p_get_pll90xx(unsigned long baseclk,
157                                             u32 pll_con, u32 pll_conk)
158 {
159         unsigned long result;
160         u32 mdiv, pdiv, sdiv, kdiv;
161         u64 tmp;
162
163         mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
164         pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
165         sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
166         kdiv = pll_conk & PLL90XX_KDIV_MASK;
167
168         /* We need to multiple baseclk by mdiv (the integer part) and kdiv
169          * which is in 2^16ths, so shift mdiv up (does not overflow) and
170          * add kdiv before multiplying. The use of tmp is to avoid any
171          * overflows before shifting bac down into result when multipling
172          * by the mdiv and kdiv pair.
173          */
174
175         tmp = baseclk;
176         tmp *= (mdiv << 16) + kdiv;
177         do_div(tmp, (pdiv << sdiv));
178         result = tmp >> 16;
179
180         return result;
181 }
182
183 #define PLL65XX_MDIV_MASK       (0x3FF)
184 #define PLL65XX_PDIV_MASK       (0x3F)
185 #define PLL65XX_SDIV_MASK       (0x7)
186 #define PLL65XX_MDIV_SHIFT      (16)
187 #define PLL65XX_PDIV_SHIFT      (8)
188 #define PLL65XX_SDIV_SHIFT      (0)
189
190 static inline unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con)
191 {
192         u32 mdiv, pdiv, sdiv;
193         u64 fvco = baseclk;
194
195         mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK;
196         pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK;
197         sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK;
198
199         fvco *= mdiv;
200         do_div(fvco, (pdiv << sdiv));
201
202         return (unsigned long)fvco;
203 }