clk-device.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/clk.h>
  3. #include <linux/clk-provider.h>
  4. #include <linux/mutex.h>
  5. #include <linux/of_device.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/pm_domain.h>
  8. #include <linux/pm_opp.h>
  9. #include <linux/pm_runtime.h>
  10. #include <linux/slab.h>
  11. #include <soc/tegra/common.h>
  12. #include "clk.h"
  13. /*
  14. * This driver manages performance state of the core power domain for the
  15. * independent PLLs and system clocks. We created a virtual clock device
  16. * for such clocks, see tegra_clk_dev_register().
  17. */
  18. struct tegra_clk_device {
  19. struct notifier_block clk_nb;
  20. struct device *dev;
  21. struct clk_hw *hw;
  22. struct mutex lock;
  23. };
  24. static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev,
  25. unsigned long rate)
  26. {
  27. struct device *dev = clk_dev->dev;
  28. struct dev_pm_opp *opp;
  29. unsigned int pstate;
  30. opp = dev_pm_opp_find_freq_ceil(dev, &rate);
  31. if (opp == ERR_PTR(-ERANGE)) {
  32. /*
  33. * Some clocks may be unused by a particular board and they
  34. * may have uninitiated clock rate that is overly high. In
  35. * this case clock is expected to be disabled, but still we
  36. * need to set up performance state of the power domain and
  37. * not error out clk initialization. A typical example is
  38. * a PCIe clock on Android tablets.
  39. */
  40. dev_dbg(dev, "failed to find ceil OPP for %luHz\n", rate);
  41. opp = dev_pm_opp_find_freq_floor(dev, &rate);
  42. }
  43. if (IS_ERR(opp)) {
  44. dev_err(dev, "failed to find OPP for %luHz: %pe\n", rate, opp);
  45. return PTR_ERR(opp);
  46. }
  47. pstate = dev_pm_opp_get_required_pstate(opp, 0);
  48. dev_pm_opp_put(opp);
  49. return dev_pm_genpd_set_performance_state(dev, pstate);
  50. }
  51. static int tegra_clock_change_notify(struct notifier_block *nb,
  52. unsigned long msg, void *data)
  53. {
  54. struct clk_notifier_data *cnd = data;
  55. struct tegra_clk_device *clk_dev;
  56. int err = 0;
  57. clk_dev = container_of(nb, struct tegra_clk_device, clk_nb);
  58. mutex_lock(&clk_dev->lock);
  59. switch (msg) {
  60. case PRE_RATE_CHANGE:
  61. if (cnd->new_rate > cnd->old_rate)
  62. err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
  63. break;
  64. case ABORT_RATE_CHANGE:
  65. err = tegra_clock_set_pd_state(clk_dev, cnd->old_rate);
  66. break;
  67. case POST_RATE_CHANGE:
  68. if (cnd->new_rate < cnd->old_rate)
  69. err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
  70. break;
  71. default:
  72. break;
  73. }
  74. mutex_unlock(&clk_dev->lock);
  75. return notifier_from_errno(err);
  76. }
  77. static int tegra_clock_sync_pd_state(struct tegra_clk_device *clk_dev)
  78. {
  79. unsigned long rate;
  80. int ret;
  81. mutex_lock(&clk_dev->lock);
  82. rate = clk_hw_get_rate(clk_dev->hw);
  83. ret = tegra_clock_set_pd_state(clk_dev, rate);
  84. mutex_unlock(&clk_dev->lock);
  85. return ret;
  86. }
  87. static int tegra_clock_probe(struct platform_device *pdev)
  88. {
  89. struct tegra_core_opp_params opp_params = {};
  90. struct tegra_clk_device *clk_dev;
  91. struct device *dev = &pdev->dev;
  92. struct clk *clk;
  93. int err;
  94. if (!dev->pm_domain)
  95. return -EINVAL;
  96. clk_dev = devm_kzalloc(dev, sizeof(*clk_dev), GFP_KERNEL);
  97. if (!clk_dev)
  98. return -ENOMEM;
  99. clk = devm_clk_get(dev, NULL);
  100. if (IS_ERR(clk))
  101. return PTR_ERR(clk);
  102. clk_dev->dev = dev;
  103. clk_dev->hw = __clk_get_hw(clk);
  104. clk_dev->clk_nb.notifier_call = tegra_clock_change_notify;
  105. mutex_init(&clk_dev->lock);
  106. platform_set_drvdata(pdev, clk_dev);
  107. /*
  108. * Runtime PM was already enabled for this device by the parent clk
  109. * driver and power domain state should be synced under clk_dev lock,
  110. * hence we don't use the common OPP helper that initializes OPP
  111. * state. For some clocks common OPP helper may fail to find ceil
  112. * rate, it's handled by this driver.
  113. */
  114. err = devm_tegra_core_dev_init_opp_table(dev, &opp_params);
  115. if (err)
  116. return err;
  117. err = clk_notifier_register(clk, &clk_dev->clk_nb);
  118. if (err) {
  119. dev_err(dev, "failed to register clk notifier: %d\n", err);
  120. return err;
  121. }
  122. /*
  123. * The driver is attaching to a potentially active/resumed clock, hence
  124. * we need to sync the power domain performance state in a accordance to
  125. * the clock rate if clock is resumed.
  126. */
  127. err = tegra_clock_sync_pd_state(clk_dev);
  128. if (err)
  129. goto unreg_clk;
  130. return 0;
  131. unreg_clk:
  132. clk_notifier_unregister(clk, &clk_dev->clk_nb);
  133. return err;
  134. }
  135. /*
  136. * Tegra GENPD driver enables clocks during NOIRQ phase. It can't be done
  137. * for clocks served by this driver because runtime PM is unavailable in
  138. * NOIRQ phase. We will keep clocks resumed during suspend to mitigate this
  139. * problem. In practice this makes no difference from a power management
  140. * perspective since voltage is kept at a nominal level during suspend anyways.
  141. */
  142. static const struct dev_pm_ops tegra_clock_pm = {
  143. SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_resume_and_get, pm_runtime_put)
  144. };
  145. static const struct of_device_id tegra_clock_match[] = {
  146. { .compatible = "nvidia,tegra20-sclk" },
  147. { .compatible = "nvidia,tegra30-sclk" },
  148. { .compatible = "nvidia,tegra30-pllc" },
  149. { .compatible = "nvidia,tegra30-plle" },
  150. { .compatible = "nvidia,tegra30-pllm" },
  151. { }
  152. };
  153. static struct platform_driver tegra_clock_driver = {
  154. .driver = {
  155. .name = "tegra-clock",
  156. .of_match_table = tegra_clock_match,
  157. .pm = &tegra_clock_pm,
  158. .suppress_bind_attrs = true,
  159. },
  160. .probe = tegra_clock_probe,
  161. };
  162. builtin_platform_driver(tegra_clock_driver);