clk-master.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. */
  10. #include <linux/clk-provider.h>
  11. #include <linux/clkdev.h>
  12. #include <linux/clk/at91_pmc.h>
  13. #include <linux/of.h>
  14. #include <linux/mfd/syscon.h>
  15. #include <linux/regmap.h>
  16. #include "pmc.h"
  17. #define MASTER_PRES_MASK 0x7
  18. #define MASTER_PRES_MAX MASTER_PRES_MASK
  19. #define MASTER_DIV_SHIFT 8
  20. #define MASTER_DIV_MASK 0x3
  21. #define to_clk_master(hw) container_of(hw, struct clk_master, hw)
  22. struct clk_master {
  23. struct clk_hw hw;
  24. struct regmap *regmap;
  25. const struct clk_master_layout *layout;
  26. const struct clk_master_characteristics *characteristics;
  27. };
  28. static inline bool clk_master_ready(struct regmap *regmap)
  29. {
  30. unsigned int status;
  31. regmap_read(regmap, AT91_PMC_SR, &status);
  32. return status & AT91_PMC_MCKRDY ? 1 : 0;
  33. }
  34. static int clk_master_prepare(struct clk_hw *hw)
  35. {
  36. struct clk_master *master = to_clk_master(hw);
  37. while (!clk_master_ready(master->regmap))
  38. cpu_relax();
  39. return 0;
  40. }
  41. static int clk_master_is_prepared(struct clk_hw *hw)
  42. {
  43. struct clk_master *master = to_clk_master(hw);
  44. return clk_master_ready(master->regmap);
  45. }
  46. static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
  47. unsigned long parent_rate)
  48. {
  49. u8 pres;
  50. u8 div;
  51. unsigned long rate = parent_rate;
  52. struct clk_master *master = to_clk_master(hw);
  53. const struct clk_master_layout *layout = master->layout;
  54. const struct clk_master_characteristics *characteristics =
  55. master->characteristics;
  56. unsigned int mckr;
  57. regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
  58. mckr &= layout->mask;
  59. pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
  60. div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
  61. if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
  62. rate /= 3;
  63. else
  64. rate >>= pres;
  65. rate /= characteristics->divisors[div];
  66. if (rate < characteristics->output.min)
  67. pr_warn("master clk is underclocked");
  68. else if (rate > characteristics->output.max)
  69. pr_warn("master clk is overclocked");
  70. return rate;
  71. }
  72. static u8 clk_master_get_parent(struct clk_hw *hw)
  73. {
  74. struct clk_master *master = to_clk_master(hw);
  75. unsigned int mckr;
  76. regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
  77. return mckr & AT91_PMC_CSS;
  78. }
  79. static const struct clk_ops master_ops = {
  80. .prepare = clk_master_prepare,
  81. .is_prepared = clk_master_is_prepared,
  82. .recalc_rate = clk_master_recalc_rate,
  83. .get_parent = clk_master_get_parent,
  84. };
  85. struct clk_hw * __init
  86. at91_clk_register_master(struct regmap *regmap,
  87. const char *name, int num_parents,
  88. const char **parent_names,
  89. const struct clk_master_layout *layout,
  90. const struct clk_master_characteristics *characteristics)
  91. {
  92. struct clk_master *master;
  93. struct clk_init_data init;
  94. struct clk_hw *hw;
  95. int ret;
  96. if (!name || !num_parents || !parent_names)
  97. return ERR_PTR(-EINVAL);
  98. master = kzalloc(sizeof(*master), GFP_KERNEL);
  99. if (!master)
  100. return ERR_PTR(-ENOMEM);
  101. init.name = name;
  102. init.ops = &master_ops;
  103. init.parent_names = parent_names;
  104. init.num_parents = num_parents;
  105. init.flags = 0;
  106. master->hw.init = &init;
  107. master->layout = layout;
  108. master->characteristics = characteristics;
  109. master->regmap = regmap;
  110. hw = &master->hw;
  111. ret = clk_hw_register(NULL, &master->hw);
  112. if (ret) {
  113. kfree(master);
  114. hw = ERR_PTR(ret);
  115. }
  116. return hw;
  117. }
  118. const struct clk_master_layout at91rm9200_master_layout = {
  119. .mask = 0x31F,
  120. .pres_shift = 2,
  121. };
  122. const struct clk_master_layout at91sam9x5_master_layout = {
  123. .mask = 0x373,
  124. .pres_shift = 4,
  125. };