1 /* 2 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 3 * Copyright (c) 2013 Linaro Ltd. 4 * Author: Thomas Abraham <thomas.ab@samsung.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This file includes utility functions to register clocks to common 11 * clock framework for Samsung platforms. 12 */ 13 14 #include <linux/of_address.h> 15 #include <linux/syscore_ops.h> 16 17 #include "clk.h" 18 19 static LIST_HEAD(clock_reg_cache_list); 20 21 void samsung_clk_save(void __iomem *base, 22 struct samsung_clk_reg_dump *rd, 23 unsigned int num_regs) 24 { 25 for (; num_regs > 0; --num_regs, ++rd) 26 rd->value = readl(base + rd->offset); 27 } 28 29 void samsung_clk_restore(void __iomem *base, 30 const struct samsung_clk_reg_dump *rd, 31 unsigned int num_regs) 32 { 33 for (; num_regs > 0; --num_regs, ++rd) 34 writel(rd->value, base + rd->offset); 35 } 36 37 struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( 38 const unsigned long *rdump, 39 unsigned long nr_rdump) 40 { 41 struct samsung_clk_reg_dump *rd; 42 unsigned int i; 43 44 rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL); 45 if (!rd) 46 return NULL; 47 48 for (i = 0; i < nr_rdump; ++i) 49 rd[i].offset = rdump[i]; 50 51 return rd; 52 } 53 54 /* setup the essentials required to support clock lookup using ccf */ 55 struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np, 56 void __iomem *base, unsigned long nr_clks) 57 { 58 struct samsung_clk_provider *ctx; 59 struct clk **clk_table; 60 int i; 61 62 ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL); 63 if (!ctx) 64 panic("could not allocate clock provider context.\n"); 65 66 clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); 67 if (!clk_table) 68 panic("could not allocate clock lookup table\n"); 69 70 for (i = 0; i < nr_clks; ++i) 71 clk_table[i] = ERR_PTR(-ENOENT); 72 73 ctx->reg_base = base; 74 ctx->clk_data.clks = clk_table; 75 ctx->clk_data.clk_num = nr_clks; 76 spin_lock_init(&ctx->lock); 77 78 return ctx; 79 } 80 81 void __init samsung_clk_of_add_provider(struct device_node *np, 82 struct samsung_clk_provider *ctx) 83 { 84 if (np) { 85 if (of_clk_add_provider(np, of_clk_src_onecell_get, 86 &ctx->clk_data)) 87 panic("could not register clk provider\n"); 88 } 89 } 90 91 /* add a clock instance to the clock lookup table used for dt based lookup */ 92 void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk, 93 unsigned int id) 94 { 95 if (ctx->clk_data.clks && id) 96 ctx->clk_data.clks[id] = clk; 97 } 98 99 /* register a list of aliases */ 100 void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx, 101 struct samsung_clock_alias *list, 102 unsigned int nr_clk) 103 { 104 struct clk *clk; 105 unsigned int idx, ret; 106 107 if (!ctx->clk_data.clks) { 108 pr_err("%s: clock table missing\n", __func__); 109 return; 110 } 111 112 for (idx = 0; idx < nr_clk; idx++, list++) { 113 if (!list->id) { 114 pr_err("%s: clock id missing for index %d\n", __func__, 115 idx); 116 continue; 117 } 118 119 clk = ctx->clk_data.clks[list->id]; 120 if (!clk) { 121 pr_err("%s: failed to find clock %d\n", __func__, 122 list->id); 123 continue; 124 } 125 126 ret = clk_register_clkdev(clk, list->alias, list->dev_name); 127 if (ret) 128 pr_err("%s: failed to register lookup %s\n", 129 __func__, list->alias); 130 } 131 } 132 133 /* register a list of fixed clocks */ 134 void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx, 135 struct samsung_fixed_rate_clock *list, unsigned int nr_clk) 136 { 137 struct clk *clk; 138 unsigned int idx, ret; 139 140 for (idx = 0; idx < nr_clk; idx++, list++) { 141 clk = clk_register_fixed_rate(NULL, list->name, 142 list->parent_name, list->flags, list->fixed_rate); 143 if (IS_ERR(clk)) { 144 pr_err("%s: failed to register clock %s\n", __func__, 145 list->name); 146 continue; 147 } 148 149 samsung_clk_add_lookup(ctx, clk, list->id); 150 151 /* 152 * Unconditionally add a clock lookup for the fixed rate clocks. 153 * There are not many of these on any of Samsung platforms. 154 */ 155 ret = clk_register_clkdev(clk, list->name, NULL); 156 if (ret) 157 pr_err("%s: failed to register clock lookup for %s", 158 __func__, list->name); 159 } 160 } 161 162 /* register a list of fixed factor clocks */ 163 void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx, 164 struct samsung_fixed_factor_clock *list, unsigned int nr_clk) 165 { 166 struct clk *clk; 167 unsigned int idx; 168 169 for (idx = 0; idx < nr_clk; idx++, list++) { 170 clk = clk_register_fixed_factor(NULL, list->name, 171 list->parent_name, list->flags, list->mult, list->div); 172 if (IS_ERR(clk)) { 173 pr_err("%s: failed to register clock %s\n", __func__, 174 list->name); 175 continue; 176 } 177 178 samsung_clk_add_lookup(ctx, clk, list->id); 179 } 180 } 181 182 /* register a list of mux clocks */ 183 void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx, 184 struct samsung_mux_clock *list, 185 unsigned int nr_clk) 186 { 187 struct clk *clk; 188 unsigned int idx, ret; 189 190 for (idx = 0; idx < nr_clk; idx++, list++) { 191 clk = clk_register_mux(NULL, list->name, list->parent_names, 192 list->num_parents, list->flags, 193 ctx->reg_base + list->offset, 194 list->shift, list->width, list->mux_flags, &ctx->lock); 195 if (IS_ERR(clk)) { 196 pr_err("%s: failed to register clock %s\n", __func__, 197 list->name); 198 continue; 199 } 200 201 samsung_clk_add_lookup(ctx, clk, list->id); 202 203 /* register a clock lookup only if a clock alias is specified */ 204 if (list->alias) { 205 ret = clk_register_clkdev(clk, list->alias, 206 list->dev_name); 207 if (ret) 208 pr_err("%s: failed to register lookup %s\n", 209 __func__, list->alias); 210 } 211 } 212 } 213 214 /* register a list of div clocks */ 215 void __init samsung_clk_register_div(struct samsung_clk_provider *ctx, 216 struct samsung_div_clock *list, 217 unsigned int nr_clk) 218 { 219 struct clk *clk; 220 unsigned int idx, ret; 221 222 for (idx = 0; idx < nr_clk; idx++, list++) { 223 if (list->table) 224 clk = clk_register_divider_table(NULL, list->name, 225 list->parent_name, list->flags, 226 ctx->reg_base + list->offset, 227 list->shift, list->width, list->div_flags, 228 list->table, &ctx->lock); 229 else 230 clk = clk_register_divider(NULL, list->name, 231 list->parent_name, list->flags, 232 ctx->reg_base + list->offset, list->shift, 233 list->width, list->div_flags, &ctx->lock); 234 if (IS_ERR(clk)) { 235 pr_err("%s: failed to register clock %s\n", __func__, 236 list->name); 237 continue; 238 } 239 240 samsung_clk_add_lookup(ctx, clk, list->id); 241 242 /* register a clock lookup only if a clock alias is specified */ 243 if (list->alias) { 244 ret = clk_register_clkdev(clk, list->alias, 245 list->dev_name); 246 if (ret) 247 pr_err("%s: failed to register lookup %s\n", 248 __func__, list->alias); 249 } 250 } 251 } 252 253 /* register a list of gate clocks */ 254 void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, 255 struct samsung_gate_clock *list, 256 unsigned int nr_clk) 257 { 258 struct clk *clk; 259 unsigned int idx, ret; 260 261 for (idx = 0; idx < nr_clk; idx++, list++) { 262 clk = clk_register_gate(NULL, list->name, list->parent_name, 263 list->flags, ctx->reg_base + list->offset, 264 list->bit_idx, list->gate_flags, &ctx->lock); 265 if (IS_ERR(clk)) { 266 pr_err("%s: failed to register clock %s\n", __func__, 267 list->name); 268 continue; 269 } 270 271 /* register a clock lookup only if a clock alias is specified */ 272 if (list->alias) { 273 ret = clk_register_clkdev(clk, list->alias, 274 list->dev_name); 275 if (ret) 276 pr_err("%s: failed to register lookup %s\n", 277 __func__, list->alias); 278 } 279 280 samsung_clk_add_lookup(ctx, clk, list->id); 281 } 282 } 283 284 /* 285 * obtain the clock speed of all external fixed clock sources from device 286 * tree and register it 287 */ 288 void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx, 289 struct samsung_fixed_rate_clock *fixed_rate_clk, 290 unsigned int nr_fixed_rate_clk, 291 const struct of_device_id *clk_matches) 292 { 293 const struct of_device_id *match; 294 struct device_node *clk_np; 295 u32 freq; 296 297 for_each_matching_node_and_match(clk_np, clk_matches, &match) { 298 if (of_property_read_u32(clk_np, "clock-frequency", &freq)) 299 continue; 300 fixed_rate_clk[(unsigned long)match->data].fixed_rate = freq; 301 } 302 samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk); 303 } 304 305 /* utility function to get the rate of a specified clock */ 306 unsigned long _get_rate(const char *clk_name) 307 { 308 struct clk *clk; 309 310 clk = __clk_lookup(clk_name); 311 if (!clk) { 312 pr_err("%s: could not find clock %s\n", __func__, clk_name); 313 return 0; 314 } 315 316 return clk_get_rate(clk); 317 } 318 319 #ifdef CONFIG_PM_SLEEP 320 static int samsung_clk_suspend(void) 321 { 322 struct samsung_clock_reg_cache *reg_cache; 323 324 list_for_each_entry(reg_cache, &clock_reg_cache_list, node) 325 samsung_clk_save(reg_cache->reg_base, reg_cache->rdump, 326 reg_cache->rd_num); 327 return 0; 328 } 329 330 static void samsung_clk_resume(void) 331 { 332 struct samsung_clock_reg_cache *reg_cache; 333 334 list_for_each_entry(reg_cache, &clock_reg_cache_list, node) 335 samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump, 336 reg_cache->rd_num); 337 } 338 339 static struct syscore_ops samsung_clk_syscore_ops = { 340 .suspend = samsung_clk_suspend, 341 .resume = samsung_clk_resume, 342 }; 343 344 static void samsung_clk_sleep_init(void __iomem *reg_base, 345 const unsigned long *rdump, 346 unsigned long nr_rdump) 347 { 348 struct samsung_clock_reg_cache *reg_cache; 349 350 reg_cache = kzalloc(sizeof(struct samsung_clock_reg_cache), 351 GFP_KERNEL); 352 if (!reg_cache) 353 panic("could not allocate register reg_cache.\n"); 354 reg_cache->rdump = samsung_clk_alloc_reg_dump(rdump, nr_rdump); 355 356 if (!reg_cache->rdump) 357 panic("could not allocate register dump storage.\n"); 358 359 if (list_empty(&clock_reg_cache_list)) 360 register_syscore_ops(&samsung_clk_syscore_ops); 361 362 reg_cache->reg_base = reg_base; 363 reg_cache->rd_num = nr_rdump; 364 list_add_tail(®_cache->node, &clock_reg_cache_list); 365 } 366 367 #else 368 static void samsung_clk_sleep_init(void __iomem *reg_base, 369 const unsigned long *rdump, 370 unsigned long nr_rdump) {} 371 #endif 372 373 /* 374 * Common function which registers plls, muxes, dividers and gates 375 * for each CMU. It also add CMU register list to register cache. 376 */ 377 struct samsung_clk_provider * __init samsung_cmu_register_one( 378 struct device_node *np, 379 struct samsung_cmu_info *cmu) 380 { 381 void __iomem *reg_base; 382 struct samsung_clk_provider *ctx; 383 384 reg_base = of_iomap(np, 0); 385 if (!reg_base) { 386 panic("%s: failed to map registers\n", __func__); 387 return NULL; 388 } 389 390 ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids); 391 if (!ctx) { 392 panic("%s: unable to alllocate ctx\n", __func__); 393 return ctx; 394 } 395 396 if (cmu->pll_clks) 397 samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks, 398 reg_base); 399 if (cmu->mux_clks) 400 samsung_clk_register_mux(ctx, cmu->mux_clks, 401 cmu->nr_mux_clks); 402 if (cmu->div_clks) 403 samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks); 404 if (cmu->gate_clks) 405 samsung_clk_register_gate(ctx, cmu->gate_clks, 406 cmu->nr_gate_clks); 407 if (cmu->fixed_clks) 408 samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks, 409 cmu->nr_fixed_clks); 410 if (cmu->fixed_factor_clks) 411 samsung_clk_register_fixed_factor(ctx, cmu->fixed_factor_clks, 412 cmu->nr_fixed_factor_clks); 413 if (cmu->clk_regs) 414 samsung_clk_sleep_init(reg_base, cmu->clk_regs, 415 cmu->nr_clk_regs); 416 417 samsung_clk_of_add_provider(np, ctx); 418 419 return ctx; 420 } 421