1 /* 2 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 3 * Copyright (c) 2013 Linaro Ltd. 4 * 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. 8 * 9 * This file contains the utility functions to register the pll clocks. 10 */ 11 12 #include <linux/errno.h> 13 #include "clk.h" 14 #include "clk-pll.h" 15 16 /* 17 * PLL35xx Clock Type 18 */ 19 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) 26 27 struct samsung_clk_pll35xx { 28 struct clk_hw hw; 29 const void __iomem *con_reg; 30 }; 31 32 #define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw) 33 34 static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, 35 unsigned long parent_rate) 36 { 37 struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw); 38 u32 mdiv, pdiv, sdiv, pll_con; 39 u64 fvco = parent_rate; 40 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; 45 46 fvco *= mdiv; 47 do_div(fvco, (pdiv << sdiv)); 48 49 return (unsigned long)fvco; 50 } 51 52 static const struct clk_ops samsung_pll35xx_clk_ops = { 53 .recalc_rate = samsung_pll35xx_recalc_rate, 54 }; 55 56 struct clk * __init samsung_clk_register_pll35xx(const char *name, 57 const char *pname, const void __iomem *con_reg) 58 { 59 struct samsung_clk_pll35xx *pll; 60 struct clk *clk; 61 struct clk_init_data init; 62 63 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 64 if (!pll) { 65 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 66 return NULL; 67 } 68 69 init.name = name; 70 init.ops = &samsung_pll35xx_clk_ops; 71 init.flags = CLK_GET_RATE_NOCACHE; 72 init.parent_names = &pname; 73 init.num_parents = 1; 74 75 pll->hw.init = &init; 76 pll->con_reg = con_reg; 77 78 clk = clk_register(NULL, &pll->hw); 79 if (IS_ERR(clk)) { 80 pr_err("%s: failed to register pll clock %s\n", __func__, 81 name); 82 kfree(pll); 83 } 84 85 if (clk_register_clkdev(clk, name, NULL)) 86 pr_err("%s: failed to register lookup for %s", __func__, name); 87 88 return clk; 89 } 90 91 /* 92 * PLL36xx Clock Type 93 */ 94 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) 102 103 struct samsung_clk_pll36xx { 104 struct clk_hw hw; 105 const void __iomem *con_reg; 106 }; 107 108 #define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw) 109 110 static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, 111 unsigned long parent_rate) 112 { 113 struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw); 114 u32 mdiv, pdiv, sdiv, pll_con0, pll_con1; 115 s16 kdiv; 116 u64 fvco = parent_rate; 117 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); 124 125 fvco *= (mdiv << 16) + kdiv; 126 do_div(fvco, (pdiv << sdiv)); 127 fvco >>= 16; 128 129 return (unsigned long)fvco; 130 } 131 132 static const struct clk_ops samsung_pll36xx_clk_ops = { 133 .recalc_rate = samsung_pll36xx_recalc_rate, 134 }; 135 136 struct clk * __init samsung_clk_register_pll36xx(const char *name, 137 const char *pname, const void __iomem *con_reg) 138 { 139 struct samsung_clk_pll36xx *pll; 140 struct clk *clk; 141 struct clk_init_data init; 142 143 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 144 if (!pll) { 145 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 146 return NULL; 147 } 148 149 init.name = 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; 154 155 pll->hw.init = &init; 156 pll->con_reg = con_reg; 157 158 clk = clk_register(NULL, &pll->hw); 159 if (IS_ERR(clk)) { 160 pr_err("%s: failed to register pll clock %s\n", __func__, 161 name); 162 kfree(pll); 163 } 164 165 if (clk_register_clkdev(clk, name, NULL)) 166 pr_err("%s: failed to register lookup for %s", __func__, name); 167 168 return clk; 169 } 170 171 /* 172 * PLL45xx Clock Type 173 */ 174 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) 181 182 struct samsung_clk_pll45xx { 183 struct clk_hw hw; 184 enum pll45xx_type type; 185 const void __iomem *con_reg; 186 }; 187 188 #define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw) 189 190 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, 191 unsigned long parent_rate) 192 { 193 struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw); 194 u32 mdiv, pdiv, sdiv, pll_con; 195 u64 fvco = parent_rate; 196 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; 201 202 if (pll->type == pll_4508) 203 sdiv = sdiv - 1; 204 205 fvco *= mdiv; 206 do_div(fvco, (pdiv << sdiv)); 207 208 return (unsigned long)fvco; 209 } 210 211 static const struct clk_ops samsung_pll45xx_clk_ops = { 212 .recalc_rate = samsung_pll45xx_recalc_rate, 213 }; 214 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) 218 { 219 struct samsung_clk_pll45xx *pll; 220 struct clk *clk; 221 struct clk_init_data init; 222 223 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 224 if (!pll) { 225 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 226 return NULL; 227 } 228 229 init.name = 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; 234 235 pll->hw.init = &init; 236 pll->con_reg = con_reg; 237 pll->type = type; 238 239 clk = clk_register(NULL, &pll->hw); 240 if (IS_ERR(clk)) { 241 pr_err("%s: failed to register pll clock %s\n", __func__, 242 name); 243 kfree(pll); 244 } 245 246 if (clk_register_clkdev(clk, name, NULL)) 247 pr_err("%s: failed to register lookup for %s", __func__, name); 248 249 return clk; 250 } 251 252 /* 253 * PLL46xx Clock Type 254 */ 255 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) 262 263 #define PLL46XX_KDIV_MASK (0xFFFF) 264 #define PLL4650C_KDIV_MASK (0xFFF) 265 #define PLL46XX_KDIV_SHIFT (0) 266 267 struct samsung_clk_pll46xx { 268 struct clk_hw hw; 269 enum pll46xx_type type; 270 const void __iomem *con_reg; 271 }; 272 273 #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw) 274 275 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw, 276 unsigned long parent_rate) 277 { 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; 281 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; 289 290 shift = pll->type == pll_4600 ? 16 : 10; 291 fvco *= (mdiv << shift) + kdiv; 292 do_div(fvco, (pdiv << sdiv)); 293 fvco >>= shift; 294 295 return (unsigned long)fvco; 296 } 297 298 static const struct clk_ops samsung_pll46xx_clk_ops = { 299 .recalc_rate = samsung_pll46xx_recalc_rate, 300 }; 301 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) 305 { 306 struct samsung_clk_pll46xx *pll; 307 struct clk *clk; 308 struct clk_init_data init; 309 310 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 311 if (!pll) { 312 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 313 return NULL; 314 } 315 316 init.name = 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; 321 322 pll->hw.init = &init; 323 pll->con_reg = con_reg; 324 pll->type = type; 325 326 clk = clk_register(NULL, &pll->hw); 327 if (IS_ERR(clk)) { 328 pr_err("%s: failed to register pll clock %s\n", __func__, 329 name); 330 kfree(pll); 331 } 332 333 if (clk_register_clkdev(clk, name, NULL)) 334 pr_err("%s: failed to register lookup for %s", __func__, name); 335 336 return clk; 337 } 338 339 /* 340 * PLL2550x Clock Type 341 */ 342 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) 351 352 struct samsung_clk_pll2550x { 353 struct clk_hw hw; 354 const void __iomem *reg_base; 355 unsigned long offset; 356 }; 357 358 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw) 359 360 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw, 361 unsigned long parent_rate) 362 { 363 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw); 364 u32 r, p, m, s, pll_stat; 365 u64 fvco = parent_rate; 366 367 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3); 368 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK; 369 if (!r) 370 return 0; 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; 374 375 fvco *= m; 376 do_div(fvco, (p << s)); 377 378 return (unsigned long)fvco; 379 } 380 381 static const struct clk_ops samsung_pll2550x_clk_ops = { 382 .recalc_rate = samsung_pll2550x_recalc_rate, 383 }; 384 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) 388 { 389 struct samsung_clk_pll2550x *pll; 390 struct clk *clk; 391 struct clk_init_data init; 392 393 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 394 if (!pll) { 395 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 396 return NULL; 397 } 398 399 init.name = 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; 404 405 pll->hw.init = &init; 406 pll->reg_base = reg_base; 407 pll->offset = offset; 408 409 clk = clk_register(NULL, &pll->hw); 410 if (IS_ERR(clk)) { 411 pr_err("%s: failed to register pll clock %s\n", __func__, 412 name); 413 kfree(pll); 414 } 415 416 if (clk_register_clkdev(clk, name, NULL)) 417 pr_err("%s: failed to register lookup for %s", __func__, name); 418 419 return clk; 420 } 421