exynos-cpufreq.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  3. * http://www.samsung.com
  4. *
  5. * EXYNOS - CPU frequency scaling support for EXYNOS series
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/err.h>
  13. #include <linux/clk.h>
  14. #include <linux/io.h>
  15. #include <linux/slab.h>
  16. #include <linux/regulator/consumer.h>
  17. #include <linux/cpufreq.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/of.h>
  20. #include "exynos-cpufreq.h"
  21. static struct exynos_dvfs_info *exynos_info;
  22. static struct regulator *arm_regulator;
  23. static unsigned int locking_frequency;
  24. static int exynos_cpufreq_get_index(unsigned int freq)
  25. {
  26. struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
  27. struct cpufreq_frequency_table *pos;
  28. cpufreq_for_each_entry(pos, freq_table)
  29. if (pos->frequency == freq)
  30. break;
  31. if (pos->frequency == CPUFREQ_TABLE_END)
  32. return -EINVAL;
  33. return pos - freq_table;
  34. }
  35. static int exynos_cpufreq_scale(unsigned int target_freq)
  36. {
  37. struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
  38. unsigned int *volt_table = exynos_info->volt_table;
  39. struct cpufreq_policy *policy = cpufreq_cpu_get(0);
  40. unsigned int arm_volt, safe_arm_volt = 0;
  41. unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
  42. struct device *dev = exynos_info->dev;
  43. unsigned int old_freq;
  44. int index, old_index;
  45. int ret = 0;
  46. old_freq = policy->cur;
  47. /*
  48. * The policy max have been changed so that we cannot get proper
  49. * old_index with cpufreq_frequency_table_target(). Thus, ignore
  50. * policy and get the index from the raw frequency table.
  51. */
  52. old_index = exynos_cpufreq_get_index(old_freq);
  53. if (old_index < 0) {
  54. ret = old_index;
  55. goto out;
  56. }
  57. index = exynos_cpufreq_get_index(target_freq);
  58. if (index < 0) {
  59. ret = index;
  60. goto out;
  61. }
  62. /*
  63. * ARM clock source will be changed APLL to MPLL temporary
  64. * To support this level, need to control regulator for
  65. * required voltage level
  66. */
  67. if (exynos_info->need_apll_change != NULL) {
  68. if (exynos_info->need_apll_change(old_index, index) &&
  69. (freq_table[index].frequency < mpll_freq_khz) &&
  70. (freq_table[old_index].frequency < mpll_freq_khz))
  71. safe_arm_volt = volt_table[exynos_info->pll_safe_idx];
  72. }
  73. arm_volt = volt_table[index];
  74. /* When the new frequency is higher than current frequency */
  75. if ((target_freq > old_freq) && !safe_arm_volt) {
  76. /* Firstly, voltage up to increase frequency */
  77. ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
  78. if (ret) {
  79. dev_err(dev, "failed to set cpu voltage to %d\n",
  80. arm_volt);
  81. return ret;
  82. }
  83. }
  84. if (safe_arm_volt) {
  85. ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
  86. safe_arm_volt);
  87. if (ret) {
  88. dev_err(dev, "failed to set cpu voltage to %d\n",
  89. safe_arm_volt);
  90. return ret;
  91. }
  92. }
  93. exynos_info->set_freq(old_index, index);
  94. /* When the new frequency is lower than current frequency */
  95. if ((target_freq < old_freq) ||
  96. ((target_freq > old_freq) && safe_arm_volt)) {
  97. /* down the voltage after frequency change */
  98. ret = regulator_set_voltage(arm_regulator, arm_volt,
  99. arm_volt);
  100. if (ret) {
  101. dev_err(dev, "failed to set cpu voltage to %d\n",
  102. arm_volt);
  103. goto out;
  104. }
  105. }
  106. out:
  107. cpufreq_cpu_put(policy);
  108. return ret;
  109. }
  110. static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
  111. {
  112. return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
  113. }
  114. static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
  115. {
  116. policy->clk = exynos_info->cpu_clk;
  117. policy->suspend_freq = locking_frequency;
  118. return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
  119. }
  120. static struct cpufreq_driver exynos_driver = {
  121. .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
  122. .verify = cpufreq_generic_frequency_table_verify,
  123. .target_index = exynos_target,
  124. .get = cpufreq_generic_get,
  125. .init = exynos_cpufreq_cpu_init,
  126. .name = "exynos_cpufreq",
  127. .attr = cpufreq_generic_attr,
  128. #ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
  129. .boost_supported = true,
  130. #endif
  131. #ifdef CONFIG_PM
  132. .suspend = cpufreq_generic_suspend,
  133. #endif
  134. };
  135. static int exynos_cpufreq_probe(struct platform_device *pdev)
  136. {
  137. int ret = -EINVAL;
  138. exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
  139. if (!exynos_info)
  140. return -ENOMEM;
  141. exynos_info->dev = &pdev->dev;
  142. if (of_machine_is_compatible("samsung,exynos4210")) {
  143. exynos_info->type = EXYNOS_SOC_4210;
  144. ret = exynos4210_cpufreq_init(exynos_info);
  145. } else if (of_machine_is_compatible("samsung,exynos4212")) {
  146. exynos_info->type = EXYNOS_SOC_4212;
  147. ret = exynos4x12_cpufreq_init(exynos_info);
  148. } else if (of_machine_is_compatible("samsung,exynos4412")) {
  149. exynos_info->type = EXYNOS_SOC_4412;
  150. ret = exynos4x12_cpufreq_init(exynos_info);
  151. } else if (of_machine_is_compatible("samsung,exynos5250")) {
  152. exynos_info->type = EXYNOS_SOC_5250;
  153. ret = exynos5250_cpufreq_init(exynos_info);
  154. } else {
  155. pr_err("%s: Unknown SoC type\n", __func__);
  156. return -ENODEV;
  157. }
  158. if (ret)
  159. goto err_vdd_arm;
  160. if (exynos_info->set_freq == NULL) {
  161. dev_err(&pdev->dev, "No set_freq function (ERR)\n");
  162. goto err_vdd_arm;
  163. }
  164. arm_regulator = regulator_get(NULL, "vdd_arm");
  165. if (IS_ERR(arm_regulator)) {
  166. dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
  167. goto err_vdd_arm;
  168. }
  169. /* Done here as we want to capture boot frequency */
  170. locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
  171. if (!cpufreq_register_driver(&exynos_driver))
  172. return 0;
  173. dev_err(&pdev->dev, "failed to register cpufreq driver\n");
  174. regulator_put(arm_regulator);
  175. err_vdd_arm:
  176. kfree(exynos_info);
  177. return -EINVAL;
  178. }
  179. static struct platform_driver exynos_cpufreq_platdrv = {
  180. .driver = {
  181. .name = "exynos-cpufreq",
  182. .owner = THIS_MODULE,
  183. },
  184. .probe = exynos_cpufreq_probe,
  185. };
  186. module_platform_driver(exynos_cpufreq_platdrv);