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, pll_con0, pll_con1;
116 u64 fvco = parent_rate;
118 pll_con0 = __raw_readl(pll->con_reg);
119 pll_con1 = __raw_readl(pll->con_reg + 4);
120 mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
121 pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
122 sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
123 kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
125 fvco *= (mdiv << 16) + kdiv;
126 do_div(fvco, (pdiv << sdiv));
129 return (unsigned long)fvco;
132 static const struct clk_ops samsung_pll36xx_clk_ops = {
133 .recalc_rate = samsung_pll36xx_recalc_rate,
136 struct clk * __init samsung_clk_register_pll36xx(const char *name,
137 const char *pname, const void __iomem *con_reg)
139 struct samsung_clk_pll36xx *pll;
141 struct clk_init_data init;
143 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
145 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
150 init.ops = &samsung_pll36xx_clk_ops;
151 init.flags = CLK_GET_RATE_NOCACHE;
152 init.parent_names = &pname;
153 init.num_parents = 1;
155 pll->hw.init = &init;
156 pll->con_reg = con_reg;
158 clk = clk_register(NULL, &pll->hw);
160 pr_err("%s: failed to register pll clock %s\n", __func__,
165 if (clk_register_clkdev(clk, name, NULL))
166 pr_err("%s: failed to register lookup for %s", __func__, name);
175 #define PLL45XX_MDIV_MASK (0x3FF)
176 #define PLL45XX_PDIV_MASK (0x3F)
177 #define PLL45XX_SDIV_MASK (0x7)
178 #define PLL45XX_MDIV_SHIFT (16)
179 #define PLL45XX_PDIV_SHIFT (8)
180 #define PLL45XX_SDIV_SHIFT (0)
182 struct samsung_clk_pll45xx {
184 enum pll45xx_type type;
185 const void __iomem *con_reg;
188 #define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
190 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
191 unsigned long parent_rate)
193 struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
194 u32 mdiv, pdiv, sdiv, pll_con;
195 u64 fvco = parent_rate;
197 pll_con = __raw_readl(pll->con_reg);
198 mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
199 pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
200 sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
202 if (pll->type == pll_4508)
206 do_div(fvco, (pdiv << sdiv));
208 return (unsigned long)fvco;
211 static const struct clk_ops samsung_pll45xx_clk_ops = {
212 .recalc_rate = samsung_pll45xx_recalc_rate,
215 struct clk * __init samsung_clk_register_pll45xx(const char *name,
216 const char *pname, const void __iomem *con_reg,
217 enum pll45xx_type type)
219 struct samsung_clk_pll45xx *pll;
221 struct clk_init_data init;
223 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
225 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
230 init.ops = &samsung_pll45xx_clk_ops;
231 init.flags = CLK_GET_RATE_NOCACHE;
232 init.parent_names = &pname;
233 init.num_parents = 1;
235 pll->hw.init = &init;
236 pll->con_reg = con_reg;
239 clk = clk_register(NULL, &pll->hw);
241 pr_err("%s: failed to register pll clock %s\n", __func__,
246 if (clk_register_clkdev(clk, name, NULL))
247 pr_err("%s: failed to register lookup for %s", __func__, name);
256 #define PLL46XX_MDIV_MASK (0x1FF)
257 #define PLL46XX_PDIV_MASK (0x3F)
258 #define PLL46XX_SDIV_MASK (0x7)
259 #define PLL46XX_MDIV_SHIFT (16)
260 #define PLL46XX_PDIV_SHIFT (8)
261 #define PLL46XX_SDIV_SHIFT (0)
263 #define PLL46XX_KDIV_MASK (0xFFFF)
264 #define PLL4650C_KDIV_MASK (0xFFF)
265 #define PLL46XX_KDIV_SHIFT (0)
267 struct samsung_clk_pll46xx {
269 enum pll46xx_type type;
270 const void __iomem *con_reg;
273 #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
275 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
276 unsigned long parent_rate)
278 struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
279 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
280 u64 fvco = parent_rate;
282 pll_con0 = __raw_readl(pll->con_reg);
283 pll_con1 = __raw_readl(pll->con_reg + 4);
284 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
285 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
286 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
287 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
288 pll_con1 & PLL46XX_KDIV_MASK;
290 shift = pll->type == pll_4600 ? 16 : 10;
291 fvco *= (mdiv << shift) + kdiv;
292 do_div(fvco, (pdiv << sdiv));
295 return (unsigned long)fvco;
298 static const struct clk_ops samsung_pll46xx_clk_ops = {
299 .recalc_rate = samsung_pll46xx_recalc_rate,
302 struct clk * __init samsung_clk_register_pll46xx(const char *name,
303 const char *pname, const void __iomem *con_reg,
304 enum pll46xx_type type)
306 struct samsung_clk_pll46xx *pll;
308 struct clk_init_data init;
310 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
312 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
317 init.ops = &samsung_pll46xx_clk_ops;
318 init.flags = CLK_GET_RATE_NOCACHE;
319 init.parent_names = &pname;
320 init.num_parents = 1;
322 pll->hw.init = &init;
323 pll->con_reg = con_reg;
326 clk = clk_register(NULL, &pll->hw);
328 pr_err("%s: failed to register pll clock %s\n", __func__,
333 if (clk_register_clkdev(clk, name, NULL))
334 pr_err("%s: failed to register lookup for %s", __func__, name);
340 * PLL2550x Clock Type
343 #define PLL2550X_R_MASK (0x1)
344 #define PLL2550X_P_MASK (0x3F)
345 #define PLL2550X_M_MASK (0x3FF)
346 #define PLL2550X_S_MASK (0x7)
347 #define PLL2550X_R_SHIFT (20)
348 #define PLL2550X_P_SHIFT (14)
349 #define PLL2550X_M_SHIFT (4)
350 #define PLL2550X_S_SHIFT (0)
352 struct samsung_clk_pll2550x {
354 const void __iomem *reg_base;
355 unsigned long offset;
358 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
360 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
361 unsigned long parent_rate)
363 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
364 u32 r, p, m, s, pll_stat;
365 u64 fvco = parent_rate;
367 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
368 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
371 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
372 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
373 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
376 do_div(fvco, (p << s));
378 return (unsigned long)fvco;
381 static const struct clk_ops samsung_pll2550x_clk_ops = {
382 .recalc_rate = samsung_pll2550x_recalc_rate,
385 struct clk * __init samsung_clk_register_pll2550x(const char *name,
386 const char *pname, const void __iomem *reg_base,
387 const unsigned long offset)
389 struct samsung_clk_pll2550x *pll;
391 struct clk_init_data init;
393 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
395 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
400 init.ops = &samsung_pll2550x_clk_ops;
401 init.flags = CLK_GET_RATE_NOCACHE;
402 init.parent_names = &pname;
403 init.num_parents = 1;
405 pll->hw.init = &init;
406 pll->reg_base = reg_base;
407 pll->offset = offset;
409 clk = clk_register(NULL, &pll->hw);
411 pr_err("%s: failed to register pll clock %s\n", __func__,
416 if (clk_register_clkdev(clk, name, NULL))
417 pr_err("%s: failed to register lookup for %s", __func__, name);