icc-clk.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (c) 2023, Linaro Ltd.
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/device.h>
  7. #include <linux/interconnect-clk.h>
  8. #include <linux/interconnect-provider.h>
  9. struct icc_clk_node {
  10. struct clk *clk;
  11. bool enabled;
  12. };
  13. struct icc_clk_provider {
  14. struct icc_provider provider;
  15. int num_clocks;
  16. struct icc_clk_node clocks[] __counted_by(num_clocks);
  17. };
  18. #define to_icc_clk_provider(_provider) \
  19. container_of(_provider, struct icc_clk_provider, provider)
  20. static int icc_clk_set(struct icc_node *src, struct icc_node *dst)
  21. {
  22. struct icc_clk_node *qn = src->data;
  23. int ret;
  24. if (!qn || !qn->clk)
  25. return 0;
  26. if (!src->peak_bw) {
  27. if (qn->enabled)
  28. clk_disable_unprepare(qn->clk);
  29. qn->enabled = false;
  30. return 0;
  31. }
  32. if (!qn->enabled) {
  33. ret = clk_prepare_enable(qn->clk);
  34. if (ret)
  35. return ret;
  36. qn->enabled = true;
  37. }
  38. return clk_set_rate(qn->clk, icc_units_to_bps(src->peak_bw));
  39. }
  40. static int icc_clk_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
  41. {
  42. struct icc_clk_node *qn = node->data;
  43. if (!qn || !qn->clk)
  44. *peak = INT_MAX;
  45. else
  46. *peak = Bps_to_icc(clk_get_rate(qn->clk));
  47. return 0;
  48. }
  49. /**
  50. * icc_clk_register() - register a new clk-based interconnect provider
  51. * @dev: device supporting this provider
  52. * @first_id: an ID of the first provider's node
  53. * @num_clocks: number of instances of struct icc_clk_data
  54. * @data: data for the provider
  55. *
  56. * Registers and returns a clk-based interconnect provider. It is a simple
  57. * wrapper around COMMON_CLK framework, allowing other devices to vote on the
  58. * clock rate.
  59. *
  60. * Return: 0 on success, or an error code otherwise
  61. */
  62. struct icc_provider *icc_clk_register(struct device *dev,
  63. unsigned int first_id,
  64. unsigned int num_clocks,
  65. const struct icc_clk_data *data)
  66. {
  67. struct icc_clk_provider *qp;
  68. struct icc_provider *provider;
  69. struct icc_onecell_data *onecell;
  70. struct icc_node *node;
  71. int ret, i, j;
  72. onecell = devm_kzalloc(dev, struct_size(onecell, nodes, 2 * num_clocks), GFP_KERNEL);
  73. if (!onecell)
  74. return ERR_PTR(-ENOMEM);
  75. onecell->num_nodes = 2 * num_clocks;
  76. qp = devm_kzalloc(dev, struct_size(qp, clocks, num_clocks), GFP_KERNEL);
  77. if (!qp)
  78. return ERR_PTR(-ENOMEM);
  79. qp->num_clocks = num_clocks;
  80. provider = &qp->provider;
  81. provider->dev = dev;
  82. provider->get_bw = icc_clk_get_bw;
  83. provider->set = icc_clk_set;
  84. provider->aggregate = icc_std_aggregate;
  85. provider->xlate = of_icc_xlate_onecell;
  86. INIT_LIST_HEAD(&provider->nodes);
  87. provider->data = onecell;
  88. icc_provider_init(provider);
  89. for (i = 0, j = 0; i < num_clocks; i++) {
  90. qp->clocks[i].clk = data[i].clk;
  91. node = icc_node_create(first_id + data[i].master_id);
  92. if (IS_ERR(node)) {
  93. ret = PTR_ERR(node);
  94. goto err;
  95. }
  96. node->name = devm_kasprintf(dev, GFP_KERNEL, "%s_master", data[i].name);
  97. if (!node->name) {
  98. icc_node_destroy(node->id);
  99. ret = -ENOMEM;
  100. goto err;
  101. }
  102. node->data = &qp->clocks[i];
  103. icc_node_add(node, provider);
  104. /* link to the next node, slave */
  105. icc_link_create(node, first_id + data[i].slave_id);
  106. onecell->nodes[j++] = node;
  107. node = icc_node_create(first_id + data[i].slave_id);
  108. if (IS_ERR(node)) {
  109. ret = PTR_ERR(node);
  110. goto err;
  111. }
  112. node->name = devm_kasprintf(dev, GFP_KERNEL, "%s_slave", data[i].name);
  113. if (!node->name) {
  114. icc_node_destroy(node->id);
  115. ret = -ENOMEM;
  116. goto err;
  117. }
  118. /* no data for slave node */
  119. icc_node_add(node, provider);
  120. onecell->nodes[j++] = node;
  121. }
  122. ret = icc_provider_register(provider);
  123. if (ret)
  124. goto err;
  125. return provider;
  126. err:
  127. icc_nodes_remove(provider);
  128. return ERR_PTR(ret);
  129. }
  130. EXPORT_SYMBOL_GPL(icc_clk_register);
  131. static void devm_icc_release(void *res)
  132. {
  133. icc_clk_unregister(res);
  134. }
  135. int devm_icc_clk_register(struct device *dev, unsigned int first_id,
  136. unsigned int num_clocks, const struct icc_clk_data *data)
  137. {
  138. struct icc_provider *prov;
  139. prov = icc_clk_register(dev, first_id, num_clocks, data);
  140. if (IS_ERR(prov))
  141. return PTR_ERR(prov);
  142. return devm_add_action_or_reset(dev, devm_icc_release, prov);
  143. }
  144. EXPORT_SYMBOL_GPL(devm_icc_clk_register);
  145. /**
  146. * icc_clk_unregister() - unregister a previously registered clk interconnect provider
  147. * @provider: provider returned by icc_clk_register()
  148. */
  149. void icc_clk_unregister(struct icc_provider *provider)
  150. {
  151. struct icc_clk_provider *qp = container_of(provider, struct icc_clk_provider, provider);
  152. int i;
  153. icc_provider_deregister(&qp->provider);
  154. icc_nodes_remove(&qp->provider);
  155. for (i = 0; i < qp->num_clocks; i++) {
  156. struct icc_clk_node *qn = &qp->clocks[i];
  157. if (qn->enabled)
  158. clk_disable_unprepare(qn->clk);
  159. }
  160. }
  161. EXPORT_SYMBOL_GPL(icc_clk_unregister);
  162. MODULE_LICENSE("GPL");
  163. MODULE_DESCRIPTION("Interconnect wrapper for clocks");
  164. MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");