2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * Copyright (c) 2013 Linaro Ltd.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This file contains the utility functions to register the pll clocks.
12 #include <linux/errno.h>
20 #define PLL35XX_MDIV_MASK (0x3FF)
21 #define PLL35XX_PDIV_MASK (0x3F)
22 #define PLL35XX_SDIV_MASK (0x7)
23 #define PLL35XX_MDIV_SHIFT (16)
24 #define PLL35XX_PDIV_SHIFT (8)
25 #define PLL35XX_SDIV_SHIFT (0)
27 struct samsung_clk_pll35xx {
29 const void __iomem *con_reg;
32 #define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw)
34 static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
35 unsigned long parent_rate)
37 struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw);
38 u32 mdiv, pdiv, sdiv, pll_con;
39 u64 fvco = parent_rate;
41 pll_con = __raw_readl(pll->con_reg);
42 mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
43 pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
44 sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
47 do_div(fvco, (pdiv << sdiv));
49 return (unsigned long)fvco;
52 static const struct clk_ops samsung_pll35xx_clk_ops = {
53 .recalc_rate = samsung_pll35xx_recalc_rate,
56 struct clk * __init samsung_clk_register_pll35xx(const char *name,
57 const char *pname, const void __iomem *con_reg)
59 struct samsung_clk_pll35xx *pll;
61 struct clk_init_data init;
63 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
65 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
70 init.ops = &samsung_pll35xx_clk_ops;
71 init.flags = CLK_GET_RATE_NOCACHE;
72 init.parent_names = &pname;
76 pll->con_reg = con_reg;
78 clk = clk_register(NULL, &pll->hw);
80 pr_err("%s: failed to register pll clock %s\n", __func__,
85 if (clk_register_clkdev(clk, name, NULL))
86 pr_err("%s: failed to register lookup for %s", __func__, name);
95 #define PLL36XX_KDIV_MASK (0xFFFF)
96 #define PLL36XX_MDIV_MASK (0x1FF)
97 #define PLL36XX_PDIV_MASK (0x3F)
98 #define PLL36XX_SDIV_MASK (0x7)
99 #define PLL36XX_MDIV_SHIFT (16)
100 #define PLL36XX_PDIV_SHIFT (8)
101 #define PLL36XX_SDIV_SHIFT (0)
103 struct samsung_clk_pll36xx {
105 const void __iomem *con_reg;
108 #define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw)
110 static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
111 unsigned long parent_rate)
113 struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw);
114 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
115 u64 fvco = parent_rate;
117 pll_con0 = __raw_readl(pll->con_reg);
118 pll_con1 = __raw_readl(pll->con_reg + 4);
119 mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
120 pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
121 sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
122 kdiv = pll_con1 & PLL36XX_KDIV_MASK;
124 fvco *= (mdiv << 16) + kdiv;
125 do_div(fvco, (pdiv << sdiv));
128 return (unsigned long)fvco;
131 static const struct clk_ops samsung_pll36xx_clk_ops = {
132 .recalc_rate = samsung_pll36xx_recalc_rate,
135 struct clk * __init samsung_clk_register_pll36xx(const char *name,
136 const char *pname, const void __iomem *con_reg)
138 struct samsung_clk_pll36xx *pll;
140 struct clk_init_data init;
142 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
144 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
149 init.ops = &samsung_pll36xx_clk_ops;
150 init.flags = CLK_GET_RATE_NOCACHE;
151 init.parent_names = &pname;
152 init.num_parents = 1;
154 pll->hw.init = &init;
155 pll->con_reg = con_reg;
157 clk = clk_register(NULL, &pll->hw);
159 pr_err("%s: failed to register pll clock %s\n", __func__,
164 if (clk_register_clkdev(clk, name, NULL))
165 pr_err("%s: failed to register lookup for %s", __func__, name);
174 #define PLL45XX_MDIV_MASK (0x3FF)
175 #define PLL45XX_PDIV_MASK (0x3F)
176 #define PLL45XX_SDIV_MASK (0x7)
177 #define PLL45XX_MDIV_SHIFT (16)
178 #define PLL45XX_PDIV_SHIFT (8)
179 #define PLL45XX_SDIV_SHIFT (0)
181 struct samsung_clk_pll45xx {
183 enum pll45xx_type type;
184 const void __iomem *con_reg;
187 #define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
189 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
190 unsigned long parent_rate)
192 struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
193 u32 mdiv, pdiv, sdiv, pll_con;
194 u64 fvco = parent_rate;
196 pll_con = __raw_readl(pll->con_reg);
197 mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
198 pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
199 sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
201 if (pll->type == pll_4508)
205 do_div(fvco, (pdiv << sdiv));
207 return (unsigned long)fvco;
210 static const struct clk_ops samsung_pll45xx_clk_ops = {
211 .recalc_rate = samsung_pll45xx_recalc_rate,
214 struct clk * __init samsung_clk_register_pll45xx(const char *name,
215 const char *pname, const void __iomem *con_reg,
216 enum pll45xx_type type)
218 struct samsung_clk_pll45xx *pll;
220 struct clk_init_data init;
222 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
224 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
229 init.ops = &samsung_pll45xx_clk_ops;
230 init.flags = CLK_GET_RATE_NOCACHE;
231 init.parent_names = &pname;
232 init.num_parents = 1;
234 pll->hw.init = &init;
235 pll->con_reg = con_reg;
238 clk = clk_register(NULL, &pll->hw);
240 pr_err("%s: failed to register pll clock %s\n", __func__,
245 if (clk_register_clkdev(clk, name, NULL))
246 pr_err("%s: failed to register lookup for %s", __func__, name);
255 #define PLL46XX_MDIV_MASK (0x1FF)
256 #define PLL46XX_PDIV_MASK (0x3F)
257 #define PLL46XX_SDIV_MASK (0x7)
258 #define PLL46XX_MDIV_SHIFT (16)
259 #define PLL46XX_PDIV_SHIFT (8)
260 #define PLL46XX_SDIV_SHIFT (0)
262 #define PLL46XX_KDIV_MASK (0xFFFF)
263 #define PLL4650C_KDIV_MASK (0xFFF)
264 #define PLL46XX_KDIV_SHIFT (0)
266 struct samsung_clk_pll46xx {
268 enum pll46xx_type type;
269 const void __iomem *con_reg;
272 #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
274 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
275 unsigned long parent_rate)
277 struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
278 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
279 u64 fvco = parent_rate;
281 pll_con0 = __raw_readl(pll->con_reg);
282 pll_con1 = __raw_readl(pll->con_reg + 4);
283 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
284 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
285 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
286 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
287 pll_con1 & PLL46XX_KDIV_MASK;
289 shift = pll->type == pll_4600 ? 16 : 10;
290 fvco *= (mdiv << shift) + kdiv;
291 do_div(fvco, (pdiv << sdiv));
294 return (unsigned long)fvco;
297 static const struct clk_ops samsung_pll46xx_clk_ops = {
298 .recalc_rate = samsung_pll46xx_recalc_rate,
301 struct clk * __init samsung_clk_register_pll46xx(const char *name,
302 const char *pname, const void __iomem *con_reg,
303 enum pll46xx_type type)
305 struct samsung_clk_pll46xx *pll;
307 struct clk_init_data init;
309 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
311 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
316 init.ops = &samsung_pll46xx_clk_ops;
317 init.flags = CLK_GET_RATE_NOCACHE;
318 init.parent_names = &pname;
319 init.num_parents = 1;
321 pll->hw.init = &init;
322 pll->con_reg = con_reg;
325 clk = clk_register(NULL, &pll->hw);
327 pr_err("%s: failed to register pll clock %s\n", __func__,
332 if (clk_register_clkdev(clk, name, NULL))
333 pr_err("%s: failed to register lookup for %s", __func__, name);
339 * PLL2550x Clock Type
342 #define PLL2550X_R_MASK (0x1)
343 #define PLL2550X_P_MASK (0x3F)
344 #define PLL2550X_M_MASK (0x3FF)
345 #define PLL2550X_S_MASK (0x7)
346 #define PLL2550X_R_SHIFT (20)
347 #define PLL2550X_P_SHIFT (14)
348 #define PLL2550X_M_SHIFT (4)
349 #define PLL2550X_S_SHIFT (0)
351 struct samsung_clk_pll2550x {
353 const void __iomem *reg_base;
354 unsigned long offset;
357 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
359 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
360 unsigned long parent_rate)
362 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
363 u32 r, p, m, s, pll_stat;
364 u64 fvco = parent_rate;
366 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
367 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
370 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
371 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
372 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
375 do_div(fvco, (p << s));
377 return (unsigned long)fvco;
380 static const struct clk_ops samsung_pll2550x_clk_ops = {
381 .recalc_rate = samsung_pll2550x_recalc_rate,
384 struct clk * __init samsung_clk_register_pll2550x(const char *name,
385 const char *pname, const void __iomem *reg_base,
386 const unsigned long offset)
388 struct samsung_clk_pll2550x *pll;
390 struct clk_init_data init;
392 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
394 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
399 init.ops = &samsung_pll2550x_clk_ops;
400 init.flags = CLK_GET_RATE_NOCACHE;
401 init.parent_names = &pname;
402 init.num_parents = 1;
404 pll->hw.init = &init;
405 pll->reg_base = reg_base;
406 pll->offset = offset;
408 clk = clk_register(NULL, &pll->hw);
410 pr_err("%s: failed to register pll clock %s\n", __func__,
415 if (clk_register_clkdev(clk, name, NULL))
416 pr_err("%s: failed to register lookup for %s", __func__, name);