clk-spmi-pmic-div.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2017, The Linux Foundation. All rights reserved.
  3. */
  4. #include <linux/bitops.h>
  5. #include <linux/clk.h>
  6. #include <linux/clk-provider.h>
  7. #include <linux/delay.h>
  8. #include <linux/err.h>
  9. #include <linux/log2.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/regmap.h>
  14. #include <linux/slab.h>
  15. #include <linux/types.h>
  16. #define REG_DIV_CTL1 0x43
  17. #define DIV_CTL1_DIV_FACTOR_MASK GENMASK(2, 0)
  18. #define REG_EN_CTL 0x46
  19. #define REG_EN_MASK BIT(7)
  20. struct clkdiv {
  21. struct regmap *regmap;
  22. u16 base;
  23. spinlock_t lock;
  24. struct clk_hw hw;
  25. unsigned int cxo_period_ns;
  26. };
  27. static inline struct clkdiv *to_clkdiv(struct clk_hw *hw)
  28. {
  29. return container_of(hw, struct clkdiv, hw);
  30. }
  31. static inline unsigned int div_factor_to_div(unsigned int div_factor)
  32. {
  33. if (!div_factor)
  34. div_factor = 1;
  35. return 1 << (div_factor - 1);
  36. }
  37. static inline unsigned int div_to_div_factor(unsigned int div)
  38. {
  39. return min(ilog2(div) + 1, 7);
  40. }
  41. static bool is_spmi_pmic_clkdiv_enabled(struct clkdiv *clkdiv)
  42. {
  43. unsigned int val = 0;
  44. regmap_read(clkdiv->regmap, clkdiv->base + REG_EN_CTL, &val);
  45. return val & REG_EN_MASK;
  46. }
  47. static int
  48. __spmi_pmic_clkdiv_set_enable_state(struct clkdiv *clkdiv, bool enable,
  49. unsigned int div_factor)
  50. {
  51. int ret;
  52. unsigned int ns = clkdiv->cxo_period_ns;
  53. unsigned int div = div_factor_to_div(div_factor);
  54. ret = regmap_update_bits(clkdiv->regmap, clkdiv->base + REG_EN_CTL,
  55. REG_EN_MASK, enable ? REG_EN_MASK : 0);
  56. if (ret)
  57. return ret;
  58. if (enable)
  59. ndelay((2 + 3 * div) * ns);
  60. else
  61. ndelay(3 * div * ns);
  62. return 0;
  63. }
  64. static int spmi_pmic_clkdiv_set_enable_state(struct clkdiv *clkdiv, bool enable)
  65. {
  66. unsigned int div_factor;
  67. regmap_read(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, &div_factor);
  68. div_factor &= DIV_CTL1_DIV_FACTOR_MASK;
  69. return __spmi_pmic_clkdiv_set_enable_state(clkdiv, enable, div_factor);
  70. }
  71. static int clk_spmi_pmic_div_enable(struct clk_hw *hw)
  72. {
  73. struct clkdiv *clkdiv = to_clkdiv(hw);
  74. unsigned long flags;
  75. int ret;
  76. spin_lock_irqsave(&clkdiv->lock, flags);
  77. ret = spmi_pmic_clkdiv_set_enable_state(clkdiv, true);
  78. spin_unlock_irqrestore(&clkdiv->lock, flags);
  79. return ret;
  80. }
  81. static void clk_spmi_pmic_div_disable(struct clk_hw *hw)
  82. {
  83. struct clkdiv *clkdiv = to_clkdiv(hw);
  84. unsigned long flags;
  85. spin_lock_irqsave(&clkdiv->lock, flags);
  86. spmi_pmic_clkdiv_set_enable_state(clkdiv, false);
  87. spin_unlock_irqrestore(&clkdiv->lock, flags);
  88. }
  89. static long clk_spmi_pmic_div_round_rate(struct clk_hw *hw, unsigned long rate,
  90. unsigned long *parent_rate)
  91. {
  92. unsigned int div, div_factor;
  93. div = DIV_ROUND_UP(*parent_rate, rate);
  94. div_factor = div_to_div_factor(div);
  95. div = div_factor_to_div(div_factor);
  96. return *parent_rate / div;
  97. }
  98. static unsigned long
  99. clk_spmi_pmic_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  100. {
  101. struct clkdiv *clkdiv = to_clkdiv(hw);
  102. unsigned int div_factor;
  103. regmap_read(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, &div_factor);
  104. div_factor &= DIV_CTL1_DIV_FACTOR_MASK;
  105. return parent_rate / div_factor_to_div(div_factor);
  106. }
  107. static int clk_spmi_pmic_div_set_rate(struct clk_hw *hw, unsigned long rate,
  108. unsigned long parent_rate)
  109. {
  110. struct clkdiv *clkdiv = to_clkdiv(hw);
  111. unsigned int div_factor = div_to_div_factor(parent_rate / rate);
  112. unsigned long flags;
  113. bool enabled;
  114. int ret;
  115. spin_lock_irqsave(&clkdiv->lock, flags);
  116. enabled = is_spmi_pmic_clkdiv_enabled(clkdiv);
  117. if (enabled) {
  118. ret = spmi_pmic_clkdiv_set_enable_state(clkdiv, false);
  119. if (ret)
  120. goto unlock;
  121. }
  122. ret = regmap_update_bits(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1,
  123. DIV_CTL1_DIV_FACTOR_MASK, div_factor);
  124. if (ret)
  125. goto unlock;
  126. if (enabled)
  127. ret = __spmi_pmic_clkdiv_set_enable_state(clkdiv, true,
  128. div_factor);
  129. unlock:
  130. spin_unlock_irqrestore(&clkdiv->lock, flags);
  131. return ret;
  132. }
  133. static const struct clk_ops clk_spmi_pmic_div_ops = {
  134. .enable = clk_spmi_pmic_div_enable,
  135. .disable = clk_spmi_pmic_div_disable,
  136. .set_rate = clk_spmi_pmic_div_set_rate,
  137. .recalc_rate = clk_spmi_pmic_div_recalc_rate,
  138. .round_rate = clk_spmi_pmic_div_round_rate,
  139. };
  140. struct spmi_pmic_div_clk_cc {
  141. int nclks;
  142. struct clkdiv clks[] __counted_by(nclks);
  143. };
  144. static struct clk_hw *
  145. spmi_pmic_div_clk_hw_get(struct of_phandle_args *clkspec, void *data)
  146. {
  147. struct spmi_pmic_div_clk_cc *cc = data;
  148. int idx = clkspec->args[0] - 1; /* Start at 1 instead of 0 */
  149. if (idx < 0 || idx >= cc->nclks) {
  150. pr_err("%s: index value %u is invalid; allowed range [1, %d]\n",
  151. __func__, clkspec->args[0], cc->nclks);
  152. return ERR_PTR(-EINVAL);
  153. }
  154. return &cc->clks[idx].hw;
  155. }
  156. static int spmi_pmic_clkdiv_probe(struct platform_device *pdev)
  157. {
  158. struct spmi_pmic_div_clk_cc *cc;
  159. struct clk_init_data init = {};
  160. struct clkdiv *clkdiv;
  161. struct clk *cxo;
  162. struct regmap *regmap;
  163. struct device *dev = &pdev->dev;
  164. struct device_node *of_node = dev->of_node;
  165. struct clk_parent_data parent_data = { .index = 0, };
  166. int nclks, i, ret, cxo_hz;
  167. char name[20];
  168. u32 start;
  169. ret = of_property_read_u32(of_node, "reg", &start);
  170. if (ret < 0) {
  171. dev_err(dev, "reg property reading failed\n");
  172. return ret;
  173. }
  174. regmap = dev_get_regmap(dev->parent, NULL);
  175. if (!regmap) {
  176. dev_err(dev, "Couldn't get parent's regmap\n");
  177. return -EINVAL;
  178. }
  179. ret = of_property_read_u32(of_node, "qcom,num-clkdivs", &nclks);
  180. if (ret < 0) {
  181. dev_err(dev, "qcom,num-clkdivs property reading failed, ret=%d\n",
  182. ret);
  183. return ret;
  184. }
  185. if (!nclks)
  186. return -EINVAL;
  187. cc = devm_kzalloc(dev, struct_size(cc, clks, nclks), GFP_KERNEL);
  188. if (!cc)
  189. return -ENOMEM;
  190. cc->nclks = nclks;
  191. cxo = clk_get(dev, "xo");
  192. if (IS_ERR(cxo)) {
  193. ret = PTR_ERR(cxo);
  194. if (ret != -EPROBE_DEFER)
  195. dev_err(dev, "failed to get xo clock\n");
  196. return ret;
  197. }
  198. cxo_hz = clk_get_rate(cxo);
  199. clk_put(cxo);
  200. init.name = name;
  201. init.parent_data = &parent_data;
  202. init.num_parents = 1;
  203. init.ops = &clk_spmi_pmic_div_ops;
  204. for (i = 0, clkdiv = cc->clks; i < nclks; i++) {
  205. snprintf(name, sizeof(name), "div_clk%d", i + 1);
  206. spin_lock_init(&clkdiv[i].lock);
  207. clkdiv[i].base = start + i * 0x100;
  208. clkdiv[i].regmap = regmap;
  209. clkdiv[i].cxo_period_ns = NSEC_PER_SEC / cxo_hz;
  210. clkdiv[i].hw.init = &init;
  211. ret = devm_clk_hw_register(dev, &clkdiv[i].hw);
  212. if (ret)
  213. return ret;
  214. }
  215. return devm_of_clk_add_hw_provider(dev, spmi_pmic_div_clk_hw_get, cc);
  216. }
  217. static const struct of_device_id spmi_pmic_clkdiv_match_table[] = {
  218. { .compatible = "qcom,spmi-clkdiv" },
  219. { /* sentinel */ }
  220. };
  221. MODULE_DEVICE_TABLE(of, spmi_pmic_clkdiv_match_table);
  222. static struct platform_driver spmi_pmic_clkdiv_driver = {
  223. .driver = {
  224. .name = "qcom,spmi-pmic-clkdiv",
  225. .of_match_table = spmi_pmic_clkdiv_match_table,
  226. },
  227. .probe = spmi_pmic_clkdiv_probe,
  228. };
  229. module_platform_driver(spmi_pmic_clkdiv_driver);
  230. MODULE_DESCRIPTION("QCOM SPMI PMIC clkdiv driver");
  231. MODULE_LICENSE("GPL v2");