root/drivers/sh/clk/cpg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sh_clk_read
  2. sh_clk_write
  3. r8
  4. r16
  5. r32
  6. sh_clk_mstp_enable
  7. sh_clk_mstp_disable
  8. sh_clk_mstp_register
  9. clk_to_div_table
  10. clk_to_div_mult_table
  11. sh_clk_div_round_rate
  12. sh_clk_div_recalc
  13. sh_clk_div_set_rate
  14. sh_clk_div_enable
  15. sh_clk_div_disable
  16. sh_clk_init_parent
  17. sh_clk_div_register_ops
  18. sh_clk_div6_set_parent
  19. sh_clk_div6_register
  20. sh_clk_div6_reparent_register
  21. sh_clk_div4_set_parent
  22. sh_clk_div4_register
  23. sh_clk_div4_enable_register
  24. sh_clk_div4_reparent_register
  25. fsidiv_recalc
  26. fsidiv_round_rate
  27. fsidiv_disable
  28. fsidiv_enable
  29. fsidiv_set_rate
  30. sh_clk_fsidiv_register

   1 /*
   2  * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
   3  *
   4  *  Copyright (C) 2010  Magnus Damm
   5  *  Copyright (C) 2010 - 2012  Paul Mundt
   6  *
   7  * This file is subject to the terms and conditions of the GNU General Public
   8  * License.  See the file "COPYING" in the main directory of this archive
   9  * for more details.
  10  */
  11 #include <linux/clk.h>
  12 #include <linux/compiler.h>
  13 #include <linux/slab.h>
  14 #include <linux/io.h>
  15 #include <linux/sh_clk.h>
  16 
  17 #define CPG_CKSTP_BIT   BIT(8)
  18 
  19 static unsigned int sh_clk_read(struct clk *clk)
  20 {
  21         if (clk->flags & CLK_ENABLE_REG_8BIT)
  22                 return ioread8(clk->mapped_reg);
  23         else if (clk->flags & CLK_ENABLE_REG_16BIT)
  24                 return ioread16(clk->mapped_reg);
  25 
  26         return ioread32(clk->mapped_reg);
  27 }
  28 
  29 static void sh_clk_write(int value, struct clk *clk)
  30 {
  31         if (clk->flags & CLK_ENABLE_REG_8BIT)
  32                 iowrite8(value, clk->mapped_reg);
  33         else if (clk->flags & CLK_ENABLE_REG_16BIT)
  34                 iowrite16(value, clk->mapped_reg);
  35         else
  36                 iowrite32(value, clk->mapped_reg);
  37 }
  38 
  39 static unsigned int r8(const void __iomem *addr)
  40 {
  41         return ioread8(addr);
  42 }
  43 
  44 static unsigned int r16(const void __iomem *addr)
  45 {
  46         return ioread16(addr);
  47 }
  48 
  49 static unsigned int r32(const void __iomem *addr)
  50 {
  51         return ioread32(addr);
  52 }
  53 
  54 static int sh_clk_mstp_enable(struct clk *clk)
  55 {
  56         sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
  57         if (clk->status_reg) {
  58                 unsigned int (*read)(const void __iomem *addr);
  59                 int i;
  60                 void __iomem *mapped_status = (phys_addr_t)clk->status_reg -
  61                         (phys_addr_t)clk->enable_reg + clk->mapped_reg;
  62 
  63                 if (clk->flags & CLK_ENABLE_REG_8BIT)
  64                         read = r8;
  65                 else if (clk->flags & CLK_ENABLE_REG_16BIT)
  66                         read = r16;
  67                 else
  68                         read = r32;
  69 
  70                 for (i = 1000;
  71                      (read(mapped_status) & (1 << clk->enable_bit)) && i;
  72                      i--)
  73                         cpu_relax();
  74                 if (!i) {
  75                         pr_err("cpg: failed to enable %p[%d]\n",
  76                                clk->enable_reg, clk->enable_bit);
  77                         return -ETIMEDOUT;
  78                 }
  79         }
  80         return 0;
  81 }
  82 
  83 static void sh_clk_mstp_disable(struct clk *clk)
  84 {
  85         sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
  86 }
  87 
  88 static struct sh_clk_ops sh_clk_mstp_clk_ops = {
  89         .enable         = sh_clk_mstp_enable,
  90         .disable        = sh_clk_mstp_disable,
  91         .recalc         = followparent_recalc,
  92 };
  93 
  94 int __init sh_clk_mstp_register(struct clk *clks, int nr)
  95 {
  96         struct clk *clkp;
  97         int ret = 0;
  98         int k;
  99 
 100         for (k = 0; !ret && (k < nr); k++) {
 101                 clkp = clks + k;
 102                 clkp->ops = &sh_clk_mstp_clk_ops;
 103                 ret |= clk_register(clkp);
 104         }
 105 
 106         return ret;
 107 }
 108 
 109 /*
 110  * Div/mult table lookup helpers
 111  */
 112 static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
 113 {
 114         return clk->priv;
 115 }
 116 
 117 static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
 118 {
 119         return clk_to_div_table(clk)->div_mult_table;
 120 }
 121 
 122 /*
 123  * Common div ops
 124  */
 125 static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
 126 {
 127         return clk_rate_table_round(clk, clk->freq_table, rate);
 128 }
 129 
 130 static unsigned long sh_clk_div_recalc(struct clk *clk)
 131 {
 132         struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
 133         unsigned int idx;
 134 
 135         clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
 136                              table, clk->arch_flags ? &clk->arch_flags : NULL);
 137 
 138         idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;
 139 
 140         return clk->freq_table[idx].frequency;
 141 }
 142 
 143 static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
 144 {
 145         struct clk_div_table *dt = clk_to_div_table(clk);
 146         unsigned long value;
 147         int idx;
 148 
 149         idx = clk_rate_table_find(clk, clk->freq_table, rate);
 150         if (idx < 0)
 151                 return idx;
 152 
 153         value = sh_clk_read(clk);
 154         value &= ~(clk->div_mask << clk->enable_bit);
 155         value |= (idx << clk->enable_bit);
 156         sh_clk_write(value, clk);
 157 
 158         /* XXX: Should use a post-change notifier */
 159         if (dt->kick)
 160                 dt->kick(clk);
 161 
 162         return 0;
 163 }
 164 
 165 static int sh_clk_div_enable(struct clk *clk)
 166 {
 167         if (clk->div_mask == SH_CLK_DIV6_MSK) {
 168                 int ret = sh_clk_div_set_rate(clk, clk->rate);
 169                 if (ret < 0)
 170                         return ret;
 171         }
 172 
 173         sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
 174         return 0;
 175 }
 176 
 177 static void sh_clk_div_disable(struct clk *clk)
 178 {
 179         unsigned int val;
 180 
 181         val = sh_clk_read(clk);
 182         val |= CPG_CKSTP_BIT;
 183 
 184         /*
 185          * div6 clocks require the divisor field to be non-zero or the
 186          * above CKSTP toggle silently fails. Ensure that the divisor
 187          * array is reset to its initial state on disable.
 188          */
 189         if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
 190                 val |= clk->div_mask;
 191 
 192         sh_clk_write(val, clk);
 193 }
 194 
 195 static struct sh_clk_ops sh_clk_div_clk_ops = {
 196         .recalc         = sh_clk_div_recalc,
 197         .set_rate       = sh_clk_div_set_rate,
 198         .round_rate     = sh_clk_div_round_rate,
 199 };
 200 
 201 static struct sh_clk_ops sh_clk_div_enable_clk_ops = {
 202         .recalc         = sh_clk_div_recalc,
 203         .set_rate       = sh_clk_div_set_rate,
 204         .round_rate     = sh_clk_div_round_rate,
 205         .enable         = sh_clk_div_enable,
 206         .disable        = sh_clk_div_disable,
 207 };
 208 
 209 static int __init sh_clk_init_parent(struct clk *clk)
 210 {
 211         u32 val;
 212 
 213         if (clk->parent)
 214                 return 0;
 215 
 216         if (!clk->parent_table || !clk->parent_num)
 217                 return 0;
 218 
 219         if (!clk->src_width) {
 220                 pr_err("sh_clk_init_parent: cannot select parent clock\n");
 221                 return -EINVAL;
 222         }
 223 
 224         val  = (sh_clk_read(clk) >> clk->src_shift);
 225         val &= (1 << clk->src_width) - 1;
 226 
 227         if (val >= clk->parent_num) {
 228                 pr_err("sh_clk_init_parent: parent table size failed\n");
 229                 return -EINVAL;
 230         }
 231 
 232         clk_reparent(clk, clk->parent_table[val]);
 233         if (!clk->parent) {
 234                 pr_err("sh_clk_init_parent: unable to set parent");
 235                 return -EINVAL;
 236         }
 237 
 238         return 0;
 239 }
 240 
 241 static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
 242                         struct clk_div_table *table, struct sh_clk_ops *ops)
 243 {
 244         struct clk *clkp;
 245         void *freq_table;
 246         int nr_divs = table->div_mult_table->nr_divisors;
 247         int freq_table_size = sizeof(struct cpufreq_frequency_table);
 248         int ret = 0;
 249         int k;
 250 
 251         freq_table_size *= (nr_divs + 1);
 252         freq_table = kcalloc(nr, freq_table_size, GFP_KERNEL);
 253         if (!freq_table) {
 254                 pr_err("%s: unable to alloc memory\n", __func__);
 255                 return -ENOMEM;
 256         }
 257 
 258         for (k = 0; !ret && (k < nr); k++) {
 259                 clkp = clks + k;
 260 
 261                 clkp->ops = ops;
 262                 clkp->priv = table;
 263 
 264                 clkp->freq_table = freq_table + (k * freq_table_size);
 265                 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
 266 
 267                 ret = clk_register(clkp);
 268                 if (ret == 0)
 269                         ret = sh_clk_init_parent(clkp);
 270         }
 271 
 272         return ret;
 273 }
 274 
 275 /*
 276  * div6 support
 277  */
 278 static int sh_clk_div6_divisors[64] = {
 279         1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 280         17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
 281         33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
 282         49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
 283 };
 284 
 285 static struct clk_div_mult_table div6_div_mult_table = {
 286         .divisors = sh_clk_div6_divisors,
 287         .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
 288 };
 289 
 290 static struct clk_div_table sh_clk_div6_table = {
 291         .div_mult_table = &div6_div_mult_table,
 292 };
 293 
 294 static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
 295 {
 296         struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
 297         u32 value;
 298         int ret, i;
 299 
 300         if (!clk->parent_table || !clk->parent_num)
 301                 return -EINVAL;
 302 
 303         /* Search the parent */
 304         for (i = 0; i < clk->parent_num; i++)
 305                 if (clk->parent_table[i] == parent)
 306                         break;
 307 
 308         if (i == clk->parent_num)
 309                 return -ENODEV;
 310 
 311         ret = clk_reparent(clk, parent);
 312         if (ret < 0)
 313                 return ret;
 314 
 315         value = sh_clk_read(clk) &
 316                 ~(((1 << clk->src_width) - 1) << clk->src_shift);
 317 
 318         sh_clk_write(value | (i << clk->src_shift), clk);
 319 
 320         /* Rebuild the frequency table */
 321         clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
 322                              table, NULL);
 323 
 324         return 0;
 325 }
 326 
 327 static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
 328         .recalc         = sh_clk_div_recalc,
 329         .round_rate     = sh_clk_div_round_rate,
 330         .set_rate       = sh_clk_div_set_rate,
 331         .enable         = sh_clk_div_enable,
 332         .disable        = sh_clk_div_disable,
 333         .set_parent     = sh_clk_div6_set_parent,
 334 };
 335 
 336 int __init sh_clk_div6_register(struct clk *clks, int nr)
 337 {
 338         return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
 339                                        &sh_clk_div_enable_clk_ops);
 340 }
 341 
 342 int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
 343 {
 344         return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
 345                                        &sh_clk_div6_reparent_clk_ops);
 346 }
 347 
 348 /*
 349  * div4 support
 350  */
 351 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
 352 {
 353         struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
 354         u32 value;
 355         int ret;
 356 
 357         /* we really need a better way to determine parent index, but for
 358          * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
 359          * no CLK_ENABLE_ON_INIT means external clock...
 360          */
 361 
 362         if (parent->flags & CLK_ENABLE_ON_INIT)
 363                 value = sh_clk_read(clk) & ~(1 << 7);
 364         else
 365                 value = sh_clk_read(clk) | (1 << 7);
 366 
 367         ret = clk_reparent(clk, parent);
 368         if (ret < 0)
 369                 return ret;
 370 
 371         sh_clk_write(value, clk);
 372 
 373         /* Rebiuld the frequency table */
 374         clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
 375                              table, &clk->arch_flags);
 376 
 377         return 0;
 378 }
 379 
 380 static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
 381         .recalc         = sh_clk_div_recalc,
 382         .set_rate       = sh_clk_div_set_rate,
 383         .round_rate     = sh_clk_div_round_rate,
 384         .enable         = sh_clk_div_enable,
 385         .disable        = sh_clk_div_disable,
 386         .set_parent     = sh_clk_div4_set_parent,
 387 };
 388 
 389 int __init sh_clk_div4_register(struct clk *clks, int nr,
 390                                 struct clk_div4_table *table)
 391 {
 392         return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops);
 393 }
 394 
 395 int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
 396                                 struct clk_div4_table *table)
 397 {
 398         return sh_clk_div_register_ops(clks, nr, table,
 399                                        &sh_clk_div_enable_clk_ops);
 400 }
 401 
 402 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
 403                                 struct clk_div4_table *table)
 404 {
 405         return sh_clk_div_register_ops(clks, nr, table,
 406                                        &sh_clk_div4_reparent_clk_ops);
 407 }
 408 
 409 /* FSI-DIV */
 410 static unsigned long fsidiv_recalc(struct clk *clk)
 411 {
 412         u32 value;
 413 
 414         value = __raw_readl(clk->mapping->base);
 415 
 416         value >>= 16;
 417         if (value < 2)
 418                 return clk->parent->rate;
 419 
 420         return clk->parent->rate / value;
 421 }
 422 
 423 static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
 424 {
 425         return clk_rate_div_range_round(clk, 1, 0xffff, rate);
 426 }
 427 
 428 static void fsidiv_disable(struct clk *clk)
 429 {
 430         __raw_writel(0, clk->mapping->base);
 431 }
 432 
 433 static int fsidiv_enable(struct clk *clk)
 434 {
 435         u32 value;
 436 
 437         value  = __raw_readl(clk->mapping->base) >> 16;
 438         if (value < 2)
 439                 return 0;
 440 
 441         __raw_writel((value << 16) | 0x3, clk->mapping->base);
 442 
 443         return 0;
 444 }
 445 
 446 static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
 447 {
 448         int idx;
 449 
 450         idx = (clk->parent->rate / rate) & 0xffff;
 451         if (idx < 2)
 452                 __raw_writel(0, clk->mapping->base);
 453         else
 454                 __raw_writel(idx << 16, clk->mapping->base);
 455 
 456         return 0;
 457 }
 458 
 459 static struct sh_clk_ops fsidiv_clk_ops = {
 460         .recalc         = fsidiv_recalc,
 461         .round_rate     = fsidiv_round_rate,
 462         .set_rate       = fsidiv_set_rate,
 463         .enable         = fsidiv_enable,
 464         .disable        = fsidiv_disable,
 465 };
 466 
 467 int __init sh_clk_fsidiv_register(struct clk *clks, int nr)
 468 {
 469         struct clk_mapping *map;
 470         int i;
 471 
 472         for (i = 0; i < nr; i++) {
 473 
 474                 map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL);
 475                 if (!map) {
 476                         pr_err("%s: unable to alloc memory\n", __func__);
 477                         return -ENOMEM;
 478                 }
 479 
 480                 /* clks[i].enable_reg came from SH_CLK_FSIDIV() */
 481                 map->phys               = (phys_addr_t)clks[i].enable_reg;
 482                 map->len                = 8;
 483 
 484                 clks[i].enable_reg      = 0; /* remove .enable_reg */
 485                 clks[i].ops             = &fsidiv_clk_ops;
 486                 clks[i].mapping         = map;
 487 
 488                 clk_register(&clks[i]);
 489         }
 490 
 491         return 0;
 492 }

/* [<][>][^][v][top][bottom][index][help] */