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, kdiv, pll_con0, pll_con1; 115 u64 fvco = parent_rate; 116 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; 123 124 fvco *= (mdiv << 16) + kdiv; 125 do_div(fvco, (pdiv << sdiv)); 126 fvco >>= 16; 127 128 return (unsigned long)fvco; 129 } 130 131 static const struct clk_ops samsung_pll36xx_clk_ops = { 132 .recalc_rate = samsung_pll36xx_recalc_rate, 133 }; 134 135 struct clk * __init samsung_clk_register_pll36xx(const char *name, 136 const char *pname, const void __iomem *con_reg) 137 { 138 struct samsung_clk_pll36xx *pll; 139 struct clk *clk; 140 struct clk_init_data init; 141 142 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 143 if (!pll) { 144 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 145 return NULL; 146 } 147 148 init.name = 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; 153 154 pll->hw.init = &init; 155 pll->con_reg = con_reg; 156 157 clk = clk_register(NULL, &pll->hw); 158 if (IS_ERR(clk)) { 159 pr_err("%s: failed to register pll clock %s\n", __func__, 160 name); 161 kfree(pll); 162 } 163 164 if (clk_register_clkdev(clk, name, NULL)) 165 pr_err("%s: failed to register lookup for %s", __func__, name); 166 167 return clk; 168 } 169 170 /* 171 * PLL45xx Clock Type 172 */ 173 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) 180 181 struct samsung_clk_pll45xx { 182 struct clk_hw hw; 183 enum pll45xx_type type; 184 const void __iomem *con_reg; 185 }; 186 187 #define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw) 188 189 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, 190 unsigned long parent_rate) 191 { 192 struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw); 193 u32 mdiv, pdiv, sdiv, pll_con; 194 u64 fvco = parent_rate; 195 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; 200 201 if (pll->type == pll_4508) 202 sdiv = sdiv - 1; 203 204 fvco *= mdiv; 205 do_div(fvco, (pdiv << sdiv)); 206 207 return (unsigned long)fvco; 208 } 209 210 static const struct clk_ops samsung_pll45xx_clk_ops = { 211 .recalc_rate = samsung_pll45xx_recalc_rate, 212 }; 213 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) 217 { 218 struct samsung_clk_pll45xx *pll; 219 struct clk *clk; 220 struct clk_init_data init; 221 222 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 223 if (!pll) { 224 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 225 return NULL; 226 } 227 228 init.name = 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; 233 234 pll->hw.init = &init; 235 pll->con_reg = con_reg; 236 pll->type = type; 237 238 clk = clk_register(NULL, &pll->hw); 239 if (IS_ERR(clk)) { 240 pr_err("%s: failed to register pll clock %s\n", __func__, 241 name); 242 kfree(pll); 243 } 244 245 if (clk_register_clkdev(clk, name, NULL)) 246 pr_err("%s: failed to register lookup for %s", __func__, name); 247 248 return clk; 249 } 250 251 /* 252 * PLL46xx Clock Type 253 */ 254 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) 261 262 #define PLL46XX_KDIV_MASK (0xFFFF) 263 #define PLL4650C_KDIV_MASK (0xFFF) 264 #define PLL46XX_KDIV_SHIFT (0) 265 266 struct samsung_clk_pll46xx { 267 struct clk_hw hw; 268 enum pll46xx_type type; 269 const void __iomem *con_reg; 270 }; 271 272 #define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw) 273 274 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw, 275 unsigned long parent_rate) 276 { 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; 280 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; 288 289 shift = pll->type == pll_4600 ? 16 : 10; 290 fvco *= (mdiv << shift) + kdiv; 291 do_div(fvco, (pdiv << sdiv)); 292 fvco >>= shift; 293 294 return (unsigned long)fvco; 295 } 296 297 static const struct clk_ops samsung_pll46xx_clk_ops = { 298 .recalc_rate = samsung_pll46xx_recalc_rate, 299 }; 300 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) 304 { 305 struct samsung_clk_pll46xx *pll; 306 struct clk *clk; 307 struct clk_init_data init; 308 309 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 310 if (!pll) { 311 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 312 return NULL; 313 } 314 315 init.name = 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; 320 321 pll->hw.init = &init; 322 pll->con_reg = con_reg; 323 pll->type = type; 324 325 clk = clk_register(NULL, &pll->hw); 326 if (IS_ERR(clk)) { 327 pr_err("%s: failed to register pll clock %s\n", __func__, 328 name); 329 kfree(pll); 330 } 331 332 if (clk_register_clkdev(clk, name, NULL)) 333 pr_err("%s: failed to register lookup for %s", __func__, name); 334 335 return clk; 336 } 337 338 /* 339 * PLL2550x Clock Type 340 */ 341 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) 350 351 struct samsung_clk_pll2550x { 352 struct clk_hw hw; 353 const void __iomem *reg_base; 354 unsigned long offset; 355 }; 356 357 #define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw) 358 359 static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw, 360 unsigned long parent_rate) 361 { 362 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw); 363 u32 r, p, m, s, pll_stat; 364 u64 fvco = parent_rate; 365 366 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3); 367 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK; 368 if (!r) 369 return 0; 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; 373 374 fvco *= m; 375 do_div(fvco, (p << s)); 376 377 return (unsigned long)fvco; 378 } 379 380 static const struct clk_ops samsung_pll2550x_clk_ops = { 381 .recalc_rate = samsung_pll2550x_recalc_rate, 382 }; 383 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) 387 { 388 struct samsung_clk_pll2550x *pll; 389 struct clk *clk; 390 struct clk_init_data init; 391 392 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 393 if (!pll) { 394 pr_err("%s: could not allocate pll clk %s\n", __func__, name); 395 return NULL; 396 } 397 398 init.name = 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; 403 404 pll->hw.init = &init; 405 pll->reg_base = reg_base; 406 pll->offset = offset; 407 408 clk = clk_register(NULL, &pll->hw); 409 if (IS_ERR(clk)) { 410 pr_err("%s: failed to register pll clock %s\n", __func__, 411 name); 412 kfree(pll); 413 } 414 415 if (clk_register_clkdev(clk, name, NULL)) 416 pr_err("%s: failed to register lookup for %s", __func__, name); 417 418 return clk; 419 } 420