tegra20-cpufreq.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Copyright (C) 2010 Google, Inc.
  3. *
  4. * Author:
  5. * Colin Cross <ccross@google.com>
  6. * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
  7. *
  8. * This software is licensed under the terms of the GNU General Public
  9. * License version 2, as published by the Free Software Foundation, and
  10. * may be copied, distributed, and modified under those terms.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. */
  18. #include <linux/clk.h>
  19. #include <linux/cpufreq.h>
  20. #include <linux/err.h>
  21. #include <linux/init.h>
  22. #include <linux/module.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/types.h>
  25. static struct cpufreq_frequency_table freq_table[] = {
  26. { .frequency = 216000 },
  27. { .frequency = 312000 },
  28. { .frequency = 456000 },
  29. { .frequency = 608000 },
  30. { .frequency = 760000 },
  31. { .frequency = 816000 },
  32. { .frequency = 912000 },
  33. { .frequency = 1000000 },
  34. { .frequency = CPUFREQ_TABLE_END },
  35. };
  36. struct tegra20_cpufreq {
  37. struct device *dev;
  38. struct cpufreq_driver driver;
  39. struct clk *cpu_clk;
  40. struct clk *pll_x_clk;
  41. struct clk *pll_p_clk;
  42. bool pll_x_prepared;
  43. };
  44. static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
  45. unsigned int index)
  46. {
  47. struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
  48. unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000;
  49. /*
  50. * Don't switch to intermediate freq if:
  51. * - we are already at it, i.e. policy->cur == ifreq
  52. * - index corresponds to ifreq
  53. */
  54. if (freq_table[index].frequency == ifreq || policy->cur == ifreq)
  55. return 0;
  56. return ifreq;
  57. }
  58. static int tegra_target_intermediate(struct cpufreq_policy *policy,
  59. unsigned int index)
  60. {
  61. struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
  62. int ret;
  63. /*
  64. * Take an extra reference to the main pll so it doesn't turn
  65. * off when we move the cpu off of it as enabling it again while we
  66. * switch to it from tegra_target() would take additional time.
  67. *
  68. * When target-freq is equal to intermediate freq we don't need to
  69. * switch to an intermediate freq and so this routine isn't called.
  70. * Also, we wouldn't be using pll_x anymore and must not take extra
  71. * reference to it, as it can be disabled now to save some power.
  72. */
  73. clk_prepare_enable(cpufreq->pll_x_clk);
  74. ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk);
  75. if (ret)
  76. clk_disable_unprepare(cpufreq->pll_x_clk);
  77. else
  78. cpufreq->pll_x_prepared = true;
  79. return ret;
  80. }
  81. static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
  82. {
  83. struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
  84. unsigned long rate = freq_table[index].frequency;
  85. unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000;
  86. int ret;
  87. /*
  88. * target freq == pll_p, don't need to take extra reference to pll_x_clk
  89. * as it isn't used anymore.
  90. */
  91. if (rate == ifreq)
  92. return clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk);
  93. ret = clk_set_rate(cpufreq->pll_x_clk, rate * 1000);
  94. /* Restore to earlier frequency on error, i.e. pll_x */
  95. if (ret)
  96. dev_err(cpufreq->dev, "Failed to change pll_x to %lu\n", rate);
  97. ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_x_clk);
  98. /* This shouldn't fail while changing or restoring */
  99. WARN_ON(ret);
  100. /*
  101. * Drop count to pll_x clock only if we switched to intermediate freq
  102. * earlier while transitioning to a target frequency.
  103. */
  104. if (cpufreq->pll_x_prepared) {
  105. clk_disable_unprepare(cpufreq->pll_x_clk);
  106. cpufreq->pll_x_prepared = false;
  107. }
  108. return ret;
  109. }
  110. static int tegra_cpu_init(struct cpufreq_policy *policy)
  111. {
  112. struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
  113. int ret;
  114. clk_prepare_enable(cpufreq->cpu_clk);
  115. /* FIXME: what's the actual transition time? */
  116. ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
  117. if (ret) {
  118. clk_disable_unprepare(cpufreq->cpu_clk);
  119. return ret;
  120. }
  121. policy->clk = cpufreq->cpu_clk;
  122. policy->suspend_freq = freq_table[0].frequency;
  123. return 0;
  124. }
  125. static int tegra_cpu_exit(struct cpufreq_policy *policy)
  126. {
  127. struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
  128. clk_disable_unprepare(cpufreq->cpu_clk);
  129. return 0;
  130. }
  131. static int tegra20_cpufreq_probe(struct platform_device *pdev)
  132. {
  133. struct tegra20_cpufreq *cpufreq;
  134. int err;
  135. cpufreq = devm_kzalloc(&pdev->dev, sizeof(*cpufreq), GFP_KERNEL);
  136. if (!cpufreq)
  137. return -ENOMEM;
  138. cpufreq->cpu_clk = clk_get_sys(NULL, "cclk");
  139. if (IS_ERR(cpufreq->cpu_clk))
  140. return PTR_ERR(cpufreq->cpu_clk);
  141. cpufreq->pll_x_clk = clk_get_sys(NULL, "pll_x");
  142. if (IS_ERR(cpufreq->pll_x_clk)) {
  143. err = PTR_ERR(cpufreq->pll_x_clk);
  144. goto put_cpu;
  145. }
  146. cpufreq->pll_p_clk = clk_get_sys(NULL, "pll_p");
  147. if (IS_ERR(cpufreq->pll_p_clk)) {
  148. err = PTR_ERR(cpufreq->pll_p_clk);
  149. goto put_pll_x;
  150. }
  151. cpufreq->dev = &pdev->dev;
  152. cpufreq->driver.get = cpufreq_generic_get;
  153. cpufreq->driver.attr = cpufreq_generic_attr;
  154. cpufreq->driver.init = tegra_cpu_init;
  155. cpufreq->driver.exit = tegra_cpu_exit;
  156. cpufreq->driver.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK;
  157. cpufreq->driver.verify = cpufreq_generic_frequency_table_verify;
  158. cpufreq->driver.suspend = cpufreq_generic_suspend;
  159. cpufreq->driver.driver_data = cpufreq;
  160. cpufreq->driver.target_index = tegra_target;
  161. cpufreq->driver.get_intermediate = tegra_get_intermediate;
  162. cpufreq->driver.target_intermediate = tegra_target_intermediate;
  163. snprintf(cpufreq->driver.name, CPUFREQ_NAME_LEN, "tegra");
  164. err = cpufreq_register_driver(&cpufreq->driver);
  165. if (err)
  166. goto put_pll_p;
  167. platform_set_drvdata(pdev, cpufreq);
  168. return 0;
  169. put_pll_p:
  170. clk_put(cpufreq->pll_p_clk);
  171. put_pll_x:
  172. clk_put(cpufreq->pll_x_clk);
  173. put_cpu:
  174. clk_put(cpufreq->cpu_clk);
  175. return err;
  176. }
  177. static int tegra20_cpufreq_remove(struct platform_device *pdev)
  178. {
  179. struct tegra20_cpufreq *cpufreq = platform_get_drvdata(pdev);
  180. cpufreq_unregister_driver(&cpufreq->driver);
  181. clk_put(cpufreq->pll_p_clk);
  182. clk_put(cpufreq->pll_x_clk);
  183. clk_put(cpufreq->cpu_clk);
  184. return 0;
  185. }
  186. static struct platform_driver tegra20_cpufreq_driver = {
  187. .probe = tegra20_cpufreq_probe,
  188. .remove = tegra20_cpufreq_remove,
  189. .driver = {
  190. .name = "tegra20-cpufreq",
  191. },
  192. };
  193. module_platform_driver(tegra20_cpufreq_driver);
  194. MODULE_ALIAS("platform:tegra20-cpufreq");
  195. MODULE_AUTHOR("Colin Cross <ccross@android.com>");
  196. MODULE_DESCRIPTION("NVIDIA Tegra20 cpufreq driver");
  197. MODULE_LICENSE("GPL");