Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
s5p-clock.c
Go to the documentation of this file.
1 /*
2  * Copyright 2009 Samsung Electronics Co., Ltd.
3  * http://www.samsung.com/
4  *
5  * S5P - Common clock support
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10 */
11 
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/list.h>
16 #include <linux/errno.h>
17 #include <linux/err.h>
18 #include <linux/clk.h>
19 #include <linux/device.h>
20 #include <linux/io.h>
21 #include <asm/div64.h>
22 
23 #include <mach/regs-clock.h>
24 
25 #include <plat/clock.h>
26 #include <plat/clock-clksrc.h>
27 #include <plat/s5p-clock.h>
28 
29 /* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
30  * clk_ext_xtal_mux.
31 */
33  .name = "ext_xtal",
34  .id = -1,
35 };
36 
37 struct clk clk_xusbxti = {
38  .name = "xusbxti",
39  .id = -1,
40  .rate = 24000000,
41 };
42 
43 struct clk s5p_clk_27m = {
44  .name = "clk_27m",
45  .id = -1,
46  .rate = 27000000,
47 };
48 
49 /* 48MHz USB Phy clock output */
50 struct clk clk_48m = {
51  .name = "clk_48m",
52  .id = -1,
53  .rate = 48000000,
54 };
55 
56 /* APLL clock output
57  * No need .ctrlbit, this is always on
58 */
59 struct clk clk_fout_apll = {
60  .name = "fout_apll",
61  .id = -1,
62 };
63 
64 /* BPLL clock output */
65 
66 struct clk clk_fout_bpll = {
67  .name = "fout_bpll",
68  .id = -1,
69 };
70 
72  .name = "fout_bpll_div2",
73  .id = -1,
74 };
75 
76 /* CPLL clock output */
77 
78 struct clk clk_fout_cpll = {
79  .name = "fout_cpll",
80  .id = -1,
81 };
82 
83 /* MPLL clock output
84  * No need .ctrlbit, this is always on
85 */
86 struct clk clk_fout_mpll = {
87  .name = "fout_mpll",
88  .id = -1,
89 };
90 
92  .name = "fout_mpll_div2",
93  .id = -1,
94 };
95 
96 /* EPLL clock output */
97 struct clk clk_fout_epll = {
98  .name = "fout_epll",
99  .id = -1,
100  .ctrlbit = (1 << 31),
101 };
102 
103 /* DPLL clock output */
104 struct clk clk_fout_dpll = {
105  .name = "fout_dpll",
106  .id = -1,
107  .ctrlbit = (1 << 31),
108 };
109 
110 /* VPLL clock output */
111 struct clk clk_fout_vpll = {
112  .name = "fout_vpll",
113  .id = -1,
114  .ctrlbit = (1 << 31),
115 };
116 
117 /* Possible clock sources for APLL Mux */
118 static struct clk *clk_src_apll_list[] = {
119  [0] = &clk_fin_apll,
120  [1] = &clk_fout_apll,
121 };
122 
124  .sources = clk_src_apll_list,
125  .nr_sources = ARRAY_SIZE(clk_src_apll_list),
126 };
127 
128 /* Possible clock sources for BPLL Mux */
129 static struct clk *clk_src_bpll_list[] = {
130  [0] = &clk_fin_bpll,
131  [1] = &clk_fout_bpll,
132 };
133 
135  .sources = clk_src_bpll_list,
136  .nr_sources = ARRAY_SIZE(clk_src_bpll_list),
137 };
138 
139 static struct clk *clk_src_bpll_fout_list[] = {
140  [0] = &clk_fout_bpll_div2,
141  [1] = &clk_fout_bpll,
142 };
143 
145  .sources = clk_src_bpll_fout_list,
146  .nr_sources = ARRAY_SIZE(clk_src_bpll_fout_list),
147 };
148 
149 /* Possible clock sources for CPLL Mux */
150 static struct clk *clk_src_cpll_list[] = {
151  [0] = &clk_fin_cpll,
152  [1] = &clk_fout_cpll,
153 };
154 
156  .sources = clk_src_cpll_list,
157  .nr_sources = ARRAY_SIZE(clk_src_cpll_list),
158 };
159 
160 /* Possible clock sources for MPLL Mux */
161 static struct clk *clk_src_mpll_list[] = {
162  [0] = &clk_fin_mpll,
163  [1] = &clk_fout_mpll,
164 };
165 
167  .sources = clk_src_mpll_list,
168  .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
169 };
170 
171 static struct clk *clk_src_mpll_fout_list[] = {
172  [0] = &clk_fout_mpll_div2,
173  [1] = &clk_fout_mpll,
174 };
175 
177  .sources = clk_src_mpll_fout_list,
178  .nr_sources = ARRAY_SIZE(clk_src_mpll_fout_list),
179 };
180 
181 /* Possible clock sources for EPLL Mux */
182 static struct clk *clk_src_epll_list[] = {
183  [0] = &clk_fin_epll,
184  [1] = &clk_fout_epll,
185 };
186 
188  .sources = clk_src_epll_list,
189  .nr_sources = ARRAY_SIZE(clk_src_epll_list),
190 };
191 
192 /* Possible clock sources for DPLL Mux */
193 static struct clk *clk_src_dpll_list[] = {
194  [0] = &clk_fin_dpll,
195  [1] = &clk_fout_dpll,
196 };
197 
199  .sources = clk_src_dpll_list,
200  .nr_sources = ARRAY_SIZE(clk_src_dpll_list),
201 };
202 
203 struct clk clk_vpll = {
204  .name = "vpll",
205  .id = -1,
206 };
207 
208 int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable)
209 {
210  unsigned int ctrlbit = clk->ctrlbit;
211  u32 con;
212 
213  con = __raw_readl(reg);
214  con = enable ? (con | ctrlbit) : (con & ~ctrlbit);
215  __raw_writel(con, reg);
216  return 0;
217 }
218 
219 int s5p_epll_enable(struct clk *clk, int enable)
220 {
221  unsigned int ctrlbit = clk->ctrlbit;
222  unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
223 
224  if (enable)
225  __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
226  else
227  __raw_writel(epll_con, S5P_EPLL_CON);
228 
229  return 0;
230 }
231 
232 unsigned long s5p_epll_get_rate(struct clk *clk)
233 {
234  return clk->rate;
235 }
236 
237 int s5p_spdif_set_rate(struct clk *clk, unsigned long rate)
238 {
239  struct clk *pclk;
240  int ret;
241 
242  pclk = clk_get_parent(clk);
243  if (IS_ERR(pclk))
244  return -EINVAL;
245 
246  ret = pclk->ops->set_rate(pclk, rate);
247  clk_put(pclk);
248 
249  return ret;
250 }
251 
252 unsigned long s5p_spdif_get_rate(struct clk *clk)
253 {
254  struct clk *pclk;
255  int rate;
256 
257  pclk = clk_get_parent(clk);
258  if (IS_ERR(pclk))
259  return -EINVAL;
260 
261  rate = pclk->ops->get_rate(pclk);
262  clk_put(pclk);
263 
264  return rate;
265 }
266 
268  .set_rate = s5p_spdif_set_rate,
269  .get_rate = s5p_spdif_get_rate,
270 };
271 
272 static struct clk *s5p_clks[] __initdata = {
273  &clk_ext_xtal_mux,
274  &clk_48m,
275  &s5p_clk_27m,
276  &clk_fout_apll,
277  &clk_fout_mpll,
278  &clk_fout_epll,
279  &clk_fout_dpll,
280  &clk_fout_vpll,
281  &clk_vpll,
282  &clk_xusbxti,
283 };
284 
285 void __init s5p_register_clocks(unsigned long xtal_freq)
286 {
287  int ret;
288 
289  clk_ext_xtal_mux.rate = xtal_freq;
290 
291  ret = s3c24xx_register_clocks(s5p_clks, ARRAY_SIZE(s5p_clks));
292  if (ret > 0)
293  printk(KERN_ERR "Failed to register s5p clocks\n");
294 }