2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
5 * EXYNOS - CPU frequency scaling support for EXYNOS series
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.
12 #include <linux/kernel.h>
13 #include <linux/err.h>
14 #include <linux/clk.h>
16 #include <linux/slab.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/cpufreq.h>
19 #include <linux/platform_device.h>
23 #include "exynos-cpufreq.h"
25 static struct exynos_dvfs_info
*exynos_info
;
26 static struct regulator
*arm_regulator
;
27 static unsigned int locking_frequency
;
29 static int exynos_cpufreq_get_index(unsigned int freq
)
31 struct cpufreq_frequency_table
*freq_table
= exynos_info
->freq_table
;
35 freq_table
[index
].frequency
!= CPUFREQ_TABLE_END
; index
++)
36 if (freq_table
[index
].frequency
== freq
)
39 if (freq_table
[index
].frequency
== CPUFREQ_TABLE_END
)
45 static int exynos_cpufreq_scale(unsigned int target_freq
)
47 struct cpufreq_frequency_table
*freq_table
= exynos_info
->freq_table
;
48 unsigned int *volt_table
= exynos_info
->volt_table
;
49 struct cpufreq_policy
*policy
= cpufreq_cpu_get(0);
50 unsigned int arm_volt
, safe_arm_volt
= 0;
51 unsigned int mpll_freq_khz
= exynos_info
->mpll_freq_khz
;
52 unsigned int old_freq
;
56 old_freq
= policy
->cur
;
59 * The policy max have been changed so that we cannot get proper
60 * old_index with cpufreq_frequency_table_target(). Thus, ignore
61 * policy and get the index from the raw frequency table.
63 old_index
= exynos_cpufreq_get_index(old_freq
);
69 index
= exynos_cpufreq_get_index(target_freq
);
76 * ARM clock source will be changed APLL to MPLL temporary
77 * To support this level, need to control regulator for
78 * required voltage level
80 if (exynos_info
->need_apll_change
!= NULL
) {
81 if (exynos_info
->need_apll_change(old_index
, index
) &&
82 (freq_table
[index
].frequency
< mpll_freq_khz
) &&
83 (freq_table
[old_index
].frequency
< mpll_freq_khz
))
84 safe_arm_volt
= volt_table
[exynos_info
->pll_safe_idx
];
86 arm_volt
= volt_table
[index
];
88 /* When the new frequency is higher than current frequency */
89 if ((target_freq
> old_freq
) && !safe_arm_volt
) {
90 /* Firstly, voltage up to increase frequency */
91 ret
= regulator_set_voltage(arm_regulator
, arm_volt
, arm_volt
);
93 pr_err("%s: failed to set cpu voltage to %d\n",
100 ret
= regulator_set_voltage(arm_regulator
, safe_arm_volt
,
103 pr_err("%s: failed to set cpu voltage to %d\n",
104 __func__
, safe_arm_volt
);
109 exynos_info
->set_freq(old_index
, index
);
111 /* When the new frequency is lower than current frequency */
112 if ((target_freq
< old_freq
) ||
113 ((target_freq
> old_freq
) && safe_arm_volt
)) {
114 /* down the voltage after frequency change */
115 ret
= regulator_set_voltage(arm_regulator
, arm_volt
,
118 pr_err("%s: failed to set cpu voltage to %d\n",
125 cpufreq_cpu_put(policy
);
130 static int exynos_target(struct cpufreq_policy
*policy
, unsigned int index
)
132 return exynos_cpufreq_scale(exynos_info
->freq_table
[index
].frequency
);
135 static int exynos_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
137 policy
->clk
= exynos_info
->cpu_clk
;
138 policy
->suspend_freq
= locking_frequency
;
139 return cpufreq_generic_init(policy
, exynos_info
->freq_table
, 100000);
142 static struct cpufreq_driver exynos_driver
= {
143 .flags
= CPUFREQ_STICKY
| CPUFREQ_NEED_INITIAL_FREQ_CHECK
,
144 .verify
= cpufreq_generic_frequency_table_verify
,
145 .target_index
= exynos_target
,
146 .get
= cpufreq_generic_get
,
147 .init
= exynos_cpufreq_cpu_init
,
148 .name
= "exynos_cpufreq",
149 .attr
= cpufreq_generic_attr
,
150 #ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
151 .boost_supported
= true,
154 .suspend
= cpufreq_generic_suspend
,
158 static int exynos_cpufreq_probe(struct platform_device
*pdev
)
162 exynos_info
= kzalloc(sizeof(*exynos_info
), GFP_KERNEL
);
166 if (soc_is_exynos4210())
167 ret
= exynos4210_cpufreq_init(exynos_info
);
168 else if (soc_is_exynos4212() || soc_is_exynos4412())
169 ret
= exynos4x12_cpufreq_init(exynos_info
);
170 else if (soc_is_exynos5250())
171 ret
= exynos5250_cpufreq_init(exynos_info
);
178 if (exynos_info
->set_freq
== NULL
) {
179 pr_err("%s: No set_freq function (ERR)\n", __func__
);
183 arm_regulator
= regulator_get(NULL
, "vdd_arm");
184 if (IS_ERR(arm_regulator
)) {
185 pr_err("%s: failed to get resource vdd_arm\n", __func__
);
189 /* Done here as we want to capture boot frequency */
190 locking_frequency
= clk_get_rate(exynos_info
->cpu_clk
) / 1000;
192 if (!cpufreq_register_driver(&exynos_driver
))
195 pr_err("%s: failed to register cpufreq driver\n", __func__
);
196 regulator_put(arm_regulator
);
202 static struct platform_driver exynos_cpufreq_platdrv
= {
204 .name
= "exynos-cpufreq",
205 .owner
= THIS_MODULE
,
207 .probe
= exynos_cpufreq_probe
,
209 module_platform_driver(exynos_cpufreq_platdrv
);